]> git.ipfire.org Git - thirdparty/git.git/commitdiff
Merge branch 'js/format-2047'
authorJeff King <peff@peff.net>
Fri, 9 Nov 2012 17:42:32 +0000 (12:42 -0500)
committerJeff King <peff@peff.net>
Fri, 9 Nov 2012 17:42:32 +0000 (12:42 -0500)
Fixes many rfc2047 quoting issues in the output from format-patch.

* js/format-2047:
  format-patch tests: check quoting/encoding in To: and Cc: headers
  format-patch: fix rfc2047 address encoding with respect to rfc822 specials
  format-patch: make rfc2047 encoding more strict
  format-patch: introduce helper function last_line_length()
  format-patch: do not wrap rfc2047 encoded headers too late
  format-patch: do not wrap non-rfc2047 headers too early
  utf8: fix off-by-one wrapping of text

475 files changed:
.gitignore
.mailmap
Documentation/Makefile
Documentation/RelNotes/1.5.2.1.txt
Documentation/RelNotes/1.6.0.2.txt
Documentation/RelNotes/1.6.1.3.txt
Documentation/RelNotes/1.6.1.4.txt
Documentation/RelNotes/1.6.1.txt
Documentation/RelNotes/1.7.12.1.txt [new file with mode: 0644]
Documentation/RelNotes/1.7.12.2.txt [new file with mode: 0644]
Documentation/RelNotes/1.7.12.3.txt [new file with mode: 0644]
Documentation/RelNotes/1.7.12.4.txt [new file with mode: 0644]
Documentation/RelNotes/1.7.12.txt [new file with mode: 0644]
Documentation/RelNotes/1.8.0.txt [new file with mode: 0644]
Documentation/config.txt
Documentation/diff-config.txt
Documentation/fetch-options.txt
Documentation/git-add.txt
Documentation/git-apply.txt
Documentation/git-blame.txt
Documentation/git-branch.txt
Documentation/git-cherry-pick.txt
Documentation/git-clean.txt
Documentation/git-clone.txt
Documentation/git-commit.txt
Documentation/git-config.txt
Documentation/git-credential-cache--daemon.txt
Documentation/git-credential-cache.txt
Documentation/git-credential-store.txt
Documentation/git-credential.txt [new file with mode: 0644]
Documentation/git-daemon.txt
Documentation/git-difftool.txt
Documentation/git-fast-import.txt
Documentation/git-filter-branch.txt
Documentation/git-for-each-ref.txt
Documentation/git-format-patch.txt
Documentation/git-grep.txt
Documentation/git-log.txt
Documentation/git-ls-remote.txt
Documentation/git-merge-base.txt
Documentation/git-merge.txt
Documentation/git-mergetool.txt
Documentation/git-p4.txt
Documentation/git-push.txt
Documentation/git-rebase.txt
Documentation/git-remote-helpers.txt
Documentation/git-remote.txt
Documentation/git-reset.txt
Documentation/git-rev-parse.txt
Documentation/git-rm.txt
Documentation/git-shortlog.txt
Documentation/git-status.txt
Documentation/git-submodule.txt
Documentation/git-svn.txt
Documentation/git.txt
Documentation/gitattributes.txt
Documentation/gitcli.txt
Documentation/gitcore-tutorial.txt
Documentation/gitignore.txt
Documentation/gitmodules.txt
Documentation/gitrepository-layout.txt
Documentation/gittutorial.txt
Documentation/merge-config.txt
Documentation/merge-strategies.txt
Documentation/pretty-formats.txt
Documentation/pretty-options.txt
Documentation/rev-list-options.txt
Documentation/revisions.txt
Documentation/technical/api-argv-array.txt
Documentation/technical/api-credentials.txt
Documentation/technical/api-sha1-array.txt
Documentation/technical/api-string-list.txt
Documentation/technical/pack-protocol.txt
Documentation/urls.txt
Documentation/user-manual.txt
GIT-VERSION-GEN
Makefile
RelNotes
abspath.c
archive-zip.c
archive.c
argv-array.c
argv-array.h
attr.c
bisect.c
branch.c
builtin.h
builtin/add.c
builtin/apply.c
builtin/archive.c
builtin/bisect--helper.c
builtin/blame.c
builtin/branch.c
builtin/cat-file.c
builtin/check-attr.c
builtin/checkout-index.c
builtin/checkout.c
builtin/clean.c
builtin/clone.c
builtin/column.c
builtin/commit-tree.c
builtin/commit.c
builtin/config.c
builtin/count-objects.c
builtin/credential.c [new file with mode: 0644]
builtin/describe.c
builtin/fast-export.c
builtin/fetch-pack.c
builtin/fetch.c
builtin/fmt-merge-msg.c
builtin/for-each-ref.c
builtin/fsck.c
builtin/gc.c
builtin/grep.c
builtin/hash-object.c
builtin/help.c
builtin/index-pack.c
builtin/init-db.c
builtin/log.c
builtin/ls-files.c
builtin/ls-remote.c
builtin/ls-tree.c
builtin/mailinfo.c
builtin/merge-base.c
builtin/merge-file.c
builtin/merge.c
builtin/mktree.c
builtin/mv.c
builtin/name-rev.c
builtin/notes.c
builtin/pack-objects.c
builtin/pack-refs.c
builtin/prune-packed.c
builtin/prune.c
builtin/push.c
builtin/read-tree.c
builtin/receive-pack.c
builtin/reflog.c
builtin/remote.c
builtin/replace.c
builtin/rerere.c
builtin/reset.c
builtin/rev-parse.c
builtin/revert.c
builtin/rm.c
builtin/send-pack.c
builtin/shortlog.c
builtin/show-branch.c
builtin/show-ref.c
builtin/symbolic-ref.c
builtin/tag.c
builtin/update-index.c
builtin/update-ref.c
builtin/update-server-info.c
builtin/verify-pack.c
builtin/verify-tag.c
builtin/write-tree.c
cache.h
command-list.txt
commit.c
commit.h
compat/mingw.c
compat/mingw.h
compat/mkdir.c [new file with mode: 0644]
compat/poll/poll.c [moved from compat/win32/poll.c with 97% similarity]
compat/poll/poll.h [moved from compat/win32/poll.h with 100% similarity]
compat/precompose_utf8.c [new file with mode: 0644]
compat/precompose_utf8.h [new file with mode: 0644]
config.c
config.mak.in
configure.ac
connect.c
contrib/completion/git-completion.bash [changed mode: 0755->0644]
contrib/completion/git-prompt.sh [new file with mode: 0644]
contrib/credential/gnome-keyring/.gitignore [new file with mode: 0644]
contrib/credential/gnome-keyring/Makefile [new file with mode: 0644]
contrib/credential/gnome-keyring/git-credential-gnome-keyring.c [new file with mode: 0644]
contrib/credential/wincred/Makefile [new file with mode: 0644]
contrib/credential/wincred/git-credential-wincred.c [new file with mode: 0644]
contrib/examples/builtin-fetch--tool.c
contrib/git-jump/git-jump
contrib/hooks/post-receive-email
contrib/mw-to-git/Makefile [new file with mode: 0644]
contrib/mw-to-git/git-remote-mediawiki
contrib/mw-to-git/t/.gitignore [new file with mode: 0644]
contrib/mw-to-git/t/Makefile [new file with mode: 0644]
contrib/mw-to-git/t/README [new file with mode: 0644]
contrib/mw-to-git/t/install-wiki.sh [new file with mode: 0755]
contrib/mw-to-git/t/install-wiki/.gitignore [new file with mode: 0644]
contrib/mw-to-git/t/install-wiki/LocalSettings.php [new file with mode: 0644]
contrib/mw-to-git/t/install-wiki/db_install.php [new file with mode: 0644]
contrib/mw-to-git/t/push-pull-tests.sh [new file with mode: 0644]
contrib/mw-to-git/t/t9360-mw-to-git-clone.sh [new file with mode: 0755]
contrib/mw-to-git/t/t9361-mw-to-git-push-pull.sh [new file with mode: 0755]
contrib/mw-to-git/t/t9362-mw-to-git-utf8.sh [new file with mode: 0755]
contrib/mw-to-git/t/t9363-mw-to-git-export-import.sh [new file with mode: 0755]
contrib/mw-to-git/t/t9364-pull-by-rev.sh [new file with mode: 0755]
contrib/mw-to-git/t/test-gitmw-lib.sh [new file with mode: 0755]
contrib/mw-to-git/t/test-gitmw.pl [new file with mode: 0755]
contrib/mw-to-git/t/test.config [new file with mode: 0644]
contrib/svn-fe/svn-fe.c
contrib/svn-fe/svnrdump_sim.py [new file with mode: 0755]
credential.c
credential.h
daemon.c
diff.c
diff.h
dir.c
dir.h
environment.c
fast-import.c
fetch-pack.h
gettext.c
gettext.h
git-am.sh
git-compat-util.h
git-cvsimport.perl
git-difftool.perl
git-filter-branch.sh
git-gui/GIT-VERSION-GEN
git-gui/git-gui.sh
git-gui/lib/commit.tcl
git-gui/lib/status_bar.tcl
git-gui/macosx/AppMain.tcl
git-gui/po/de.po
git-gui/po/fr.po
git-gui/po/git-gui.pot
git-gui/po/hu.po
git-gui/po/it.po
git-gui/po/ja.po
git-gui/po/nb.po
git-gui/po/pt_br.po
git-gui/po/ru.po
git-gui/po/sv.po
git-mergetool--lib.sh
git-p4.py
git-pull.sh
git-rebase--am.sh
git-rebase--interactive.sh
git-rebase--merge.sh
git-rebase.sh
git-send-email.perl
git-sh-setup.sh
git-submodule.sh
git-svn.perl
git.c
gitk-git/gitk
gitweb/gitweb.perl
graph.c
graph.h
grep.c
grep.h
help.c
http-push.c
http-walker.c
http.c
http.h
ident.c
ll-merge.c
mailmap.c
merge-recursive.c
mergetools/codecompare [new file with mode: 0644]
mergetools/defaults
mergetools/p4merge
notes-merge.c
notes.c
notes.h
pager.c
parse-options.c
parse-options.h
path.c
perl/.gitignore
perl/Git/IndexInfo.pm [new file with mode: 0644]
perl/Git/SVN.pm [new file with mode: 0644]
perl/Git/SVN/Editor.pm
perl/Git/SVN/Fetcher.pm
perl/Git/SVN/GlobSpec.pm [new file with mode: 0644]
perl/Git/SVN/Log.pm [new file with mode: 0644]
perl/Git/SVN/Migration.pm [new file with mode: 0644]
perl/Git/SVN/Ra.pm
perl/Git/SVN/Utils.pm [new file with mode: 0644]
perl/Makefile
perl/Makefile.PL
pkt-line.c
pkt-line.h
po/TEAMS
po/de.po
po/git.pot
po/sv.po
po/vi.po
po/zh_CN.po
read-cache.c
refs.c
remote-curl.c
remote-testsvn.c [new file with mode: 0644]
rerere.c
rerere.h
revision.c
revision.h
run-command.c
run-command.h
sequencer.c
sequencer.h
setup.c
sha1-array.c
sha1-array.h
sha1_file.c
sha1_name.c
strbuf.c
strbuf.h
string-list.c
string-list.h
submodule.c
submodule.h
symlinks.c
t/Git-SVN/00compile.t [new file with mode: 0644]
t/Git-SVN/Utils/add_path_to_url.t [new file with mode: 0644]
t/Git-SVN/Utils/can_compress.t [new file with mode: 0644]
t/Git-SVN/Utils/canonicalize_url.t [new file with mode: 0644]
t/Git-SVN/Utils/collapse_dotdot.t [new file with mode: 0644]
t/Git-SVN/Utils/fatal.t [new file with mode: 0644]
t/Git-SVN/Utils/join_paths.t [new file with mode: 0644]
t/README
t/lib-bash.sh [new file with mode: 0644]
t/lib-credential.sh
t/lib-git-p4.sh
t/lib-httpd.sh
t/lib-httpd/apache.conf
t/perf/.gitignore
t/perf/perf-lib.sh
t/t0000-basic.sh
t/t0003-attributes.sh
t/t0006-date.sh
t/t0040-parse-options.sh
t/t0050-filesystem.sh
t/t0060-path-utils.sh
t/t0063-string-list.sh [new file with mode: 0755]
t/t0201-gettext-fallbacks.sh
t/t0300-credentials.sh
t/t1050-large.sh
t/t1100-commit-tree-options.sh
t/t1300-repo-config.sh
t/t1304-default-acl.sh
t/t1306-xdg-files.sh [new file with mode: 0755]
t/t1450-fsck.sh
t/t1502-rev-parse-parseopt.sh
t/t1512-rev-parse-disambiguation.sh [new file with mode: 0755]
t/t2006-checkout-index-basic.sh
t/t2107-update-index-basic.sh
t/t3001-ls-files-others-exclude.sh
t/t3004-ls-files-basic.sh
t/t3200-branch.sh
t/t3300-funny-names.sh
t/t3400-rebase.sh
t/t3404-rebase-interactive.sh
t/t3405-rebase-malformed.sh
t/t3406-rebase-message.sh
t/t3412-rebase-root.sh
t/t3501-revert-cherry-pick.sh
t/t3505-cherry-pick-empty.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/t3902-quoted.sh
t/t3903-stash.sh
t/t3910-mac-os-precompose.sh [new file with mode: 0755]
t/t4006-diff-mode.sh
t/t4012-diff-binary.sh
t/t4016-diff-quote.sh
t/t4018-diff-funcname.sh
t/t4034-diff-words.sh
t/t4034/ada/expect [new file with mode: 0644]
t/t4034/ada/post [new file with mode: 0644]
t/t4034/ada/pre [new file with mode: 0644]
t/t4055-diff-context.sh [new file with mode: 0755]
t/t4108-apply-threeway.sh [new file with mode: 0755]
t/t4117-apply-reject.sh
t/t4120-apply-popt.sh
t/t4133-apply-filenames.sh
t/t4200-rerere.sh
t/t4202-log.sh
t/t4205-log-pretty-formats.sh
t/t5100-mailinfo.sh
t/t5100/info0017 [new file with mode: 0644]
t/t5100/msg0017 [new file with mode: 0644]
t/t5100/patch0017 [new file with mode: 0644]
t/t5100/sample.mbox
t/t5300-pack-object.sh
t/t5400-send-pack.sh
t/t5500-fetch-pack.sh
t/t5504-fetch-receive-strict.sh
t/t5505-remote.sh
t/t5512-ls-remote.sh
t/t5514-fetch-multiple.sh
t/t5530-upload-pack-error.sh
t/t5540-http-push.sh
t/t5541-http-push.sh
t/t5550-http-fetch.sh
t/t5551-http-fetch.sh
t/t5701-clone-local.sh
t/t5709-clone-refspec.sh [new file with mode: 0755]
t/t5800-remote-helpers.sh
t/t6022-merge-rename.sh
t/t6037-merge-ours-theirs.sh
t/t6042-merge-rename-corner-cases.sh
t/t6500-gc.sh
t/t7003-filter-branch.sh
t/t7008-grep-binary.sh
t/t7060-wtstatus.sh
t/t7400-submodule-basic.sh
t/t7403-submodule-sync.sh
t/t7406-submodule-update.sh
t/t7409-submodule-detached-worktree.sh [new file with mode: 0755]
t/t7502-commit.sh
t/t7508-status.sh
t/t7512-status-help.sh [new file with mode: 0755]
t/t7600-merge.sh
t/t7610-mergetool.sh
t/t7800-difftool.sh
t/t7810-grep.sh
t/t8004-blame-with-conflicts.sh
t/t9020-remote-svn.sh [new file with mode: 0755]
t/t9107-git-svn-migrate.sh
t/t9118-git-svn-funky-branch-names.sh
t/t9154-git-svn-fancy-glob.sh
t/t9163-git-svn-reset-clears-caches.sh [new file with mode: 0755]
t/t9164-git-svn-dcommit-concurrent.sh [new file with mode: 0755]
t/t9165-git-svn-fetch-merge-branch-of-branch.sh [new file with mode: 0755]
t/t9166-git-svn-fetch-merge-branch-of-branch2.sh [new file with mode: 0755]
t/t9200-git-cvsexportcommit.sh
t/t9800-git-p4-basic.sh
t/t9801-git-p4-branch.sh
t/t9805-git-p4-skip-submit-edit.sh
t/t9806-git-p4-options.sh
t/t9807-git-p4-submit.sh
t/t9808-git-p4-chdir.sh
t/t9809-git-p4-client-view.sh
t/t9810-git-p4-rcs.sh
t/t9812-git-p4-wildcards.sh [new file with mode: 0755]
t/t9813-git-p4-preserve-users.sh [new file with mode: 0755]
t/t9814-git-p4-rename.sh [new file with mode: 0755]
t/t9815-git-p4-submit-fail.sh [new file with mode: 0755]
t/t9902-completion.sh
t/t9903-bash-prompt.sh [new file with mode: 0755]
t/test-lib-functions.sh
t/test-lib.sh
test-credential.c [deleted file]
test-line-buffer.c
test-string-list.c [new file with mode: 0644]
test-svn-fe.c
trace.c
transport-helper.c
transport.c
transport.h
tree.c
unpack-trees.c
upload-pack.c
userdiff.c
utf8.c
utf8.h
vcs-svn/fast_export.c
vcs-svn/fast_export.h
vcs-svn/line_buffer.c
vcs-svn/line_buffer.h
vcs-svn/sliding_window.c
vcs-svn/svndiff.c
vcs-svn/svndump.c
vcs-svn/svndump.h
version.c [new file with mode: 0644]
version.h [new file with mode: 0644]
wrapper.c
write_or_die.c
wt-status.c
wt-status.h

index f1acd3e777f5b8be846b3bdabf4743b84ad4fbca..f702415c12c5a4a66180f7ffd697347e5343ac4a 100644 (file)
@@ -2,6 +2,9 @@
 /GIT-CFLAGS
 /GIT-LDFLAGS
 /GIT-GUI-VARS
+/GIT-PREFIX
+/GIT-SCRIPT-DEFINES
+/GIT-USER-AGENT
 /GIT-VERSION-FILE
 /bin-wrappers/
 /git
@@ -31,6 +34,7 @@
 /git-commit-tree
 /git-config
 /git-count-objects
+/git-credential
 /git-credential-cache
 /git-credential-cache--daemon
 /git-credential-store
 /git-remote-fd
 /git-remote-ext
 /git-remote-testgit
+/git-remote-testsvn
 /git-repack
 /git-replace
 /git-repo-config
 /gitweb/static/gitweb.js
 /gitweb/static/gitweb.min.*
 /test-chmtime
-/test-credential
 /test-ctype
 /test-date
 /test-delta
 /test-run-command
 /test-sha1
 /test-sigchain
+/test-string-list
 /test-subprocess
 /test-svn-fe
 /common-cmds.h
index 6303782106cc733dd06ad6e85c866610aa020c65..bcf4f8770f0751a61cf1c1b89a0d66cff559c54e 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -18,6 +18,7 @@ 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>
+Erik Faye-Lund <kusmabite@gmail.com> <kusmabite@googlemail.com>
 Fredrik Kuivinen <freku045@student.liu.se>
 H. Peter Anvin <hpa@bonde.sc.orionmulti.com>
 H. Peter Anvin <hpa@tazenda.sc.orionmulti.com>
@@ -26,6 +27,9 @@ Horst H. von Brand <vonbrand@inf.utfsm.cl>
 İsmail Dönmez <ismail@pardus.org.tr>
 Jay Soffian <jaysoffian+git@gmail.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>
+Johannes Sixt <j6t@kdbg.org> <J.Sixt@eudaptics.com>
 Jon Loeliger <jdl@freescale.com>
 Jon Seymour <jon@blackcubes.dyndns.org>
 Jonathan Nieder <jrnieder@uchicago.edu>
@@ -43,6 +47,7 @@ Lars Doelle <lars.doelle@on-line.de>
 Li Hong <leehong@pku.edu.cn>
 Lukas Sandström <lukass@etek.chalmers.se>
 Martin Langhoff <martin@laptop.org>
+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>
 Michael W. Olson <mwolson@gnu.org>
@@ -51,7 +56,10 @@ Nanako Shiraishi <nanako3@bluebottle.com>
 Nanako Shiraishi <nanako3@lavabit.com>
 Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
 <nico@fluxnic.net> <nico@cam.org>
+Peter Krefting <peter@softwolves.pp.se> <peter@svarten.intern.softwolves.pp.se>
+Peter Krefting <peter@softwolves.pp.se> <peter@softwolves.pp.se>
 Philippe Bruhat <book@cpan.org>
+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>
@@ -61,6 +69,7 @@ Sean Estabrooks <seanlkml@sympatico.ca>
 Shawn O. Pearce <spearce@spearce.org>
 Steven Grimm <koreth@midwinter.com>
 Theodore Ts'o <tytso@mit.edu>
+Thomas Rast <trast@inf.ethz.ch> <trast@student.ethz.ch>
 Tony Luck <tony.luck@intel.com>
 Uwe Kleine-König <Uwe_Zeisberger@digi.com>
 Uwe Kleine-König <Uwe.Kleine-Koenig@digi.com>
index 5d76a840781bcd4b48157057bb439bdac691766e..267dfe135ddef1d5e6cc452d6fdcd8b22b9e36a2 100644 (file)
@@ -44,9 +44,10 @@ man5dir=$(mandir)/man5
 man7dir=$(mandir)/man7
 # DESTDIR=
 
-ASCIIDOC=asciidoc
+ASCIIDOC = asciidoc
 ASCIIDOC_EXTRA =
 MANPAGE_XSL = manpage-normal.xsl
+XMLTO = xmlto
 XMLTO_EXTRA =
 INSTALL?=install
 RM ?= rm -f
@@ -65,12 +66,6 @@ endif
 -include ../config.mak.autogen
 -include ../config.mak
 
-#
-# For asciidoc ...
-#      -7.1.2, set ASCIIDOC7
-#      8.0-,   no extra settings are needed
-#
-
 #
 # For docbook-xsl ...
 #      -1.68.1,        no extra settings are needed?
@@ -81,9 +76,6 @@ endif
 #      1.73.0-,        no extra settings are needed
 #
 
-ifndef ASCIIDOC7
-ASCIIDOC_EXTRA += -a asciidoc7compatible
-endif
 ifdef DOCBOOK_XSL_172
 ASCIIDOC_EXTRA += -a git-asciidoc-no-roff
 MANPAGE_XSL = manpage-1.72.xsl
@@ -134,15 +126,6 @@ DEFAULT_EDITOR_SQ = $(subst ','\'',$(DEFAULT_EDITOR))
 ASCIIDOC_EXTRA += -a 'git-default-editor=$(DEFAULT_EDITOR_SQ)'
 endif
 
-#
-# Please note that there is a minor bug in asciidoc.
-# The version after 6.0.3 _will_ include the patch found here:
-#   http://marc.theaimsgroup.com/?l=git&m=111558757202243&w=2
-#
-# Until that version is released you may have to apply the patch
-# yourself - yes, all 6 characters of it!
-#
-
 QUIET_SUBDIR0  = +$(MAKE) -C # space to separate -C and subdir
 QUIET_SUBDIR1  =
 
@@ -263,7 +246,7 @@ manpage-base-url.xsl: manpage-base-url.xsl.in
 
 %.1 %.5 %.7 : %.xml manpage-base-url.xsl
        $(QUIET_XMLTO)$(RM) $@ && \
-       xmlto -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $<
+       $(XMLTO) -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $<
 
 %.xml : %.txt
        $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
@@ -362,4 +345,7 @@ require-htmlrepo::
 quick-install-html: require-htmlrepo
        '$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(HTML_REPO) $(DESTDIR)$(htmldir)
 
+print-man1:
+       @for i in $(MAN1_TXT); do echo $$i; done
+
 .PHONY: FORCE
index ebf20e22a74284f7085a5027f588ba295fb767d0..d41984df0b6b78edd5a37d290ad25da106777a76 100644 (file)
@@ -45,9 +45,3 @@ Fixes since v1.5.2
   - git-fastimport --import-marks was broken; fixed.
 
   - A lot of documentation updates, clarifications and fixes.
-
---
-exec >/var/tmp/1
-O=v1.5.2-65-g996e2d6
-echo O=`git describe refs/heads/maint`
-git shortlog --no-merges $O..refs/heads/maint
index e1e24b3295d4079c1bf784d11a8d6ec1691ec819..7d8fb85e1b49d9e842cbb66950057a5b80fe3594 100644 (file)
@@ -79,9 +79,3 @@ Fixes since v1.6.0.1
   packfile.
 
 Also contains many documentation updates.
-
---
-exec >/var/tmp/1
-O=v1.6.0.1-78-g3632cfc
-echo O=$(git describe maint)
-git shortlog --no-merges $O..maint
index 6f0bde156a038e75f1c6e2d9b6ada17390c0174a..cd08d8174ec124ac4cf4d1553e129791810ab913 100644 (file)
@@ -26,7 +26,3 @@ Fixes since v1.6.1.2
 * RPM binary package installed the html manpages in a wrong place.
 
 Also includes minor documentation fixes and updates.
-
-
---
-git shortlog --no-merges v1.6.1.2-33-gc789350..
index 0ce6316d75356500faf7e830eca54f9618064701..ccbad794c0345da05e3217ad189d95e4def762cb 100644 (file)
@@ -39,6 +39,3 @@ Fixes since v1.6.1.3
   This fix was first merged to 1.6.2.3.
 
 Also includes minor documentation fixes and updates.
-
---
-git shortlog --no-merges v1.6.1.3..
index adb7ccab0a4dc3895f46a1cff840988554f62ec4..7b152a6fdc5d29f1a321e939a7bc63fa3b8b1e79 100644 (file)
@@ -278,9 +278,3 @@ release, unless otherwise noted.
 
 * "gitweb" did not mark non-ASCII characters imported from external HTML fragments
   correctly.
-
---
-exec >/var/tmp/1
-O=v1.6.1-rc3-74-gf66bc5f
-echo O=$(git describe master)
-git shortlog --no-merges $O..master ^maint
diff --git a/Documentation/RelNotes/1.7.12.1.txt b/Documentation/RelNotes/1.7.12.1.txt
new file mode 100644 (file)
index 0000000..b8f04af
--- /dev/null
@@ -0,0 +1,134 @@
+Git 1.7.12.1 Release Notes
+==========================
+
+Fixes since v1.7.12
+-------------------
+
+ * "git apply -p0" did not parse pathnames on "diff --git" line
+   correctly.  This caused patches that had pathnames in no other
+   places to be mistakenly rejected (most notably, binary patch that
+   does not rename nor change mode).  Textual patches, renames or mode
+   changes have preimage and postimage pathnames in different places
+   in a form that can be parsed unambiguously and did not suffer from
+   this problem.
+
+ * "git cherry-pick A C B" used to replay changes in A and then B and
+   then C if these three commits had committer timestamps in that
+   order, which is not what the user who said "A C B" naturally
+   expects.
+
+ * "git commit --amend" let the user edit the log message and then
+   died when the human-readable committer name was given
+   insufficiently by getpwent(3).
+
+ * Some capabilities were asked by fetch-pack even when upload-pack
+   did not advertise that they are available.  fetch-pack has been
+   fixed not to do so.
+
+ * "git diff" had a confusion between taking data from a path in the
+   working tree and taking data from an object that happens to have
+   name 0{40} recorded in a tree.
+
+ * "git for-each-ref" did not correctly support more than one --sort
+   option.
+
+ * "git log .." errored out saying it is both rev range and a path
+   when there is no disambiguating "--" is on the command line.
+   Update the command line parser to interpret ".." as a path in such
+   a case.
+
+ * The "--topo-order", "--date-order" (and the lack of either means
+   the default order) options to "rev-list" and "log" family of
+   commands were poorly described in the documentation.
+
+ * "git prune" without "-v" used to warn about leftover temporary
+   files (which is an indication of an earlier aborted operation).
+
+ * Pushing to smart HTTP server with recent Git fails without having
+   the username in the URL to force authentication, if the server is
+   configured to allow GET anonymously, while requiring authentication
+   for POST.
+
+ * The reflog entries left by "git rebase" and "git rebase -i" were
+   inconsistent (the interactive one gave an abbreviated object name).
+
+ * When "git push" triggered the automatic gc on the receiving end, a
+   message from "git prune" that said it was removing cruft leaked to
+   the standard output, breaking the communication protocol.
+
+ * "git show --quiet" ought to be a synonym for "git show -s", but
+   wasn't.
+
+ * "git show --format='%ci'" did not give timestamp correctly for
+   commits created without human readable name on "committer" line.
+
+ * "git send-email" did not unquote encoded words that appear on the
+   header correctly, and lost "_" from strings.
+
+ * The interactive prompt "git send-email" gives was error prone. It
+   asked "What e-mail address do you want to use?" with the address it
+   guessed (correctly) the user would want to use in its prompt,
+   tempting the user to say "y". But the response was taken as "No,
+   please use 'y' as the e-mail address instead", which is most
+   certainly not what the user meant.
+
+ * "gitweb" when used with PATH_INFO failed to notice directories with
+   SP (and other characters that need URL-style quoting) in them.
+
+ * When the user gives an argument that can be taken as both a
+   revision name and a pathname without disambiguating with "--", we
+   used to give a help message "Use '--' to separate".  The message
+   has been clarified to show where that '--' goes on the command
+   line.
+
+ * When the user exports a non-default IFS without HT, scripts that
+   rely on being able to parse "ls-files -s | while read a b c..."
+   started to fail.  Protect them from such a misconfiguration.
+
+ * The attribute system may be asked for a path that itself or its
+   leading directories no longer exists in the working tree, and it is
+   fine if we cannot open .gitattribute file in such a case.  Failure
+   to open per-directory .gitattributes with error status other than
+   ENOENT and ENOTDIR should be diagnosed, but it wasn't.
+
+ * After "gitk" showed the contents of a tag, neither "Reread
+   references" nor "Reload" did not update what is shown as the
+   contents of it, when the user overwrote the tag with "git tag -f".
+
+ * "ciabot" script (in contrib/) has been updated with extensive
+   documentation.
+
+ * "git-jump" script (in contrib/) did not work well when
+   diff.noprefix or diff.mnemonicprefix is in effect.
+
+ * Older parts of the documentation described as if having a regular
+   file in .git/refs/ hierarchy were the only way to have branches and
+   tags, which is not true for quite some time.
+
+ * A utility shell function test_seq has been added as a replacement
+   for the 'seq' utility found on some platforms.
+
+ * Compatibility wrapper to learn the maximum number of file
+   descriptors we can open around sysconf(_SC_OPEN_MAX) and
+   getrlimit(RLIMIT_NO_FILE) has been introduced for portability.
+
+ * We used curl_easy_strerror() without checking version of cURL,
+   breaking the build for versions before curl 7.12.0.
+
+ * Code to work around MacOS X UTF-8 gotcha has been cleaned up.
+
+ * Fallback 'getpass' implementation made unportable use of stdio API.
+
+ * The "--rebase" option to "git pull" can be abbreviated to "-r",
+   but we didn't document it.
+
+ * It was generally understood that "--long-option"s to many of our
+   subcommands can be abbreviated to the unique prefix, but it was not
+   easy to find it described for new readers of the documentation set.
+
+ * The synopsis said "checkout [-B branch]" to make it clear the
+   branch name is a parameter to the option, but the heading for the
+   option description was "-B::", not "-B branch::", making the
+   documentation misleading.
+
+Also contains numerous documentation updates.
diff --git a/Documentation/RelNotes/1.7.12.2.txt b/Documentation/RelNotes/1.7.12.2.txt
new file mode 100644 (file)
index 0000000..6925574
--- /dev/null
@@ -0,0 +1,40 @@
+Git 1.7.12.2 Release Notes
+==========================
+
+Fixes since v1.7.12.1
+---------------------
+
+ * When "git am" is fed an input that has multiple "Content-type: ..."
+   header, it did not grok charset= attribute correctly.
+
+ * Even during a conflicted merge, "git blame $path" always meant to
+   blame uncommitted changes to the "working tree" version; make it
+   more useful by showing cleanly merged parts as coming from the other
+   branch that is being merged.
+
+ * "git blame MAKEFILE" run in a history that has "Makefile" but not
+   "MAKEFILE" should say "No such file MAKEFILE in HEAD", but got
+   confused on a case insensitive filesystem and failed to do so.
+
+ * "git fetch --all", when passed "--no-tags", did not honor the
+   "--no-tags" option while fetching from individual remotes (the same
+   issue existed with "--tags", but combination "--all --tags" makes
+   much less sense than "--all --no-tags").
+
+ * "git log/diff/format-patch --stat" showed the "N line(s) added"
+   comment in user's locale and caused careless submitters to send
+   patches with such a line in them to projects whose project language
+   is not their language, mildly irritating others. Localization to
+   the line has been disabled for now.
+
+ * "git log --all-match --grep=A --grep=B" ought to show commits that
+   mention both A and B, but when these three options are used with
+   --author or --committer, it showed commits that mention either A or
+   B (or both) instead.
+
+ * The subcommand to remove the definition of a remote in "git remote"
+   was named "rm" even though all other subcommands were spelled out.
+   Introduce "git remote remove" to remove confusion, and keep "rm" as
+   a backward compatible synonym.
+
+Also contains a handful of documentation updates.
diff --git a/Documentation/RelNotes/1.7.12.3.txt b/Documentation/RelNotes/1.7.12.3.txt
new file mode 100644 (file)
index 0000000..ecda427
--- /dev/null
@@ -0,0 +1,34 @@
+Git 1.7.12.3 Release Notes
+==========================
+
+Fixes since v1.7.12.2
+---------------------
+
+ * "git am" mishandled a patch attached as application/octet-stream
+   (e.g. not text/*); Content-Transfer-Encoding (e.g. base64) was not
+   honored correctly.
+
+ * It was unclear in the documentation for "git blame" that it is
+   unnecessary for users to use the "--follow" option.
+
+ * A repository created with "git clone --single" had its fetch
+   refspecs set up just like a clone without "--single", leading the
+   subsequent "git fetch" to slurp all the other branches, defeating
+   the whole point of specifying "only this branch".
+
+ * "git fetch" over http had an old workaround for an unlikely server
+   misconfiguration; it turns out that this hurts debuggability of the
+   configuration in general, and has been reverted.
+
+ * "git fetch" over http advertised that it supports "deflate", which
+   is much less common, and did not advertise the more common "gzip" on
+   its Accept-Encoding header.
+
+ * "git receive-pack" (the counterpart to "git push") did not give
+   progress output while processing objects it received to the puser
+   when run over the smart-http protocol.
+
+ * "git status" honored the ignore=dirty settings in .gitmodules but
+   "git commit" didn't.
+
+Also contains a handful of documentation updates.
diff --git a/Documentation/RelNotes/1.7.12.4.txt b/Documentation/RelNotes/1.7.12.4.txt
new file mode 100644 (file)
index 0000000..c6da3cc
--- /dev/null
@@ -0,0 +1,23 @@
+Git 1.7.12.4 Release Notes
+==========================
+
+Fixes since v1.7.12.3
+---------------------
+
+ * "git fetch" over the dumb-http revision walker could segfault when
+   curl's multi interface was used.
+
+ * It was possible to give specific paths for "asciidoc" and other
+   tools in the documentation toolchain, but not for "xmlto".
+
+ * "gitweb" did not give the correct committer timezone in its feed
+   output due to a typo.
+
+ * The "-Xours" (and similarly -Xtheirs) backend option to "git
+   merge -s recursive" was ignored for binary files.  Now it is
+   honored.
+
+ * The "binary" synthetic attribute made "diff" to treat the path as
+   binary, but not "merge".
+
+Also contains many documentation updates.
diff --git a/Documentation/RelNotes/1.7.12.txt b/Documentation/RelNotes/1.7.12.txt
new file mode 100644 (file)
index 0000000..010d8c7
--- /dev/null
@@ -0,0 +1,136 @@
+Git v1.7.12 Release Notes
+=========================
+
+Updates since v1.7.11
+---------------------
+
+UI, Workflows & Features
+
+ * Git can be told to normalize pathnames it read from readdir(3) and
+   all arguments it got from the command line into precomposed UTF-8
+   (assuming that they come as decomposed UTF-8), in order to work
+   around issues on Mac OS.
+
+   I think there still are other places that need conversion
+   (e.g. paths that are read from stdin for some commands), but this
+   should be a good first step in the right direction.
+
+ * Per-user $HOME/.gitconfig file can optionally be stored in
+   $HOME/.config/git/config instead, which is in line with XDG.
+
+ * The value of core.attributesfile and core.excludesfile default to
+   $HOME/.config/git/attributes and $HOME/.config/git/ignore respectively
+   when these files exist.
+
+ * Logic to disambiguate abbreviated object names have been taught to
+   take advantage of object types that are expected in the context,
+   e.g. XXXXXX in the "git describe" output v1.2.3-gXXXXXX must be a
+   commit object, not a blob nor a tree.  This will help us prolong
+   the lifetime of abbreviated object names.
+
+ * "git apply" learned to wiggle the base version and perform three-way
+   merge when a patch does not exactly apply to the version you have.
+
+ * Scripted Porcelain writers now have access to the credential API via
+   the "git credential" plumbing command.
+
+ * "git help" used to always default to "man" format even on platforms
+   where "man" viewer is not widely available.
+
+ * "git clone --local $path" started its life as an experiment to
+   optionally use link/copy when cloning a repository on the disk, but
+   we didn't deprecate it after we made the option a no-op to always
+   use the optimization.  The command learned "--no-local" option to
+   turn this off, as a more explicit alternative over use of file://
+   URL.
+
+ * "git fetch" and friends used to say "remote side hung up
+   unexpectedly" when they failed to get response they expect from the
+   other side, but one common reason why they don't get expected
+   response is that the remote repository does not exist or cannot be
+   read. The error message in this case was updated to give better
+   hints to the user.
+
+ * "git help -w $cmd" can show HTML version of documentation for
+   "git-$cmd" by setting help.htmlpath to somewhere other than the
+   default location where the build procedure installs them locally;
+   the variable can even point at a http:// URL.
+
+ * "git rebase [-i] --root $tip" can now be used to rewrite all the
+   history leading to "$tip" down to the root commit.
+
+ * "git rebase -i" learned "-x <cmd>" to insert "exec <cmd>" after
+   each commit in the resulting history.
+
+ * "git status" gives finer classification to various states of paths
+   in conflicted state and offer advice messages in its output.
+
+ * "git submodule" learned to deal with nested submodule structure
+   where a module is contained within a module whose origin is
+   specified as a relative URL to its superproject's origin.
+
+ * A rather heavy-ish "git completion" script has been split to create
+   a separate "git prompting" script, to help lazy-autoloading of the
+   completion part while making prompting part always available.
+
+ * "gitweb" pays attention to various forms of credits that are
+   similar to "Signed-off-by:" lines in the commit objects and
+   highlights them accordingly.
+
+
+Foreign Interface
+
+ * "mediawiki" remote helper (in contrib/) learned to handle file
+   attachments.
+
+ * "git p4" now uses "Jobs:" and "p4 move" when appropriate.
+
+ * vcs-svn has been updated to clean-up compilation, lift 32-bit
+   limitations, etc.
+
+
+Performance, Internal Implementation, etc. (please report possible regressions)
+
+ * Some tests showed false failures caused by a bug in ecryptofs.
+
+ * We no longer use AsciiDoc7 syntax in our documentation and favor a
+   more modern style.
+
+ * "git am --rebasing" codepath was taught to grab authorship, log
+   message and the patch text directly out of existing commits.  This
+   will help rebasing commits that have confusing "diff" output in
+   their log messages.
+
+ * "git index-pack" and "git pack-objects" use streaming API to read
+   from the object store to avoid having to hold a large blob object
+   in-core while they are doing their thing.
+
+ * Code to match paths with exclude patterns learned to avoid calling
+   fnmatch() by comparing fixed leading substring literally when
+   possible.
+
+ * "git log -n 1 -- rarely-touched-path" was spending unnecessary
+   cycles after showing the first change to find the next one, only to
+   discard it.
+
+ * "git svn" got a large-looking code reorganization at the last
+   minute before the code freeze.
+
+
+Also contains minor documentation updates and code clean-ups.
+
+
+Fixes since v1.7.11
+-------------------
+
+Unless otherwise noted, all the fixes since v1.7.11 in the maintenance
+releases are contained in this release (see release notes to them for
+details).
+
+ * "git submodule add" was confused when the superproject did not have
+   its repository in its usual place in the working tree and GIT_DIR
+   and GIT_WORK_TREE was used to access it.
+
+ * "git commit --amend" let the user edit the log message and then died
+   when the human-readable committer name was given insufficiently by
+   getpwent(3).
diff --git a/Documentation/RelNotes/1.8.0.txt b/Documentation/RelNotes/1.8.0.txt
new file mode 100644 (file)
index 0000000..43883c1
--- /dev/null
@@ -0,0 +1,267 @@
+Git v1.8.0 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.
+
+
+Updates since v1.7.12
+---------------------
+
+UI, Workflows & Features
+
+ * A credential helper for Win32 to allow access to the keychain of
+   the logged-in user has been added.
+
+ * An initial port to HP NonStop.
+
+ * A credential helper to allow access to the Gnome keyring has been
+   added.
+
+ * When "git am" sanitizes the "Subject:" line, we strip the prefix from
+   "Re: subject" and also from a less common "re: subject", but left
+   the even less common "RE: subject" intact.  Now we strip that too.
+
+ * It was tempting to say "git branch --set-upstream origin/master",
+   but that tells Git to arrange the local branch "origin/master" to
+   integrate with the currently checked out branch, which is highly
+   unlikely what the user meant.  The option is deprecated; use the
+   new "--set-upstream-to" (with a short-and-sweet "-u") option
+   instead.
+
+ * "git cherry-pick" learned the "--allow-empty-message" option to
+   allow it to replay a commit without any log message.
+
+ * After "git cherry-pick -s" gave control back to the user asking
+   help to resolve conflicts, concluding "git commit" used to need to
+   be run with "-s" if the user wants to sign it off; now the command
+   leaves the sign-off line in the log template.
+
+ * "git daemon" learned the "--access-hook" option to allow an
+   external command to decline service based on the client address,
+   repository path, etc.
+
+ * "git difftool --dir-diff" learned to use symbolic links to prepare
+   a temporary copy of the working tree when available.
+
+ * "git grep" learned to use a non-standard pattern type by default if
+   a configuration variable tells it to.
+
+ * Accumulated updates to "git gui" has been merged.
+
+ * "git log -g" learned the "--grep-reflog=<pattern>" option to limit
+   its output to commits with a reflog message that matches the given
+   pattern.
+
+ * "git merge-base" learned the "--is-ancestor A B" option to tell if A is
+   an ancestor of B.  The result is indicated by its exit status code.
+
+ * "git mergetool" now allows users to override the actual command used
+   with the mergetool.$name.cmd configuration variable even for built-in
+   mergetool backends.
+
+ * "git rebase -i" learned the "--edit-todo" option to open an editor
+   to edit the instruction sheet.
+
+
+Foreign Interface
+
+ * "git svn" has been updated to work with SVN 1.7.
+
+ * "git p4" learned the "--conflicts" option to specify what to do when
+   encountering a conflict during "p4 submit".
+
+
+Performance, Internal Implementation, etc.
+
+ * Git ships with a fall-back regexp implementation for platforms with
+   buggy regexp library, but it was easy for people to keep using their
+   platform regexp by mistake.  A new test has been added to check this.
+
+ * The "check-docs" build target has been updated and greatly
+   simplified.
+
+ * The test suite is run under MALLOC_CHECK_ when running with a glibc
+   that supports the feature.
+
+ * The documentation in the TeXinfo format was using indented output
+   for materials meant to be examples that are better typeset in
+   monospace.
+
+ * Compatibility wrapper around some mkdir(2) implementations that
+   reject parameters with trailing slash has been introduced.
+
+ * Compatibility wrapper for systems that lack usable setitimer() has
+   been added.
+
+ * The option parsing of "git checkout" had error checking, dwim and
+   defaulting missing options, all mixed in the code, and issuing an
+   appropriate error message with useful context was getting harder.
+   The code has been reorganized to allow giving a proper diagnosis
+   when the user says "git checkout -b -t foo bar" (e.g. "-t" is not a
+   good name for a branch).
+
+ * Many internal uses of a "git merge-base" equivalent were only to see
+   if one commit fast-forwards to the other, which did not need the
+   full set of merge bases to be computed. They have been updated to
+   use less expensive checks.
+
+ * The heuristics to detect and silently convert latin1 to utf8 when
+   we were told to use utf-8 in the log message has been transplanted
+   from "mailinfo" to "commit" and "commit-tree".
+
+ * Messages given by "git <subcommand> -h" from many subcommands have
+   been marked for translation.
+
+
+Also contains minor documentation updates and code clean-ups.
+
+
+Fixes since v1.7.12
+-------------------
+
+Unless otherwise noted, all the fixes since v1.7.12 in the
+maintenance track are contained in this release (see release notes
+to them for details).
+
+ * The attribute system may be asked for a path that itself or its
+   leading directories no longer exists in the working tree, and it is
+   fine if we cannot open .gitattribute file in such a case.  Failure
+   to open per-directory .gitattributes with error status other than
+   ENOENT and ENOTDIR should be diagnosed, but it wasn't.
+
+ * When looking for $HOME/.gitconfig etc., it is OK if we cannot read
+   them because they do not exist, but we did not diagnose existing
+   files that we cannot read.
+
+ * When "git am" is fed an input that has multiple "Content-type: ..."
+   header, it did not grok charset= attribute correctly.
+
+ * "git am" mishandled a patch attached as application/octet-stream
+   (e.g. not text/*); Content-Transfer-Encoding (e.g. base64) was not
+   honored correctly.
+
+ * "git blame MAKEFILE" run in a history that has "Makefile" but not
+   "MAKEFILE" should say "No such file MAKEFILE in HEAD", but got
+   confused on a case insensitive filesystem and failed to do so.
+
+ * Even during a conflicted merge, "git blame $path" always meant to
+   blame uncommitted changes to the "working tree" version; make it
+   more useful by showing cleanly merged parts as coming from the other
+   branch that is being merged.
+
+ * It was unclear in the documentation for "git blame" that it is
+   unnecessary for users to use the "--follow" option.
+
+ * Output from "git branch -v" contains "(no branch)" that could be
+   localized, but the code to align it along with the names of
+   branches was counting in bytes, not in display columns.
+
+ * "git cherry-pick A C B" used to replay changes in A and then B and
+   then C if these three commits had committer timestamps in that
+   order, which is not what the user who said "A C B" naturally
+   expects.
+
+ * A repository created with "git clone --single" had its fetch
+   refspecs set up just like a clone without "--single", leading the
+   subsequent "git fetch" to slurp all the other branches, defeating
+   the whole point of specifying "only this branch".
+
+ * Documentation talked about "first line of commit log" when it meant
+   the title of the commit.  The description was clarified by defining
+   how the title is decided and rewording the casual mention of "first
+   line" to "title".
+
+ * "git cvsimport" did not thoroughly cleanse tag names that it
+   inferred from the names of the tags it obtained from CVS, which
+   caused "git tag" to barf and stop the import in the middle.
+
+ * Earlier we made the diffstat summary line that shows the number of
+   lines added/deleted localizable, but it was found irritating having
+   to see them in various languages on a list whose discussion language
+   is English, and this change has been reverted.
+
+ * "git fetch --all", when passed "--no-tags", did not honor the
+   "--no-tags" option while fetching from individual remotes (the same
+   issue existed with "--tags", but the combination "--all --tags" makes
+   much less sense than "--all --no-tags").
+
+ * "git fetch" over http had an old workaround for an unlikely server
+   misconfiguration; it turns out that this hurts debuggability of the
+   configuration in general, and has been reverted.
+
+ * "git fetch" over http advertised that it supports "deflate", which
+   is much less common, and did not advertise the more common "gzip" on
+   its Accept-Encoding header.
+
+ * "git fetch" over the dumb-http revision walker could segfault when
+   curl's multi interface was used.
+
+ * "git gc --auto" notified the user that auto-packing has triggered
+    even under the "--quiet" option.
+
+ * After "gitk" showed the contents of a tag, neither "Reread
+   references" nor "Reload" updated what is shown as the
+   contents of it when the user overwrote the tag with "git tag -f".
+
+ * "git log --all-match --grep=A --grep=B" ought to show commits that
+   mention both A and B, but when these three options are used with
+   --author or --committer, it showed commits that mention either A or
+   B (or both) instead.
+
+ * The "-Xours" backend option to "git merge -s recursive" was ignored
+   for binary files.
+
+ * "git p4", when "--use-client-spec" and "--detect-branches" are used
+   together, misdetected branches.
+
+ * "git receive-pack" (the counterpart to "git push") did not give
+   progress output while processing objects it received to the puser
+   when run over the smart-http protocol.
+
+ * When you misspell the command name you give to the "exec" action in
+   the "git rebase -i" instruction sheet you were told that 'rebase' is not a
+   git subcommand from "git rebase --continue".
+
+ * The subcommand in "git remote" to remove a defined remote was
+   "rm" and the command did not take a fully-spelled "remove".
+
+ * The interactive prompt that "git send-email" gives was error prone. It
+   asked "What e-mail address do you want to use?" with the address it
+   guessed (correctly) the user would want to use in its prompt,
+   tempting the user to say "y". But the response was taken as "No,
+   please use 'y' as the e-mail address instead", which is most
+   certainly not what the user meant.
+
+ * "git show --format='%ci'" did not give the timestamp correctly for
+   commits created without human readable name on the "committer" line.
+
+ * "git show --quiet" ought to be a synonym for "git show -s", but
+   wasn't.
+
+ * "git submodule frotz" was not diagnosed as "frotz" being an unknown
+   subcommand to "git submodule"; the user instead got a complaint
+   that "git submodule status" was run with an unknown path "frotz".
+
+ * "git status" honored the ignore=dirty settings in .gitmodules but
+   "git commit" didn't.
+
+ * "gitweb" did not give the correct committer timezone in its feed
+   output due to a typo.
index b49feb582ef6c780a9dd1831bcd7e013e774b7c6..9a0544cf1fba605bde7031c23016bc24db741417 100644 (file)
@@ -159,9 +159,10 @@ advice.*::
                specified a refspec that isn't your current branch) and
                it resulted in a non-fast-forward error.
        statusHints::
-               Directions on how to stage/unstage/add shown in the
-               output of linkgit:git-status[1] and the template shown
-               when writing commit messages.
+               Show directions on how to proceed from the current
+               state in the output of linkgit:git-status[1] and in
+               the template shown when writing commit messages in
+               linkgit:git-commit[1].
        commitBeforeMerge::
                Advice shown when linkgit:git-merge[1] refuses to
                merge to avoid overwriting local changes.
@@ -213,6 +214,15 @@ The default is false, except linkgit:git-clone[1] or linkgit:git-init[1]
 will probe and set core.ignorecase true if appropriate when the repository
 is created.
 
+core.precomposeunicode::
+       This option is only used by Mac OS implementation of git.
+       When core.precomposeunicode=true, git reverts the unicode decomposition
+       of filenames done by Mac OS. This is useful when sharing a repository
+       between Mac OS and Linux or Windows.
+       (Git for Windows 1.7.10 or higher is needed, or git under cygwin 1.7).
+       When false, file names are handled fully transparent by git,
+       which is backward compatible with older versions of git.
+
 core.trustctime::
        If false, the ctime differences between the index and the
        working tree are ignored; useful when the inode change time
@@ -486,7 +496,9 @@ core.excludesfile::
        '.git/info/exclude', git looks into this file for patterns
        of files which are not meant to be tracked.  "`~/`" is expanded
        to the value of `$HOME` and "`~user/`" to the specified user's
-       home directory.  See linkgit:gitignore[5].
+       home directory. Its default value is $XDG_CONFIG_HOME/git/ignore.
+       If $XDG_CONFIG_HOME is either not set or empty, $HOME/.config/git/ignore
+       is used instead. See linkgit:gitignore[5].
 
 core.askpass::
        Some commands (e.g. svn and http interfaces) that interactively
@@ -501,7 +513,9 @@ core.attributesfile::
        In addition to '.gitattributes' (per-directory) and
        '.git/info/attributes', git looks into this file for attributes
        (see linkgit:gitattributes[5]). Path expansions are made the same
-       way as for `core.excludesfile`.
+       way as for `core.excludesfile`. Its default value is
+       $XDG_CONFIG_HOME/git/attributes. If $XDG_CONFIG_HOME is either not
+       set or empty, $HOME/.config/git/attributes is used instead.
 
 core.editor::
        Commands such as `commit` and `tag` that lets you edit
@@ -524,14 +538,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
@@ -545,8 +559,9 @@ core.whitespace::
 * `space-before-tab` treats a space character that appears immediately
   before a tab character in the initial indent part of the line as an
   error (enabled by default).
-* `indent-with-non-tab` treats a line that is indented with 8 or more
-  space characters as an error (not enabled by default).
+* `indent-with-non-tab` treats a line that is indented with space
+  characters instead of the equivalent tabs as an error (not enabled by
+  default).
 * `tab-in-indent` treats a tab character in the initial indent part of
   the line as an error (not enabled by default).
 * `blank-at-eof` treats blank lines added at the end of file as an error
@@ -883,7 +898,7 @@ column.ui::
        make equal size columns
 --
 +
-       This option defaults to 'never'.
+This option defaults to 'never'.
 
 column.branch::
        Specify whether to output branch listing in `git branch` in columns.
@@ -1196,8 +1211,16 @@ gitweb.snapshot::
 grep.lineNumber::
        If set to true, enable '-n' option by default.
 
+grep.patternType::
+       Set the default matching behavior. Using a value of 'basic', 'extended',
+       'fixed', or 'perl' will enable the '--basic-regexp', '--extended-regexp',
+       '--fixed-strings', or '--perl-regexp' option accordingly, while the
+       value 'default' will return to the default matching behavior.
+
 grep.extendedRegexp::
-       If set to true, enable '--extended-regexp' option by default.
+       If set to true, enable '--extended-regexp' option by default. This
+       option is ignored when the 'grep.patternType' option is set to a value
+       other than 'default'.
 
 gpg.program::
        Use this custom program instead of "gpg" found on $PATH when
@@ -1723,6 +1746,7 @@ push.default::
        no refspec is implied by any of the options given on the command
        line. Possible values are:
 +
+--
 * `nothing` - do not push anything.
 * `matching` - push all branches having the same name in both ends.
   This is for those who prepare all the branches into a publishable
@@ -1742,12 +1766,13 @@ push.default::
   option and is well-suited for beginners. It will become the default
   in Git 2.0.
 * `current` - push the current branch to a branch of the same name.
-  +
-  The `simple`, `current` and `upstream` modes are for those who want to
-  push out a single branch after finishing work, even when the other
-  branches are not yet ready to be pushed out. If you are working with
-  other people to push into the same shared repository, you would want
-  to use one of these.
+--
++
+The `simple`, `current` and `upstream` modes are for those who want to
+push out a single branch after finishing work, even when the other
+branches are not yet ready to be pushed out. If you are working with
+other people to push into the same shared repository, you would want
+to use one of these.
 
 rebase.stat::
        Whether to show a diffstat of what changed upstream since the last
index 67a90a828c04b7277fc603c6518fd0ecd8247d32..75ab8a51ca17ce825d2f1faee5de14abc2fdb6f6 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
index 39d326abc63af01d7cffe3d6f0c3df9279bc667e..b4d6476ac898db8ff99ab3639efce08050ef71c4 100644 (file)
@@ -10,7 +10,8 @@
 --depth=<depth>::
        Deepen the history of a 'shallow' repository created by
        `git clone` with `--depth=<depth>` option (see linkgit:git-clone[1])
-       by the specified number of commits.
+       to the specified number of commits from the tip of each remote
+       branch history. Tags for the deepened commits are not fetched.
 
 ifndef::git-pull[]
 --dry-run::
index 9c1d3957223355e00eea917d4a7dff6d50343f32..fd9e36b99f5506964ac8352b82bb7af05551a523 100644 (file)
@@ -155,7 +155,7 @@ Configuration
 The optional configuration variable `core.excludesfile` indicates a path to a
 file containing patterns of file names to exclude from git-add, similar to
 $GIT_DIR/info/exclude.  Patterns in the exclude file are used in addition to
-those in info/exclude.  See linkgit:gitrepository-layout[5].
+those in info/exclude.  See linkgit:gitignore[5].
 
 
 EXAMPLES
index afd2c9ae59e9145f377d5c702df27bf861c9b2f5..634b84e4b9a06b58f4c818a314c5cb2d5880e1bd 100644 (file)
@@ -9,7 +9,7 @@ git-apply - Apply a patch to files and/or to the index
 SYNOPSIS
 --------
 [verse]
-'git apply' [--stat] [--numstat] [--summary] [--check] [--index]
+'git apply' [--stat] [--numstat] [--summary] [--check] [--index] [--3way]
          [--apply] [--no-add] [--build-fake-ancestor=<file>] [-R | --reverse]
          [--allow-binary-replacement | --binary] [--reject] [-z]
          [-p<n>] [-C<n>] [--inaccurate-eof] [--recount] [--cached]
@@ -72,6 +72,15 @@ OPTIONS
        cached data, apply the patch, and store the result in the index
        without using the working tree. This implies `--index`.
 
+-3::
+--3way::
+       When the patch does not apply cleanly, fall back on 3-way merge if
+       the patch records the identity of blobs it is supposed to apply to,
+       and we have those blobs available locally, possibly leaving the
+       conflict markers in the files in the working tree for the user to
+       resolve.  This option implies the `--index` option, and is incompatible
+       with the `--reject` and the `--cached` options.
+
 --build-fake-ancestor=<file>::
        Newer 'git diff' output has embedded 'index information'
        for each blob to help identify the original version that
index 7ee923629ecc0dbf12a845f18d02c317b6266066..e44173f66afa9e1e1656e7b388fd707c417a1d28 100644 (file)
@@ -20,6 +20,12 @@ last modified the line. Optionally, start annotating from the given revision.
 
 The command can also limit the range of lines annotated.
 
+The origin of lines is automatically followed across whole-file
+renames (currently there is no option to turn the rename-following
+off). To follow lines moved from one file to another, or to follow
+lines that were copied and pasted from another file, etc., see the
+`-C` and `-M` options.
+
 The report does not tell you anything about lines which have been deleted or
 replaced; you need to use a tool such as 'git diff' or the "pickaxe"
 interface briefly mentioned in the following paragraph.
index 47235bea0403bf25fa73529a37a7c5f87d0d7eb9..45a225e0aa0ea662393eb65fcb32b702bdd608e6 100644 (file)
@@ -13,6 +13,8 @@ SYNOPSIS
        [--column[=<options>] | --no-column]
        [(--merged | --no-merged | --contains) [<commit>]] [<pattern>...]
 'git branch' [--set-upstream | --track | --no-track] [-l] [-f] <branchname> [<start-point>]
+'git branch' (--set-upstream-to=<upstream> | -u <upstream>) [<branchname>]
+'git branch' --unset-upstream [<branchname>]
 'git branch' (-m | -M) [<oldbranch>] <newbranch>
 'git branch' (-d | -D) [-r] <branchname>...
 'git branch' --edit-description [<branchname>]
@@ -48,7 +50,7 @@ branch so that 'git pull' will appropriately merge from
 the remote-tracking branch. This behavior may be changed via the global
 `branch.autosetupmerge` configuration flag. That setting can be
 overridden by using the `--track` and `--no-track` options, and
-changed later using `git branch --set-upstream`.
+changed later using `git branch --set-upstream-to`.
 
 With a `-m` or `-M` option, <oldbranch> will be renamed to <newbranch>.
 If <oldbranch> had a corresponding reflog, it is renamed to match
@@ -129,11 +131,13 @@ This option is only applicable in non-verbose mode.
        use `git branch --list <pattern>` to list matching branches.
 
 -v::
+-vv::
 --verbose::
        When in list mode,
        show sha1 and commit subject line for each head, along with
        relationship to upstream branch (if any). If given twice, print
-       the name of the upstream branch, as well.
+       the name of the upstream branch, as well (see also `git remote
+       show <remote>`).
 
 -q::
 --quiet::
@@ -173,6 +177,16 @@ start-point is either a local or remote-tracking branch.
        like `--track` would when creating the branch, except that where
        branch points to is not changed.
 
+-u <upstream>::
+--set-upstream-to=<upstream>::
+       Set up <branchname>'s tracking information so <upstream> is
+       considered <branchname>'s upstream branch. If no <branchname>
+       is specified, then it defaults to the current branch.
+
+--unset-upstream::
+       Remove the upstream information for <branchname>. If no branch
+       is specified it defaults to the current branch.
+
 --edit-description::
        Open an editor and edit the text to explain what the branch is
        for, to be used by various other commands (e.g. `request-pull`).
index 0e170a51cac1de3f20b31f8dba7f832c292b815c..c205d2363e426ed6b1a91df2b8d9b4a3c576a5ea 100644 (file)
@@ -118,6 +118,11 @@ effect to your index in a row.
        previous commit are dropped.  To force the inclusion of those commits
        use `--keep-redundant-commits`.
 
+--allow-empty-message::
+       By default, cherry-picking a commit with an empty message will fail.
+       This option overrides that behaviour, allowing commits with empty
+       messages to be cherry picked.
+
 --keep-redundant-commits::
        If a commit being cherry picked duplicates a commit already in the
        current history, it will become empty.  By default these
index 79fb9841441d02cd635dcdd2aecef42d38c6b59d..9f42c0d0e63e8d23bfbf4b582a6a9a60280cca47 100644 (file)
@@ -63,6 +63,10 @@ OPTIONS
        Remove only files ignored by git.  This may be useful to rebuild
        everything from scratch, but keep manually created files.
 
+SEE ALSO
+--------
+linkgit:gitignore[5]
+
 GIT
 ---
 Part of the linkgit:git[1] suite
index 6e22522c4f7e97dbab42b3cbb5b538cdea3b4d74..7fefdb0384307d0029eb6016bdf37735e84ebdd8 100644 (file)
@@ -29,7 +29,8 @@ currently active branch.
 After the clone, a plain `git fetch` without arguments will update
 all the remote-tracking branches, and a `git pull` without
 arguments will in addition merge the remote master branch into the
-current master branch, if any.
+current master branch, if any (this is untrue when "--single-branch"
+is given; see below).
 
 This default configuration is achieved by creating references to
 the remote branch heads under `refs/remotes/origin` and
@@ -46,13 +47,18 @@ OPTIONS
        mechanism and clones the repository by making a copy of
        HEAD and everything under objects and refs directories.
        The files under `.git/objects/` directory are hardlinked
-       to save space when possible.  This is now the default when
-       the source repository is specified with `/path/to/repo`
-       syntax, so it essentially is a no-op option.  To force
-       copying instead of hardlinking (which may be desirable
-       if you are trying to make a back-up of your repository),
-       but still avoid the usual "git aware" transport
-       mechanism, `--no-hardlinks` can be used.
+       to save space when possible.
++
+If the repository is specified as a local path (e.g., `/path/to/repo`),
+this is the default, and --local is essentially a no-op.  If the
+repository is specified as a URL, then this flag is ignored (and we
+never use the local optimizations).  Specifying `--no-local` will
+override the default when `/path/to/repo` is given, using the regular
+git transport instead.
++
+To force copying instead of hardlinking (which may be desirable if you
+are trying to make a back-up of your repository), but still avoid the
+usual "git aware" transport mechanism, `--no-hardlinks` can be used.
 
 --no-hardlinks::
        Optimize the cloning process from a repository on a
@@ -147,9 +153,10 @@ objects from the source repository into a pack in the cloned repository.
 -b <name>::
        Instead of pointing the newly created HEAD to the branch pointed
        to by the cloned repository's HEAD, point to `<name>` branch
-       instead. `--branch` can also take tags and treat them like
-       detached HEAD. In a non-bare repository, this is the branch
-       that will be checked out.
+       instead. In a non-bare repository, this is the branch that will
+       be checked out.
+       `--branch` can also take tags and detaches the HEAD at that commit
+       in the resulting repository.
 
 --upload-pack <upload-pack>::
 -u <upload-pack>::
@@ -188,6 +195,11 @@ objects from the source repository into a pack in the cloned repository.
        clone with the `--depth` option, this is the default, unless
        `--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
+       initial cloning.  If the HEAD at the remote did not point at any
+       branch when `--single-branch` clone was made, no remote-tracking
+       branch is created.
 
 --recursive::
 --recurse-submodules::
index 4622297ec98cddc2e1f2e4417b9eeec11a3c91b1..0295890621117ae3981485eec5872d3dcfb23af6 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
@@ -276,6 +280,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.
 
@@ -389,8 +397,10 @@ DISCUSSION
 Though not required, it's a good idea to begin the commit message
 with a single short (less than 50 character) line summarizing the
 change, followed by a blank line and then a more thorough description.
-Tools that turn commits into email, for example, use the first line
-on the Subject: line and the rest of the commit in the body.
+The text up to the first blank line in a commit message is treated
+as the commit title, and that title is used throughout git.
+For example, linkgit:git-format-patch[1] turns a commit into email, and it uses
+the title on the Subject line and the rest of the commit in the body.
 
 include::i18n.txt[]
 
index 21b8f6110bfc2a9c7891c166e3ee78a8246dcb1e..eaea0791657386469e448def614b949c0a1f45e9 100644 (file)
@@ -97,10 +97,11 @@ OPTIONS
 
 --global::
        For writing options: write to global ~/.gitconfig file rather than
-       the repository .git/config.
+       the repository .git/config, write to $XDG_CONFIG_HOME/git/config file
+       if this file exists and the ~/.gitconfig file doesn't.
 +
-For reading options: read only from global ~/.gitconfig rather than
-from all available files.
+For reading options: read only from global ~/.gitconfig and from
+$XDG_CONFIG_HOME/git/config rather than from all available files.
 +
 See also <<FILES>>.
 
@@ -194,7 +195,7 @@ See also <<FILES>>.
 FILES
 -----
 
-If not set explicitly with '--file', there are three files where
+If not set explicitly with '--file', there are four files where
 'git config' will search for configuration options:
 
 $GIT_DIR/config::
@@ -204,6 +205,14 @@ $GIT_DIR/config::
        User-specific configuration file. Also called "global"
        configuration file.
 
+$XDG_CONFIG_HOME/git/config::
+       Second user-specific configuration file. If $XDG_CONFIG_HOME is not set
+       or empty, $HOME/.config/git/config will be used. Any single-valued
+       variable set in this file will be overwritten by whatever is in
+       ~/.gitconfig.  It is a good idea not to create this file if
+       you sometimes use older versions of Git, as support for this
+       file was added fairly recently.
+
 $(prefix)/etc/gitconfig::
        System-wide configuration file.
 
index 11edc5a173e89e80952a5663c3c197dee4c6329c..d15db42d43b9e94628246a30e7c12df41b45b935 100644 (file)
@@ -3,7 +3,7 @@ git-credential-cache--daemon(1)
 
 NAME
 ----
-git-credential-cache--daemon - temporarily store user credentials in memory
+git-credential-cache--daemon - Temporarily store user credentials in memory
 
 SYNOPSIS
 --------
index f3d09c5d51bc49d05c423de81504d68f18f99ede..eeff5fa9891fd7e3f1afac7cac6b9e5b17112449 100644 (file)
@@ -3,7 +3,7 @@ git-credential-cache(1)
 
 NAME
 ----
-git-credential-cache - helper to temporarily store passwords in memory
+git-credential-cache - Helper to temporarily store passwords in memory
 
 SYNOPSIS
 --------
index 31093467d1bc0af0f8229cd335ad0a56c4911b36..b27c03c361111a01dbc5c2407c209e5f8530eec2 100644 (file)
@@ -3,7 +3,7 @@ git-credential-store(1)
 
 NAME
 ----
-git-credential-store - helper to store credentials on disk
+git-credential-store - Helper to store credentials on disk
 
 SYNOPSIS
 --------
diff --git a/Documentation/git-credential.txt b/Documentation/git-credential.txt
new file mode 100644 (file)
index 0000000..810e957
--- /dev/null
@@ -0,0 +1,154 @@
+git-credential(1)
+=================
+
+NAME
+----
+git-credential - Retrieve and store user credentials
+
+SYNOPSIS
+--------
+------------------
+git credential <fill|approve|reject>
+------------------
+
+DESCRIPTION
+-----------
+
+Git has an internal interface for storing and retrieving credentials
+from system-specific helpers, as well as prompting the user for
+usernames and passwords. The git-credential command exposes this
+interface to scripts which may want to retrieve, store, or prompt for
+credentials in the same manner as git. The design of this scriptable
+interface models the internal C API; see
+link:technical/api-credentials.txt[the git credential API] for more
+background on the concepts.
+
+git-credential takes an "action" option on the command-line (one of
+`fill`, `approve`, or `reject`) and reads a credential description
+on stdin (see <<IOFMT,INPUT/OUTPUT FORMAT>>).
+
+If the action is `fill`, git-credential will attempt to add "username"
+and "password" attributes to the description by reading config files,
+by contacting any configured credential helpers, or by prompting the
+user. The username and password attributes of the credential
+description are then printed to stdout together with the attributes
+already provided.
+
+If the action is `approve`, git-credential will send the description
+to any configured credential helpers, which may store the credential
+for later use.
+
+If the action is `reject`, git-credential will send the description to
+any configured credential helpers, which may erase any stored
+credential matching the description.
+
+If the action is `approve` or `reject`, no output should be emitted.
+
+TYPICAL USE OF GIT CREDENTIAL
+-----------------------------
+
+An application using git-credential will typically use `git
+credential` following these steps:
+
+  1. Generate a credential description based on the context.
++
+For example, if we want a password for
+`https://example.com/foo.git`, we might generate the following
+credential description (don't forget the blank line at the end; it
+tells `git credential` that the application finished feeding all the
+infomation it has):
+
+        protocol=https
+        host=example.com
+        path=foo.git
+
+  2. Ask git-credential to give us a username and password for this
+     description. This is done by running `git credential fill`,
+     feeding the description from step (1) to its standard input. The complete
+     credential description (including the credential per se, i.e. the
+     login and password) will be produced on standard output, like:
+
+       protocol=https
+       host=example.com
+       username=bob
+       password=secr3t
++
+In most cases, this means the attributes given in the input will be
+repeated in the output, but git may also modify the credential
+description, for example by removing the `path` attribute when the
+protocol is HTTP(s) and `credential.useHttpPath` is false.
++
+If the `git credential` knew about the password, this step may
+not have involved the user actually typing this password (the
+user may have typed a password to unlock the keychain instead,
+or no user interaction was done if the keychain was already
+unlocked) before it returned `password=secr3t`.
+
+  3. Use the credential (e.g., access the URL with the username and
+     password from step (2)), and see if it's accepted.
+
+  4. Report on the success or failure of the password. If the
+     credential allowed the operation to complete successfully, then
+     it can be marked with an "approve" action to tell `git
+     credential` to reuse it in its next invocation. If the credential
+     was rejected during the operation, use the "reject" action so
+     that `git credential` will ask for a new password in its next
+     invocation. In either case, `git credential` should be fed with
+     the credential description obtained from step (2) (which also
+     contain the ones provided in step (1)).
+
+[[IOFMT]]
+INPUT/OUTPUT FORMAT
+-------------------
+
+`git credential` reads and/or writes (depending on the action used)
+credential information in its standard input/output. This information
+can correspond either to keys for which `git credential` will obtain
+the login/password information (e.g. host, protocol, path), or to the
+actual credential data to be obtained (login/password).
+
+The credential is split into a set of named attributes, with one
+attribute per line. Each attribute is
+specified by a key-value pair, separated by an `=` (equals) sign,
+followed by a newline. The key may contain any bytes except `=`,
+newline, or NUL. The value may contain any bytes except newline or NUL.
+In both cases, all bytes are treated as-is (i.e., there is no quoting,
+and one cannot transmit a value with newline or NUL in it). The list of
+attributes is terminated by a blank line or end-of-file.
+Git understands the following attributes:
+
+`protocol`::
+
+       The protocol over which the credential will be used (e.g.,
+       `https`).
+
+`host`::
+
+       The remote hostname for a network credential.
+
+`path`::
+
+       The path with which the credential will be used. E.g., for
+       accessing a remote https repository, this will be the
+       repository's path on the server.
+
+`username`::
+
+       The credential's username, if we already have one (e.g., from a
+       URL, from the user, or from a previously run helper).
+
+`password`::
+
+       The credential's password, if we are asking it to be stored.
+
+`url`::
+
+       When this special attribute is read by `git credential`, the
+       value is parsed as a URL and treated as if its constituent parts
+       were read (e.g., `url=https://example.com` would behave as if
+       `protocol=https` and `host=example.com` had been provided). This
+       can help callers avoid parsing URLs themselves.  Note that any
+       components which are missing from the URL (e.g., there is no
+       username in the example above) will be set to empty; if you want
+       to provide a URL and override some attributes, provide the URL
+       attribute first, followed by any overrides.
index e8f757704c7fcf93e8e19f66c34557b8887ef29a..7e5098a95e48bbe0a82630e2ca5d4cebec6c3112 100644 (file)
@@ -16,6 +16,7 @@ SYNOPSIS
             [--reuseaddr] [--detach] [--pid-file=<file>]
             [--enable=<service>] [--disable=<service>]
             [--allow-override=<service>] [--forbid-override=<service>]
+            [--access-hook=<path>]
             [--inetd | [--listen=<host_or_ipaddr>] [--port=<n>] [--user=<user> [--group=<group>]]
             [<directory>...]
 
@@ -171,6 +172,21 @@ the facility of inet daemon to achieve the same before spawning
        errors are not enabled, all errors report "access denied" to the
        client. The default is --no-informative-errors.
 
+--access-hook=<path>::
+       Every time a client connects, first run an external command
+       specified by the <path> with service name (e.g. "upload-pack"),
+       path to the repository, hostname (%H), canonical hostname
+       (%CH), ip address (%IP), and tcp port (%P) as its command line
+       arguments. The external command can decide to decline the
+       service by exiting with a non-zero status (or to allow it by
+       exiting with a zero status).  It can also look at the $REMOTE_ADDR
+       and $REMOTE_PORT environment variables to learn about the
+       requestor when making this decision.
++
+The external command can optionally write a single line to its
+standard output to be sent to the requestor as an error message when
+it declines the service.
+
 <directory>::
        A directory to add to the whitelist of allowed directories. Unless
        --strict-paths is specified this will also include subdirectories
index 31fc2e3aed613acd8cb6e4a56ae66c378fb07a0d..73ca7025a39630907e3a019dfed14542f4ac7538 100644 (file)
@@ -69,6 +69,14 @@ with custom merge tool commands and has the same value as `$MERGED`.
 --tool-help::
        Print a list of diff tools that may be used with `--tool`.
 
+--symlinks::
+--no-symlinks::
+       'git difftool''s default behavior is create symlinks to the
+       working tree when run in `--dir-diff` mode.
++
+       Specifying `--no-symlinks` instructs 'git difftool' to create
+       copies instead.  `--no-symlinks` is the default on Windows.
+
 -x <command>::
 --extcmd=<command>::
        Specify a custom command for viewing diffs.
index 2620d28b4b38ed3f57ee426e27a2115db8160343..6603a7ab733f4c59dd8725ada536b44bf5e8d12a 100644 (file)
@@ -39,6 +39,10 @@ OPTIONS
        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
@@ -1047,7 +1051,9 @@ done::
        Error out if the stream ends without a 'done' command.
        Without this feature, errors causing the frontend to end
        abruptly at a convenient point in the stream can go
-       undetected.
+       undetected.  This may occur, for example, if an import
+       front end dies in mid-operation without emitting SIGTERM
+       or SIGKILL at its subordinate git fast-import instance.
 
 `option`
 ~~~~~~~~
index 15e7ac80c087eee7d0bf10af5653f421bcbee0dc..e2301f5c0106a35e5fa14d63944abeea2cb09e9b 100644 (file)
@@ -304,6 +304,11 @@ committed a merge between P1 and P2, it will be propagated properly
 and all children of the merge will become merge commits with P1,P2
 as their parents instead of the merge commit.
 
+*NOTE* the changes introduced by the commits, and which are not reverted
+by subsequent commits, will still be in the rewritten branch. If you want
+to throw out _changes_ together with the commits, you should use the
+interactive mode of 'git rebase'.
+
 You can rewrite the commit log messages using `--msg-filter`.  For
 example, 'git svn-id' strings in a repository created by 'git svn' can
 be removed this way:
@@ -314,11 +319,6 @@ git filter-branch --msg-filter '
 '
 -------------------------------------------------------
 
-To restrict rewriting to only part of the history, specify a revision
-range in addition to the new branch name.  The new branch name will
-point to the top-most revision that a 'git rev-list' of this range
-will print.
-
 If you need to add 'Acked-by' lines to, say, the last 10 commits (none
 of which is a merge), use this command:
 
@@ -329,11 +329,10 @@ git filter-branch --msg-filter '
 ' HEAD~10..HEAD
 --------------------------------------------------------
 
-*NOTE* the changes introduced by the commits, and which are not reverted
-by subsequent commits, will still be in the rewritten branch. If you want
-to throw out _changes_ together with the commits, you should use the
-interactive mode of 'git rebase'.
-
+To restrict rewriting to only part of the history, specify a revision
+range in addition to the new branch name.  The new branch name will
+point to the top-most revision that a 'git rev-list' of this range
+will print.
 
 Consider this history:
 
index c872b883ba25144457eccb9967bc68003a3332ea..db55a4e0bbc524c20f08e6862daaa97dd1785b71 100644 (file)
@@ -102,9 +102,10 @@ Fields that have name-email-date tuple as its value (`author`,
 and `date` to extract the named component.
 
 The complete message in a commit and tag object is `contents`.
-Its first line is `contents:subject`, the remaining lines
-are `contents:body` and the optional GPG signature
-is `contents:signature`.
+Its first line is `contents:subject`, where subject is the concatenation
+of all lines of the commit message up to the first blank line.  The next
+line is 'contents:body', where body is all of the lines after the first
+blank line.  Finally, the optional GPG signature is `contents:signature`.
 
 For sorting purposes, fields with numeric values sort in numeric
 order (`objectsize`, `authordate`, `committerdate`, `taggerdate`).
index 04c7346e3e8ba12465e71ad1197ed6a109a473b1..6d43f56279fe7a0d42510035e33424df0bc584f1 100644 (file)
@@ -58,10 +58,13 @@ output, unless the `--stdout` option is specified.
 If `-o` is specified, output files are created in <dir>.  Otherwise
 they are created in the current working directory.
 
-By default, the subject of a single patch is "[PATCH] First Line" and
-the subject when multiple patches are output is "[PATCH n/m] First
-Line". To force 1/1 to be added for a single patch, use `-n`.  To omit
-patch numbers from the subject, use `-N`.
+By default, the subject of a single patch is "[PATCH] " followed by
+the concatenation of lines from the commit message up to the first blank
+line (see the DISCUSSION section of linkgit:git-commit[1]).
+
+When multiple patches are output, the subject prefix will instead be
+"[PATCH n/m] ".  To force 1/1 to be added for a single patch, use `-n`.
+To omit patch numbers from the subject, use `-N`.
 
 If given `--thread`, `git-format-patch` will generate `In-Reply-To` and
 `References` headers to make the second and subsequent patch mails appear
index 3bec0368831a04bc3653f11d3a0b1bff5a335907..cfecf848fb330333a655b0a54d58000041b73338 100644 (file)
@@ -42,8 +42,16 @@ CONFIGURATION
 grep.lineNumber::
        If set to true, enable '-n' option by default.
 
+grep.patternType::
+       Set the default matching behavior. Using a value of 'basic', 'extended',
+       'fixed', or 'perl' will enable the '--basic-regexp', '--extended-regexp',
+       '--fixed-strings', or '--perl-regexp' option accordingly, while the
+       value 'default' will return to the default matching behavior.
+
 grep.extendedRegexp::
-       If set to true, enable '--extended-regexp' option by default.
+       If set to true, enable '--extended-regexp' option by default. This
+       option is ignored when the 'grep.patternType' option is set to a value
+       other than 'default'.
 
 
 OPTIONS
index 1f906208f9514180fe9f20293ab28ce8180b5357..585dac40baabbee291f43a6e7c59c36340286e43 100644 (file)
@@ -24,10 +24,6 @@ each commit introduces are shown.
 OPTIONS
 -------
 
--<n>::
-       Limits the number of commits to show.
-       Note that this is a commit limiting option, see below.
-
 <since>..<until>::
        Show only commits between the named two commits.  When
        either <since> or <until> is omitted, it defaults to
@@ -137,6 +133,8 @@ Examples
        This makes sense only when following a strict policy of merging all
        topic branches when staying on a single integration branch.
 
+`git log -3`::
+       Limits the number of commits to show to 3.
 
 Discussion
 ----------
index 7a9b86a58a1c00c08803e9ef40bb6a17146125a9..774de5e9d9fc2d4d88e4f820be177ea6c0a09360 100644 (file)
@@ -42,6 +42,11 @@ OPTIONS
        it successfully talked with the remote repository, whether it
        found any matching refs.
 
+--get-url::
+       Expand the URL of the given remote repository taking into account any
+       "url.<base>.insteadOf" config setting (See linkgit:git-config[1]) and
+       exit without talking to the remote.
+
 <repository>::
        Location of the repository.  The shorthand defined in
        $GIT_DIR/branches/ can be used. Use "." (dot) to list references in
index b295bf83302de3fdac2833df756799a7aad6b404..87842e33f8aebc7d27fa732af1de15f0e4175c07 100644 (file)
@@ -11,6 +11,7 @@ SYNOPSIS
 [verse]
 'git merge-base' [-a|--all] <commit> <commit>...
 'git merge-base' [-a|--all] --octopus <commit>...
+'git merge-base' --is-ancestor <commit> <commit>
 'git merge-base' --independent <commit>...
 
 DESCRIPTION
@@ -50,6 +51,12 @@ from linkgit:git-show-branch[1] when used with the `--merge-base` option.
        from any other.  This mimics the behavior of 'git show-branch
        --independent'.
 
+--is-ancestor::
+       Check if the first <commit> is an ancestor of the second <commit>,
+       and exit with status 0 if true, or with status 1 if not.
+       Errors are signaled by a non-zero status that is not 1.
+
+
 OPTIONS
 -------
 -a::
@@ -110,6 +117,27 @@ both '1' and '2' are merge-bases of A and B.  Neither one is better than
 the other (both are 'best' merge bases).  When the `--all` option is not given,
 it is unspecified which best one is output.
 
+A common idiom to check "fast-forward-ness" between two commits A
+and B is (or at least used to be) to compute the merge base between
+A and B, and check if it is the same as A, in which case, A is an
+ancestor of B.  You will see this idiom used often in older scripts.
+
+       A=$(git rev-parse --verify A)
+       if test "$A" = "$(git merge-base A B)"
+       then
+               ... A is an ancestor of B ...
+       fi
+
+In modern git, you can say this in a more direct way:
+
+       if git merge-base --is-ancestor A B
+       then
+               ... A is an ancestor of B ...
+       fi
+
+instead.
+
+
 See also
 --------
 linkgit:git-rev-list[1],
index 20f9228511e82ac9ced81889bcc66f41504710a3..d34ea3c50bae192cf0f43c782662a48a3df18f8c 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 d7207bd9b9bba59a0e1f97341fb77927026e1b52..6b563c500f660486951cbcac62876bbda5cc3975 100644 (file)
@@ -64,6 +64,9 @@ variable `mergetool.<tool>.trustExitCode` can be set to `true`.
 Otherwise, 'git mergetool' will prompt the user to indicate the
 success of the resolution after the custom tool has exited.
 
+--tool-help::
+       Print a list of merge tools that may be used with `--tool`.
+
 -y::
 --no-prompt::
        Don't prompt before each invocation of the merge resolution
index fe1f49bc6f26950987bc5520267663f4f335dab0..beff6229c8cc4541ca3a8ddd0faf724fceb439e7 100644 (file)
@@ -163,7 +163,7 @@ All commands except clone accept these options.
 --git-dir <dir>::
        Set the 'GIT_DIR' environment variable.  See linkgit:git[1].
 
---verbose::
+--verbose, -v::
        Provide more progress information.
 
 Sync options
@@ -255,7 +255,7 @@ These options can be used to modify 'git p4 submit' behavior.
        p4.  By default, this is the most recent p4 commit reachable
        from 'HEAD'.
 
--M[<n>]::
+-M::
        Detect renames.  See linkgit:git-diff[1].  Renames will be
        represented in p4 using explicit 'move' operations.  There
        is no corresponding option to detect copies, but there are
@@ -269,6 +269,24 @@ These options can be used to modify 'git p4 submit' behavior.
        Export tags from git as p4 labels. Tags found in git are applied
        to the perforce working directory.
 
+--dry-run, -n::
+       Show just what commits would be submitted to p4; do not change
+       state in git or p4.
+
+--prepare-p4-only::
+       Apply a commit to the p4 workspace, opening, adding and deleting
+       files in p4 as for a normal submit operation.  Do not issue the
+       final "p4 submit", but instead print a message about how to
+       submit manually or revert.  This option always stops after the
+       first (oldest) commit.  Git tags are not exported to p4.
+
+--conflict=(ask|skip|quit)::
+       Conflicts can occur when applying a commit to p4.  When this
+       happens, the default behavior ("ask") is to prompt whether to
+       skip this commit and continue, or quit.  This option can be used
+       to bypass the prompt, causing conflicting commits to be automatically
+       skipped, or to quit trying to apply commits, without prompting.
+
 Rebase options
 ~~~~~~~~~~~~~~
 These options can be used to modify 'git p4 rebase' behavior.
@@ -465,13 +483,15 @@ git-p4.useClientSpec::
 Submit variables
 ~~~~~~~~~~~~~~~~
 git-p4.detectRenames::
-       Detect renames.  See linkgit:git-diff[1].
+       Detect renames.  See linkgit:git-diff[1].  This can be true,
+       false, or a score as expected by 'git diff -M'.
 
 git-p4.detectCopies::
-       Detect copies.  See linkgit:git-diff[1].
+       Detect copies.  See linkgit:git-diff[1].  This can be true,
+       false, or a score as expected by 'git diff -C'.
 
 git-p4.detectCopiesHarder::
-       Detect copies harder.  See linkgit:git-diff[1].
+       Detect copies harder.  See linkgit:git-diff[1].  A boolean.
 
 git-p4.preserveUser::
        On submit, re-author changes to reflect the git author,
@@ -517,6 +537,10 @@ git-p4.labelExportRegexp::
        Only p4 labels matching this regular expression will be exported. The
        default value is '[a-zA-Z0-9_\-.]+$'.
 
+git-p4.conflict::
+       Specify submit behavior when a conflict with p4 is found, as per
+       --conflict.  The default behavior is 'ask'.
+
 IMPLEMENTATION DETAILS
 ----------------------
 * Changesets from p4 are imported using git fast-import.
index cb97cc1c3b44d2b5201af8593e593a08bd36855e..fe46c4258a9c8a9dbab0b789215716065bef00ad 100644 (file)
@@ -37,7 +37,9 @@ OPTIONS[[OPTIONS]]
        `+`, followed by the source ref <src>, followed
        by a colon `:`, followed by the destination ref <dst>.
        It is used to specify with what <src> object the <dst> ref
-       in the remote repository is to be updated.
+       in the remote repository is to be updated.  If not specified,
+       the behavior of the command is controlled by the `push.default`
+       configuration variable.
 +
 The <src> is often the name of the branch you would want to push, but
 it can be any arbitrary "SHA-1 expression", such as `master~4` or
@@ -65,7 +67,8 @@ directs git to push "matching" branches: for every branch that exists on
 the local side, the remote side is updated if a branch of the same name
 already exists on the remote side.  This is the default operation mode
 if no explicit refspec is found (that is neither on the command line
-nor in any Push line of the corresponding remotes file---see below).
+nor in any Push line of the corresponding remotes file---see below) and
+no `push.default` configuration variable is set.
 
 --all::
        Instead of naming each ref to push, specifies that all
@@ -172,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
@@ -357,7 +360,8 @@ Examples
        `git push origin :`.
 +
 The default behavior of this command when no <refspec> is given can be
-configured by setting the `push` option of the remote.
+configured by setting the `push` option of the remote, or the `push.default`
+configuration variable.
 +
 For example, to default to pushing only the current branch to `origin`
 use `git config remote.origin.push HEAD`.  Any valid <refspec> (like
index feb51a6ea3e9cd3ddca3179b4cf542cf39f0efc1..da067ecafa37cfc18ed42c971cd62da2c8571931 100644 (file)
@@ -8,11 +8,11 @@ git-rebase - Forward-port local commits to the updated upstream head
 SYNOPSIS
 --------
 [verse]
-'git rebase' [-i | --interactive] [options] [--onto <newbase>]
+'git rebase' [-i | --interactive] [options] [--exec <cmd>] [--onto <newbase>]
        [<upstream>] [<branch>]
-'git rebase' [-i | --interactive] [options] --onto <newbase>
+'git rebase' [-i | --interactive] [options] [--exec <cmd>] [--onto <newbase>]
        --root [<branch>]
-'git rebase' --continue | --skip | --abort
+'git rebase' --continue | --skip | --abort | --edit-todo
 
 DESCRIPTION
 -----------
@@ -210,7 +210,7 @@ rebase.autosquash::
 
 OPTIONS
 -------
-<newbase>::
+--onto <newbase>::
        Starting point at which to create the new commits. If the
        --onto option is not specified, the starting point is
        <upstream>.  May be any valid commit, and not just an
@@ -245,6 +245,9 @@ leave out at most one of A and B, in which case it defaults to HEAD.
 --skip::
        Restart the rebasing process by skipping the current patch.
 
+--edit-todo::
+       Edit the todo list during an interactive rebase.
+
 -m::
 --merge::
        Use merging strategies to rebase.  When the recursive (default) merge
@@ -344,14 +347,36 @@ This uses the `--interactive` machinery internally, but combining it
 with the `--interactive` option explicitly is generally not a good
 idea unless you know what you are doing (see BUGS below).
 
+-x <cmd>::
+--exec <cmd>::
+       Append "exec <cmd>" after each line creating a commit in the
+       final history. <cmd> will be interpreted as one or more shell
+       commands.
++
+This option can only be used with the `--interactive` option
+(see INTERACTIVE MODE below).
++
+You may execute several commands by either using one instance of `--exec`
+with several commands:
++
+       git rebase -i --exec "cmd1 && cmd2 && ..."
++
+or by giving more than one `--exec`:
++
+       git rebase -i --exec "cmd1" --exec "cmd2" --exec ...
++
+If `--autosquash` is used, "exec" lines will not be appended for
+the intermediate commits, and will only appear at the end of each
+squash/fixup series.
 
 --root::
        Rebase all commits reachable from <branch>, instead of
        limiting them with an <upstream>.  This allows you to rebase
-       the root commit(s) on a branch.  Must be used with --onto, and
+       the root commit(s) on a branch.  When used with --onto, it
        will skip changes already contained in <newbase> (instead of
-       <upstream>).  When used together with --preserve-merges, 'all'
-       root commits will be rewritten to have <newbase> as parent
+       <upstream>) whereas without --onto it will operate on every change.
+       When used together with both --onto and --preserve-merges,
+       'all' root commits will be rewritten to have <newbase> as parent
        instead.
 
 --autosquash::
@@ -521,6 +546,24 @@ in `$SHELL`, or the default shell if `$SHELL` is not set), so you can
 use shell features (like "cd", ">", ";" ...). The command is run from
 the root of the working tree.
 
+----------------------------------
+$ git rebase -i --exec "make test"
+----------------------------------
+
+This command lets you check that intermediate commits are compilable.
+The todo list becomes like that:
+
+--------------------
+pick 5928aea one
+exec make test
+pick 04d0fda two
+exec make test
+pick ba46169 three
+exec make test
+pick f4593f9 four
+exec make test
+--------------------
+
 SPLITTING COMMITS
 -----------------
 
index f5836e46d080d8f1f9931a8cd1aa22d0654341ba..5ce4cda8e72ff27a46cd79ae66e8587a9cc2b7d8 100644 (file)
@@ -98,6 +98,20 @@ advertised with this capability must cover all refs reported by
 the list command.  If no 'refspec' capability is advertised,
 there is an implied `refspec *:*`.
 
+'bidi-import'::
+       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.
+
 Capabilities for Pushing
 ~~~~~~~~~~~~~~~~~~~~~~~~
 'connect'::
@@ -286,7 +300,12 @@ terminated with a blank line. For each batch of 'import', the remote
 helper should produce a fast-import stream terminated by a 'done'
 command.
 +
-Supported if the helper has the "import" capability.
+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.
 
 'connect' <service>::
        Connects to given service. Standard input and standard output
index a308f4c79f1a879e124486ef6cffbb2e9f8e606c..e8c396b5f92903777ce5905cf52e2ef879850739 100644 (file)
@@ -12,7 +12,7 @@ SYNOPSIS
 'git remote' [-v | --verbose]
 'git remote add' [-t <branch>] [-m <master>] [-f] [--tags|--no-tags] [--mirror=<fetch|push>] <name> <url>
 'git remote rename' <old> <new>
-'git remote rm' <name>
+'git remote remove' <name>
 'git remote set-head' <name> (-a | -d | <branch>)
 'git remote set-branches' [--add] <name> <branch>...
 'git remote set-url' [--push] <name> <newurl> [<oldurl>]
@@ -85,6 +85,7 @@ In case <old> and <new> are the same, and <old> is a file under
 `$GIT_DIR/remotes` or `$GIT_DIR/branches`, the remote is converted to
 the configuration file format.
 
+'remove'::
 'rm'::
 
 Remove the remote named <name>. All remote-tracking branches and
index 117e3743a62f59a1b6b57f8a36f4ee938f6e1848..978d8da50c150a695565958d89daade5434ce8e0 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 4cc3e9586fcfd79ddeb7f636141e1a878285b0b5..3c63561f02aca6f934c47a2897f8e50cf4ac5fe5 100644 (file)
@@ -101,6 +101,12 @@ OPTIONS
        The option core.warnAmbiguousRefs is used to select the strict
        abbreviation mode.
 
+--disambiguate=<prefix>::
+       Show every object whose name begins with the given prefix.
+       The <prefix> must be at least 4 hexadecimal digits long to
+       avoid listing each and every object in the repository by
+       mistake.
+
 --all::
        Show all refs found in `refs/`.
 
index 5d31860eb1ddf57251d61d16b34693cebc4fd297..882cb1171bb361cd527cd71b8b06639237582dba 100644 (file)
@@ -107,6 +107,21 @@ as well as modifications of existing paths.
 Typically you would first remove all tracked files from the working
 tree using this command:
 
+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.
+
 ----------------
 git ls-files -z | xargs -0 rm -f
 ----------------
index 01d8417316e23bc74f2c86df9004091710437ba7..afeb4cdf16df91f63197d390fdbf1540eff66837 100644 (file)
@@ -14,8 +14,7 @@ git log --pretty=short | 'git shortlog' [-h] [-n] [-s] [-e] [-w]
 DESCRIPTION
 -----------
 Summarizes 'git log' output in a format suitable for inclusion
-in release announcements. Each commit will be grouped by author and
-the first line of the commit message will be shown.
+in release announcements. Each commit will be grouped by author and title.
 
 Additionally, "[PATCH]" will be stripped from the commit description.
 
index 67e5f53a9ef00991954b6bf95286a418c7e4af23..9f1ef9a463a8f884ba69474fdf5e1f338cc43bb9 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 2de7bf090094cd4a5c2d6697493040b445077bf7..1d6527ab9f46fb0eb5d52ef335c1c4b4c377a72b 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>...]
@@ -112,7 +112,6 @@ status::
        initialized, `+` if the currently checked out submodule commit
        does not match the SHA-1 found in the index of the containing
        repository and `U` if the submodule has merge conflicts.
-       This command is the default command for 'git submodule'.
 +
 If `--recursive` is specified, this command will recurse into nested
 submodules, and show their status as well.
@@ -266,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 cfe8d2b5df78b85b7a675423f77a3996ebe24092..8b0d3adfede9ebffbddc294d6f30eedea0e2dfa0 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;
index 65c37c4544f2bed6c979000e726ee5500f588ceb..4a89a1251366ab8312cb20d77b73ecf40ca92349 100644 (file)
@@ -22,18 +22,17 @@ unusually rich command set that provides both high-level operations
 and full access to internals.
 
 See linkgit:gittutorial[7] to get started, then see
-link:everyday.html[Everyday Git] for a useful minimum set of commands, and
-"man git-commandname" for documentation of each command.  CVS users may
-also want to read linkgit:gitcvs-migration[7].  See
-the link:user-manual.html[Git User's Manual] for a more in-depth
-introduction.
+link:everyday.html[Everyday Git] for a useful minimum set of
+commands.  The link:user-manual.html[Git User's Manual] has a more
+in-depth introduction.
 
-The '<command>' is either a name of a Git command (see below) or an alias
-as defined in the configuration file (see linkgit:git-config[1]).
+After you mastered the basic concepts, you can come back to this
+page to learn what commands git offers.  You can learn more about
+individual git commands with "git help command".  linkgit:gitcli[7]
+manual page gives you an overview of the command line command syntax.
 
-Formatted and hyperlinked version of the latest git
-documentation can be viewed at
-`http://www.kernel.org/pub/software/scm/git/docs/`.
+Formatted and hyperlinked version of the latest git documentation
+can be viewed at `http://git-htmldocs.googlecode.com/git/git.html`.
 
 ifdef::stalenotes[]
 [NOTE]
@@ -44,6 +43,20 @@ 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]
+
+* release notes for
+  link:RelNotes/1.8.0.txt[1.8.0],
+
+* link:v1.7.12.4/git.html[documentation for release 1.7.12.4]
+
+* release notes for
+  link:RelNotes/1.7.12.4.txt[1.7.12.4],
+  link:RelNotes/1.7.12.3.txt[1.7.12.3],
+  link:RelNotes/1.7.12.2.txt[1.7.12.2],
+  link:RelNotes/1.7.12.1.txt[1.7.12.1],
+  link:RelNotes/1.7.12.txt[1.7.12].
+
 * link:v1.7.11.7/git.html[documentation for release 1.7.11.7]
 
 * release notes for
@@ -408,24 +421,6 @@ help ...`.
        linkgit:git-replace[1] for more information.
 
 
-FURTHER DOCUMENTATION
----------------------
-
-See the references above to get started using git.  The following is
-probably more detail than necessary for a first-time user.
-
-The link:user-manual.html#git-concepts[git concepts chapter of the
-user-manual] and linkgit:gitcore-tutorial[7] both provide
-introductions to the underlying git architecture.
-
-See linkgit:gitworkflows[7] for an overview of recommended workflows.
-
-See also the link:howto-index.html[howto] documents for some useful
-examples.
-
-The internals are documented in the
-link:technical/api-index.html[GIT API documentation].
-
 GIT COMMANDS
 ------------
 
@@ -845,6 +840,29 @@ The index is also capable of storing multiple entries (called "stages")
 for a given pathname.  These stages are used to hold the various
 unmerged version of a file when a merge is in progress.
 
+FURTHER DOCUMENTATION
+---------------------
+
+See the references in the "description" section to get started
+using git.  The following is probably more detail than necessary
+for a first-time user.
+
+The link:user-manual.html#git-concepts[git concepts chapter of the
+user-manual] and linkgit:gitcore-tutorial[7] both provide
+introductions to the underlying git architecture.
+
+See linkgit:gitworkflows[7] for an overview of recommended workflows.
+
+See also the link:howto-index.html[howto] documents for some useful
+examples.
+
+The internals are documented in the
+link:technical/api-index.html[GIT API documentation].
+
+Users migrating from CVS may also want to
+read linkgit:gitcvs-migration[7].
+
+
 Authors
 -------
 Git was started by Linus Torvalds, and is currently maintained by Junio
index 80120ea14f1ccd2784405c2bf2d54863bb52e8d3..2698f63cf9b492deb32b09e2a60c59f500c47f5c 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
@@ -66,6 +67,11 @@ is from the path in question, the lower its precedence). Finally
 global and system-wide files are considered (they have the lowest
 precedence).
 
+When the `.gitattributes` file is missing from the work tree, the
+path in the index is used as a fall-back.  During checkout process,
+`.gitattributes` in the index is used and then the file in the
+working tree is used as a fall-back.
+
 If you wish to affect only a single repository (i.e., to assign
 attributes to files that are particular to
 one user's workflow for that repository), then
@@ -75,6 +81,8 @@ repositories (i.e., attributes of interest to all users) should go into
 `.gitattributes` files. Attributes that should affect all repositories
 for a single user should be placed in a file specified by the
 `core.attributesfile` configuration option (see linkgit:git-config[1]).
+Its default value is $XDG_CONFIG_HOME/git/attributes. If $XDG_CONFIG_HOME
+is either not set or empty, $HOME/.config/git/attributes is used instead.
 Attributes for all users on a system should be placed in the
 `$(prefix)/etc/gitattributes` file.
 
@@ -509,6 +517,8 @@ configuration file (you still need to enable this with the
 attribute mechanism, via `.gitattributes`).  The following built in
 patterns are available:
 
+- `ada` suitable for source code in the Ada language.
+
 - `bibtex` suitable for files with BibTeX coded references.
 
 - `cpp` suitable for source code in the C and C++ languages.
@@ -925,7 +935,7 @@ file at the toplevel (i.e. not in any subdirectory).  The built-in
 macro attribute "binary" is equivalent to:
 
 ------------
-[attr]binary -diff -text
+[attr]binary -diff -merge -text
 ------------
 
 
index f6ba90c2da8f381bc714762f24bbfc33fa82b356..3bc1500eda540cf7277e602b3d0ade1a3c1dc1be 100644 (file)
@@ -93,7 +93,7 @@ ENHANCED OPTION PARSER
 From the git 1.5.4 series and further, many git commands (not all of them at the
 time of the writing though) come with an enhanced option parser.
 
-Here is an exhaustive list of the facilities provided by this option parser.
+Here is a list of the facilities provided by this option parser.
 
 
 Magic Options
@@ -137,6 +137,16 @@ options. This means that you can for example use `git rm -rf` or
 `git clean -fdx`.
 
 
+Abbreviating long options
+~~~~~~~~~~~~~~~~~~~~~~~~~
+Commands that support the enhanced option parser accepts unique
+prefix of a long option as if it is fully spelled out, but use this
+with a caution.  For example, `git commit --amen` behaves as if you
+typed `git commit --amend`, but that is true only until a later version
+of Git introduces another option that shares the same prefix,
+e.g `git commit --amenity" option.
+
+
 Separating argument from the option
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 You can write the mandatory option parameter to an option as a separate
index 9d893369a00b6a924876fb234c1082db2021abf3..5325c5a7d5cab3f74c3866319a60d35e4299da2e 100644 (file)
@@ -956,12 +956,11 @@ $ git show-branch --topo-order --more=1 master mybranch
 ------------------------------------------------
 
 The first two lines indicate that it is showing the two branches
-and the first line of the commit log message from their
-top-of-the-tree commits, you are currently on `master` branch
-(notice the asterisk `*` character), and the first column for
-the later output lines is used to show commits contained in the
+with the titles of their top-of-the-tree commits, you are currently on
+`master` branch (notice the asterisk `*` character), and the first
+column for the later output lines is used to show commits contained in the
 `master` branch, and the second column for the `mybranch`
-branch. Three commits are shown along with their log messages.
+branch. Three commits are shown along with their titles.
 All of them have non blank characters in the first column (`*`
 shows an ordinary commit on the current branch, `-` is a merge commit), which
 means they are now part of the `master` branch. Only the "Some
index 2e7328b8306f4e949e22456b33d495226c1f014b..1b82fe1969ed1cf965d946178a423771dd3cfe5f 100644 (file)
@@ -41,16 +41,24 @@ precedence, the last matching pattern decides the outcome):
    variable 'core.excludesfile'.
 
 Which file to place a pattern in depends on how the pattern is meant to
-be used. Patterns which should be version-controlled and distributed to
-other repositories via clone (i.e., files that all developers will want
-to ignore) should go into a `.gitignore` file. Patterns which are
-specific to a particular repository but which do not need to be shared
-with other related repositories (e.g., auxiliary files that live inside
-the repository but are specific to one user's workflow) should go into
-the `$GIT_DIR/info/exclude` file.  Patterns which a user wants git to
-ignore in all situations (e.g., backup or temporary files generated by
-the user's editor of choice) generally go into a file specified by
-`core.excludesfile` in the user's `~/.gitconfig`.
+be used.
+
+ * Patterns which should be version-controlled and distributed to
+   other repositories via clone (i.e., files that all developers will want
+   to ignore) should go into a `.gitignore` file.
+
+ * Patterns which are
+   specific to a particular repository but which do not need to be shared
+   with other related repositories (e.g., auxiliary files that live inside
+   the repository but are specific to one user's workflow) should go into
+   the `$GIT_DIR/info/exclude` file.
+
+ * Patterns which a user wants git to
+   ignore in all situations (e.g., backup or temporary files generated by
+   the user's editor of choice) generally go into a file specified by
+   `core.excludesfile` in the user's `~/.gitconfig`. Its default value is
+   $XDG_CONFIG_HOME/git/ignore. If $XDG_CONFIG_HOME is either not set or
+   empty, $HOME/.config/git/ignore is used instead.
 
 The underlying git plumbing tools, such as
 'git ls-files' and 'git read-tree', read
@@ -66,11 +74,15 @@ PATTERN FORMAT
    for readability.
 
  - A line starting with # serves as a comment.
+   Put a backslash ("`\`") in front of the first hash for patterns
+   that begin with a hash.
 
- - An optional prefix '!' which negates the pattern; any
+ - An optional prefix "`!`" which negates the pattern; any
    matching file excluded by a previous pattern will become
    included again.  If a negated pattern matches, this will
    override lower precedence patterns sources.
+   Put a backslash ("`\`") in front of the first "`!`" for patterns
+   that begin with a literal "`!`", for example, "`\!important!.txt`".
 
  - If the pattern ends with a slash, it is removed for the
    purpose of the following description, but it would only find
index 4effd789026e48085d6b0834cbef990968bedbb2..ab3e91c054ca7b4dcf7373b0aac839c18275a791 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 5c891f1169b35e53bccc19f0423b5b7e98db720b..9f628862b4f571608c5bd9185e39cb240b137037 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 dee050567e65301066629c566613b84c6c065169..f1cb6f3be67fbb03583a35601791f0db839fbe1b 100644 (file)
@@ -139,9 +139,11 @@ them to the index, and commit, all in one step.
 A note on commit messages: Though not required, it's a good idea to
 begin the commit message with a single short (less than 50 character)
 line summarizing the change, followed by a blank line and then a more
-thorough description.  Tools that turn commits into email, for
-example, use the first line on the Subject: line and the rest of the
-commit in the body.
+thorough description. The text up to the first blank line in a commit
+message is treated as the commit title, and that title is used
+throughout git.  For example, linkgit:git-format-patch[1] turns a
+commit into email, and it uses the title on the Subject line and the
+rest of the commit in the body.
 
 Git tracks content not files
 ----------------------------
index 861bd6f55352a12db6d1d680508e1d02a8e90d12..9bb4956ccdbef507ab115ac19dfe8ad326afb7c2 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::
index 595a3cf1a7118ba29a1d57d7fc17d233d89cd3d0..66db80296f505a9bd830c746f82bb54e3f49f313 100644 (file)
@@ -32,13 +32,14 @@ ours;;
        This option forces conflicting hunks to be auto-resolved cleanly by
        favoring 'our' version.  Changes from the other tree that do not
        conflict with our side are reflected to the merge result.
+       For a binary file, the entire contents are taken from our side.
 +
 This should not be confused with the 'ours' merge strategy, which does not
 even look at what the other tree contains at all.  It discards everything
 the other tree did, declaring 'our' history contains all that happened in it.
 
 theirs;;
-       This is opposite of 'ours'.
+       This is the opposite of 'ours'.
 
 patience;;
        With this option, 'merge-recursive' spends a little extra time
index e3d8a83b23aff51c8dd4281f18de8661514b62b1..d9eddedc72a5e6362d68df1b126b76804b9676e1 100644 (file)
@@ -130,6 +130,9 @@ The placeholders are:
 - '%b': body
 - '%B': raw body (unwrapped subject and body)
 - '%N': commit notes
+- '%GG': raw verification message from GPG for a signed commit
+- '%G?': show either "G" for Good or "B" for Bad for a signed commit
+- '%GS': show the name of the signer for a signed commit
 - '%gD': reflog selector, e.g., `refs/stash@{1}`
 - '%gd': shortened reflog selector, e.g., `stash@{1}`
 - '%gn': reflog identity name
index 2a3dc8664f16957a05bc4d81824d7995517ac89c..5e499421a43526e133c7bd3be134da803b35c00d 100644 (file)
@@ -66,3 +66,7 @@ being displayed. Examples: "--notes=foo" will show only notes from
 --[no-]standard-notes::
        These options are deprecated. Use the above --notes/--no-notes
        options instead.
+
+--show-signature::
+       Check the validity of a signed commit object by passing the signature
+       to `gpg --verify` and show the output.
index def1340ac73cc3abab8084f14dfb8d54d2476177..1ec14a068e750b114ac5f1ad2f468de8d0664a16 100644 (file)
@@ -3,12 +3,20 @@ Commit Limiting
 
 Besides specifying a range of commits that should be listed using the
 special notations explained in the description, additional commit
-limiting may be applied. Note that they are applied before commit
-ordering and formatting options, such as '--reverse'.
+limiting may be applied.
+
+Using more options generally further limits the output (e.g.
+`--since=<date1>` limits to commits newer than `<date1>`, and using it
+with `--grep=<pattern>` further limits to commits whose log message
+has a line that matches `<pattern>`), unless otherwise noted.
+
+Note that these are applied before commit
+ordering and formatting options, such as `--reverse`.
 
 --
 
--n 'number'::
+-<number>::
+-n <number>::
 --max-count=<number>::
 
        Limit the number of commits to output.
@@ -38,22 +46,44 @@ endif::git-rev-list[]
 --committer=<pattern>::
 
        Limit the commits output to ones with author/committer
-       header lines that match the specified pattern (regular expression).
+       header lines that match the specified pattern (regular
+       expression).  With more than one `--author=<pattern>`,
+       commits whose author matches any of the given patterns are
+       chosen (similarly for multiple `--committer=<pattern>`).
+
+--grep-reflog=<pattern>::
+
+       Limit the commits output to ones with reflog entries that
+       match the specified pattern (regular expression). With
+       more than one `--grep-reflog`, commits whose reflog message
+       matches any of the given patterns are chosen.  It is an
+       error to use this option unless `--walk-reflogs` is in use.
 
 --grep=<pattern>::
 
        Limit the commits output to ones with log message that
-       matches the specified pattern (regular expression).
+       matches the specified pattern (regular expression).  With
+       more than one `--grep=<pattern>`, commits whose message
+       matches any of the given patterns are chosen (but see
+       `--all-match`).
++
+When `--show-notes` is in effect, the message from the notes as
+if it is part of the log message.
 
 --all-match::
        Limit the commits output to ones that match all given --grep,
-       --author and --committer instead of ones that match at least one.
+       instead of ones that match at least one.
 
 -i::
 --regexp-ignore-case::
 
        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::
 
@@ -66,6 +96,11 @@ endif::git-rev-list[]
        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.
@@ -636,10 +671,14 @@ These options are mostly targeted for packing of git repositories.
        Only useful with '--objects'; print the object IDs that are not
        in packs.
 
---no-walk::
+--no-walk[=(sorted|unsorted)]::
 
-       Only show the given revs, but do not traverse their ancestors.
-       This has no effect if a range is specified.
+       Only show the given commits, but do not traverse their ancestors.
+       This has no effect if a range is specified. If the argument
+       "unsorted" is given, the commits are show in the order they were
+       given on the command line. Otherwise (if "sorted" or no argument
+       was given), the commits are show in reverse chronological order
+       by commit time.
 
 --do-walk::
 
index 69d996bc3899a89de49b0cbdf65f5b8ebd47d714..991fcd8f3fabe5a1d399db3b4c7f79e3989e5019 100644 (file)
@@ -55,6 +55,8 @@ when you run `git cherry-pick`.
 +
 Note that any of the 'refs/*' cases above may come either from
 the '$GIT_DIR/refs' directory or from the '$GIT_DIR/packed-refs' file.
+While the ref name encoding is unspecified, UTF-8 is prefered as
+some output processing may assume ref names in UTF-8.
 
 '<refname>@\{<date>\}', e.g. 'master@\{yesterday\}', 'HEAD@\{5 minutes ago\}'::
   A ref followed by the suffix '@' with a date specification
index 1b7d8f140c27d76cfa460c0839c44c6742110df7..a959517b2339847e92464c86a73f9c472bfdb2d0 100644 (file)
@@ -46,6 +46,18 @@ Functions
        Format a string and push it onto the end of the array. This is a
        convenience wrapper combining `strbuf_addf` and `argv_array_push`.
 
+`argv_array_pop`::
+       Remove the final element from the array. If there are no
+       elements in the array, do nothing.
+
 `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 adb6f0c8962377b3dc04fcdc948e40bfbd132a1b..5977b58e57344e60bd683553d9b1b9a44b3c31a7 100644 (file)
@@ -241,42 +241,9 @@ appended to its command line, which is one of:
        Remove a matching credential, if any, from the helper's storage.
 
 The details of the credential will be provided on the helper's stdin
-stream. The credential is split into a set of named attributes.
-Attributes are provided to the helper, one per line. Each attribute is
-specified by a key-value pair, separated by an `=` (equals) sign,
-followed by a newline. The key may contain any bytes except `=`,
-newline, or NUL. The value may contain any bytes except newline or NUL.
-In both cases, all bytes are treated as-is (i.e., there is no quoting,
-and one cannot transmit a value with newline or NUL in it). The list of
-attributes is terminated by a blank line or end-of-file.
-
-Git will send the following attributes (but may not send all of
-them for a given credential; for example, a `host` attribute makes no
-sense when dealing with a non-network protocol):
-
-`protocol`::
-
-       The protocol over which the credential will be used (e.g.,
-       `https`).
-
-`host`::
-
-       The remote hostname for a network credential.
-
-`path`::
-
-       The path with which the credential will be used. E.g., for
-       accessing a remote https repository, this will be the
-       repository's path on the server.
-
-`username`::
-
-       The credential's username, if we already have one (e.g., from a
-       URL, from the user, or from a previously run helper).
-
-`password`::
-
-       The credential's password, if we are asking it to be stored.
+stream. The exact format is the same as the input/output format of the
+`git credential` plumbing command (see the section `INPUT/OUTPUT
+FORMAT` in linkgit:git-credential[7] for a detailed specification).
 
 For a `get` operation, the helper should produce a list of attributes
 on stdout in the same format. A helper is free to produce a subset, or
index 4a4bae81093d7a985625d42effd92db9a957ba78..45d1c517cd862878198db6023d5fdbd35f9fbb6c 100644 (file)
@@ -25,9 +25,6 @@ Functions
        the array (but note that some operations below may lose this
        ordering).
 
-`sha1_array_sort`::
-       Sort the elements in the array.
-
 `sha1_array_lookup`::
        Perform a binary search of the array for a specific sha1.
        If found, returns the offset (in number of elements) of the
index 5a0c14fcebfcf4d5cbad4900d062703412c501e1..94d7a2bd999ce5e8603f6d6639ba34d224c2bee5 100644 (file)
@@ -1,8 +1,9 @@
 string-list API
 ===============
 
-The string_list API offers a data structure and functions to handle sorted
-and unsorted string lists.
+The string_list API offers a data structure and functions to handle
+sorted and unsorted string lists.  A "sorted" list is one whose
+entries are sorted by string value in `strcmp()` order.
 
 The 'string_list' struct used to be called 'path_list', but was renamed
 because it is not specific to paths.
@@ -20,8 +21,9 @@ If you need something advanced, you can manually malloc() the `items`
 member (you need this if you add things later) and you should set the
 `nr` and `alloc` members in that case, too.
 
-. Adds new items to the list, using `string_list_append` or
-  `string_list_insert`.
+. Adds new items to the list, using `string_list_append`,
+  `string_list_append_nodup`, `string_list_insert`,
+  `string_list_split`, and/or `string_list_split_in_place`.
 
 . Can check if a string is in the list using `string_list_has_string` or
   `unsorted_string_list_has_string` and get it from the list using
@@ -29,18 +31,23 @@ member (you need this if you add things later) and you should set the
 
 . Can sort an unsorted list using `sort_string_list`.
 
+. Can remove duplicate items from a sorted list using
+  `string_list_remove_duplicates`.
+
 . Can remove individual items of an unsorted list using
   `unsorted_string_list_delete_item`.
 
+. Can remove items not matching a criterion from a sorted or unsorted
+  list using `filter_string_list`.
+
 . Finally it should free the list using `string_list_clear`.
 
 Example:
 
 ----
-struct string_list list;
+struct string_list list = STRING_LIST_INIT_NODUP;
 int i;
 
-memset(&list, 0, sizeof(struct string_list));
 string_list_append(&list, "foo");
 string_list_append(&list, "bar");
 for (i = 0; i < list.nr; i++)
@@ -60,6 +67,22 @@ Functions
 
 * General ones (works with sorted and unsorted lists as well)
 
+`filter_string_list`::
+
+       Apply a function to each item in a list, retaining only the
+       items for which the function returns true.  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.
+
+`string_list_longest_prefix`::
+
+       Return the longest string within a string_list that is a
+       prefix (in the sense of prefixcmp()) of the specified string,
+       or NULL if no such prefix exists.  This function does not
+       require the string_list to be sorted (it does a linear
+       search).
+
 `print_string_list`::
 
        Dump a string_list to stdout, useful mainly for debugging purposes. It
@@ -96,15 +119,32 @@ write `string_list_insert(...)->util = ...;`.
        Look up a given string in the string_list, returning the containing
        string_list_item. If the string is not found, NULL is returned.
 
+`string_list_remove_duplicates`::
+
+       Remove all but the first of consecutive entries that have the
+       same string value.  If free_util is true, call free() on the
+       util members of any items that have to be deleted.
+
 * Functions for unsorted lists only
 
 `string_list_append`::
 
-       Append a new string to the end of the string_list.
+       Append a new string to the end of the string_list.  If
+       `strdup_string` is set, then the string argument is copied;
+       otherwise the new `string_list_entry` refers to the input
+       string.
+
+`string_list_append_nodup`::
+
+       Append a new string to the end of the string_list.  The new
+       `string_list_entry` always refers to the input string, even if
+       `strdup_string` is set.  This function can be used to hand
+       ownership of a malloc()ed string to a `string_list` that has
+       `strdup_string` set.
 
 `sort_string_list`::
 
-       Make an unsorted list sorted.
+       Sort the list's entries by string value in `strcmp()` order.
 
 `unsorted_string_list_has_string`::
 
@@ -124,6 +164,25 @@ counterpart for sorted lists, which performs a binary search.
        is set. The third parameter controls if the `util` pointer of the
        items should be freed or not.
 
+`string_list_split`::
+`string_list_split_in_place`::
+
+       Split a string into substrings on a delimiter character and
+       append the substrings to a `string_list`.  If `maxsplit` is
+       non-negative, then split at most `maxsplit` times.  Return the
+       number of substrings appended to the list.
++
+`string_list_split` requires a `string_list` that has `strdup_strings`
+set to true; it leaves the input string untouched and makes copies of
+the substrings in newly-allocated memory.
+`string_list_split_in_place` requires a `string_list` that has
+`strdup_strings` set to false; it splits the input string in place,
+overwriting the delimiter characters with NULs and creating new
+string_list_items that point into the original string (the original
+string must therefore not be modified or freed while the `string_list`
+is in use).
+
+
 Data structures
 ---------------
 
index 49cdc571cd7e276df2913b0ccf9d1e2320b31c9d..d51e20f3526e2681b8c05c296b91dd90a4d3e322 100644 (file)
@@ -259,8 +259,10 @@ a positive depth, this step is skipped.
 ----
 
 If the client has requested a positive depth, the server will compute
-the set of commits which are no deeper than the desired depth, starting
-at the client's wants. The server writes 'shallow' lines for each
+the set of commits which are no deeper than the desired depth. The set
+of commits start at the client's wants.
+
+The server writes 'shallow' lines for each
 commit whose parents will not be sent as a result. The server writes
 an 'unshallow' line for each commit which the client has indicated is
 shallow, but is no longer shallow at the currently requested depth
index 289019478d16719e5d2c86b7a17017005bd9a80d..1d15ee7e5209f93a387db348dcccd6abd9cb306f 100644 (file)
@@ -6,8 +6,12 @@ address of the remote server, and the path to the repository.
 Depending on the transport protocol, some of this information may be
 absent.
 
-Git natively supports ssh, git, http, https, ftp, ftps, and rsync
-protocols. The following syntaxes may be used with them:
+Git supports ssh, git, http, and https protocols (in addition, ftp,
+and ftps can be used for fetching and rsync can be used for fetching
+and pushing, but these are inefficient and deprecated; do not use
+them).
+
+The following syntaxes may be used with them:
 
 - ssh://{startsb}user@{endsb}host.xz{startsb}:port{endsb}/path/to/repo.git/
 - git://host.xz{startsb}:port{endsb}/path/to/repo.git/
index 03d95dc290cecd2223116be90b591f75d40ced2b..85651b57ae466496e98e9c2507072f9fa8125c4d 100644 (file)
@@ -1136,9 +1136,12 @@ Creating good commit messages
 Though not required, it's a good idea to begin the commit message
 with a single short (less than 50 character) line summarizing the
 change, followed by a blank line and then a more thorough
-description.  Tools that turn commits into email, for example, use
-the first line on the Subject line and the rest of the commit in the
-body.
+description.  The text up to the first blank line in a commit
+message is treated as the commit title, and that title is used
+throughout git.  For example, linkgit:git-format-patch[1] turns a
+commit into email, and it uses the title on the Subject line and the
+rest of the commit in the body.
+
 
 [[ignoring-files]]
 Ignoring files
index 28f12902a692c1107886efc9b5a3cc8438989f17..b09d264a865fc6ad4a2f0acd930d82150f0e1280 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v1.7.11.7
+DEF_VER=v1.8.0
 
 LF='
 '
index 13293d33fd1debc5a7dce38b7bf93ea9a89d11ca..40829a9e994ef57e07bdcc16f0c6c8fd137f01fc 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -90,6 +90,8 @@ all::
 #
 # Define NO_MKDTEMP if you don't have mkdtemp in the C library.
 #
+# Define MKDIR_WO_TRAILING_SLASH if your mkdir() can't deal with trailing slash.
+#
 # Define NO_MKSTEMPS if you don't have mkstemps in the C library.
 #
 # Define NO_STRTOK_R if you don't have strtok_r in the C library.
@@ -143,6 +145,12 @@ all::
 #
 # Define NEEDS_LIBICONV if linking with libc is not enough (Darwin).
 #
+# Define NEEDS_LIBINTL_BEFORE_LIBICONV if you need libintl before libiconv.
+#
+# Define NO_INTPTR_T if you don't have intptr_t nor uintptr_t.
+#
+# Define NO_UINTMAX_T if you don't have uintmax_t.
+#
 # Define NEEDS_SOCKET if linking with libc is not enough (SunOS,
 # Patrick Mauritz).
 #
@@ -152,11 +160,21 @@ all::
 #
 # Define NO_MMAP if you want to avoid mmap.
 #
+# Define NO_SYS_POLL_H if you don't have sys/poll.h.
+#
+# Define NO_POLL if you do not have or don't want to use poll().
+# This also implies NO_SYS_POLL_H.
+#
 # Define NO_PTHREADS if you do not have or do not want to use Pthreads.
 #
 # Define NO_PREAD if you have a problem with pread() system call (e.g.
 # cygwin1.dll before v1.5.22).
 #
+# Define NO_SETITIMER if you don't have setitimer()
+#
+# Define NO_STRUCT_ITIMERVAL if you don't have struct itimerval
+# This also implies NO_SETITIMER
+#
 # Define NO_THREAD_SAFE_PREAD if your pread() implementation is not
 # thread-safe. (e.g. compat/pread.c or cygwin)
 #
@@ -205,8 +223,6 @@ all::
 # Define NO_ST_BLOCKS_IN_STRUCT_STAT if your platform does not have st_blocks
 # field that counts the on-disk footprint in 512-byte blocks.
 #
-# Define ASCIIDOC7 if you want to format documentation with AsciiDoc 7
-#
 # Define DOCBOOK_XSL_172 if you want to format man pages with DocBook XSL v1.72
 # (not v1.73 or v1.71).
 #
@@ -298,6 +314,13 @@ all::
 # the diff algorithm.  It gives a nice speedup if your processor has
 # fast unaligned word loads.  Does NOT work on big-endian systems!
 # Enabled by default on x86_64.
+#
+# Define GIT_USER_AGENT if you want to change how git identifies itself during
+# network interactions.  The default is "git/$(GIT_VERSION)".
+#
+# Define DEFAULT_HELP_FORMAT to "man", "info" or "html"
+# (defaults to "man") if you want to have a different default when
+# "git help" is called without a parameter specifying the format.
 
 GIT-VERSION-FILE: FORCE
        @$(SHELL_PATH) ./GIT-VERSION-GEN
@@ -391,12 +414,9 @@ BUILTIN_OBJS =
 BUILT_INS =
 COMPAT_CFLAGS =
 COMPAT_OBJS =
-XDIFF_H =
 XDIFF_OBJS =
-VCSSVN_H =
 VCSSVN_OBJS =
-VCSSVN_TEST_OBJS =
-MISC_H =
+GENERATED_H =
 EXTRA_CPPFLAGS =
 LIB_H =
 LIB_OBJS =
@@ -475,6 +495,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 =
@@ -482,7 +503,6 @@ X =
 PROGRAMS += $(patsubst %.o,git-%$X,$(PROGRAM_OBJS))
 
 TEST_PROGRAMS_NEED_X += test-chmtime
-TEST_PROGRAMS_NEED_X += test-credential
 TEST_PROGRAMS_NEED_X += test-ctype
 TEST_PROGRAMS_NEED_X += test-date
 TEST_PROGRAMS_NEED_X += test-delta
@@ -501,6 +521,7 @@ TEST_PROGRAMS_NEED_X += test-run-command
 TEST_PROGRAMS_NEED_X += test-scrap-cache-tree
 TEST_PROGRAMS_NEED_X += test-sha1
 TEST_PROGRAMS_NEED_X += test-sigchain
+TEST_PROGRAMS_NEED_X += test-string-list
 TEST_PROGRAMS_NEED_X += test-subprocess
 TEST_PROGRAMS_NEED_X += test-svn-fe
 
@@ -558,54 +579,47 @@ LIB_FILE=libgit.a
 XDIFF_LIB=xdiff/lib.a
 VCSSVN_LIB=vcs-svn/lib.a
 
-XDIFF_H += xdiff/xinclude.h
-XDIFF_H += xdiff/xmacros.h
-XDIFF_H += xdiff/xdiff.h
-XDIFF_H += xdiff/xtypes.h
-XDIFF_H += xdiff/xutils.h
-XDIFF_H += xdiff/xprepare.h
-XDIFF_H += xdiff/xdiffi.h
-XDIFF_H += xdiff/xemit.h
-
-VCSSVN_H += vcs-svn/line_buffer.h
-VCSSVN_H += vcs-svn/sliding_window.h
-VCSSVN_H += vcs-svn/repo_tree.h
-VCSSVN_H += vcs-svn/fast_export.h
-VCSSVN_H += vcs-svn/svndiff.h
-VCSSVN_H += vcs-svn/svndump.h
-
-MISC_H += bisect.h
-MISC_H += branch.h
-MISC_H += bundle.h
-MISC_H += common-cmds.h
-MISC_H += fetch-pack.h
-MISC_H += reachable.h
-MISC_H += send-pack.h
-MISC_H += shortlog.h
-MISC_H += tar.h
-MISC_H += thread-utils.h
-MISC_H += url.h
-MISC_H += walker.h
-MISC_H += wt-status.h
+LIB_H += xdiff/xinclude.h
+LIB_H += xdiff/xmacros.h
+LIB_H += xdiff/xdiff.h
+LIB_H += xdiff/xtypes.h
+LIB_H += xdiff/xutils.h
+LIB_H += xdiff/xprepare.h
+LIB_H += xdiff/xdiffi.h
+LIB_H += xdiff/xemit.h
+
+LIB_H += vcs-svn/line_buffer.h
+LIB_H += vcs-svn/sliding_window.h
+LIB_H += vcs-svn/repo_tree.h
+LIB_H += vcs-svn/fast_export.h
+LIB_H += vcs-svn/svndiff.h
+LIB_H += vcs-svn/svndump.h
+
+GENERATED_H += common-cmds.h
 
 LIB_H += advice.h
 LIB_H += archive.h
 LIB_H += argv-array.h
 LIB_H += attr.h
+LIB_H += bisect.h
 LIB_H += blob.h
+LIB_H += branch.h
 LIB_H += builtin.h
 LIB_H += bulk-checkin.h
-LIB_H += cache.h
+LIB_H += bundle.h
 LIB_H += cache-tree.h
+LIB_H += cache.h
 LIB_H += color.h
+LIB_H += column.h
 LIB_H += commit.h
 LIB_H += compat/bswap.h
 LIB_H += compat/cygwin.h
 LIB_H += compat/mingw.h
 LIB_H += compat/obstack.h
+LIB_H += compat/poll/poll.h
+LIB_H += compat/precompose_utf8.h
 LIB_H += compat/terminal.h
 LIB_H += compat/win32/dirent.h
-LIB_H += compat/win32/poll.h
 LIB_H += compat/win32/pthread.h
 LIB_H += compat/win32/syslog.h
 LIB_H += connected.h
@@ -618,6 +632,7 @@ LIB_H += diff.h
 LIB_H += diffcore.h
 LIB_H += dir.h
 LIB_H += exec_cmd.h
+LIB_H += fetch-pack.h
 LIB_H += fmt-merge-msg.h
 LIB_H += fsck.h
 LIB_H += gettext.h
@@ -627,6 +642,7 @@ LIB_H += graph.h
 LIB_H += grep.h
 LIB_H += hash.h
 LIB_H += help.h
+LIB_H += http.h
 LIB_H += kwset.h
 LIB_H += levenshtein.h
 LIB_H += list-objects.h
@@ -636,19 +652,20 @@ LIB_H += mailmap.h
 LIB_H += merge-file.h
 LIB_H += merge-recursive.h
 LIB_H += mergesort.h
-LIB_H += notes.h
 LIB_H += notes-cache.h
 LIB_H += notes-merge.h
+LIB_H += notes.h
 LIB_H += object.h
-LIB_H += pack.h
 LIB_H += pack-refs.h
 LIB_H += pack-revindex.h
+LIB_H += pack.h
 LIB_H += parse-options.h
 LIB_H += patch-ids.h
 LIB_H += pkt-line.h
 LIB_H += progress.h
 LIB_H += prompt.h
 LIB_H += quote.h
+LIB_H += reachable.h
 LIB_H += reflog-walk.h
 LIB_H += refs.h
 LIB_H += remote.h
@@ -656,9 +673,11 @@ LIB_H += rerere.h
 LIB_H += resolve-undo.h
 LIB_H += revision.h
 LIB_H += run-command.h
+LIB_H += send-pack.h
 LIB_H += sequencer.h
 LIB_H += sha1-array.h
 LIB_H += sha1-lookup.h
+LIB_H += shortlog.h
 LIB_H += sideband.h
 LIB_H += sigchain.h
 LIB_H += strbuf.h
@@ -666,14 +685,18 @@ LIB_H += streaming.h
 LIB_H += string-list.h
 LIB_H += submodule.h
 LIB_H += tag.h
+LIB_H += tar.h
 LIB_H += thread-utils.h
 LIB_H += transport.h
-LIB_H += tree.h
 LIB_H += tree-walk.h
+LIB_H += tree.h
 LIB_H += unpack-trees.h
+LIB_H += url.h
 LIB_H += userdiff.h
 LIB_H += utf8.h
 LIB_H += varint.h
+LIB_H += walker.h
+LIB_H += wt-status.h
 LIB_H += xdiff-interface.h
 LIB_H += xdiff/xdiff.h
 
@@ -802,6 +825,7 @@ LIB_OBJS += usage.o
 LIB_OBJS += userdiff.o
 LIB_OBJS += utf8.o
 LIB_OBJS += varint.o
+LIB_OBJS += version.o
 LIB_OBJS += walker.o
 LIB_OBJS += wrapper.o
 LIB_OBJS += write_or_die.o
@@ -830,6 +854,7 @@ BUILTIN_OBJS += builtin/commit-tree.o
 BUILTIN_OBJS += builtin/commit.o
 BUILTIN_OBJS += builtin/config.o
 BUILTIN_OBJS += builtin/count-objects.o
+BUILTIN_OBJS += builtin/credential.o
 BUILTIN_OBJS += builtin/describe.o
 BUILTIN_OBJS += builtin/diff-files.o
 BUILTIN_OBJS += builtin/diff-index.o
@@ -907,6 +932,8 @@ BUILTIN_OBJS += builtin/write-tree.o
 GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
 EXTLIBS =
 
+GIT_USER_AGENT = git/$(GIT_VERSION)
+
 #
 # Platform specific tweaks
 #
@@ -993,6 +1020,8 @@ ifeq ($(uname_S),Darwin)
        NO_MEMMEM = YesPlease
        USE_ST_TIMESPEC = YesPlease
        HAVE_DEV_TTY = YesPlease
+       COMPAT_OBJS += compat/precompose_utf8.o
+       BASIC_CFLAGS += -DPRECOMPOSE_UNICODE
 endif
 ifeq ($(uname_S),SunOS)
        NEEDS_SOCKET = YesPlease
@@ -1208,7 +1237,7 @@ ifeq ($(uname_S),Windows)
        NO_PREAD = YesPlease
        NEEDS_CRYPTO_WITH_SSL = YesPlease
        NO_LIBGEN_H = YesPlease
-       NO_SYS_POLL_H = YesPlease
+       NO_POLL = YesPlease
        NO_SYMLINK_HEAD = YesPlease
        NO_IPV6 = YesPlease
        NO_UNIX_SOCKETS = YesPlease
@@ -1241,6 +1270,7 @@ ifeq ($(uname_S),Windows)
        BLK_SHA1 = YesPlease
        NO_POSIX_GOODIES = UnfortunatelyYes
        NATIVE_CRLF = YesPlease
+       DEFAULT_HELP_FORMAT = html
 
        CC = compat/vcbuild/scripts/clink.pl
        AR = compat/vcbuild/scripts/lib.pl
@@ -1248,7 +1278,7 @@ ifeq ($(uname_S),Windows)
        BASIC_CFLAGS = -nologo -I. -I../zlib -Icompat/vcbuild -Icompat/vcbuild/include -DWIN32 -D_CONSOLE -DHAVE_STRING_H -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE
        COMPAT_OBJS = compat/msvc.o compat/winansi.o \
                compat/win32/pthread.o compat/win32/syslog.o \
-               compat/win32/poll.o compat/win32/dirent.o
+               compat/win32/dirent.o
        COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/regex -Icompat/win32 -DSTRIP_EXTENSION=\".exe\"
        BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRT.lib
        EXTLIBS = user32.lib advapi32.lib shell32.lib wininet.lib ws2_32.lib
@@ -1298,12 +1328,67 @@ ifeq ($(uname_S),Minix)
        NO_CURL =
        NO_EXPAT =
 endif
+ifeq ($(uname_S),NONSTOP_KERNEL)
+       # Needs some C99 features, "inline" is just one of them.
+       # INLINE='' would just replace one set of warnings with another and
+       # still not compile in c89 mode, due to non-const array initializations.
+       CC = cc -c99
+       # Disable all optimization, seems to result in bad code, with -O or -O2
+       # or even -O1 (default), /usr/local/libexec/git-core/git-pack-objects
+       # abends on "git push". Needs more investigation.
+       CFLAGS = -g -O0
+       # We'd want it to be here.
+       prefix = /usr/local
+       # Our's are in ${prefix}/bin (perl might also be in /usr/bin/perl).
+       PERL_PATH = ${prefix}/bin/perl
+       PYTHON_PATH = ${prefix}/bin/python
+
+       # As detected by './configure'.
+       # Missdetected, hence commented out, see below.
+       #NO_CURL = YesPlease
+       # Added manually, see above.
+       NEEDS_SSL_WITH_CURL = YesPlease
+       HAVE_LIBCHARSET_H = YesPlease
+       NEEDS_LIBICONV = YesPlease
+       NEEDS_LIBINTL_BEFORE_LIBICONV = YesPlease
+       NO_SYS_SELECT_H = UnfortunatelyYes
+       NO_D_TYPE_IN_DIRENT = YesPlease
+       NO_HSTRERROR = YesPlease
+       NO_STRCASESTR = YesPlease
+       NO_FNMATCH_CASEFOLD = YesPlease
+       NO_MEMMEM = YesPlease
+       NO_STRLCPY = YesPlease
+       NO_SETENV = YesPlease
+       NO_UNSETENV = YesPlease
+       NO_MKDTEMP = YesPlease
+       NO_MKSTEMPS = YesPlease
+       # Currently libiconv-1.9.1.
+       OLD_ICONV = UnfortunatelyYes
+       NO_REGEX = YesPlease
+       NO_PTHREADS = UnfortunatelyYes
+
+       # Not detected (nor checked for) by './configure'.
+       # We don't have SA_RESTART on NonStop, unfortunalety.
+       COMPAT_CFLAGS += -DSA_RESTART=0
+       # Apparently needed in compat/fnmatch/fnmatch.c.
+       COMPAT_CFLAGS += -DHAVE_STRING_H=1
+       NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
+       NO_NSEC = YesPlease
+       NO_PREAD = YesPlease
+       NO_MMAP = YesPlease
+       NO_POLL = YesPlease
+       NO_INTPTR_T = UnfortunatelyYes
+       # Bug report 10-120822-4477 submitted to HP NonStop development.
+       MKDIR_WO_TRAILING_SLASH = YesPlease
+       # RFE 10-120912-4693 submitted to HP NonStop development.
+       NO_SETITIMER = UnfortunatelyYes
+endif
 ifneq (,$(findstring MINGW,$(uname_S)))
        pathsep = ;
        NO_PREAD = YesPlease
        NEEDS_CRYPTO_WITH_SSL = YesPlease
        NO_LIBGEN_H = YesPlease
-       NO_SYS_POLL_H = YesPlease
+       NO_POLL = YesPlease
        NO_SYMLINK_HEAD = YesPlease
        NO_UNIX_SOCKETS = YesPlease
        NO_SETENV = YesPlease
@@ -1338,7 +1423,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
        COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
        COMPAT_OBJS += compat/mingw.o compat/winansi.o \
                compat/win32/pthread.o compat/win32/syslog.o \
-               compat/win32/poll.o compat/win32/dirent.o
+               compat/win32/dirent.o
        EXTLIBS += -lws2_32
        PTHREAD_LIBS =
        X = .exe
@@ -1534,6 +1619,9 @@ ifdef NEEDS_LIBICONV
        else
                ICONV_LINK =
        endif
+       ifdef NEEDS_LIBINTL_BEFORE_LIBICONV
+               ICONV_LINK += -lintl
+       endif
        EXTLIBS += $(ICONV_LINK) -liconv
 endif
 ifdef NEEDS_LIBGEN
@@ -1592,6 +1680,11 @@ ifdef NO_GETTEXT
        BASIC_CFLAGS += -DNO_GETTEXT
        USE_GETTEXT_SCHEME ?= fallthrough
 endif
+ifdef NO_POLL
+       NO_SYS_POLL_H = YesPlease
+       COMPAT_CFLAGS += -DNO_POLL -Icompat/poll
+       COMPAT_OBJS += compat/poll/poll.o
+endif
 ifdef NO_STRCASESTR
        COMPAT_CFLAGS += -DNO_STRCASESTR
        COMPAT_OBJS += compat/strcasestr.o
@@ -1630,6 +1723,10 @@ ifdef NO_MKDTEMP
        COMPAT_CFLAGS += -DNO_MKDTEMP
        COMPAT_OBJS += compat/mkdtemp.o
 endif
+ifdef MKDIR_WO_TRAILING_SLASH
+       COMPAT_CFLAGS += -DMKDIR_WO_TRAILING_SLASH
+       COMPAT_OBJS += compat/mkdir.o
+endif
 ifdef NO_MKSTEMPS
        COMPAT_CFLAGS += -DNO_MKSTEMPS
 endif
@@ -1661,6 +1758,13 @@ endif
 ifdef OBJECT_CREATION_USES_RENAMES
        COMPAT_CFLAGS += -DOBJECT_CREATION_MODE=1
 endif
+ifdef NO_STRUCT_ITIMERVAL
+       COMPAT_CFLAGS += -DNO_STRUCT_ITIMERVAL
+       NO_SETITIMER=YesPlease
+endif
+ifdef NO_SETITIMER
+       COMPAT_CFLAGS += -DNO_SETITIMER
+endif
 ifdef NO_PREAD
        COMPAT_CFLAGS += -DNO_PREAD
        COMPAT_OBJS += compat/pread.o
@@ -1678,6 +1782,9 @@ endif
 ifdef NO_IPV6
        BASIC_CFLAGS += -DNO_IPV6
 endif
+ifdef NO_INTPTR_T
+       COMPAT_CFLAGS += -DNO_INTPTR_T
+endif
 ifdef NO_UINTMAX_T
        BASIC_CFLAGS += -Duintmax_t=uint32_t
 endif
@@ -1843,10 +1950,6 @@ ifndef V
 endif
 endif
 
-ifdef ASCIIDOC7
-       export ASCIIDOC7
-endif
-
 ifdef NO_INSTALL_HARDLINKS
        export NO_INSTALL_HARDLINKS
 endif
@@ -1924,6 +2027,18 @@ SHELL_PATH_CQ_SQ = $(subst ','\'',$(SHELL_PATH_CQ))
 BASIC_CFLAGS += -DSHELL_PATH='$(SHELL_PATH_CQ_SQ)'
 endif
 
+GIT_USER_AGENT_SQ = $(subst ','\'',$(GIT_USER_AGENT))
+GIT_USER_AGENT_CQ = "$(subst ",\",$(subst \,\\,$(GIT_USER_AGENT)))"
+GIT_USER_AGENT_CQ_SQ = $(subst ','\'',$(GIT_USER_AGENT_CQ))
+GIT-USER-AGENT: FORCE
+       @if test x'$(GIT_USER_AGENT_SQ)' != x"`cat GIT-USER-AGENT 2>/dev/null`"; then \
+               echo '$(GIT_USER_AGENT_SQ)' >GIT-USER-AGENT; \
+       fi
+
+ifdef DEFAULT_HELP_FORMAT
+BASIC_CFLAGS += -DDEFAULT_HELP_FORMAT='"$(DEFAULT_HELP_FORMAT)"'
+endif
+
 ALL_CFLAGS += $(BASIC_CFLAGS)
 ALL_LDFLAGS += $(BASIC_LDFLAGS)
 
@@ -1970,8 +2085,41 @@ shell_compatibility_test: please_set_SHELL_PATH_to_a_more_modern_shell
 strip: $(PROGRAMS) git$X
        $(STRIP) $(STRIP_OPTS) $(PROGRAMS) git$X
 
-git.o: common-cmds.h
-git.sp git.s git.o: EXTRA_CPPFLAGS = -DGIT_VERSION='"$(GIT_VERSION)"' \
+### Target-specific flags and dependencies
+
+# The generic compilation pattern rule and automatically
+# computed header dependencies (falling back to a dependency on
+# LIB_H) are enough to describe how most targets should be built,
+# but some targets are special enough to need something a little
+# different.
+#
+# - When a source file "foo.c" #includes a generated header file,
+#   we need to list that dependency for the "foo.o" target.
+#
+#   We also list it from other targets that are built from foo.c
+#   like "foo.sp" and "foo.s", even though that is easy to forget
+#   to do because the generated header is already present around
+#   after a regular build attempt.
+#
+# - Some code depends on configuration kept in makefile
+#   variables. The target-specific variable EXTRA_CPPFLAGS can
+#   be used to convey that information to the C preprocessor
+#   using -D options.
+#
+#   The "foo.o" target should have a corresponding dependency on
+#   a file that changes when the value of the makefile variable
+#   changes.  For example, targets making use of the
+#   $(GIT_VERSION) variable depend on GIT-VERSION-FILE.
+#
+#   Technically the ".sp" and ".s" targets do not need this
+#   dependency because they are force-built, but they get the
+#   same dependency for consistency. This way, you do not have to
+#   know how each target is implemented. And it means the
+#   dependencies here will not need to change if the force-build
+#   details change some day.
+
+git.sp git.s git.o: GIT-PREFIX
+git.sp git.s git.o: EXTRA_CPPFLAGS = \
        '-DGIT_HTML_PATH="$(htmldir_SQ)"' \
        '-DGIT_MAN_PATH="$(mandir_SQ)"' \
        '-DGIT_INFO_PATH="$(infodir_SQ)"'
@@ -1980,14 +2128,19 @@ git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS)
        $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ git.o \
                $(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS)
 
-help.sp help.o: common-cmds.h
+help.sp help.s help.o: common-cmds.h
 
-builtin/help.sp builtin/help.o: common-cmds.h
+builtin/help.sp builtin/help.s builtin/help.o: common-cmds.h GIT-PREFIX
 builtin/help.sp builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \
        '-DGIT_HTML_PATH="$(htmldir_SQ)"' \
        '-DGIT_MAN_PATH="$(mandir_SQ)"' \
        '-DGIT_INFO_PATH="$(infodir_SQ)"'
 
+version.sp version.s version.o: GIT-VERSION-FILE GIT-USER-AGENT
+version.sp version.s version.o: EXTRA_CPPFLAGS = \
+       '-DGIT_VERSION="$(GIT_VERSION)"' \
+       '-DGIT_USER_AGENT=$(GIT_USER_AGENT_CQ_SQ)'
+
 $(BUILT_INS): git$X
        $(QUIET_BUILT_IN)$(RM) $@ && \
        ln git$X $@ 2>/dev/null || \
@@ -1999,35 +2152,54 @@ common-cmds.h: ./generate-cmdlist.sh command-list.txt
 common-cmds.h: $(wildcard Documentation/git-*.txt)
        $(QUIET_GEN)./generate-cmdlist.sh > $@+ && mv $@+ $@
 
+SCRIPT_DEFINES = $(SHELL_PATH_SQ):$(DIFF_SQ):$(GIT_VERSION):\
+       $(localedir_SQ):$(NO_CURL):$(USE_GETTEXT_SCHEME):$(SANE_TOOL_PATH_SQ):\
+       $(gitwebdir_SQ):$(PERL_PATH_SQ)
 define cmd_munge_script
 $(RM) $@ $@+ && \
 sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
     -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \
     -e 's|@@DIFF@@|$(DIFF_SQ)|' \
-    -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
     -e 's|@@LOCALEDIR@@|$(localedir_SQ)|g' \
     -e 's/@@NO_CURL@@/$(NO_CURL)/g' \
     -e 's/@@USE_GETTEXT_SCHEME@@/$(USE_GETTEXT_SCHEME)/g' \
     -e $(BROKEN_PATH_FIX) \
+    -e 's|@@GITWEBDIR@@|$(gitwebdir_SQ)|g' \
+    -e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \
     $@.sh >$@+
 endef
 
-$(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh
+GIT-SCRIPT-DEFINES: FORCE
+       @FLAGS='$(SCRIPT_DEFINES)'; \
+           if test x"$$FLAGS" != x"`cat $@ 2>/dev/null`" ; then \
+               echo 1>&2 "    * new script parameters"; \
+               echo "$$FLAGS" >$@; \
+            fi
+
+
+$(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh GIT-SCRIPT-DEFINES
        $(QUIET_GEN)$(cmd_munge_script) && \
        chmod +x $@+ && \
        mv $@+ $@
 
-$(SCRIPT_LIB) : % : %.sh
+$(SCRIPT_LIB) : % : %.sh GIT-SCRIPT-DEFINES
        $(QUIET_GEN)$(cmd_munge_script) && \
        mv $@+ $@
 
 ifndef NO_PERL
 $(patsubst %.perl,%,$(SCRIPT_PERL)): perl/perl.mak
 
-perl/perl.mak: GIT-CFLAGS perl/Makefile perl/Makefile.PL
+perl/perl.mak: perl/PM.stamp
+
+perl/PM.stamp: FORCE
+       $(QUIET_GEN)$(FIND) perl -type f -name '*.pm' | sort >$@+ && \
+       { cmp $@+ $@ >/dev/null 2>/dev/null || mv $@+ $@; } && \
+       $(RM) $@+
+
+perl/perl.mak: GIT-CFLAGS GIT-PREFIX perl/Makefile perl/Makefile.PL
        $(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' $(@F)
 
-$(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl
+$(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl GIT-VERSION-FILE
        $(QUIET_GEN)$(RM) $@ $@+ && \
        INSTLIBDIR=`MAKEFLAGS= $(MAKE) -C perl -s --no-print-directory instlibdir` && \
        sed -e '1{' \
@@ -2047,14 +2219,8 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl
 gitweb:
        $(QUIET_SUBDIR0)gitweb $(QUIET_SUBDIR1) all
 
-git-instaweb: git-instaweb.sh gitweb
-       $(QUIET_GEN)$(RM) $@ $@+ && \
-       sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
-           -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
-           -e 's/@@NO_CURL@@/$(NO_CURL)/g' \
-           -e 's|@@GITWEBDIR@@|$(gitwebdir_SQ)|g' \
-           -e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \
-           $@.sh > $@+ && \
+git-instaweb: git-instaweb.sh gitweb GIT-SCRIPT-DEFINES
+       $(QUIET_GEN)$(cmd_munge_script) && \
        chmod +x $@+ && \
        mv $@+ $@
 else # NO_PERL
@@ -2068,7 +2234,7 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)) git-instaweb: % : unimplemented.sh
 endif # NO_PERL
 
 ifndef NO_PYTHON
-$(patsubst %.py,%,$(SCRIPT_PYTHON)): GIT-CFLAGS
+$(patsubst %.py,%,$(SCRIPT_PYTHON)): GIT-CFLAGS GIT-PREFIX
 $(patsubst %.py,%,$(SCRIPT_PYTHON)): % : %.py
        $(QUIET_GEN)$(RM) $@ $@+ && \
        INSTLIBDIR=`MAKEFLAGS= $(MAKE) -C git_remote_helpers -s \
@@ -2090,24 +2256,23 @@ $(patsubst %.py,%,$(SCRIPT_PYTHON)): % : unimplemented.sh
        mv $@+ $@
 endif # NO_PYTHON
 
-configure: configure.ac
+configure: configure.ac GIT-VERSION-FILE
        $(QUIET_GEN)$(RM) $@ $<+ && \
        sed -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
            $< > $<+ && \
        autoconf -o $@ $<+ && \
        $(RM) $<+
 
-# These can record GIT_VERSION
-git.o git.spec http.o \
-       $(patsubst %.sh,%,$(SCRIPT_SH)) \
-       $(patsubst %.perl,%,$(SCRIPT_PERL)) \
-       : GIT-VERSION-FILE
-
-TEST_OBJS := $(patsubst test-%$X,test-%.o,$(TEST_PROGRAMS))
-GIT_OBJS := $(LIB_OBJS) $(BUILTIN_OBJS) $(PROGRAM_OBJS) $(TEST_OBJS) \
-       git.o
-ifndef NO_CURL
-       GIT_OBJS += http.o http-walker.o remote-curl.o
+ifdef AUTOCONFIGURED
+config.status: configure
+       $(QUIET_GEN)if test -f config.status; then \
+         ./config.status --recheck; \
+       else \
+         ./configure; \
+       fi
+reconfigure config.mak.autogen: config.status
+       $(QUIET_GEN)./config.status
+.PHONY: reconfigure # This is a convenience target.
 endif
 
 XDIFF_OBJS += xdiff/xdiffi.o
@@ -2125,9 +2290,14 @@ VCSSVN_OBJS += vcs-svn/fast_export.o
 VCSSVN_OBJS += vcs-svn/svndiff.o
 VCSSVN_OBJS += vcs-svn/svndump.o
 
-VCSSVN_TEST_OBJS += test-line-buffer.o
-
-OBJECTS := $(GIT_OBJS) $(XDIFF_OBJS) $(VCSSVN_OBJS)
+TEST_OBJS := $(patsubst test-%$X,test-%.o,$(TEST_PROGRAMS))
+OBJECTS := $(LIB_OBJS) $(BUILTIN_OBJS) $(PROGRAM_OBJS) $(TEST_OBJS) \
+       $(XDIFF_OBJS) \
+       $(VCSSVN_OBJS) \
+       git.o
+ifndef NO_CURL
+       OBJECTS += http.o http-walker.o remote-curl.o
+endif
 
 dep_files := $(foreach f,$(OBJECTS),$(dir $f).depend/$(notdir $f).d)
 dep_dirs := $(addsuffix .depend,$(sort $(dir $(OBJECTS))))
@@ -2226,51 +2396,32 @@ else
 # Dependencies on automatically generated headers such as common-cmds.h
 # should _not_ be included here, since they are necessary even when
 # building an object for the first time.
-#
-# XXX. Please check occasionally that these include all dependencies
-# gcc detects!
-
-$(GIT_OBJS): $(LIB_H)
-builtin/branch.o builtin/checkout.o builtin/clone.o builtin/reset.o branch.o transport.o: branch.h
-builtin/bundle.o bundle.o transport.o: bundle.h
-builtin/bisect--helper.o builtin/rev-list.o bisect.o: bisect.h
-builtin/clone.o builtin/fetch-pack.o transport.o: fetch-pack.h
-builtin/index-pack.o builtin/grep.o builtin/pack-objects.o transport-helper.o thread-utils.o: thread-utils.h
-builtin/send-pack.o transport.o: send-pack.h
-builtin/log.o builtin/shortlog.o: shortlog.h
-builtin/prune.o builtin/reflog.o reachable.o: reachable.h
-builtin/commit.o builtin/revert.o wt-status.o: wt-status.h
-builtin/tar-tree.o archive-tar.o: tar.h
-connect.o transport.o url.o http-backend.o: url.h
-builtin/branch.o builtin/commit.o builtin/tag.o column.o help.o pager.o: column.h
-http-fetch.o http-walker.o remote-curl.o transport.o walker.o: walker.h
-http.o http-walker.o http-push.o http-fetch.o remote-curl.o: http.h url.h
 
-xdiff-interface.o $(XDIFF_OBJS): $(XDIFF_H)
-
-$(VCSSVN_OBJS) $(VCSSVN_TEST_OBJS): $(LIB_H) $(VCSSVN_H)
+$(OBJECTS): $(LIB_H)
 endif
 
+exec_cmd.sp exec_cmd.s exec_cmd.o: GIT-PREFIX
 exec_cmd.sp exec_cmd.s exec_cmd.o: EXTRA_CPPFLAGS = \
        '-DGIT_EXEC_PATH="$(gitexecdir_SQ)"' \
        '-DBINDIR="$(bindir_relative_SQ)"' \
        '-DPREFIX="$(prefix_SQ)"'
 
+builtin/init-db.sp builtin/init-db.s builtin/init-db.o: GIT-PREFIX
 builtin/init-db.sp builtin/init-db.s builtin/init-db.o: EXTRA_CPPFLAGS = \
        -DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"'
 
+config.sp config.s config.o: GIT-PREFIX
 config.sp config.s config.o: EXTRA_CPPFLAGS = \
        -DETC_GITCONFIG='"$(ETC_GITCONFIG_SQ)"'
 
+attr.sp attr.s attr.o: GIT-PREFIX
 attr.sp attr.s attr.o: EXTRA_CPPFLAGS = \
        -DETC_GITATTRIBUTES='"$(ETC_GITATTRIBUTES_SQ)"'
 
+gettext.sp gettext.s gettext.o: GIT-PREFIX
 gettext.sp gettext.s gettext.o: EXTRA_CPPFLAGS = \
        -DGIT_LOCALE_PATH='"$(localedir_SQ)"'
 
-http.sp http.s http.o: EXTRA_CPPFLAGS = \
-       -DGIT_HTTP_USER_AGENT='"git/$(GIT_VERSION)"'
-
 ifdef NO_EXPAT
 http-walker.sp http-walker.s http-walker.o: EXTRA_CPPFLAGS = -DNO_EXPAT
 endif
@@ -2299,6 +2450,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 || \
@@ -2342,9 +2497,10 @@ XGETTEXT_FLAGS = \
        --from-code=UTF-8
 XGETTEXT_FLAGS_C = $(XGETTEXT_FLAGS) --language=C \
        --keyword=_ --keyword=N_ --keyword="Q_:1,2"
-XGETTEXT_FLAGS_SH = $(XGETTEXT_FLAGS) --language=Shell
+XGETTEXT_FLAGS_SH = $(XGETTEXT_FLAGS) --language=Shell \
+       --keyword=gettextln --keyword=eval_gettextln
 XGETTEXT_FLAGS_PERL = $(XGETTEXT_FLAGS) --keyword=__ --language=Perl
-LOCALIZED_C := $(C_OBJ:o=c) $(LIB_H) $(XDIFF_H) $(VCSSVN_H) $(MISC_H)
+LOCALIZED_C := $(C_OBJ:o=c) $(LIB_H) $(GENERATED_H)
 LOCALIZED_SH := $(SCRIPT_SH)
 LOCALIZED_PERL := $(SCRIPT_PERL)
 
@@ -2391,14 +2547,22 @@ cscope:
        $(FIND_SOURCE_FILES) | xargs cscope -b
 
 ### Detect prefix changes
-TRACK_CFLAGS = $(CC):$(subst ','\'',$(ALL_CFLAGS)):\
-             $(bindir_SQ):$(gitexecdir_SQ):$(template_dir_SQ):$(prefix_SQ):\
-             $(localedir_SQ):$(USE_GETTEXT_SCHEME)
+TRACK_PREFIX = $(bindir_SQ):$(gitexecdir_SQ):$(template_dir_SQ):$(prefix_SQ):\
+               $(localedir_SQ)
+
+GIT-PREFIX: FORCE
+       @FLAGS='$(TRACK_PREFIX)'; \
+       if test x"$$FLAGS" != x"`cat GIT-PREFIX 2>/dev/null`" ; then \
+               echo 1>&2 "    * new prefix flags"; \
+               echo "$$FLAGS" >GIT-PREFIX; \
+       fi
+
+TRACK_CFLAGS = $(CC):$(subst ','\'',$(ALL_CFLAGS)):$(USE_GETTEXT_SCHEME)
 
 GIT-CFLAGS: FORCE
        @FLAGS='$(TRACK_CFLAGS)'; \
            if test x"$$FLAGS" != x"`cat GIT-CFLAGS 2>/dev/null`" ; then \
-               echo 1>&2 "    * new build flags or prefix"; \
+               echo 1>&2 "    * new build flags"; \
                echo "$$FLAGS" >GIT-CFLAGS; \
             fi
 
@@ -2477,6 +2641,7 @@ bin-wrappers/%: wrap-for-bin.sh
 # with that.
 
 export NO_SVN_TESTS
+export TEST_NO_MALLOC_CHECK
 
 ### Testing rules
 
@@ -2650,7 +2815,7 @@ quick-install-html:
 
 ### Maintainer's dist rules
 
-git.spec: git.spec.in
+git.spec: git.spec.in GIT-VERSION-FILE
        sed -e 's/@@VERSION@@/$(GIT_VERSION)/g' < $< > $@+
        mv $@+ $@
 
@@ -2700,6 +2865,9 @@ dist-doc:
 
 distclean: clean
        $(RM) configure
+       $(RM) config.log config.status config.cache
+       $(RM) config.mak.autogen config.mak.append
+       $(RM) -r autom4te.cache
 
 profile-clean:
        $(RM) $(addsuffix *.gcda,$(addprefix $(PROFILE_DIR)/, $(object_dirs)))
@@ -2714,8 +2882,6 @@ clean: profile-clean
        $(RM) -r $(dep_dirs)
        $(RM) -r po/build/
        $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h $(ETAGS_TARGET) tags cscope*
-       $(RM) -r autom4te.cache
-       $(RM) config.log config.mak.autogen config.mak.append config.status config.cache
        $(RM) -r $(GIT_TARNAME) .doc-tmp-dir
        $(RM) $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz
        $(RM) $(htmldocs).tar.gz $(manpages).tar.gz
@@ -2734,6 +2900,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
 
 .PHONY: all install profile-clean clean strip
 .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
@@ -2741,8 +2908,13 @@ endif
 
 ### Check documentation
 #
+ALL_COMMANDS = $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS)
+ALL_COMMANDS += git
+ALL_COMMANDS += gitk
+ALL_COMMANDS += gitweb
+ALL_COMMANDS += git-gui git-citool
 check-docs::
-       @(for v in $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) git gitk; \
+       @(for v in $(ALL_COMMANDS); \
        do \
                case "$$v" in \
                git-merge-octopus | git-merge-ours | git-merge-recursive | \
@@ -2764,35 +2936,13 @@ check-docs::
                sed -e '/^#/d' \
                    -e 's/[     ].*//' \
                    -e 's/^/listed /' command-list.txt; \
-               ls -1 Documentation/git*txt | \
+               $(MAKE) -C Documentation print-man1 | \
+               grep '\.txt$$' | \
                sed -e 's|Documentation/|documented |' \
                    -e 's/\.txt//'; \
        ) | while read how cmd; \
        do \
-               case "$$how,$$cmd" in \
-               *,git-citool | \
-               *,git-gui | \
-               *,git-help | \
-               documented,gitattributes | \
-               documented,gitignore | \
-               documented,gitmodules | \
-               documented,gitcli | \
-               documented,git-tools | \
-               documented,gitcore-tutorial | \
-               documented,gitcvs-migration | \
-               documented,gitdiffcore | \
-               documented,gitglossary | \
-               documented,githooks | \
-               documented,gitrepository-layout | \
-               documented,gitrevisions | \
-               documented,gittutorial | \
-               documented,gittutorial-2 | \
-               documented,git-bisect-lk2009 | \
-               documented,git-remote-helpers | \
-               documented,gitworkflows | \
-               sentinel,not,matching,is,ok ) continue ;; \
-               esac; \
-               case " $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) git gitk " in \
+               case " $(ALL_COMMANDS) " in \
                *" $$cmd "*)    ;; \
                *) echo "removed but $$how: $$cmd" ;; \
                esac; \
index 6205f6cd4f83a45883ddc46824aeb050e5a59237..2484b38bbbae654684f65a874653487439f0df2f 120000 (symlink)
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/1.7.11.7.txt
\ No newline at end of file
+Documentation/RelNotes/1.8.0.txt
\ No newline at end of file
index f04ac18e33063f7e2cb9ab9eab9a6b86cb089b5a..05f2d7934878a832f5a2efdf4222c16223050853 100644 (file)
--- a/abspath.c
+++ b/abspath.c
@@ -35,6 +35,9 @@ 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 (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)
                die ("Too long path: %.*s", 60, path);
 
@@ -42,8 +45,8 @@ const char *real_path(const char *path)
                if (!is_directory(buf)) {
                        char *last_slash = find_last_dir_sep(buf);
                        if (last_slash) {
-                               *last_slash = '\0';
                                last_elem = xstrdup(last_slash + 1);
+                               last_slash[1] = '\0';
                        } else {
                                last_elem = xstrdup(buf);
                                *buf = '\0';
@@ -123,7 +126,9 @@ const char *absolute_path(const char *path)
 {
        static char buf[PATH_MAX + 1];
 
-       if (is_absolute_path(path)) {
+       if (!*path) {
+               die("The empty string is not a valid path");
+       } else if (is_absolute_path(path)) {
                if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)
                        die("Too long path: %.*s", 60, path);
        } else {
index f5af81f904df081002dad46a71be2eca8e3bebab..55f66b4060c64789bdb443f6c71f82a75ef22d0b 100644 (file)
@@ -4,6 +4,7 @@
 #include "cache.h"
 #include "archive.h"
 #include "streaming.h"
+#include "utf8.h"
 
 static int zip_date;
 static int zip_time;
@@ -16,7 +17,8 @@ static unsigned int zip_dir_offset;
 static unsigned int zip_dir_entries;
 
 #define ZIP_DIRECTORY_MIN_SIZE (1024 * 1024)
-#define ZIP_STREAM (8)
+#define ZIP_STREAM     (1 <<  3)
+#define ZIP_UTF8       (1 << 11)
 
 struct zip_local_header {
        unsigned char magic[4];
@@ -74,6 +76,14 @@ struct zip_dir_trailer {
        unsigned char _end[1];
 };
 
+struct zip_extra_mtime {
+       unsigned char magic[2];
+       unsigned char extra_size[2];
+       unsigned char flags[1];
+       unsigned char mtime[4];
+       unsigned char _end[1];
+};
+
 /*
  * On ARM, padding is added at the end of the struct, so a simple
  * sizeof(struct ...) reports two bytes more than the payload size
@@ -83,6 +93,9 @@ struct zip_dir_trailer {
 #define ZIP_DATA_DESC_SIZE     offsetof(struct zip_data_desc, _end)
 #define ZIP_DIR_HEADER_SIZE    offsetof(struct zip_dir_header, _end)
 #define ZIP_DIR_TRAILER_SIZE   offsetof(struct zip_dir_trailer, _end)
+#define ZIP_EXTRA_MTIME_SIZE   offsetof(struct zip_extra_mtime, _end)
+#define ZIP_EXTRA_MTIME_PAYLOAD_SIZE \
+       (ZIP_EXTRA_MTIME_SIZE - offsetof(struct zip_extra_mtime, flags))
 
 static void copy_le16(unsigned char *dest, unsigned int n)
 {
@@ -164,6 +177,17 @@ static void set_zip_header_data_desc(struct zip_local_header *header,
        copy_le32(header->size, size);
 }
 
+static int has_only_ascii(const char *s)
+{
+       for (;;) {
+               int c = *s++;
+               if (c == '\0')
+                       return 1;
+               if (!isascii(c))
+                       return 0;
+       }
+}
+
 #define STREAM_BUFFER_SIZE (1024 * 16)
 
 static int write_zip_entry(struct archiver_args *args,
@@ -173,6 +197,7 @@ static int write_zip_entry(struct archiver_args *args,
 {
        struct zip_local_header header;
        struct zip_dir_header dirent;
+       struct zip_extra_mtime extra;
        unsigned long attr2;
        unsigned long compressed_size;
        unsigned long crc;
@@ -187,6 +212,13 @@ static int write_zip_entry(struct archiver_args *args,
 
        crc = crc32(0, NULL, 0);
 
+       if (!has_only_ascii(path)) {
+               if (is_utf8(path))
+                       flags |= ZIP_UTF8;
+               else
+                       warning("Path is not valid UTF-8: %s", path);
+       }
+
        if (pathlen > 0xffff) {
                return error("path too long (%d chars, SHA1: %s): %s",
                                (int)pathlen, sha1_to_hex(sha1), path);
@@ -246,8 +278,13 @@ static int write_zip_entry(struct archiver_args *args,
                }
        }
 
+       copy_le16(extra.magic, 0x5455);
+       copy_le16(extra.extra_size, ZIP_EXTRA_MTIME_PAYLOAD_SIZE);
+       extra.flags[0] = 1;     /* just mtime */
+       copy_le32(extra.mtime, args->time);
+
        /* make sure we have enough free space in the dictionary */
-       direntsize = ZIP_DIR_HEADER_SIZE + pathlen;
+       direntsize = ZIP_DIR_HEADER_SIZE + pathlen + ZIP_EXTRA_MTIME_SIZE;
        while (zip_dir_size < zip_dir_offset + direntsize) {
                zip_dir_size += ZIP_DIRECTORY_MIN_SIZE;
                zip_dir = xrealloc(zip_dir, zip_dir_size);
@@ -263,7 +300,7 @@ static int write_zip_entry(struct archiver_args *args,
        copy_le16(dirent.mdate, zip_date);
        set_zip_dir_data_desc(&dirent, size, compressed_size, crc);
        copy_le16(dirent.filename_length, pathlen);
-       copy_le16(dirent.extra_length, 0);
+       copy_le16(dirent.extra_length, ZIP_EXTRA_MTIME_SIZE);
        copy_le16(dirent.comment_length, 0);
        copy_le16(dirent.disk, 0);
        copy_le16(dirent.attr1, 0);
@@ -281,11 +318,13 @@ static int write_zip_entry(struct archiver_args *args,
        else
                set_zip_header_data_desc(&header, size, compressed_size, crc);
        copy_le16(header.filename_length, pathlen);
-       copy_le16(header.extra_length, 0);
+       copy_le16(header.extra_length, ZIP_EXTRA_MTIME_SIZE);
        write_or_die(1, &header, ZIP_LOCAL_HEADER_SIZE);
        zip_offset += ZIP_LOCAL_HEADER_SIZE;
        write_or_die(1, path, pathlen);
        zip_offset += pathlen;
+       write_or_die(1, &extra, ZIP_EXTRA_MTIME_SIZE);
+       zip_offset += ZIP_EXTRA_MTIME_SIZE;
        if (stream && method == 0) {
                unsigned char buf[STREAM_BUFFER_SIZE];
                ssize_t readlen;
@@ -382,6 +421,8 @@ static int write_zip_entry(struct archiver_args *args,
        zip_dir_offset += ZIP_DIR_HEADER_SIZE;
        memcpy(zip_dir + zip_dir_offset, path, pathlen);
        zip_dir_offset += pathlen;
+       memcpy(zip_dir + zip_dir_offset, &extra, ZIP_EXTRA_MTIME_SIZE);
+       zip_dir_offset += ZIP_EXTRA_MTIME_SIZE;
        zip_dir_entries++;
 
        return 0;
index a4844330fb4da325aa364640dc80f052dc7b7ad7..466640479ecb332d8d06f6f26254023eb6e22c85 100644 (file)
--- a/archive.c
+++ b/archive.c
@@ -7,10 +7,10 @@
 #include "unpack-trees.h"
 
 static char const * const archive_usage[] = {
-       "git archive [options] <tree-ish> [<path>...]",
-       "git archive --list",
-       "git archive --remote <repo> [--exec <cmd>] [options] <tree-ish> [<path>...]",
-       "git archive --remote <repo> [--exec <cmd>] --list",
+       N_("git archive [options] <tree-ish> [<path>...]"),
+       N_("git archive --list"),
+       N_("git archive --remote <repo> [--exec <cmd>] [options] <tree-ish> [<path>...]"),
+       N_("git archive --remote <repo> [--exec <cmd>] --list"),
        NULL
 };
 
@@ -319,16 +319,16 @@ static int parse_archive_args(int argc, const char **argv,
        int worktree_attributes = 0;
        struct option opts[] = {
                OPT_GROUP(""),
-               OPT_STRING(0, "format", &format, "fmt", "archive format"),
-               OPT_STRING(0, "prefix", &base, "prefix",
-                       "prepend prefix to each pathname in the archive"),
-               OPT_STRING('o', "output", &output, "file",
-                       "write the archive to this file"),
+               OPT_STRING(0, "format", &format, N_("fmt"), N_("archive format")),
+               OPT_STRING(0, "prefix", &base, N_("prefix"),
+                       N_("prepend prefix to each pathname in the archive")),
+               OPT_STRING('o', "output", &output, N_("file"),
+                       N_("write the archive to this file")),
                OPT_BOOL(0, "worktree-attributes", &worktree_attributes,
-                       "read .gitattributes in working directory"),
-               OPT__VERBOSE(&verbose, "report archived files on stderr"),
-               OPT__COMPR('0', &compression_level, "store only", 0),
-               OPT__COMPR('1', &compression_level, "compress faster", 1),
+                       N_("read .gitattributes in working directory")),
+               OPT__VERBOSE(&verbose, N_("report archived files on stderr")),
+               OPT__COMPR('0', &compression_level, N_("store only"), 0),
+               OPT__COMPR('1', &compression_level, N_("compress faster"), 1),
                OPT__COMPR_HIDDEN('2', &compression_level, 2),
                OPT__COMPR_HIDDEN('3', &compression_level, 3),
                OPT__COMPR_HIDDEN('4', &compression_level, 4),
@@ -336,15 +336,15 @@ static int parse_archive_args(int argc, const char **argv,
                OPT__COMPR_HIDDEN('6', &compression_level, 6),
                OPT__COMPR_HIDDEN('7', &compression_level, 7),
                OPT__COMPR_HIDDEN('8', &compression_level, 8),
-               OPT__COMPR('9', &compression_level, "compress better", 9),
+               OPT__COMPR('9', &compression_level, N_("compress better"), 9),
                OPT_GROUP(""),
                OPT_BOOL('l', "list", &list,
-                       "list supported archive formats"),
+                       N_("list supported archive formats")),
                OPT_GROUP(""),
-               OPT_STRING(0, "remote", &remote, "repo",
-                       "retrieve the archive from remote repository <repo>"),
-               OPT_STRING(0, "exec", &exec, "cmd",
-                       "path to the remote git-upload-archive command"),
+               OPT_STRING(0, "remote", &remote, N_("repo"),
+                       N_("retrieve the archive from remote repository <repo>")),
+               OPT_STRING(0, "exec", &exec, N_("command"),
+                       N_("path to the remote git-upload-archive command")),
                OPT_END()
        };
 
index 0b5f8898a10f16df8a6273f8960f05b670ba94bc..9e960d549c158a4c761942bb17824c1d5e075d49 100644 (file)
@@ -49,13 +49,42 @@ void argv_array_pushl(struct argv_array *array, ...)
        va_end(ap);
 }
 
+void argv_array_pop(struct argv_array *array)
+{
+       if (!array->argc)
+               return;
+       free((char *)array->argv[array->argc - 1]);
+       array->argv[array->argc - 1] = NULL;
+       array->argc--;
+}
+
 void argv_array_clear(struct argv_array *array)
 {
        if (array->argv != empty_argv) {
                int i;
                for (i = 0; i < array->argc; i++)
-                       free((char **)array->argv[i]);
+                       free((char *)array->argv[i]);
                free(array->argv);
        }
        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 b93a69c36cb8d391c1d7de93f75b3d54c00e60ca..40248d424c31662a3a574cfea13635084feb14f5 100644 (file)
@@ -16,6 +16,9 @@ void argv_array_push(struct argv_array *, const char *);
 __attribute__((format (printf,2,3)))
 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 303751f6c2bd4d558cffbb928c636581efb2b310..097ae87f3c2b4093fffe6586f036918367fa672e 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;
@@ -306,7 +321,7 @@ static void free_attr_elem(struct attr_stack *e)
 }
 
 static const char *builtin_attr[] = {
-       "[attr]binary -diff -text",
+       "[attr]binary -diff -merge -text",
        NULL,
 };
 
@@ -352,8 +367,11 @@ static struct attr_stack *read_attr_from_file(const char *path, int macro_ok)
        char buf[2048];
        int lineno = 0;
 
-       if (!fp)
+       if (!fp) {
+               if (errno != ENOENT && errno != ENOTDIR)
+                       warn_on_inaccessible(path);
                return NULL;
+       }
        res = xcalloc(1, sizeof(*res));
        while (fgets(buf, sizeof(buf), fp))
                handle_attr_line(res, buf, path, ++lineno, macro_ok);
@@ -497,6 +515,7 @@ static int git_attr_system(void)
 static void bootstrap_attr_stack(void)
 {
        struct attr_stack *elem;
+       char *xdg_attributes_file;
 
        if (attr_stack)
                return;
@@ -515,6 +534,10 @@ static void bootstrap_attr_stack(void)
                }
        }
 
+       if (!git_attributes_file) {
+               home_config_paths(NULL, &xdg_attributes_file, "attributes");
+               git_attributes_file = xdg_attributes_file;
+       }
        if (git_attributes_file) {
                elem = read_attr_from_file(git_attributes_file, 1);
                if (elem) {
@@ -527,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);
@@ -620,7 +644,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);
@@ -637,28 +661,22 @@ 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);
+       const char *pattern = pat->pattern;
+       int prefix = pat->nowildcardlen;
+
+       if (pat->flags & EXC_FLAG_NODIR) {
+               return match_basename(basename,
+                                     pathlen - (basename - pathname),
+                                     pattern, prefix,
+                                     pat->patternlen, pat->flags);
        }
-       /*
-        * 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))
-               return 0;
-       if (baselen != 0)
-               baselen++;
-       return fnmatch_icase(pattern, pathname + baselen, FNM_PATHNAME) == 0;
+       return match_pathname(pathname, pathlen,
+                             base, baselen,
+                             pattern, prefix, pat->patternlen, pat->flags);
 }
 
 static int macroexpand_one(int attr_nr, int rem);
@@ -685,7 +703,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 : "";
@@ -694,8 +713,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;
@@ -733,15 +752,19 @@ static void collect_all_attrs(const char *path)
 {
        struct attr_stack *stk;
        int i, pathlen, rem;
+       const char *basename;
 
        prepare_attr_stack(path);
        for (i = 0; i < attr_nr; i++)
                check_all_attr[i].value = ATTR__UNKNOWN;
 
+       basename = strrchr(path, '/');
+       basename = basename ? basename + 1 : path;
+
        pathlen = strlen(path);
        rem = attr_nr;
        for (stk = attr_stack; 0 < rem && stk; stk = stk->prev)
-               rem = fill(path, pathlen, stk, rem);
+               rem = fill(path, pathlen, basename, stk, rem);
 }
 
 int git_check_attr(const char *path, int num, struct git_attr_check *check)
index 48acf73391271c1d9061b178a53653357f07f391..1aad49b1a642a308f449001960958ccab79347d1 100644 (file)
--- a/bisect.c
+++ b/bisect.c
@@ -833,7 +833,7 @@ static int check_ancestors(const char *prefix)
  */
 static void check_good_are_ancestors_of_bad(const char *prefix, int no_checkout)
 {
-       char *filename = xstrdup(git_path("BISECT_ANCESTORS_OK"));
+       char *filename = git_pathdup("BISECT_ANCESTORS_OK");
        struct stat st;
        int fd;
 
index eccdaf93924334137833e5acf7541aa514588c2d..2bef1e7e71b7cb3375b3d96fab5c4f20e0c3adff 100644 (file)
--- a/branch.c
+++ b/branch.c
@@ -74,25 +74,33 @@ void install_branch_config(int flag, const char *local, const char *origin, cons
                strbuf_addf(&key, "branch.%s.rebase", local);
                git_config_set(key.buf, "true");
        }
+       strbuf_release(&key);
 
        if (flag & BRANCH_CONFIG_VERBOSE) {
-               strbuf_reset(&key);
-
-               strbuf_addstr(&key, origin ? "remote" : "local");
-
-               /* Are we tracking a proper "branch"? */
-               if (remote_is_branch) {
-                       strbuf_addf(&key, " branch %s", shortname);
-                       if (origin)
-                               strbuf_addf(&key, " from %s", origin);
-               }
+               if (remote_is_branch && origin)
+                       printf(rebasing ?
+                              "Branch %s set up to track remote branch %s from %s by rebasing.\n" :
+                              "Branch %s set up to track remote branch %s from %s.\n",
+                              local, shortname, origin);
+               else if (remote_is_branch && !origin)
+                       printf(rebasing ?
+                              "Branch %s set up to track local branch %s by rebasing.\n" :
+                              "Branch %s set up to track local branch %s.\n",
+                              local, shortname);
+               else if (!remote_is_branch && origin)
+                       printf(rebasing ?
+                              "Branch %s set up to track remote ref %s by rebasing.\n" :
+                              "Branch %s set up to track remote ref %s.\n",
+                              local, remote);
+               else if (!remote_is_branch && !origin)
+                       printf(rebasing ?
+                              "Branch %s set up to track local ref %s by rebasing.\n" :
+                              "Branch %s set up to track local ref %s.\n",
+                              local, remote);
                else
-                       strbuf_addf(&key, " ref %s", remote);
-               printf("Branch %s set up to track %s%s.\n",
-                      local, key.buf,
-                      rebasing ? " by rebasing" : "");
+                       die("BUG: impossible combination of %d and %p",
+                           remote_is_branch, origin);
        }
-       strbuf_release(&key);
 }
 
 /*
index dffb34ef4e29799bcb9a8c78bdf439547845794f..95116b85358637d3457288c7d28526cb1fa93630 100644 (file)
--- a/builtin.h
+++ b/builtin.h
@@ -9,7 +9,6 @@
 
 #define DEFAULT_MERGE_LOG_LEN 20
 
-extern const char git_version_string[];
 extern const char git_usage_string[];
 extern const char git_more_info_string[];
 
@@ -22,7 +21,6 @@ struct fmt_merge_msg_opts {
 
 extern int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
                         struct fmt_merge_msg_opts *);
-extern void commit_notes(struct notes_tree *t, const char *msg);
 
 struct notes_rewrite_cfg {
        struct notes_tree **trees;
@@ -34,7 +32,6 @@ struct notes_rewrite_cfg {
        int mode_from_env;
 };
 
-combine_notes_fn parse_combine_notes_fn(const char *v);
 struct notes_rewrite_cfg *init_copy_notes_for_rewrite(const char *cmd);
 int copy_note_for_rewrite(struct notes_rewrite_cfg *c,
                          const unsigned char *from_obj, const unsigned char *to_obj);
@@ -68,6 +65,7 @@ extern int cmd_commit(int argc, const char **argv, const char *prefix);
 extern int cmd_commit_tree(int argc, const char **argv, const char *prefix);
 extern int cmd_config(int argc, const char **argv, const char *prefix);
 extern int cmd_count_objects(int argc, const char **argv, const char *prefix);
+extern int cmd_credential(int argc, const char **argv, const char *prefix);
 extern int cmd_describe(int argc, const char **argv, const char *prefix);
 extern int cmd_diff_files(int argc, const char **argv, const char *prefix);
 extern int cmd_diff_index(int argc, const char **argv, const char *prefix);
index 89dce56a240d69ccb224590bf134c9656d8a0522..e664100c7122d6c4116763716c2260756feffac2 100644 (file)
@@ -16,7 +16,7 @@
 #include "bulk-checkin.h"
 
 static const char * const builtin_add_usage[] = {
-       "git add [options] [--] <filepattern>...",
+       N_("git add [options] [--] <filepattern>..."),
        NULL
 };
 static int patch_interactive, add_interactive, edit_interactive;
@@ -260,7 +260,7 @@ int interactive_add(int argc, const char **argv, const char *prefix, int patch)
 
 static int edit_patch(int argc, const char **argv, const char *prefix)
 {
-       char *file = xstrdup(git_path("ADD_EDIT.patch"));
+       char *file = git_pathdup("ADD_EDIT.patch");
        const char *apply_argv[] = { "apply", "--recount", "--cached",
                NULL, NULL };
        struct child_process child;
@@ -303,6 +303,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix)
                die (_("Could not apply '%s'"), file);
 
        unlink(file);
+       free(file);
        return 0;
 }
 
@@ -315,19 +316,19 @@ static int verbose = 0, show_only = 0, ignored_too = 0, refresh_only = 0;
 static int ignore_add_errors, addremove, intent_to_add, ignore_missing = 0;
 
 static struct option builtin_add_options[] = {
-       OPT__DRY_RUN(&show_only, "dry run"),
-       OPT__VERBOSE(&verbose, "be verbose"),
+       OPT__DRY_RUN(&show_only, N_("dry run")),
+       OPT__VERBOSE(&verbose, N_("be verbose")),
        OPT_GROUP(""),
-       OPT_BOOLEAN('i', "interactive", &add_interactive, "interactive picking"),
-       OPT_BOOLEAN('p', "patch", &patch_interactive, "select hunks interactively"),
-       OPT_BOOLEAN('e', "edit", &edit_interactive, "edit current diff and apply"),
-       OPT__FORCE(&ignored_too, "allow adding otherwise ignored files"),
-       OPT_BOOLEAN('u', "update", &take_worktree_changes, "update tracked files"),
-       OPT_BOOLEAN('N', "intent-to-add", &intent_to_add, "record only the fact that the path will be added later"),
-       OPT_BOOLEAN('A', "all", &addremove, "add changes from all tracked and untracked files"),
-       OPT_BOOLEAN( 0 , "refresh", &refresh_only, "don't add, only refresh the index"),
-       OPT_BOOLEAN( 0 , "ignore-errors", &ignore_add_errors, "just skip files which cannot be added because of errors"),
-       OPT_BOOLEAN( 0 , "ignore-missing", &ignore_missing, "check if - even missing - files are ignored in dry run"),
+       OPT_BOOLEAN('i', "interactive", &add_interactive, N_("interactive picking")),
+       OPT_BOOLEAN('p', "patch", &patch_interactive, N_("select hunks interactively")),
+       OPT_BOOLEAN('e', "edit", &edit_interactive, N_("edit current diff and apply")),
+       OPT__FORCE(&ignored_too, N_("allow adding otherwise ignored files")),
+       OPT_BOOLEAN('u', "update", &take_worktree_changes, N_("update tracked files")),
+       OPT_BOOLEAN('N', "intent-to-add", &intent_to_add, N_("record only the fact that the path will be added later")),
+       OPT_BOOLEAN('A', "all", &addremove, N_("add changes from all tracked and untracked files")),
+       OPT_BOOLEAN( 0 , "refresh", &refresh_only, N_("don't add, only refresh the index")),
+       OPT_BOOLEAN( 0 , "ignore-errors", &ignore_add_errors, N_("just skip files which cannot be added because of errors")),
+       OPT_BOOLEAN( 0 , "ignore-missing", &ignore_missing, N_("check if - even missing - files are ignored in dry run")),
        OPT_END(),
 };
 
index d2180b03744e093c51ffe61168391d4c4f814212..156b3ce3b72f51013baacff0a8ffd37ac97e6158 100644 (file)
@@ -16,6 +16,9 @@
 #include "dir.h"
 #include "diff.h"
 #include "parse-options.h"
+#include "xdiff-interface.h"
+#include "ll-merge.h"
+#include "rerere.h"
 
 /*
  *  --check turns on checking that the working tree matches the
@@ -46,6 +49,7 @@ static int apply_with_reject;
 static int apply_verbosely;
 static int allow_overlap;
 static int no_add;
+static int threeway;
 static const char *fake_ancestor;
 static int line_termination = '\n';
 static unsigned int p_context = UINT_MAX;
@@ -192,12 +196,17 @@ struct patch {
        unsigned int is_copy:1;
        unsigned int is_rename:1;
        unsigned int recount:1;
+       unsigned int conflicted_threeway:1;
+       unsigned int direct_to_threeway:1;
        struct fragment *fragments;
        char *result;
        size_t resultsize;
        char old_sha1_prefix[41];
        char new_sha1_prefix[41];
        struct patch *next;
+
+       /* three-way fallback result */
+       unsigned char threeway_stage[3][20];
 };
 
 static void free_fragment_list(struct fragment *list)
@@ -370,8 +379,8 @@ static void prepare_image(struct image *image, char *buf, size_t len,
 static void clear_image(struct image *image)
 {
        free(image->buf);
-       image->buf = NULL;
-       image->len = 0;
+       free(image->line_allocated);
+       memset(image, 0, sizeof(*image));
 }
 
 /* fmt must contain _one_ %s and no other substitution */
@@ -2954,20 +2963,17 @@ static int apply_fragments(struct image *img, struct patch *patch)
        return 0;
 }
 
-static int read_file_or_gitlink(struct cache_entry *ce, struct strbuf *buf)
+static int read_blob_object(struct strbuf *buf, const unsigned char *sha1, unsigned mode)
 {
-       if (!ce)
-               return 0;
-
-       if (S_ISGITLINK(ce->ce_mode)) {
+       if (S_ISGITLINK(mode)) {
                strbuf_grow(buf, 100);
-               strbuf_addf(buf, "Subproject commit %s\n", sha1_to_hex(ce->sha1));
+               strbuf_addf(buf, "Subproject commit %s\n", sha1_to_hex(sha1));
        } else {
                enum object_type type;
                unsigned long sz;
                char *result;
 
-               result = read_sha1_file(ce->sha1, &type, &sz);
+               result = read_sha1_file(sha1, &type, &sz);
                if (!result)
                        return -1;
                /* XXX read_sha1_file NUL-terminates */
@@ -2976,6 +2982,13 @@ static int read_file_or_gitlink(struct cache_entry *ce, struct strbuf *buf)
        return 0;
 }
 
+static int read_file_or_gitlink(struct cache_entry *ce, struct strbuf *buf)
+{
+       if (!ce)
+               return 0;
+       return read_blob_object(buf, ce->sha1, ce->ce_mode);
+}
+
 static struct patch *in_fn_table(const char *name)
 {
        struct string_list_item *item;
@@ -2994,9 +3007,15 @@ static struct patch *in_fn_table(const char *name)
  * item->util in the filename table records the status of the path.
  * Usually it points at a patch (whose result records the contents
  * of it after applying it), but it could be PATH_WAS_DELETED for a
- * path that a previously applied patch has already removed.
+ * path that a previously applied patch has already removed, or
+ * PATH_TO_BE_DELETED for a path that a later patch would remove.
+ *
+ * The latter is needed to deal with a case where two paths A and B
+ * are swapped by first renaming A to B and then renaming B to A;
+ * moving A to B should not be prevented due to presense of B as we
+ * will remove it in a later patch.
  */
- #define PATH_TO_BE_DELETED ((struct patch *) -2)
+#define PATH_TO_BE_DELETED ((struct patch *) -2)
 #define PATH_WAS_DELETED ((struct patch *) -1)
 
 static int to_be_deleted(struct patch *patch)
@@ -3048,127 +3067,324 @@ static void prepare_fn_table(struct patch *patch)
        }
 }
 
-static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce)
+static int checkout_target(struct cache_entry *ce, struct stat *st)
+{
+       struct checkout costate;
+
+       memset(&costate, 0, sizeof(costate));
+       costate.base_dir = "";
+       costate.refresh_cache = 1;
+       if (checkout_entry(ce, &costate, NULL) || lstat(ce->name, st))
+               return error(_("cannot checkout %s"), ce->name);
+       return 0;
+}
+
+static struct patch *previous_patch(struct patch *patch, int *gone)
+{
+       struct patch *previous;
+
+       *gone = 0;
+       if (patch->is_copy || patch->is_rename)
+               return NULL; /* "git" patches do not depend on the order */
+
+       previous = in_fn_table(patch->old_name);
+       if (!previous)
+               return NULL;
+
+       if (to_be_deleted(previous))
+               return NULL; /* the deletion hasn't happened yet */
+
+       if (was_deleted(previous))
+               *gone = 1;
+
+       return previous;
+}
+
+static int verify_index_match(struct cache_entry *ce, struct stat *st)
+{
+       if (S_ISGITLINK(ce->ce_mode)) {
+               if (!S_ISDIR(st->st_mode))
+                       return -1;
+               return 0;
+       }
+       return ce_match_stat(ce, st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);
+}
+
+#define SUBMODULE_PATCH_WITHOUT_INDEX 1
+
+static int load_patch_target(struct strbuf *buf,
+                            struct cache_entry *ce,
+                            struct stat *st,
+                            const char *name,
+                            unsigned expected_mode)
+{
+       if (cached) {
+               if (read_file_or_gitlink(ce, buf))
+                       return error(_("read of %s failed"), name);
+       } else if (name) {
+               if (S_ISGITLINK(expected_mode)) {
+                       if (ce)
+                               return read_file_or_gitlink(ce, buf);
+                       else
+                               return SUBMODULE_PATCH_WITHOUT_INDEX;
+               } else {
+                       if (read_old_data(st, name, buf))
+                               return error(_("read of %s failed"), name);
+               }
+       }
+       return 0;
+}
+
+/*
+ * We are about to apply "patch"; populate the "image" with the
+ * current version we have, from the working tree or from the index,
+ * depending on the situation e.g. --cached/--index.  If we are
+ * applying a non-git patch that incrementally updates the tree,
+ * we read from the result of a previous diff.
+ */
+static int load_preimage(struct image *image,
+                        struct patch *patch, struct stat *st, struct cache_entry *ce)
 {
        struct strbuf buf = STRBUF_INIT;
-       struct image image;
        size_t len;
        char *img;
-       struct patch *tpatch;
+       struct patch *previous;
+       int status;
 
-       if (!(patch->is_copy || patch->is_rename) &&
-           (tpatch = in_fn_table(patch->old_name)) != NULL && !to_be_deleted(tpatch)) {
-               if (was_deleted(tpatch)) {
-                       return error(_("patch %s has been renamed/deleted"),
-                               patch->old_name);
-               }
+       previous = previous_patch(patch, &status);
+       if (status)
+               return error(_("path %s has been renamed/deleted"),
+                            patch->old_name);
+       if (previous) {
                /* We have a patched copy in memory; use that. */
-               strbuf_add(&buf, tpatch->result, tpatch->resultsize);
-       } else if (cached) {
-               if (read_file_or_gitlink(ce, &buf))
+               strbuf_add(&buf, previous->result, previous->resultsize);
+       } else {
+               status = load_patch_target(&buf, ce, st,
+                                          patch->old_name, patch->old_mode);
+               if (status < 0)
+                       return status;
+               else if (status == SUBMODULE_PATCH_WITHOUT_INDEX) {
+                       /*
+                        * There is no way to apply subproject
+                        * patch without looking at the index.
+                        * NEEDSWORK: shouldn't this be flagged
+                        * as an error???
+                        */
+                       free_fragment_list(patch->fragments);
+                       patch->fragments = NULL;
+               } else if (status) {
                        return error(_("read of %s failed"), patch->old_name);
-       } else if (patch->old_name) {
-               if (S_ISGITLINK(patch->old_mode)) {
-                       if (ce) {
-                               read_file_or_gitlink(ce, &buf);
-                       } else {
-                               /*
-                                * There is no way to apply subproject
-                                * patch without looking at the index.
-                                * NEEDSWORK: shouldn't this be flagged
-                                * as an error???
-                                */
-                               free_fragment_list(patch->fragments);
-                               patch->fragments = NULL;
-                       }
-               } else {
-                       if (read_old_data(st, patch->old_name, &buf))
-                               return error(_("read of %s failed"), patch->old_name);
                }
        }
 
        img = strbuf_detach(&buf, &len);
-       prepare_image(&image, img, len, !patch->is_binary);
+       prepare_image(image, img, len, !patch->is_binary);
+       return 0;
+}
 
-       if (apply_fragments(&image, patch) < 0)
-               return -1; /* note with --reject this succeeds. */
-       patch->result = image.buf;
-       patch->resultsize = image.len;
-       add_to_fn_table(patch);
-       free(image.line_allocated);
+static int three_way_merge(struct image *image,
+                          char *path,
+                          const unsigned char *base,
+                          const unsigned char *ours,
+                          const unsigned char *theirs)
+{
+       mmfile_t base_file, our_file, their_file;
+       mmbuffer_t result = { NULL };
+       int status;
 
-       if (0 < patch->is_delete && patch->resultsize)
-               return error(_("removal patch leaves file contents"));
+       read_mmblob(&base_file, base);
+       read_mmblob(&our_file, ours);
+       read_mmblob(&their_file, theirs);
+       status = ll_merge(&result, path,
+                         &base_file, "base",
+                         &our_file, "ours",
+                         &their_file, "theirs", NULL);
+       free(base_file.ptr);
+       free(our_file.ptr);
+       free(their_file.ptr);
+       if (status < 0 || !result.ptr) {
+               free(result.ptr);
+               return -1;
+       }
+       clear_image(image);
+       image->buf = result.ptr;
+       image->len = result.size;
 
+       return status;
+}
+
+/*
+ * When directly falling back to add/add three-way merge, we read from
+ * the current contents of the new_name.  In no cases other than that
+ * this function will be called.
+ */
+static int load_current(struct image *image, struct patch *patch)
+{
+       struct strbuf buf = STRBUF_INIT;
+       int status, pos;
+       size_t len;
+       char *img;
+       struct stat st;
+       struct cache_entry *ce;
+       char *name = patch->new_name;
+       unsigned mode = patch->new_mode;
+
+       if (!patch->is_new)
+               die("BUG: patch to %s is not a creation", patch->old_name);
+
+       pos = cache_name_pos(name, strlen(name));
+       if (pos < 0)
+               return error(_("%s: does not exist in index"), name);
+       ce = active_cache[pos];
+       if (lstat(name, &st)) {
+               if (errno != ENOENT)
+                       return error(_("%s: %s"), name, strerror(errno));
+               if (checkout_target(ce, &st))
+                       return -1;
+       }
+       if (verify_index_match(ce, &st))
+               return error(_("%s: does not match index"), name);
+
+       status = load_patch_target(&buf, ce, &st, name, mode);
+       if (status < 0)
+               return status;
+       else if (status)
+               return -1;
+       img = strbuf_detach(&buf, &len);
+       prepare_image(image, img, len, !patch->is_binary);
        return 0;
 }
 
-static int check_to_create_blob(const char *new_name, int ok_if_exists)
+static int try_threeway(struct image *image, struct patch *patch,
+                       struct stat *st, struct cache_entry *ce)
 {
-       struct stat nst;
-       if (!lstat(new_name, &nst)) {
-               if (S_ISDIR(nst.st_mode) || ok_if_exists)
-                       return 0;
-               /*
-                * A leading component of new_name might be a symlink
-                * that is going to be removed with this patch, but
-                * still pointing at somewhere that has the path.
-                * In such a case, path "new_name" does not exist as
-                * far as git is concerned.
-                */
-               if (has_symlink_leading_path(new_name, strlen(new_name)))
-                       return 0;
+       unsigned char pre_sha1[20], post_sha1[20], our_sha1[20];
+       struct strbuf buf = STRBUF_INIT;
+       size_t len;
+       int status;
+       char *img;
+       struct image tmp_image;
+
+       /* No point falling back to 3-way merge in these cases */
+       if (patch->is_delete ||
+           S_ISGITLINK(patch->old_mode) || S_ISGITLINK(patch->new_mode))
+               return -1;
 
-               return error(_("%s: already exists in working directory"), new_name);
+       /* Preimage the patch was prepared for */
+       if (patch->is_new)
+               write_sha1_file("", 0, blob_type, pre_sha1);
+       else if (get_sha1(patch->old_sha1_prefix, pre_sha1) ||
+                read_blob_object(&buf, pre_sha1, patch->old_mode))
+               return error("repository lacks the necessary blob to fall back on 3-way merge.");
+
+       fprintf(stderr, "Falling back to three-way merge...\n");
+
+       img = strbuf_detach(&buf, &len);
+       prepare_image(&tmp_image, img, len, 1);
+       /* Apply the patch to get the post image */
+       if (apply_fragments(&tmp_image, patch) < 0) {
+               clear_image(&tmp_image);
+               return -1;
+       }
+       /* post_sha1[] is theirs */
+       write_sha1_file(tmp_image.buf, tmp_image.len, blob_type, post_sha1);
+       clear_image(&tmp_image);
+
+       /* our_sha1[] is ours */
+       if (patch->is_new) {
+               if (load_current(&tmp_image, patch))
+                       return error("cannot read the current contents of '%s'",
+                                    patch->new_name);
+       } else {
+               if (load_preimage(&tmp_image, patch, st, ce))
+                       return error("cannot read the current contents of '%s'",
+                                    patch->old_name);
+       }
+       write_sha1_file(tmp_image.buf, tmp_image.len, blob_type, our_sha1);
+       clear_image(&tmp_image);
+
+       /* in-core three-way merge between post and our using pre as base */
+       status = three_way_merge(image, patch->new_name,
+                                pre_sha1, our_sha1, post_sha1);
+       if (status < 0) {
+               fprintf(stderr, "Failed to fall back on three-way merge...\n");
+               return status;
+       }
+
+       if (status) {
+               patch->conflicted_threeway = 1;
+               if (patch->is_new)
+                       hashclr(patch->threeway_stage[0]);
+               else
+                       hashcpy(patch->threeway_stage[0], pre_sha1);
+               hashcpy(patch->threeway_stage[1], our_sha1);
+               hashcpy(patch->threeway_stage[2], post_sha1);
+               fprintf(stderr, "Applied patch to '%s' with conflicts.\n", patch->new_name);
+       } else {
+               fprintf(stderr, "Applied patch to '%s' cleanly.\n", patch->new_name);
        }
-       else if ((errno != ENOENT) && (errno != ENOTDIR))
-               return error("%s: %s", new_name, strerror(errno));
        return 0;
 }
 
-static int verify_index_match(struct cache_entry *ce, struct stat *st)
+static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce)
 {
-       if (S_ISGITLINK(ce->ce_mode)) {
-               if (!S_ISDIR(st->st_mode))
+       struct image image;
+
+       if (load_preimage(&image, patch, st, ce) < 0)
+               return -1;
+
+       if (patch->direct_to_threeway ||
+           apply_fragments(&image, patch) < 0) {
+               /* Note: with --reject, apply_fragments() returns 0 */
+               if (!threeway || try_threeway(&image, patch, st, ce) < 0)
                        return -1;
-               return 0;
        }
-       return ce_match_stat(ce, st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);
+       patch->result = image.buf;
+       patch->resultsize = image.len;
+       add_to_fn_table(patch);
+       free(image.line_allocated);
+
+       if (0 < patch->is_delete && patch->resultsize)
+               return error(_("removal patch leaves file contents"));
+
+       return 0;
 }
 
+/*
+ * If "patch" that we are looking at modifies or deletes what we have,
+ * we would want it not to lose any local modification we have, either
+ * in the working tree or in the index.
+ *
+ * This also decides if a non-git patch is a creation patch or a
+ * modification to an existing empty file.  We do not check the state
+ * of the current tree for a creation patch in this function; the caller
+ * check_patch() separately makes sure (and errors out otherwise) that
+ * the path the patch creates does not exist in the current tree.
+ */
 static int check_preimage(struct patch *patch, struct cache_entry **ce, struct stat *st)
 {
        const char *old_name = patch->old_name;
-       struct patch *tpatch = NULL;
-       int stat_ret = 0;
+       struct patch *previous = NULL;
+       int stat_ret = 0, status;
        unsigned st_mode = 0;
 
-       /*
-        * Make sure that we do not have local modifications from the
-        * index when we are looking at the index.  Also make sure
-        * we have the preimage file to be patched in the work tree,
-        * unless --cached, which tells git to apply only in the index.
-        */
        if (!old_name)
                return 0;
 
        assert(patch->is_new <= 0);
+       previous = previous_patch(patch, &status);
 
-       if (!(patch->is_copy || patch->is_rename) &&
-           (tpatch = in_fn_table(old_name)) != NULL && !to_be_deleted(tpatch)) {
-               if (was_deleted(tpatch))
-                       return error(_("%s: has been deleted/renamed"), old_name);
-               st_mode = tpatch->new_mode;
+       if (status)
+               return error(_("path %s has been renamed/deleted"), old_name);
+       if (previous) {
+               st_mode = previous->new_mode;
        } else if (!cached) {
                stat_ret = lstat(old_name, st);
                if (stat_ret && errno != ENOENT)
                        return error(_("%s: %s"), old_name, strerror(errno));
        }
 
-       if (to_be_deleted(tpatch))
-               tpatch = NULL;
-
-       if (check_index && !tpatch) {
+       if (check_index && !previous) {
                int pos = cache_name_pos(old_name, strlen(old_name));
                if (pos < 0) {
                        if (patch->is_new < 0)
@@ -3177,13 +3393,7 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s
                }
                *ce = active_cache[pos];
                if (stat_ret < 0) {
-                       struct checkout costate;
-                       /* checkout */
-                       memset(&costate, 0, sizeof(costate));
-                       costate.base_dir = "";
-                       costate.refresh_cache = 1;
-                       if (checkout_entry(*ce, &costate, NULL) ||
-                           lstat(old_name, st))
+                       if (checkout_target(*ce, st))
                                return -1;
                }
                if (!cached && verify_index_match(*ce, st))
@@ -3196,7 +3406,7 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s
                return error(_("%s: %s"), old_name, strerror(errno));
        }
 
-       if (!cached && !tpatch)
+       if (!cached && !previous)
                st_mode = ce_mode_from_stat(*ce, st->st_mode);
 
        if (patch->is_new < 0)
@@ -3220,6 +3430,41 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s
        return 0;
 }
 
+
+#define EXISTS_IN_INDEX 1
+#define EXISTS_IN_WORKTREE 2
+
+static int check_to_create(const char *new_name, int ok_if_exists)
+{
+       struct stat nst;
+
+       if (check_index &&
+           cache_name_pos(new_name, strlen(new_name)) >= 0 &&
+           !ok_if_exists)
+               return EXISTS_IN_INDEX;
+       if (cached)
+               return 0;
+
+       if (!lstat(new_name, &nst)) {
+               if (S_ISDIR(nst.st_mode) || ok_if_exists)
+                       return 0;
+               /*
+                * A leading component of new_name might be a symlink
+                * that is going to be removed with this patch, but
+                * still pointing at somewhere that has the path.
+                * In such a case, path "new_name" does not exist as
+                * far as git is concerned.
+                */
+               if (has_symlink_leading_path(new_name, strlen(new_name)))
+                       return 0;
+
+               return EXISTS_IN_WORKTREE;
+       } else if ((errno != ENOENT) && (errno != ENOTDIR)) {
+               return error("%s: %s", new_name, strerror(errno));
+       }
+       return 0;
+}
+
 /*
  * Check and apply the patch in-core; leave the result in patch->result
  * for the caller to write it out to the final destination.
@@ -3242,31 +3487,45 @@ static int check_patch(struct patch *patch)
                return status;
        old_name = patch->old_name;
 
+       /*
+        * A type-change diff is always split into a patch to delete
+        * old, immediately followed by a patch to create new (see
+        * diff.c::run_diff()); in such a case it is Ok that the entry
+        * to be deleted by the previous patch is still in the working
+        * tree and in the index.
+        *
+        * A patch to swap-rename between A and B would first rename A
+        * to B and then rename B to A.  While applying the first one,
+        * the presense of B should not stop A from getting renamed to
+        * B; ask to_be_deleted() about the later rename.  Removal of
+        * B and rename from A to B is handled the same way by asking
+        * was_deleted().
+        */
        if ((tpatch = in_fn_table(new_name)) &&
-                       (was_deleted(tpatch) || to_be_deleted(tpatch)))
-               /*
-                * A type-change diff is always split into a patch to
-                * delete old, immediately followed by a patch to
-                * create new (see diff.c::run_diff()); in such a case
-                * it is Ok that the entry to be deleted by the
-                * previous patch is still in the working tree and in
-                * the index.
-                */
+           (was_deleted(tpatch) || to_be_deleted(tpatch)))
                ok_if_exists = 1;
        else
                ok_if_exists = 0;
 
        if (new_name &&
            ((0 < patch->is_new) | (0 < patch->is_rename) | patch->is_copy)) {
-               if (check_index &&
-                   cache_name_pos(new_name, strlen(new_name)) >= 0 &&
-                   !ok_if_exists)
+               int err = check_to_create(new_name, ok_if_exists);
+
+               if (err && threeway) {
+                       patch->direct_to_threeway = 1;
+               } else switch (err) {
+               case 0:
+                       break; /* happy */
+               case EXISTS_IN_INDEX:
                        return error(_("%s: already exists in index"), new_name);
-               if (!cached) {
-                       int err = check_to_create_blob(new_name, ok_if_exists);
-                       if (err)
-                               return err;
+                       break;
+               case EXISTS_IN_WORKTREE:
+                       return error(_("%s: already exists in working directory"),
+                                    new_name);
+               default:
+                       return err;
                }
+
                if (!patch->new_mode) {
                        if (0 < patch->is_new)
                                patch->new_mode = S_IFREG | 0644;
@@ -3347,7 +3606,7 @@ 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(patch->old_sha1_prefix, sha1))
+               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))
@@ -3527,7 +3786,8 @@ static void add_index_file(const char *path, unsigned mode, void *buf, unsigned
        ce = xcalloc(1, ce_size);
        memcpy(ce->name, path, namelen);
        ce->ce_mode = create_ce_mode(mode);
-       ce->ce_flags = namelen;
+       ce->ce_flags = create_ce_flags(0);
+       ce->ce_namelen = namelen;
        if (S_ISGITLINK(mode)) {
                const char *s = buf;
 
@@ -3629,6 +3889,33 @@ static void create_one_file(char *path, unsigned mode, const char *buf, unsigned
        die_errno(_("unable to write file '%s' mode %o"), path, mode);
 }
 
+static void add_conflicted_stages_file(struct patch *patch)
+{
+       int stage, namelen;
+       unsigned ce_size, mode;
+       struct cache_entry *ce;
+
+       if (!update_index)
+               return;
+       namelen = strlen(patch->new_name);
+       ce_size = cache_entry_size(namelen);
+       mode = patch->new_mode ? patch->new_mode : (S_IFREG | 0644);
+
+       remove_file_from_cache(patch->new_name);
+       for (stage = 1; stage < 4; stage++) {
+               if (is_null_sha1(patch->threeway_stage[stage - 1]))
+                       continue;
+               ce = xcalloc(1, ce_size);
+               memcpy(ce->name, patch->new_name, namelen);
+               ce->ce_mode = create_ce_mode(mode);
+               ce->ce_flags = create_ce_flags(stage);
+               ce->ce_namelen = namelen;
+               hashcpy(ce->sha1, patch->threeway_stage[stage - 1]);
+               if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD) < 0)
+                       die(_("unable to add cache entry for %s"), patch->new_name);
+       }
+}
+
 static void create_file(struct patch *patch)
 {
        char *path = patch->new_name;
@@ -3639,7 +3926,11 @@ static void create_file(struct patch *patch)
        if (!mode)
                mode = S_IFREG | 0644;
        create_one_file(path, mode, buf, size);
-       add_index_file(path, mode, buf, size);
+
+       if (patch->conflicted_threeway)
+               add_conflicted_stages_file(patch);
+       else
+               add_index_file(path, mode, buf, size);
 }
 
 /* phase zero is to remove, phase one is to create */
@@ -3741,6 +4032,7 @@ static int write_out_results(struct patch *list)
        int phase;
        int errs = 0;
        struct patch *l;
+       struct string_list cpath = STRING_LIST_INIT_DUP;
 
        for (phase = 0; phase < 2; phase++) {
                l = list;
@@ -3749,12 +4041,30 @@ static int write_out_results(struct patch *list)
                                errs = 1;
                        else {
                                write_out_one_result(l, phase);
-                               if (phase == 1 && write_out_one_reject(l))
-                                       errs = 1;
+                               if (phase == 1) {
+                                       if (write_out_one_reject(l))
+                                               errs = 1;
+                                       if (l->conflicted_threeway) {
+                                               string_list_append(&cpath, l->new_name);
+                                               errs = 1;
+                                       }
+                               }
                        }
                        l = l->next;
                }
        }
+
+       if (cpath.nr) {
+               struct string_list_item *item;
+
+               sort_string_list(&cpath);
+               for_each_string_list_item(item, &cpath)
+                       fprintf(stderr, "U %s\n", item->string);
+               string_list_clear(&cpath, 0);
+
+               rerere(0);
+       }
+
        return errs;
 }
 
@@ -3877,8 +4187,12 @@ static int apply_patch(int fd, const char *filename, int options)
            !apply_with_reject)
                exit(1);
 
-       if (apply && write_out_results(list))
-               exit(1);
+       if (apply && write_out_results(list)) {
+               if (apply_with_reject)
+                       exit(1);
+               /* with --3way, we still need to write the index out */
+               return 1;
+       }
 
        if (fake_ancestor)
                build_fake_ancestor(list, fake_ancestor);
@@ -4000,7 +4314,7 @@ int cmd_apply(int argc, const char **argv, const char *prefix_)
                OPT_NOOP_NOARG(0, "allow-binary-replacement"),
                OPT_NOOP_NOARG(0, "binary"),
                OPT_BOOLEAN(0, "numstat", &numstat,
-                       N_("shows number of added and deleted lines in decimal notation")),
+                       N_("show number of added and deleted lines in decimal notation")),
                OPT_BOOLEAN(0, "summary", &summary,
                        N_("instead of applying the patch, output a summary for the input")),
                OPT_BOOLEAN(0, "check", &check,
@@ -4011,6 +4325,8 @@ int cmd_apply(int argc, const char **argv, const char *prefix_)
                        N_("apply a patch without touching the working tree")),
                OPT_BOOLEAN(0, "apply", &force_apply,
                        N_("also apply the patch (use with --stat/--summary/--check)")),
+               OPT_BOOL('3', "3way", &threeway,
+                        N_( "attempt three-way merge if a patch does not apply")),
                OPT_FILENAME(0, "build-fake-ancestor", &fake_ancestor,
                        N_("build a temporary index based on embedded index information")),
                { OPTION_CALLBACK, 'z', NULL, NULL, NULL,
@@ -4059,6 +4375,15 @@ int cmd_apply(int argc, const char **argv, const char *prefix_)
        argc = parse_options(argc, argv, prefix, builtin_apply_options,
                        apply_usage, 0);
 
+       if (apply_with_reject && threeway)
+               die("--reject and --3way cannot be used together.");
+       if (cached && threeway)
+               die("--cached and --3way cannot be used together.");
+       if (threeway) {
+               if (is_not_gitdir)
+                       die(_("--3way outside a repository"));
+               check_index = 1;
+       }
        if (apply_with_reject)
                apply = apply_verbosely = 1;
        if (!force_apply && (diffstat || numstat || summary || check || fake_ancestor))
index 931956def986bbdf5b77e163f1b18c961e7be09c..9a1cfd3dac0123cb65d3db7597221a29e9010bd9 100644 (file)
@@ -88,12 +88,12 @@ int cmd_archive(int argc, const char **argv, const char *prefix)
        const char *output = NULL;
        const char *remote = NULL;
        struct option local_opts[] = {
-               OPT_STRING('o', "output", &output, "file",
-                       "write the archive to this file"),
-               OPT_STRING(0, "remote", &remote, "repo",
-                       "retrieve the archive from remote repository <repo>"),
-               OPT_STRING(0, "exec", &exec, "cmd",
-                       "path to the remote git-upload-archive command"),
+               OPT_STRING('o', "output", &output, N_("file"),
+                       N_("write the archive to this file")),
+               OPT_STRING(0, "remote", &remote, N_("repo"),
+                       N_("retrieve the archive from remote repository <repo>")),
+               OPT_STRING(0, "exec", &exec, N_("command"),
+                       N_("path to the remote git-upload-archive command")),
                OPT_END()
        };
 
index 8d325a5179f68d2810b5b2082fe66dc6d00da455..e3884e3bb61c7dfb0cd97ddba7bd0558b44c6b8f 100644 (file)
@@ -4,7 +4,7 @@
 #include "bisect.h"
 
 static const char * const git_bisect_helper_usage[] = {
-       "git bisect--helper --next-all [--no-checkout]",
+       N_("git bisect--helper --next-all [--no-checkout]"),
        NULL
 };
 
@@ -14,9 +14,9 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
        int no_checkout = 0;
        struct option options[] = {
                OPT_BOOLEAN(0, "next-all", &next_all,
-                           "perform 'git bisect next'"),
+                           N_("perform 'git bisect next'")),
                OPT_BOOLEAN(0, "no-checkout", &no_checkout,
-                           "update BISECT_HEAD instead of checking out the current commit"),
+                           N_("update BISECT_HEAD instead of checking out the current commit")),
                OPT_END()
        };
 
index cad4111a36a5b880d9d851463ef5f554f56d27d3..c27ef21c2326afd29a68146d23c734c7ea708556 100644 (file)
 #include "utf8.h"
 #include "userdiff.h"
 
-static char blame_usage[] = "git blame [options] [rev-opts] [rev] [--] file";
+static char blame_usage[] = N_("git blame [options] [rev-opts] [rev] [--] file");
 
 static const char *blame_opt_usage[] = {
        blame_usage,
        "",
-       "[rev-opts] are documented in git-rev-list(1)",
+       N_("[rev-opts] are documented in git-rev-list(1)"),
        NULL
 };
 
@@ -2069,6 +2069,55 @@ static int git_blame_config(const char *var, const char *value, void *cb)
        return git_default_config(var, value, cb);
 }
 
+static void verify_working_tree_path(struct commit *work_tree, const char *path)
+{
+       struct commit_list *parents;
+
+       for (parents = work_tree->parents; parents; parents = parents->next) {
+               const unsigned char *commit_sha1 = parents->item->object.sha1;
+               unsigned char blob_sha1[20];
+               unsigned mode;
+
+               if (!get_tree_entry(commit_sha1, path, blob_sha1, &mode) &&
+                   sha1_object_info(blob_sha1, NULL) == OBJ_BLOB)
+                       return;
+       }
+       die("no such path '%s' in HEAD", path);
+}
+
+static struct commit_list **append_parent(struct commit_list **tail, const unsigned char *sha1)
+{
+       struct commit *parent;
+
+       parent = lookup_commit_reference(sha1);
+       if (!parent)
+               die("no such commit %s", sha1_to_hex(sha1));
+       return &commit_list_insert(parent, tail)->next;
+}
+
+static void append_merge_parents(struct commit_list **tail)
+{
+       int merge_head;
+       const char *merge_head_file = git_path("MERGE_HEAD");
+       struct strbuf line = STRBUF_INIT;
+
+       merge_head = open(merge_head_file, O_RDONLY);
+       if (merge_head < 0) {
+               if (errno == ENOENT)
+                       return;
+               die("cannot open '%s' for reading", merge_head_file);
+       }
+
+       while (!strbuf_getwholeline_fd(&line, merge_head, '\n')) {
+               unsigned char sha1[20];
+               if (line.len < 40 || get_sha1_hex(line.buf, sha1))
+                       die("unknown line in '%s': %s", merge_head_file, line.buf);
+               tail = append_parent(tail, sha1);
+       }
+       close(merge_head);
+       strbuf_release(&line);
+}
+
 /*
  * Prepare a dummy commit that represents the work tree (or staged) item.
  * Note that annotating work tree item never works in the reverse.
@@ -2079,6 +2128,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
 {
        struct commit *commit;
        struct origin *origin;
+       struct commit_list **parent_tail, *parent;
        unsigned char head_sha1[20];
        struct strbuf buf = STRBUF_INIT;
        const char *ident;
@@ -2086,20 +2136,38 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
        int size, len;
        struct cache_entry *ce;
        unsigned mode;
-
-       if (get_sha1("HEAD", head_sha1))
-               die("No such ref: HEAD");
+       struct strbuf msg = STRBUF_INIT;
 
        time(&now);
        commit = xcalloc(1, sizeof(*commit));
-       commit->parents = xcalloc(1, sizeof(*commit->parents));
-       commit->parents->item = lookup_commit_reference(head_sha1);
        commit->object.parsed = 1;
        commit->date = now;
        commit->object.type = OBJ_COMMIT;
+       parent_tail = &commit->parents;
+
+       if (!resolve_ref_unsafe("HEAD", head_sha1, 1, NULL))
+               die("no such ref: HEAD");
+
+       parent_tail = append_parent(parent_tail, head_sha1);
+       append_merge_parents(parent_tail);
+       verify_working_tree_path(commit, path);
 
        origin = make_origin(commit, path);
 
+       ident = fmt_ident("Not Committed Yet", "not.committed.yet", NULL, 0);
+       strbuf_addstr(&msg, "tree 0000000000000000000000000000000000000000\n");
+       for (parent = commit->parents; parent; parent = parent->next)
+               strbuf_addf(&msg, "parent %s\n",
+                           sha1_to_hex(parent->item->object.sha1));
+       strbuf_addf(&msg,
+                   "author %s\n"
+                   "committer %s\n\n"
+                   "Version of %s from %s\n",
+                   ident, ident, path,
+                   (!contents_from ? path :
+                    (!strcmp(contents_from, "-") ? "standard input" : contents_from)));
+       commit->buffer = strbuf_detach(&msg, NULL);
+
        if (!contents_from || strcmp("-", contents_from)) {
                struct stat st;
                const char *read_from;
@@ -2136,7 +2204,6 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
        }
        else {
                /* Reading from stdin */
-               contents_from = "standard input";
                mode = 0;
                if (strbuf_read(&buf, 0, 0) < 0)
                        die_errno("failed to read from stdin");
@@ -2169,7 +2236,8 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
        ce = xcalloc(1, size);
        hashcpy(ce->sha1, origin->blob_sha1);
        memcpy(ce->name, path, len);
-       ce->ce_flags = create_ce_flags(len, 0);
+       ce->ce_flags = create_ce_flags(0);
+       ce->ce_namelen = len;
        ce->ce_mode = create_ce_mode(mode);
        add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
 
@@ -2180,16 +2248,6 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
         */
        cache_tree_invalidate_path(active_cache_tree, path);
 
-       commit->buffer = xmalloc(400);
-       ident = fmt_ident("Not Committed Yet", "not.committed.yet", NULL, 0);
-       snprintf(commit->buffer, 400,
-               "tree 0000000000000000000000000000000000000000\n"
-               "parent %s\n"
-               "author %s\n"
-               "committer %s\n\n"
-               "Version of %s from %s\n",
-               sha1_to_hex(head_sha1),
-               ident, ident, path, contents_from ? contents_from : path);
        return commit;
 }
 
@@ -2312,27 +2370,27 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
        static const char *revs_file = NULL;
        static const char *contents_from = NULL;
        static const struct option options[] = {
-               OPT_BOOLEAN(0, "incremental", &incremental, "Show blame entries as we find them, incrementally"),
-               OPT_BOOLEAN('b', NULL, &blank_boundary, "Show blank SHA-1 for boundary commits (Default: off)"),
-               OPT_BOOLEAN(0, "root", &show_root, "Do not treat root commits as boundaries (Default: off)"),
-               OPT_BOOLEAN(0, "show-stats", &show_stats, "Show work cost statistics"),
-               OPT_BIT(0, "score-debug", &output_option, "Show output score for blame entries", OUTPUT_SHOW_SCORE),
-               OPT_BIT('f', "show-name", &output_option, "Show original filename (Default: auto)", OUTPUT_SHOW_NAME),
-               OPT_BIT('n', "show-number", &output_option, "Show original linenumber (Default: off)", OUTPUT_SHOW_NUMBER),
-               OPT_BIT('p', "porcelain", &output_option, "Show in a format designed for machine consumption", OUTPUT_PORCELAIN),
-               OPT_BIT(0, "line-porcelain", &output_option, "Show porcelain format with per-line commit information", OUTPUT_PORCELAIN|OUTPUT_LINE_PORCELAIN),
-               OPT_BIT('c', NULL, &output_option, "Use the same output mode as git-annotate (Default: off)", OUTPUT_ANNOTATE_COMPAT),
-               OPT_BIT('t', NULL, &output_option, "Show raw timestamp (Default: off)", OUTPUT_RAW_TIMESTAMP),
-               OPT_BIT('l', NULL, &output_option, "Show long commit SHA1 (Default: off)", OUTPUT_LONG_OBJECT_NAME),
-               OPT_BIT('s', NULL, &output_option, "Suppress author name and timestamp (Default: off)", OUTPUT_NO_AUTHOR),
-               OPT_BIT('e', "show-email", &output_option, "Show author email instead of name (Default: off)", OUTPUT_SHOW_EMAIL),
-               OPT_BIT('w', NULL, &xdl_opts, "Ignore whitespace differences", XDF_IGNORE_WHITESPACE),
-               OPT_BIT(0, "minimal", &xdl_opts, "Spend extra cycles to find better match", XDF_NEED_MINIMAL),
-               OPT_STRING('S', NULL, &revs_file, "file", "Use revisions from <file> instead of calling git-rev-list"),
-               OPT_STRING(0, "contents", &contents_from, "file", "Use <file>'s contents as the final image"),
-               { OPTION_CALLBACK, 'C', NULL, &opt, "score", "Find line copies within and across files", PARSE_OPT_OPTARG, blame_copy_callback },
-               { OPTION_CALLBACK, 'M', NULL, &opt, "score", "Find line movements within and across files", PARSE_OPT_OPTARG, blame_move_callback },
-               OPT_CALLBACK('L', NULL, &bottomtop, "n,m", "Process only line range n,m, counting from 1", blame_bottomtop_callback),
+               OPT_BOOLEAN(0, "incremental", &incremental, N_("Show blame entries as we find them, incrementally")),
+               OPT_BOOLEAN('b', NULL, &blank_boundary, N_("Show blank SHA-1 for boundary commits (Default: off)")),
+               OPT_BOOLEAN(0, "root", &show_root, N_("Do not treat root commits as boundaries (Default: off)")),
+               OPT_BOOLEAN(0, "show-stats", &show_stats, N_("Show work cost statistics")),
+               OPT_BIT(0, "score-debug", &output_option, N_("Show output score for blame entries"), OUTPUT_SHOW_SCORE),
+               OPT_BIT('f', "show-name", &output_option, N_("Show original filename (Default: auto)"), OUTPUT_SHOW_NAME),
+               OPT_BIT('n', "show-number", &output_option, N_("Show original linenumber (Default: off)"), OUTPUT_SHOW_NUMBER),
+               OPT_BIT('p', "porcelain", &output_option, N_("Show in a format designed for machine consumption"), OUTPUT_PORCELAIN),
+               OPT_BIT(0, "line-porcelain", &output_option, N_("Show porcelain format with per-line commit information"), OUTPUT_PORCELAIN|OUTPUT_LINE_PORCELAIN),
+               OPT_BIT('c', NULL, &output_option, N_("Use the same output mode as git-annotate (Default: off)"), OUTPUT_ANNOTATE_COMPAT),
+               OPT_BIT('t', NULL, &output_option, N_("Show raw timestamp (Default: off)"), OUTPUT_RAW_TIMESTAMP),
+               OPT_BIT('l', NULL, &output_option, N_("Show long commit SHA1 (Default: off)"), OUTPUT_LONG_OBJECT_NAME),
+               OPT_BIT('s', NULL, &output_option, N_("Suppress author name and timestamp (Default: off)"), OUTPUT_NO_AUTHOR),
+               OPT_BIT('e', "show-email", &output_option, N_("Show author email instead of name (Default: off)"), OUTPUT_SHOW_EMAIL),
+               OPT_BIT('w', NULL, &xdl_opts, N_("Ignore whitespace differences"), XDF_IGNORE_WHITESPACE),
+               OPT_BIT(0, "minimal", &xdl_opts, N_("Spend extra cycles to find better match"), XDF_NEED_MINIMAL),
+               OPT_STRING('S', NULL, &revs_file, N_("file"), N_("Use revisions from <file> instead of calling git-rev-list")),
+               OPT_STRING(0, "contents", &contents_from, N_("file"), N_("Use <file>'s contents as the final image")),
+               { OPTION_CALLBACK, 'C', NULL, &opt, N_("score"), N_("Find line copies within and across files"), PARSE_OPT_OPTARG, blame_copy_callback },
+               { OPTION_CALLBACK, 'M', NULL, &opt, N_("score"), N_("Find line movements within and across files"), PARSE_OPT_OPTARG, blame_move_callback },
+               OPT_CALLBACK('L', NULL, &bottomtop, N_("n,m"), N_("Process only line range n,m, counting from 1"), blame_bottomtop_callback),
                OPT__ABBREV(&abbrev),
                OPT_END()
        };
index 0e060f2e4a982efdda0f88d021e0a9d3f23c6b75..1ec9c02612d0391984b484a5850f45c277a3e804 100644 (file)
 #include "revision.h"
 #include "string-list.h"
 #include "column.h"
+#include "utf8.h"
 
 static const char * const builtin_branch_usage[] = {
-       "git branch [options] [-r | -a] [--merged | --no-merged]",
-       "git branch [options] [-l] [-f] <branchname> [<start-point>]",
-       "git branch [options] [-r] (-d | -D) <branchname>...",
-       "git branch [options] (-m | -M) [<oldbranch>] <newbranch>",
+       N_("git branch [options] [-r | -a] [--merged | --no-merged]"),
+       N_("git branch [options] [-l] [-f] <branchname> [<start-point>]"),
+       N_("git branch [options] [-r] (-d | -D) <branchname>..."),
+       N_("git branch [options] (-m | -M) [<oldbranch>] <newbranch>"),
        NULL
 };
 
@@ -129,7 +130,7 @@ static int branch_merged(int kind, const char *name,
        if (!reference_rev)
                reference_rev = head_rev;
 
-       merged = in_merge_bases(rev, &reference_rev, 1);
+       merged = in_merge_bases(rev, reference_rev);
 
        /*
         * After the safety valve is fully redefined to "check with
@@ -139,7 +140,7 @@ static int branch_merged(int kind, const char *name,
         * a gentle reminder is in order.
         */
        if ((head_rev != reference_rev) &&
-           in_merge_bases(rev, &head_rev, 1) != merged) {
+           in_merge_bases(rev, head_rev) != merged) {
                if (merged)
                        warning(_("deleting branch '%s' that has been merged to\n"
                                "         '%s', but not yet merged to HEAD."),
@@ -153,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;
@@ -186,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' "
@@ -196,8 +227,10 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
 
                free(name);
 
-               name = xstrdup(mkpath(fmt, bname.buf));
-               if (read_ref(name, sha1)) {
+               name = mkpathdup(fmt, bname.buf);
+               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);
@@ -205,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);
@@ -249,7 +273,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
 struct ref_item {
        char *name;
        char *dest;
-       unsigned int kind, len;
+       unsigned int kind, width;
        struct commit *commit;
 };
 
@@ -354,14 +378,14 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags,
        newitem->name = xstrdup(refname);
        newitem->kind = kind;
        newitem->commit = commit;
-       newitem->len = strlen(refname);
+       newitem->width = utf8_strwidth(refname);
        newitem->dest = resolve_symref(orig_refname, prefix);
        /* adjust for "remotes/" */
        if (newitem->kind == REF_REMOTE_BRANCH &&
            ref_list->kinds != REF_REMOTE_BRANCH)
-               newitem->len += 8;
-       if (newitem->len > ref_list->maxwidth)
-               ref_list->maxwidth = newitem->len;
+               newitem->width += 8;
+       if (newitem->width > ref_list->maxwidth)
+               ref_list->maxwidth = newitem->width;
 
        return 0;
 }
@@ -490,11 +514,12 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
        }
 
        strbuf_addf(&name, "%s%s", prefix, item->name);
-       if (verbose)
+       if (verbose) {
+               int utf8_compensation = strlen(name.buf) - utf8_strwidth(name.buf);
                strbuf_addf(&out, "%c %s%-*s%s", c, branch_get_color(color),
-                           maxwidth, name.buf,
+                           maxwidth + utf8_compensation, name.buf,
                            branch_get_color(BRANCH_COLOR_RESET));
-       else
+       else
                strbuf_addf(&out, "%c %s%s%s", c, branch_get_color(color),
                            name.buf, branch_get_color(BRANCH_COLOR_RESET));
 
@@ -519,8 +544,8 @@ static int calc_maxwidth(struct ref_list *refs)
        for (i = 0; i < refs->index; i++) {
                if (!matches_merge_filter(refs->list[i].commit))
                        continue;
-               if (refs->list[i].len > w)
-                       w = refs->list[i].len;
+               if (refs->list[i].width > w)
+                       w = refs->list[i].width;
        }
        return w;
 }
@@ -533,12 +558,12 @@ static void show_detached(struct ref_list *ref_list)
        if (head_commit && is_descendant_of(head_commit, ref_list->with_commit)) {
                struct ref_item item;
                item.name = xstrdup(_("(no branch)"));
-               item.len = strlen(item.name);
+               item.width = utf8_strwidth(item.name);
                item.kind = REF_LOCAL_BRANCH;
                item.dest = NULL;
                item.commit = head_commit;
-               if (item.len > ref_list->maxwidth)
-                       ref_list->maxwidth = item.len;
+               if (item.width > ref_list->maxwidth)
+                       ref_list->maxwidth = item.width;
                print_ref_item(&item, ref_list->maxwidth, ref_list->verbose, ref_list->abbrev, 1, "");
                free(item.name);
        }
@@ -712,62 +737,65 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
        int delete = 0, rename = 0, force_create = 0, list = 0;
        int verbose = 0, abbrev = -1, detached = 0;
        int reflog = 0, edit_description = 0;
-       int quiet = 0;
+       int quiet = 0, unset_upstream = 0;
+       const char *new_upstream = NULL;
        enum branch_track track;
        int kinds = REF_LOCAL_BRANCH;
        struct commit_list *with_commit = NULL;
 
        struct option options[] = {
-               OPT_GROUP("Generic options"),
+               OPT_GROUP(N_("Generic options")),
                OPT__VERBOSE(&verbose,
-                       "show hash and subject, give twice for upstream branch"),
-               OPT__QUIET(&quiet, "suppress informational messages"),
-               OPT_SET_INT('t', "track",  &track, "set up tracking mode (see git-pull(1))",
+                       N_("show hash and subject, give twice for upstream branch")),
+               OPT__QUIET(&quiet, N_("suppress informational messages")),
+               OPT_SET_INT('t', "track",  &track, N_("set up tracking mode (see git-pull(1))"),
                        BRANCH_TRACK_EXPLICIT),
-               OPT_SET_INT( 0, "set-upstream",  &track, "change upstream info",
+               OPT_SET_INT( 0, "set-upstream",  &track, N_("change upstream info"),
                        BRANCH_TRACK_OVERRIDE),
-               OPT__COLOR(&branch_use_color, "use colored output"),
-               OPT_SET_INT('r', "remotes",     &kinds, "act on remote-tracking branches",
+               OPT_STRING('u', "set-upstream-to", &new_upstream, "upstream", "change the upstream info"),
+               OPT_BOOLEAN(0, "unset-upstream", &unset_upstream, "Unset the upstream info"),
+               OPT__COLOR(&branch_use_color, N_("use colored output")),
+               OPT_SET_INT('r', "remotes",     &kinds, N_("act on remote-tracking branches"),
                        REF_REMOTE_BRANCH),
                {
-                       OPTION_CALLBACK, 0, "contains", &with_commit, "commit",
-                       "print only branches that contain the commit",
+                       OPTION_CALLBACK, 0, "contains", &with_commit, N_("commit"),
+                       N_("print only branches that contain the commit"),
                        PARSE_OPT_LASTARG_DEFAULT,
                        parse_opt_with_commit, (intptr_t)"HEAD",
                },
                {
-                       OPTION_CALLBACK, 0, "with", &with_commit, "commit",
-                       "print only branches that contain the commit",
+                       OPTION_CALLBACK, 0, "with", &with_commit, N_("commit"),
+                       N_("print only branches that contain the commit"),
                        PARSE_OPT_HIDDEN | PARSE_OPT_LASTARG_DEFAULT,
                        parse_opt_with_commit, (intptr_t) "HEAD",
                },
                OPT__ABBREV(&abbrev),
 
-               OPT_GROUP("Specific git-branch actions:"),
-               OPT_SET_INT('a', "all", &kinds, "list both remote-tracking and local branches",
+               OPT_GROUP(N_("Specific git-branch actions:")),
+               OPT_SET_INT('a', "all", &kinds, N_("list both remote-tracking and local branches"),
                        REF_REMOTE_BRANCH | REF_LOCAL_BRANCH),
-               OPT_BIT('d', "delete", &delete, "delete fully merged branch", 1),
-               OPT_BIT('D', NULL, &delete, "delete branch (even if not merged)", 2),
-               OPT_BIT('m', "move", &rename, "move/rename a branch and its reflog", 1),
-               OPT_BIT('M', NULL, &rename, "move/rename a branch, even if target exists", 2),
-               OPT_BOOLEAN(0, "list", &list, "list branch names"),
-               OPT_BOOLEAN('l', "create-reflog", &reflog, "create the branch's reflog"),
+               OPT_BIT('d', "delete", &delete, N_("delete fully merged branch"), 1),
+               OPT_BIT('D', NULL, &delete, N_("delete branch (even if not merged)"), 2),
+               OPT_BIT('m', "move", &rename, N_("move/rename a branch and its reflog"), 1),
+               OPT_BIT('M', NULL, &rename, N_("move/rename a branch, even if target exists"), 2),
+               OPT_BOOLEAN(0, "list", &list, N_("list branch names")),
+               OPT_BOOLEAN('l', "create-reflog", &reflog, N_("create the branch's reflog")),
                OPT_BOOLEAN(0, "edit-description", &edit_description,
-                           "edit the description for the branch"),
-               OPT__FORCE(&force_create, "force creation (when already exists)"),
+                           N_("edit the description for the branch")),
+               OPT__FORCE(&force_create, N_("force creation (when already exists)")),
                {
                        OPTION_CALLBACK, 0, "no-merged", &merge_filter_ref,
-                       "commit", "print only not merged branches",
+                       N_("commit"), N_("print only not merged branches"),
                        PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NONEG,
                        opt_parse_merge_filter, (intptr_t) "HEAD",
                },
                {
                        OPTION_CALLBACK, 0, "merged", &merge_filter_ref,
-                       "commit", "print only merged branches",
+                       N_("commit"), N_("print only merged branches"),
                        PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NONEG,
                        opt_parse_merge_filter, (intptr_t) "HEAD",
                },
-               OPT_COLUMN(0, "column", &colopts, "list branches in columns"),
+               OPT_COLUMN(0, "column", &colopts, N_("list branches in columns")),
                OPT_END(),
        };
 
@@ -794,10 +822,10 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
        argc = parse_options(argc, argv, prefix, options, builtin_branch_usage,
                             0);
 
-       if (!delete && !rename && !edit_description && argc == 0)
+       if (!delete && !rename && !edit_description && !new_upstream && !unset_upstream && argc == 0)
                list = 1;
 
-       if (!!delete + !!rename + !!force_create + !!list > 1)
+       if (!!delete + !!rename + !!force_create + !!list + !!new_upstream + !!unset_upstream > 1)
                usage_with_options(builtin_branch_usage, options);
 
        if (abbrev == -1)
@@ -852,11 +880,62 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
                        rename_branch(argv[0], argv[1], rename > 1);
                else
                        usage_with_options(builtin_branch_usage, options);
+       } else if (new_upstream) {
+               struct branch *branch = branch_get(argv[0]);
+
+               if (!ref_exists(branch->refname))
+                       die(_("branch '%s' does not exist"), branch->name);
+
+               /*
+                * create_branch takes care of setting up the tracking
+                * info and making sure new_upstream is correct
+                */
+               create_branch(head, branch->name, new_upstream, 0, 0, 0, quiet, BRANCH_TRACK_OVERRIDE);
+       } else if (unset_upstream) {
+               struct branch *branch = branch_get(argv[0]);
+               struct strbuf buf = STRBUF_INIT;
+
+               if (!branch_has_merge_config(branch)) {
+                       die(_("Branch '%s' has no upstream information"), branch->name);
+               }
+
+               strbuf_addf(&buf, "branch.%s.remote", branch->name);
+               git_config_set_multivar(buf.buf, NULL, NULL, 1);
+               strbuf_reset(&buf);
+               strbuf_addf(&buf, "branch.%s.merge", branch->name);
+               git_config_set_multivar(buf.buf, NULL, NULL, 1);
+               strbuf_release(&buf);
        } else if (argc > 0 && argc <= 2) {
+               struct branch *branch = branch_get(argv[0]);
+               int branch_existed = 0, remote_tracking = 0;
+               struct strbuf buf = STRBUF_INIT;
+
                if (kinds != REF_LOCAL_BRANCH)
                        die(_("-a and -r options to 'git branch' do not make sense with a branch name"));
+
+               if (track == BRANCH_TRACK_OVERRIDE)
+                       fprintf(stderr, _("The --set-upstream flag is deprecated and will be removed. Consider using --track or --set-upstream-to\n"));
+
+               strbuf_addf(&buf, "refs/remotes/%s", branch->name);
+               remote_tracking = ref_exists(buf.buf);
+               strbuf_release(&buf);
+
+               branch_existed = ref_exists(branch->refname);
                create_branch(head, argv[0], (argc == 2) ? argv[1] : head,
                              force_create, reflog, 0, quiet, track);
+
+               /*
+                * We only show the instructions if the user gave us
+                * one branch which doesn't exist locally, but is the
+                * name of a remote-tracking branch.
+                */
+               if (argc == 1 && track == BRANCH_TRACK_OVERRIDE &&
+                   !branch_existed && remote_tracking) {
+                       fprintf(stderr, _("\nIf you wanted to make '%s' track '%s', do this:\n\n"), head, branch->name);
+                       fprintf(stderr, _("    git branch -d %s\n"), branch->name);
+                       fprintf(stderr, _("    git branch --set-upstream-to %s\n"), branch->name);
+               }
+
        } else
                usage_with_options(builtin_branch_usage, options);
 
index 60568f9c39955e72e454c7d22b143d3e72a1a9a5..00528ddc389212f045a7718ba55a26d723927f06 100644 (file)
@@ -91,7 +91,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
        unsigned long size;
        struct object_context obj_context;
 
-       if (get_sha1_with_context(obj_name, sha1, &obj_context))
+       if (get_sha1_with_context(obj_name, 0, sha1, &obj_context))
                die("Not a valid object name %s", obj_name);
 
        buf = NULL;
@@ -244,8 +244,8 @@ static int batch_objects(int print_contents)
 }
 
 static const char * const cat_file_usage[] = {
-       "git cat-file (-t|-s|-e|-p|<type>|--textconv) <object>",
-       "git cat-file (--batch|--batch-check) < <list_of_objects>",
+       N_("git cat-file (-t|-s|-e|-p|<type>|--textconv) <object>"),
+       N_("git cat-file (--batch|--batch-check) < <list_of_objects>"),
        NULL
 };
 
@@ -263,19 +263,19 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
        const char *exp_type = NULL, *obj_name = NULL;
 
        const struct option options[] = {
-               OPT_GROUP("<type> can be one of: blob, tree, commit, tag"),
-               OPT_SET_INT('t', NULL, &opt, "show object type", 't'),
-               OPT_SET_INT('s', NULL, &opt, "show object size", 's'),
+               OPT_GROUP(N_("<type> can be one of: blob, tree, commit, tag")),
+               OPT_SET_INT('t', NULL, &opt, N_("show object type"), 't'),
+               OPT_SET_INT('s', NULL, &opt, N_("show object size"), 's'),
                OPT_SET_INT('e', NULL, &opt,
-                           "exit with zero when there's no error", 'e'),
-               OPT_SET_INT('p', NULL, &opt, "pretty-print object's content", 'p'),
+                           N_("exit with zero when there's no error"), 'e'),
+               OPT_SET_INT('p', NULL, &opt, N_("pretty-print object's content"), 'p'),
                OPT_SET_INT(0, "textconv", &opt,
-                           "for blob objects, run textconv on object's content", 'c'),
+                           N_("for blob objects, run textconv on object's content"), 'c'),
                OPT_SET_INT(0, "batch", &batch,
-                           "show info and content of objects fed from the standard input",
+                           N_("show info and content of objects fed from the standard input"),
                            BATCH),
                OPT_SET_INT(0, "batch-check", &batch,
-                           "show info about objects fed from the standard input",
+                           N_("show info about objects fed from the standard input"),
                            BATCH_CHECK),
                OPT_END()
        };
index 44c421eb0fe9cd8947d6666d15d790bc241ee7f3..075d01d30c58d40abb48ff820ba6f8d310f785d0 100644 (file)
@@ -8,19 +8,19 @@ static int all_attrs;
 static int cached_attrs;
 static int stdin_paths;
 static const char * const check_attr_usage[] = {
-"git check-attr [-a | --all | attr...] [--] pathname...",
-"git check-attr --stdin [-a | --all | attr...] < <list-of-paths>",
+N_("git check-attr [-a | --all | attr...] [--] pathname..."),
+N_("git check-attr --stdin [-z] [-a | --all | attr...] < <list-of-paths>"),
 NULL
 };
 
 static int null_term_line;
 
 static const struct option check_attr_options[] = {
-       OPT_BOOLEAN('a', "all", &all_attrs, "report all attributes set on file"),
-       OPT_BOOLEAN(0,  "cached", &cached_attrs, "use .gitattributes only from the index"),
-       OPT_BOOLEAN(0 , "stdin", &stdin_paths, "read file names from stdin"),
+       OPT_BOOLEAN('a', "all", &all_attrs, N_("report all attributes set on file")),
+       OPT_BOOLEAN(0,  "cached", &cached_attrs, N_("use .gitattributes only from the index")),
+       OPT_BOOLEAN(0 , "stdin", &stdin_paths, N_("read file names from stdin")),
        OPT_BOOLEAN('z', NULL, &null_term_line,
-               "input paths are terminated by a null character"),
+               N_("input paths are terminated by a null character")),
        OPT_END()
 };
 
index c16d82b7de652026b70fc3d949ddc849f749eee8..b1feda7d5ef34f45ed2de018a56149212b51ec0a 100644 (file)
@@ -123,7 +123,7 @@ static void checkout_all(const char *prefix, int prefix_length)
 }
 
 static const char * const builtin_checkout_index_usage[] = {
-       "git checkout-index [options] [--] [<file>...]",
+       N_("git checkout-index [options] [--] [<file>...]"),
        NULL
 };
 
@@ -184,27 +184,27 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
        int force = 0, quiet = 0, not_new = 0;
        struct option builtin_checkout_index_options[] = {
                OPT_BOOLEAN('a', "all", &all,
-                       "checks out all files in the index"),
-               OPT__FORCE(&force, "forces overwrite of existing files"),
+                       N_("check out all files in the index")),
+               OPT__FORCE(&force, N_("force overwrite of existing files")),
                OPT__QUIET(&quiet,
-                       "no warning for existing files and files not in index"),
+                       N_("no warning for existing files and files not in index")),
                OPT_BOOLEAN('n', "no-create", &not_new,
-                       "don't checkout new files"),
+                       N_("don't checkout new files")),
                { OPTION_CALLBACK, 'u', "index", &newfd, NULL,
-                       "update stat information in the index file",
+                       N_("update stat information in the index file"),
                        PARSE_OPT_NOARG, option_parse_u },
                { OPTION_CALLBACK, 'z', NULL, NULL, NULL,
-                       "paths are separated with NUL character",
+                       N_("paths are separated with NUL character"),
                        PARSE_OPT_NOARG, option_parse_z },
                OPT_BOOLEAN(0, "stdin", &read_from_stdin,
-                       "read list of paths from the standard input"),
+                       N_("read list of paths from the standard input")),
                OPT_BOOLEAN(0, "temp", &to_tempfile,
-                       "write the content to temporary files"),
-               OPT_CALLBACK(0, "prefix", NULL, "string",
-                       "when creating files, prepend <string>",
+                       N_("write the content to temporary files")),
+               OPT_CALLBACK(0, "prefix", NULL, N_("string"),
+                       N_("when creating files, prepend <string>"),
                        option_parse_prefix),
                OPT_CALLBACK(0, "stage", NULL, NULL,
-                       "copy out the files from named stage",
+                       N_("copy out the files from named stage"),
                        option_parse_stage),
                OPT_END()
        };
index 45aa0a87019c4f51802ea896edead95379eab5fb..781295b2c9abf033481bc135ca1d2330ca489937 100644 (file)
 #include "argv-array.h"
 
 static const char * const checkout_usage[] = {
-       "git checkout [options] <branch>",
-       "git checkout [options] [<branch>] -- <file>...",
+       N_("git checkout [options] <branch>"),
+       N_("git checkout [options] [<branch>] -- <file>..."),
        NULL,
 };
 
 struct checkout_opts {
+       int patch_mode;
        int quiet;
        int merge;
        int force;
        int force_detach;
        int writeout_stage;
-       int writeout_error;
        int overwrite_ignore;
 
-       /* not set by parse_options */
-       int branch_exists;
-
        const char *new_branch;
        const char *new_branch_force;
        const char *new_orphan_branch;
        int new_branch_log;
        enum branch_track track;
        struct diff_options diff_options;
+
+       int branch_exists;
+       const char *prefix;
+       const char **pathspec;
+       struct tree *source_tree;
 };
 
 static int post_checkout_hook(struct commit *old, struct commit *new,
@@ -73,7 +75,8 @@ static int update_some(const unsigned char *sha1, const char *base, int baselen,
        hashcpy(ce->sha1, sha1);
        memcpy(ce->name, base, baselen);
        memcpy(ce->name + baselen, pathname, len - baselen);
-       ce->ce_flags = create_ce_flags(len, 0) | CE_UPDATE;
+       ce->ce_flags = create_ce_flags(0) | CE_UPDATE;
+       ce->ce_namelen = len;
        ce->ce_mode = create_ce_mode(mode);
        add_cache_entry(ce, ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
        return 0;
@@ -214,8 +217,8 @@ static int checkout_merged(int pos, struct checkout *state)
        return status;
 }
 
-static int checkout_paths(struct tree *source_tree, const char **pathspec,
-                         const char *prefix, struct checkout_opts *opts)
+static int checkout_paths(const struct checkout_opts *opts,
+                         const char *revision)
 {
        int pos;
        struct checkout state;
@@ -227,37 +230,65 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec,
        int stage = opts->writeout_stage;
        int merge = opts->merge;
        int newfd;
-       struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
+       struct lock_file *lock_file;
+
+       if (opts->track != BRANCH_TRACK_UNSPECIFIED)
+               die(_("'%s' cannot be used with updating paths"), "--track");
+
+       if (opts->new_branch_log)
+               die(_("'%s' cannot be used with updating paths"), "-l");
+
+       if (opts->force && opts->patch_mode)
+               die(_("'%s' cannot be used with updating paths"), "-f");
+
+       if (opts->force_detach)
+               die(_("'%s' cannot be used with updating paths"), "--detach");
+
+       if (opts->merge && opts->patch_mode)
+               die(_("'%s' cannot be used with %s"), "--merge", "--patch");
+
+       if (opts->force && opts->merge)
+               die(_("'%s' cannot be used with %s"), "-f", "-m");
+
+       if (opts->new_branch)
+               die(_("Cannot update paths and switch to branch '%s' at the same time."),
+                   opts->new_branch);
+
+       if (opts->patch_mode)
+               return run_add_interactive(revision, "--patch=checkout",
+                                          opts->pathspec);
+
+       lock_file = xcalloc(1, sizeof(struct lock_file));
 
        newfd = hold_locked_index(lock_file, 1);
-       if (read_cache_preload(pathspec) < 0)
+       if (read_cache_preload(opts->pathspec) < 0)
                return error(_("corrupt index file"));
 
-       if (source_tree)
-               read_tree_some(source_tree, pathspec);
+       if (opts->source_tree)
+               read_tree_some(opts->source_tree, opts->pathspec);
 
-       for (pos = 0; pathspec[pos]; pos++)
+       for (pos = 0; opts->pathspec[pos]; pos++)
                ;
        ps_matched = xcalloc(1, pos);
 
        for (pos = 0; pos < active_nr; pos++) {
                struct cache_entry *ce = active_cache[pos];
-               if (source_tree && !(ce->ce_flags & CE_UPDATE))
+               if (opts->source_tree && !(ce->ce_flags & CE_UPDATE))
                        continue;
-               match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, ps_matched);
+               match_pathspec(opts->pathspec, ce->name, ce_namelen(ce), 0, ps_matched);
        }
 
-       if (report_path_error(ps_matched, pathspec, prefix))
+       if (report_path_error(ps_matched, opts->pathspec, opts->prefix))
                return 1;
 
        /* "checkout -m path" to recreate conflicted state */
        if (opts->merge)
-               unmerge_cache(pathspec);
+               unmerge_cache(opts->pathspec);
 
        /* Any unmerged paths? */
        for (pos = 0; pos < active_nr; pos++) {
                struct cache_entry *ce = active_cache[pos];
-               if (match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, NULL)) {
+               if (match_pathspec(opts->pathspec, ce->name, ce_namelen(ce), 0, NULL)) {
                        if (!ce_stage(ce))
                                continue;
                        if (opts->force) {
@@ -282,9 +313,9 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec,
        state.refresh_cache = 1;
        for (pos = 0; pos < active_nr; pos++) {
                struct cache_entry *ce = active_cache[pos];
-               if (source_tree && !(ce->ce_flags & CE_UPDATE))
+               if (opts->source_tree && !(ce->ce_flags & CE_UPDATE))
                        continue;
-               if (match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, NULL)) {
+               if (match_pathspec(opts->pathspec, ce->name, ce_namelen(ce), 0, NULL)) {
                        if (!ce_stage(ce)) {
                                errs |= checkout_entry(ce, &state, NULL);
                                continue;
@@ -308,7 +339,8 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec,
        return errs;
 }
 
-static void show_local_changes(struct object *head, struct diff_options *opts)
+static void show_local_changes(struct object *head,
+                              const struct diff_options *opts)
 {
        struct rev_info rev;
        /* I think we want full paths, even if we're in a subdirectory. */
@@ -330,7 +362,8 @@ static void describe_detached_head(const char *msg, struct commit *commit)
        strbuf_release(&sb);
 }
 
-static int reset_tree(struct tree *tree, struct checkout_opts *o, int worktree)
+static int reset_tree(struct tree *tree, const struct checkout_opts *o,
+                     int worktree, int *writeout_error)
 {
        struct unpack_trees_options opts;
        struct tree_desc tree_desc;
@@ -349,7 +382,7 @@ static int reset_tree(struct tree *tree, struct checkout_opts *o, int worktree)
        init_tree_desc(&tree_desc, tree->buffer, tree->size);
        switch (unpack_trees(1, &tree_desc, &opts)) {
        case -2:
-               o->writeout_error = 1;
+               *writeout_error = 1;
                /*
                 * We return 0 nevertheless, as the index is all right
                 * and more importantly we have made best efforts to
@@ -380,8 +413,10 @@ static void setup_branch_path(struct branch_info *branch)
        branch->path = strbuf_detach(&buf, NULL);
 }
 
-static int merge_working_tree(struct checkout_opts *opts,
-                             struct branch_info *old, struct branch_info *new)
+static int merge_working_tree(const struct checkout_opts *opts,
+                             struct branch_info *old,
+                             struct branch_info *new,
+                             int *writeout_error)
 {
        int ret;
        struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
@@ -392,7 +427,7 @@ static int merge_working_tree(struct checkout_opts *opts,
 
        resolve_undo_clear();
        if (opts->force) {
-               ret = reset_tree(new->commit->tree, opts, 1);
+               ret = reset_tree(new->commit->tree, opts, 1, writeout_error);
                if (ret)
                        return ret;
        } else {
@@ -478,7 +513,8 @@ static int merge_working_tree(struct checkout_opts *opts,
                        o.verbosity = 0;
                        work = write_tree_from_memory(&o);
 
-                       ret = reset_tree(new->commit->tree, opts, 1);
+                       ret = reset_tree(new->commit->tree, opts, 1,
+                                        writeout_error);
                        if (ret)
                                return ret;
                        o.ancestor = old->name;
@@ -486,7 +522,8 @@ static int merge_working_tree(struct checkout_opts *opts,
                        o.branch2 = "local";
                        merge_trees(&o, new->commit->tree, work,
                                old->commit->tree, &result);
-                       ret = reset_tree(new->commit->tree, opts, 0);
+                       ret = reset_tree(new->commit->tree, opts, 0,
+                                        writeout_error);
                        if (ret)
                                return ret;
                }
@@ -513,7 +550,7 @@ static void report_tracking(struct branch_info *new)
        strbuf_release(&sb);
 }
 
-static void update_refs_for_switch(struct checkout_opts *opts,
+static void update_refs_for_switch(const struct checkout_opts *opts,
                                   struct branch_info *old,
                                   struct branch_info *new)
 {
@@ -700,13 +737,14 @@ static void orphaned_commit_warning(struct commit *old, struct commit *new)
        free(refs.objects);
 }
 
-static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
+static int switch_branches(const struct checkout_opts *opts,
+                          struct branch_info *new)
 {
        int ret = 0;
        struct branch_info old;
        void *path_to_free;
        unsigned char rev[20];
-       int flag;
+       int flag, writeout_error = 0;
        memset(&old, 0, sizeof(old));
        old.path = path_to_free = resolve_refdup("HEAD", rev, 0, &flag);
        old.commit = lookup_commit_reference_gently(rev, 1);
@@ -724,7 +762,7 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
                parse_commit(new->commit);
        }
 
-       ret = merge_working_tree(opts, &old, new);
+       ret = merge_working_tree(opts, &old, new, &writeout_error);
        if (ret) {
                free(path_to_free);
                return ret;
@@ -737,7 +775,7 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
 
        ret = post_checkout_hook(old.commit, new->commit, 1);
        free(path_to_free);
-       return ret || opts->writeout_error;
+       return ret || writeout_error;
 }
 
 static int git_checkout_config(const char *var, const char *value, void *cb)
@@ -754,12 +792,6 @@ static int git_checkout_config(const char *var, const char *value, void *cb)
        return git_xmerge_config(var, value, NULL);
 }
 
-static int interactive_checkout(const char *revision, const char **pathspec,
-                               struct checkout_opts *opts)
-{
-       return run_add_interactive(revision, "--patch=checkout", pathspec);
-}
-
 struct tracking_name_data {
        const char *name;
        char *remote;
@@ -909,7 +941,7 @@ static int parse_branchname_arg(int argc, const char **argv,
        return argcount;
 }
 
-static int switch_unborn_to_new_branch(struct checkout_opts *opts)
+static int switch_unborn_to_new_branch(const struct checkout_opts *opts)
 {
        int status;
        struct strbuf branch_ref = STRBUF_INIT;
@@ -922,38 +954,80 @@ static int switch_unborn_to_new_branch(struct checkout_opts *opts)
        return status;
 }
 
+static int checkout_branch(struct checkout_opts *opts,
+                          struct branch_info *new)
+{
+       if (opts->pathspec)
+               die(_("paths cannot be used with switching branches"));
+
+       if (opts->patch_mode)
+               die(_("'%s' cannot be used with switching branches"),
+                   "--patch");
+
+       if (opts->writeout_stage)
+               die(_("'%s' cannot be used with switching branches"),
+                   "--ours/--theirs");
+
+       if (opts->force && opts->merge)
+               die(_("'%s' cannot be used with '%s'"), "-f", "-m");
+
+       if (opts->force_detach && opts->new_branch)
+               die(_("'%s' cannot be used with '%s'"),
+                   "--detach", "-b/-B/--orphan");
+
+       if (opts->new_orphan_branch) {
+               if (opts->track != BRANCH_TRACK_UNSPECIFIED)
+                       die(_("'%s' cannot be used with '%s'"), "--orphan", "-t");
+       } else if (opts->force_detach) {
+               if (opts->track != BRANCH_TRACK_UNSPECIFIED)
+                       die(_("'%s' cannot be used with '%s'"), "--detach", "-t");
+       } else if (opts->track == BRANCH_TRACK_UNSPECIFIED)
+               opts->track = git_branch_track;
+
+       if (new->name && !new->commit)
+               die(_("Cannot switch branch to a non-commit '%s'"),
+                   new->name);
+
+       if (!new->commit && opts->new_branch) {
+               unsigned char rev[20];
+               int flag;
+
+               if (!read_ref_full("HEAD", rev, 0, &flag) &&
+                   (flag & REF_ISSYMREF) && is_null_sha1(rev))
+                       return switch_unborn_to_new_branch(opts);
+       }
+       return switch_branches(opts, new);
+}
+
 int cmd_checkout(int argc, const char **argv, const char *prefix)
 {
        struct checkout_opts opts;
-       unsigned char rev[20];
        struct branch_info new;
-       struct tree *source_tree = NULL;
        char *conflict_style = NULL;
-       int patch_mode = 0;
        int dwim_new_local_branch = 1;
        struct option options[] = {
-               OPT__QUIET(&opts.quiet, "suppress progress reporting"),
-               OPT_STRING('b', NULL, &opts.new_branch, "branch",
-                          "create and checkout a new branch"),
-               OPT_STRING('B', NULL, &opts.new_branch_force, "branch",
-                          "create/reset and checkout a branch"),
-               OPT_BOOLEAN('l', NULL, &opts.new_branch_log, "create reflog for new branch"),
-               OPT_BOOLEAN(0, "detach", &opts.force_detach, "detach the HEAD at named commit"),
-               OPT_SET_INT('t', "track",  &opts.track, "set upstream info for new branch",
+               OPT__QUIET(&opts.quiet, N_("suppress progress reporting")),
+               OPT_STRING('b', NULL, &opts.new_branch, N_("branch"),
+                          N_("create and checkout a new branch")),
+               OPT_STRING('B', NULL, &opts.new_branch_force, N_("branch"),
+                          N_("create/reset and checkout a branch")),
+               OPT_BOOLEAN('l', NULL, &opts.new_branch_log, N_("create reflog for new branch")),
+               OPT_BOOLEAN(0, "detach", &opts.force_detach, N_("detach the HEAD at named commit")),
+               OPT_SET_INT('t', "track",  &opts.track, N_("set upstream info for new branch"),
                        BRANCH_TRACK_EXPLICIT),
-               OPT_STRING(0, "orphan", &opts.new_orphan_branch, "new branch", "new unparented branch"),
-               OPT_SET_INT('2', "ours", &opts.writeout_stage, "checkout our version for unmerged files",
+               OPT_STRING(0, "orphan", &opts.new_orphan_branch, N_("new branch"), N_("new unparented branch")),
+               OPT_SET_INT('2', "ours", &opts.writeout_stage, N_("checkout our version for unmerged files"),
                            2),
-               OPT_SET_INT('3', "theirs", &opts.writeout_stage, "checkout their version for unmerged files",
+               OPT_SET_INT('3', "theirs", &opts.writeout_stage, N_("checkout their version for unmerged files"),
                            3),
-               OPT__FORCE(&opts.force, "force checkout (throw away local modifications)"),
-               OPT_BOOLEAN('m', "merge", &opts.merge, "perform a 3-way merge with the new branch"),
-               OPT_BOOLEAN(0, "overwrite-ignore", &opts.overwrite_ignore, "update ignored files (default)"),
-               OPT_STRING(0, "conflict", &conflict_style, "style",
-                          "conflict style (merge or diff3)"),
-               OPT_BOOLEAN('p', "patch", &patch_mode, "select hunks interactively"),
+               OPT__FORCE(&opts.force, N_("force checkout (throw away local modifications)")),
+               OPT_BOOLEAN('m', "merge", &opts.merge, N_("perform a 3-way merge with the new branch")),
+               OPT_BOOLEAN(0, "overwrite-ignore", &opts.overwrite_ignore, N_("update ignored files (default)")),
+               OPT_STRING(0, "conflict", &conflict_style, N_("style"),
+                          N_("conflict style (merge or diff3)")),
+               OPT_BOOLEAN('p', "patch", &opts.patch_mode, N_("select hunks interactively")),
                { OPTION_BOOLEAN, 0, "guess", &dwim_new_local_branch, NULL,
-                 "second guess 'git checkout no-such-branch'",
+                 N_("second guess 'git checkout no-such-branch'"),
                  PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
                OPT_END(),
        };
@@ -961,6 +1035,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
        memset(&opts, 0, sizeof(opts));
        memset(&new, 0, sizeof(new));
        opts.overwrite_ignore = 1;
+       opts.prefix = prefix;
 
        gitmodules_config();
        git_config(git_checkout_config, &opts);
@@ -970,26 +1045,27 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
        argc = parse_options(argc, argv, prefix, options, checkout_usage,
                             PARSE_OPT_KEEP_DASHDASH);
 
-       /* we can assume from now on new_branch = !new_branch_force */
-       if (opts.new_branch && opts.new_branch_force)
-               die(_("-B cannot be used with -b"));
+       if (conflict_style) {
+               opts.merge = 1; /* implied */
+               git_xmerge_config("merge.conflictstyle", conflict_style, NULL);
+       }
+
+       if ((!!opts.new_branch + !!opts.new_branch_force + !!opts.new_orphan_branch) > 1)
+               die(_("-b, -B and --orphan are mutually exclusive"));
 
-       /* copy -B over to -b, so that we can just check the latter */
+       /*
+        * From here on, new_branch will contain the branch to be checked out,
+        * and new_branch_force and new_orphan_branch will tell us which one of
+        * -b/-B/--orphan is being used.
+        */
        if (opts.new_branch_force)
                opts.new_branch = opts.new_branch_force;
 
-       if (patch_mode && (opts.track > 0 || opts.new_branch
-                          || opts.new_branch_log || opts.merge || opts.force
-                          || opts.force_detach))
-               die (_("--patch is incompatible with all other options"));
-
-       if (opts.force_detach && (opts.new_branch || opts.new_orphan_branch))
-               die(_("--detach cannot be used with -b/-B/--orphan"));
-       if (opts.force_detach && 0 < opts.track)
-               die(_("--detach cannot be used with -t"));
+       if (opts.new_orphan_branch)
+               opts.new_branch = opts.new_orphan_branch;
 
-       /* --track without -b should DWIM */
-       if (0 < opts.track && !opts.new_branch) {
+       /* --track without -b/-B/--orphan should DWIM */
+       if (opts.track != BRANCH_TRACK_UNSPECIFIED && !opts.new_branch) {
                const char *argv0 = argv[0];
                if (!argc || !strcmp(argv0, "--"))
                        die (_("--track needs a branch name"));
@@ -1003,22 +1079,6 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
                opts.new_branch = argv0 + 1;
        }
 
-       if (opts.new_orphan_branch) {
-               if (opts.new_branch)
-                       die(_("--orphan and -b|-B are mutually exclusive"));
-               if (opts.track > 0)
-                       die(_("--orphan cannot be used with -t"));
-               opts.new_branch = opts.new_orphan_branch;
-       }
-
-       if (conflict_style) {
-               opts.merge = 1; /* implied */
-               git_xmerge_config("merge.conflictstyle", conflict_style, NULL);
-       }
-
-       if (opts.force && opts.merge)
-               die(_("git checkout: -f and -m are incompatible"));
-
        /*
         * Extract branch name from command line arguments, so
         * all that is left is pathspecs.
@@ -1033,73 +1093,56 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
         * remote branches, erroring out for invalid or ambiguous cases.
         */
        if (argc) {
+               unsigned char rev[20];
                int dwim_ok =
-                       !patch_mode &&
+                       !opts.patch_mode &&
                        dwim_new_local_branch &&
                        opts.track == BRANCH_TRACK_UNSPECIFIED &&
                        !opts.new_branch;
                int n = parse_branchname_arg(argc, argv, dwim_ok,
-                               &new, &source_tree, rev, &opts.new_branch);
+                                            &new, &opts.source_tree,
+                                            rev, &opts.new_branch);
                argv += n;
                argc -= n;
        }
 
-       if (opts.track == BRANCH_TRACK_UNSPECIFIED)
-               opts.track = git_branch_track;
-
        if (argc) {
-               const char **pathspec = get_pathspec(prefix, argv);
+               opts.pathspec = get_pathspec(prefix, argv);
 
-               if (!pathspec)
+               if (!opts.pathspec)
                        die(_("invalid path specification"));
 
-               if (patch_mode)
-                       return interactive_checkout(new.name, pathspec, &opts);
-
-               /* Checkout paths */
-               if (opts.new_branch) {
-                       if (argc == 1) {
-                               die(_("git checkout: updating paths is incompatible with switching branches.\nDid you intend to checkout '%s' which can not be resolved as commit?"), argv[0]);
-                       } else {
-                               die(_("git checkout: updating paths is incompatible with switching branches."));
-                       }
-               }
+               /*
+                * Try to give more helpful suggestion.
+                * new_branch && argc > 1 will be caught later.
+                */
+               if (opts.new_branch && argc == 1)
+                       die(_("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?"),
+                           opts.new_branch, argv[0]);
 
                if (opts.force_detach)
-                       die(_("git checkout: --detach does not take a path argument"));
+                       die(_("git checkout: --detach does not take a path argument '%s'"),
+                           argv[0]);
 
                if (1 < !!opts.writeout_stage + !!opts.force + !!opts.merge)
-                       die(_("git checkout: --ours/--theirs, --force and --merge are incompatible when\nchecking out of the index."));
-
-               return checkout_paths(source_tree, pathspec, prefix, &opts);
+                       die(_("git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
+                             "checking out of the index."));
        }
 
-       if (patch_mode)
-               return interactive_checkout(new.name, NULL, &opts);
-
        if (opts.new_branch) {
                struct strbuf buf = STRBUF_INIT;
 
-               opts.branch_exists = validate_new_branchname(opts.new_branch, &buf,
-                                                            !!opts.new_branch_force,
-                                                            !!opts.new_branch_force);
+               opts.branch_exists =
+                       validate_new_branchname(opts.new_branch, &buf,
+                                               !!opts.new_branch_force,
+                                               !!opts.new_branch_force);
 
                strbuf_release(&buf);
        }
 
-       if (new.name && !new.commit) {
-               die(_("Cannot switch branch to a non-commit."));
-       }
-       if (opts.writeout_stage)
-               die(_("--ours/--theirs is incompatible with switching branches."));
-
-       if (!new.commit && opts.new_branch) {
-               unsigned char rev[20];
-               int flag;
-
-               if (!read_ref_full("HEAD", rev, 0, &flag) &&
-                   (flag & REF_ISSYMREF) && is_null_sha1(rev))
-                       return switch_unborn_to_new_branch(&opts);
-       }
-       return switch_branches(&opts, &new);
+       if (opts.patch_mode || opts.pathspec)
+               return checkout_paths(&opts, new.name);
+       else
+               return checkout_branch(&opts, &new);
 }
index 0c7b3d0f4c28c9e9c721c961e529196751271d11..69c1cda9061f248479377d2841a1ddf703ea59ba 100644 (file)
@@ -16,7 +16,7 @@
 static int force = -1; /* unset */
 
 static const char *const builtin_clean_usage[] = {
-       "git clean [-d] [-f] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>...",
+       N_("git clean [-d] [-f] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>..."),
        NULL
 };
 
@@ -48,16 +48,16 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
        const char *qname;
        char *seen = NULL;
        struct option options[] = {
-               OPT__QUIET(&quiet, "do not print names of files removed"),
-               OPT__DRY_RUN(&show_only, "dry run"),
-               OPT__FORCE(&force, "force"),
+               OPT__QUIET(&quiet, N_("do not print names of files removed")),
+               OPT__DRY_RUN(&show_only, N_("dry run")),
+               OPT__FORCE(&force, N_("force")),
                OPT_BOOLEAN('d', NULL, &remove_directories,
-                               "remove whole directories"),
-               { OPTION_CALLBACK, 'e', "exclude", &exclude_list, "pattern",
-                 "add <pattern> to ignore rules", PARSE_OPT_NONEG, exclude_cb },
-               OPT_BOOLEAN('x', NULL, &ignored, "remove ignored files, too"),
+                               N_("remove whole directories")),
+               { OPTION_CALLBACK, 'e', "exclude", &exclude_list, N_("pattern"),
+                 N_("add <pattern> to ignore rules"), PARSE_OPT_NONEG, exclude_cb },
+               OPT_BOOLEAN('x', NULL, &ignored, N_("remove ignored files, too")),
                OPT_BOOLEAN('X', NULL, &ignored_only,
-                               "remove only ignored files"),
+                               N_("remove only ignored files")),
                OPT_END()
        };
 
index 920ef7f8c9fff25f613b4261f215a0cb7dc83b61..ec2f75b4f3b9d9acfb8aa6b423f3b0fc7fbbafdf 100644 (file)
  *
  */
 static const char * const builtin_clone_usage[] = {
-       "git clone [options] [--] <repo> [<dir>]",
+       N_("git clone [options] [--] <repo> [<dir>]"),
        NULL
 };
 
 static int option_no_checkout, option_bare, option_mirror, option_single_branch = -1;
-static int option_local, option_no_hardlinks, option_shared, option_recursive;
+static int option_local = -1, option_no_hardlinks, option_shared, option_recursive;
 static char *option_template, *option_depth;
 static char *option_origin = NULL;
 static char *option_branch = NULL;
@@ -61,43 +61,43 @@ static int opt_parse_reference(const struct option *opt, const char *arg, int un
 static struct option builtin_clone_options[] = {
        OPT__VERBOSITY(&option_verbosity),
        OPT_BOOL(0, "progress", &option_progress,
-                "force progress reporting"),
+                N_("force progress reporting")),
        OPT_BOOLEAN('n', "no-checkout", &option_no_checkout,
-                   "don't create a checkout"),
-       OPT_BOOLEAN(0, "bare", &option_bare, "create a bare repository"),
+                   N_("don't create a checkout")),
+       OPT_BOOLEAN(0, "bare", &option_bare, N_("create a bare repository")),
        { OPTION_BOOLEAN, 0, "naked", &option_bare, NULL,
-               "create a bare repository",
+               N_("create a bare repository"),
                PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
        OPT_BOOLEAN(0, "mirror", &option_mirror,
-                   "create a mirror repository (implies bare)"),
-       OPT_BOOLEAN('l', "local", &option_local,
-                   "to clone from a local repository"),
+                   N_("create a mirror repository (implies bare)")),
+       OPT_BOOL('l', "local", &option_local,
+               N_("to clone from a local repository")),
        OPT_BOOLEAN(0, "no-hardlinks", &option_no_hardlinks,
-                   "don't use local hardlinks, always copy"),
+                   N_("don't use local hardlinks, always copy")),
        OPT_BOOLEAN('s', "shared", &option_shared,
-                   "setup as shared repository"),
+                   N_("setup as shared repository")),
        OPT_BOOLEAN(0, "recursive", &option_recursive,
-                   "initialize submodules in the clone"),
+                   N_("initialize submodules in the clone")),
        OPT_BOOLEAN(0, "recurse-submodules", &option_recursive,
-                   "initialize submodules in the clone"),
-       OPT_STRING(0, "template", &option_template, "template-directory",
-                  "directory from which templates will be used"),
-       OPT_CALLBACK(0 , "reference", &option_reference, "repo",
-                    "reference repository", &opt_parse_reference),
-       OPT_STRING('o', "origin", &option_origin, "name",
-                  "use <name> instead of 'origin' to track upstream"),
-       OPT_STRING('b', "branch", &option_branch, "branch",
-                  "checkout <branch> instead of the remote's HEAD"),
-       OPT_STRING('u', "upload-pack", &option_upload_pack, "path",
-                  "path to git-upload-pack on the remote"),
-       OPT_STRING(0, "depth", &option_depth, "depth",
-                   "create a shallow clone of that depth"),
+                   N_("initialize submodules in the clone")),
+       OPT_STRING(0, "template", &option_template, N_("template-directory"),
+                  N_("directory from which templates will be used")),
+       OPT_CALLBACK(0 , "reference", &option_reference, N_("repo"),
+                    N_("reference repository"), &opt_parse_reference),
+       OPT_STRING('o', "origin", &option_origin, N_("name"),
+                  N_("use <name> instead of 'origin' to track upstream")),
+       OPT_STRING('b', "branch", &option_branch, N_("branch"),
+                  N_("checkout <branch> instead of the remote's HEAD")),
+       OPT_STRING('u', "upload-pack", &option_upload_pack, N_("path"),
+                  N_("path to git-upload-pack on the remote")),
+       OPT_STRING(0, "depth", &option_depth, N_("depth"),
+                   N_("create a shallow clone of that depth")),
        OPT_BOOL(0, "single-branch", &option_single_branch,
-                   "clone only one branch, HEAD or --branch"),
-       OPT_STRING(0, "separate-git-dir", &real_git_dir, "gitdir",
-                  "separate git dir from working tree"),
-       OPT_STRING_LIST('c', "config", &option_config, "key=value",
-                       "set config inside the new repository"),
+                   N_("clone only one branch, HEAD or --branch")),
+       OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"),
+                  N_("separate git dir from working tree")),
+       OPT_STRING_LIST('c', "config", &option_config, N_("key=value"),
+                       N_("set config inside the new repository")),
        OPT_END()
 };
 
@@ -236,7 +236,7 @@ static int add_one_reference(struct string_list_item *item, void *cb_data)
        /* Beware: real_path() and mkpath() return static buffer */
        ref_git = xstrdup(real_path(item->string));
        if (is_directory(mkpath("%s/.git/objects", ref_git))) {
-               char *ref_git_git = xstrdup(mkpath("%s/.git", ref_git));
+               char *ref_git_git = mkpathdup("%s/.git", ref_git);
                free(ref_git);
                ref_git = ref_git_git;
        } else if (!is_directory(mkpath("%s/objects", ref_git)))
@@ -342,7 +342,7 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
                if (!option_no_hardlinks) {
                        if (!link(src->buf, dest->buf))
                                continue;
-                       if (option_local)
+                       if (option_local > 0)
                                die_errno(_("failed to create link '%s'"), dest->buf);
                        option_no_hardlinks = 1;
                }
@@ -610,6 +610,54 @@ static void write_config(struct string_list *config)
        }
 }
 
+static void write_refspec_config(const char* src_ref_prefix,
+               const struct ref* our_head_points_at,
+               const struct ref* remote_head_points_at, struct strbuf* branch_top)
+{
+       struct strbuf key = STRBUF_INIT;
+       struct strbuf value = STRBUF_INIT;
+
+       if (option_mirror || !option_bare) {
+               if (option_single_branch && !option_mirror) {
+                       if (option_branch) {
+                               if (strstr(our_head_points_at->name, "refs/tags/"))
+                                       strbuf_addf(&value, "+%s:%s", our_head_points_at->name,
+                                               our_head_points_at->name);
+                               else
+                                       strbuf_addf(&value, "+%s:%s%s", our_head_points_at->name,
+                                               branch_top->buf, option_branch);
+                       } else if (remote_head_points_at) {
+                               strbuf_addf(&value, "+%s:%s%s", remote_head_points_at->name,
+                                               branch_top->buf,
+                                               skip_prefix(remote_head_points_at->name, "refs/heads/"));
+                       }
+                       /*
+                        * otherwise, the next "git fetch" will
+                        * simply fetch from HEAD without updating
+                        * any remote tracking branch, which is what
+                        * we want.
+                        */
+               } else {
+                       strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top->buf);
+               }
+               /* Configure the remote */
+               if (value.len) {
+                       strbuf_addf(&key, "remote.%s.fetch", option_origin);
+                       git_config_set_multivar(key.buf, value.buf, "^$", 0);
+                       strbuf_reset(&key);
+
+                       if (option_mirror) {
+                               strbuf_addf(&key, "remote.%s.mirror", option_origin);
+                               git_config_set(key.buf, "true");
+                               strbuf_reset(&key);
+                       }
+               }
+       }
+
+       strbuf_release(&key);
+       strbuf_release(&value);
+}
+
 int cmd_clone(int argc, const char **argv, const char *prefix)
 {
        int is_bundle = 0, is_local;
@@ -671,7 +719,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
                die(_("repository '%s' does not exist"), repo_name);
        else
                repo = repo_name;
-       is_local = path && !is_bundle;
+       is_local = option_local != 0 && path && !is_bundle;
        if (is_local && option_depth)
                warning(_("--depth is ignored in local clones; use file:// instead."));
 
@@ -700,7 +748,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
                git_dir = xstrdup(dir);
        else {
                work_tree = dir;
-               git_dir = xstrdup(mkpath("%s/.git", dir));
+               git_dir = mkpathdup("%s/.git", dir);
        }
 
        if (!option_bare) {
@@ -755,20 +803,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
        }
 
        strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top.buf);
-
-       if (option_mirror || !option_bare) {
-               /* Configure the remote */
-               strbuf_addf(&key, "remote.%s.fetch", option_origin);
-               git_config_set_multivar(key.buf, value.buf, "^$", 0);
-               strbuf_reset(&key);
-
-               if (option_mirror) {
-                       strbuf_addf(&key, "remote.%s.mirror", option_origin);
-                       git_config_set(key.buf, "true");
-                       strbuf_reset(&key);
-               }
-       }
-
        strbuf_addf(&key, "remote.%s.url", option_origin);
        git_config_set(key.buf, repo);
        strbuf_reset(&key);
@@ -853,6 +887,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
                                              "refs/heads/master");
        }
 
+       write_refspec_config(src_ref_prefix, our_head_points_at,
+                       remote_head_points_at, &branch_top);
+
        if (is_local)
                clone_local(path, git_dir);
        else if (refs && complete_refs_before_fetch)
index 5ea798a7ca6a3a3969c7f911b07a01490f689f98..e125a55fc9de2b8f6d82fd5574f109b3d245934c 100644 (file)
@@ -6,7 +6,7 @@
 #include "column.h"
 
 static const char * const builtin_column_usage[] = {
-       "git column [options]",
+       N_("git column [options]"),
        NULL
 };
 static unsigned int colopts;
@@ -23,13 +23,13 @@ int cmd_column(int argc, const char **argv, const char *prefix)
        struct column_options copts;
        const char *command = NULL, *real_command = NULL;
        struct option options[] = {
-               OPT_STRING(0, "command", &real_command, "name", "lookup config vars"),
-               OPT_COLUMN(0, "mode", &colopts, "layout to use"),
-               OPT_INTEGER(0, "raw-mode", &colopts, "layout to use"),
-               OPT_INTEGER(0, "width", &copts.width, "Maximum width"),
-               OPT_STRING(0, "indent", &copts.indent, "string", "Padding space on left border"),
-               OPT_INTEGER(0, "nl", &copts.nl, "Padding space on right border"),
-               OPT_INTEGER(0, "padding", &copts.padding, "Padding space between columns"),
+               OPT_STRING(0, "command", &real_command, N_("name"), N_("lookup config vars")),
+               OPT_COLUMN(0, "mode", &colopts, N_("layout to use")),
+               OPT_INTEGER(0, "raw-mode", &colopts, N_("layout to use")),
+               OPT_INTEGER(0, "width", &copts.width, N_("Maximum width")),
+               OPT_STRING(0, "indent", &copts.indent, N_("string"), N_("Padding space on left border")),
+               OPT_INTEGER(0, "nl", &copts.nl, N_("Padding space on right border")),
+               OPT_INTEGER(0, "padding", &copts.padding, N_("Padding space between columns")),
                OPT_END()
        };
 
index a0df12ce16abda416fc9f33448bc895e74f4b0d1..eac901a0ee15f72eacffea32d1b327c7a336f19c 100644 (file)
@@ -54,7 +54,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
                        unsigned char sha1[20];
                        if (argc <= ++i)
                                usage(commit_tree_usage);
-                       if (get_sha1(argv[i], sha1))
+                       if (get_sha1_commit(argv[i], sha1))
                                die("Not a valid object name %s", argv[i]);
                        assert_sha1_type(sha1, OBJ_COMMIT);
                        new_parent(lookup_commit(sha1), &parents);
@@ -101,7 +101,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
                        continue;
                }
 
-               if (get_sha1(arg, tree_sha1))
+               if (get_sha1_tree(arg, tree_sha1))
                        die("Not a valid object name %s", arg);
                if (got_tree)
                        die("Cannot give more than one trees");
index 62028e7b44b206e9722eef750be8c067aae31b32..1dd2ec5e6f878c02e2858d72f08d8b88d67bcd85 100644 (file)
 #include "submodule.h"
 #include "gpg-interface.h"
 #include "column.h"
+#include "sequencer.h"
 
 static const char * const builtin_commit_usage[] = {
-       "git commit [options] [--] <filepattern>...",
+       N_("git commit [options] [--] <filepattern>..."),
        NULL
 };
 
 static const char * const builtin_status_usage[] = {
-       "git status [options] [--] <filepattern>...",
+       N_("git status [options] [--] <filepattern>..."),
        NULL
 };
 
@@ -111,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)
 {
@@ -453,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;
@@ -466,8 +469,6 @@ static int is_a_merge(const struct commit *current_head)
        return !!(current_head->parents && current_head->parents->next);
 }
 
-static const char sign_off_header[] = "Signed-off-by: ";
-
 static void export_one(const char *var, const char *s, const char *e, int hack)
 {
        struct strbuf buf = STRBUF_INIT;
@@ -552,47 +553,6 @@ static void determine_author_info(struct strbuf *author_ident)
        }
 }
 
-static int ends_rfc2822_footer(struct strbuf *sb)
-{
-       int ch;
-       int hit = 0;
-       int i, j, k;
-       int len = sb->len;
-       int first = 1;
-       const char *buf = sb->buf;
-
-       for (i = len - 1; i > 0; i--) {
-               if (hit && buf[i] == '\n')
-                       break;
-               hit = (buf[i] == '\n');
-       }
-
-       while (i < len - 1 && buf[i] == '\n')
-               i++;
-
-       for (; i < len; i = k) {
-               for (k = i; k < len && buf[k] != '\n'; k++)
-                       ; /* do nothing */
-               k++;
-
-               if ((buf[k] == ' ' || buf[k] == '\t') && !first)
-                       continue;
-
-               first = 0;
-
-               for (j = 0; i + j < len; j++) {
-                       ch = buf[i + j];
-                       if (ch == ':')
-                               break;
-                       if (isalnum(ch) ||
-                           (ch == '-'))
-                               continue;
-                       return 0;
-               }
-       }
-       return 1;
-}
-
 static char *cut_ident_timestamp_part(char *string)
 {
        char *ket = strrchr(string, '>');
@@ -717,21 +677,30 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
                stripspace(&sb, 0);
 
        if (signoff) {
-               struct strbuf sob = STRBUF_INIT;
-               int i;
-
-               strbuf_addstr(&sob, sign_off_header);
-               strbuf_addstr(&sob, fmt_name(getenv("GIT_COMMITTER_NAME"),
-                                            getenv("GIT_COMMITTER_EMAIL")));
-               strbuf_addch(&sob, '\n');
-               for (i = sb.len - 1; i > 0 && sb.buf[i - 1] != '\n'; i--)
-                       ; /* do nothing */
-               if (prefixcmp(sb.buf + i, sob.buf)) {
-                       if (!i || !ends_rfc2822_footer(&sb))
-                               strbuf_addch(&sb, '\n');
-                       strbuf_addbuf(&sb, &sob);
+               /*
+                * See if we have a Conflicts: block at the end. If yes, count
+                * its size, so we can ignore it.
+                */
+               int ignore_footer = 0;
+               int i, eol, previous = 0;
+               const char *nl;
+
+               for (i = 0; i < sb.len; i++) {
+                       nl = memchr(sb.buf + i, '\n', sb.len - i);
+                       if (nl)
+                               eol = nl - sb.buf;
+                       else
+                               eol = sb.len;
+                       if (!prefixcmp(sb.buf + previous, "\nConflicts:\n")) {
+                               ignore_footer = sb.len - previous;
+                               break;
+                       }
+                       while (i < eol)
+                               i++;
+                       previous = eol;
                }
-               strbuf_release(&sob);
+
+               append_signoff(&sb, ignore_footer);
        }
 
        if (fwrite(sb.buf, 1, sb.len, s->fp) < sb.len)
@@ -1091,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;
@@ -1184,26 +1157,29 @@ int cmd_status(int argc, const char **argv, const char *prefix)
        int fd;
        unsigned char sha1[20];
        static struct option builtin_status_options[] = {
-               OPT__VERBOSE(&verbose, "be verbose"),
+               OPT__VERBOSE(&verbose, N_("be verbose")),
                OPT_SET_INT('s', "short", &status_format,
-                           "show status concisely", STATUS_FORMAT_SHORT),
+                           N_("show status concisely"), STATUS_FORMAT_SHORT),
                OPT_BOOLEAN('b', "branch", &s.show_branch,
-                           "show branch information"),
+                           N_("show branch information")),
                OPT_SET_INT(0, "porcelain", &status_format,
-                           "machine-readable output",
+                           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,
-                           "terminate entries with NUL"),
+                           N_("terminate entries with NUL")),
                { OPTION_STRING, 'u', "untracked-files", &untracked_files_arg,
-                 "mode",
-                 "show untracked files, optional modes: all, normal, no. (Default: all)",
+                 N_("mode"),
+                 N_("show untracked files, optional modes: all, normal, no. (Default: all)"),
                  PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
                OPT_BOOLEAN(0, "ignored", &show_ignored_in_status,
-                           "show ignored files"),
-               { OPTION_STRING, 0, "ignore-submodules", &ignore_submodule_arg, "when",
-                 "ignore changes to submodules, optional when: all, dirty, untracked. (Default: all)",
+                           N_("show ignored files")),
+               { OPTION_STRING, 0, "ignore-submodules", &ignore_submodule_arg, N_("when"),
+                 N_("ignore changes to submodules, optional when: all, dirty, untracked. (Default: all)"),
                  PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
-               OPT_COLUMN(0, "column", &s.colopts, "list untracked files in columns"),
+               OPT_COLUMN(0, "column", &s.colopts, N_("list untracked files in columns")),
                OPT_END(),
        };
 
@@ -1219,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)
@@ -1249,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;
@@ -1384,53 +1365,56 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
 {
        static struct wt_status s;
        static struct option builtin_commit_options[] = {
-               OPT__QUIET(&quiet, "suppress summary after successful commit"),
-               OPT__VERBOSE(&verbose, "show diff in commit message template"),
-
-               OPT_GROUP("Commit message options"),
-               OPT_FILENAME('F', "file", &logfile, "read message from file"),
-               OPT_STRING(0, "author", &force_author, "author", "override author for commit"),
-               OPT_STRING(0, "date", &force_date, "date", "override date for commit"),
-               OPT_CALLBACK('m', "message", &message, "message", "commit message", opt_parse_m),
-               OPT_STRING('c', "reedit-message", &edit_message, "commit", "reuse and edit message from specified commit"),
-               OPT_STRING('C', "reuse-message", &use_message, "commit", "reuse message from specified commit"),
-               OPT_STRING(0, "fixup", &fixup_message, "commit", "use autosquash formatted message to fixup specified commit"),
-               OPT_STRING(0, "squash", &squash_message, "commit", "use autosquash formatted message to squash specified commit"),
-               OPT_BOOLEAN(0, "reset-author", &renew_authorship, "the commit is authored by me now (used with -C/-c/--amend)"),
-               OPT_BOOLEAN('s', "signoff", &signoff, "add Signed-off-by:"),
-               OPT_FILENAME('t', "template", &template_file, "use specified template file"),
-               OPT_BOOL('e', "edit", &edit_flag, "force edit of commit"),
-               OPT_STRING(0, "cleanup", &cleanup_arg, "default", "how to strip spaces and #comments from message"),
-               OPT_BOOLEAN(0, "status", &include_status, "include status in commit message template"),
-               { OPTION_STRING, 'S', "gpg-sign", &sign_commit, "key id",
-                 "GPG sign commit", PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
+               OPT__QUIET(&quiet, N_("suppress summary after successful commit")),
+               OPT__VERBOSE(&verbose, N_("show diff in commit message template")),
+
+               OPT_GROUP(N_("Commit message options")),
+               OPT_FILENAME('F', "file", &logfile, N_("read message from file")),
+               OPT_STRING(0, "author", &force_author, N_("author"), N_("override author for commit")),
+               OPT_STRING(0, "date", &force_date, N_("date"), N_("override date for commit")),
+               OPT_CALLBACK('m', "message", &message, N_("message"), N_("commit message"), opt_parse_m),
+               OPT_STRING('c', "reedit-message", &edit_message, N_("commit"), N_("reuse and edit message from specified commit")),
+               OPT_STRING('C', "reuse-message", &use_message, N_("commit"), N_("reuse message from specified commit")),
+               OPT_STRING(0, "fixup", &fixup_message, N_("commit"), N_("use autosquash formatted message to fixup specified commit")),
+               OPT_STRING(0, "squash", &squash_message, N_("commit"), N_("use autosquash formatted message to squash specified commit")),
+               OPT_BOOLEAN(0, "reset-author", &renew_authorship, N_("the commit is authored by me now (used with -C/-c/--amend)")),
+               OPT_BOOLEAN('s', "signoff", &signoff, N_("add Signed-off-by:")),
+               OPT_FILENAME('t', "template", &template_file, N_("use specified template file")),
+               OPT_BOOL('e', "edit", &edit_flag, N_("force edit of commit")),
+               OPT_STRING(0, "cleanup", &cleanup_arg, N_("default"), N_("how to strip spaces and #comments from message")),
+               OPT_BOOLEAN(0, "status", &include_status, N_("include status in commit message template")),
+               { OPTION_STRING, 'S', "gpg-sign", &sign_commit, N_("key id"),
+                 N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
                /* end commit message options */
 
-               OPT_GROUP("Commit contents options"),
-               OPT_BOOLEAN('a', "all", &all, "commit all changed files"),
-               OPT_BOOLEAN('i', "include", &also, "add specified files to index for commit"),
-               OPT_BOOLEAN(0, "interactive", &interactive, "interactively add files"),
-               OPT_BOOLEAN('p', "patch", &patch_interactive, "interactively add changes"),
-               OPT_BOOLEAN('o', "only", &only, "commit only specified files"),
-               OPT_BOOLEAN('n', "no-verify", &no_verify, "bypass pre-commit hook"),
-               OPT_BOOLEAN(0, "dry-run", &dry_run, "show what would be committed"),
-               OPT_SET_INT(0, "short", &status_format, "show status concisely",
+               OPT_GROUP(N_("Commit contents options")),
+               OPT_BOOLEAN('a', "all", &all, N_("commit all changed files")),
+               OPT_BOOLEAN('i', "include", &also, N_("add specified files to index for commit")),
+               OPT_BOOLEAN(0, "interactive", &interactive, N_("interactively add files")),
+               OPT_BOOLEAN('p', "patch", &patch_interactive, N_("interactively add changes")),
+               OPT_BOOLEAN('o', "only", &only, N_("commit only specified files")),
+               OPT_BOOLEAN('n', "no-verify", &no_verify, N_("bypass pre-commit hook")),
+               OPT_BOOLEAN(0, "dry-run", &dry_run, N_("show what would be committed")),
+               OPT_SET_INT(0, "short", &status_format, N_("show status concisely"),
                            STATUS_FORMAT_SHORT),
-               OPT_BOOLEAN(0, "branch", &s.show_branch, "show branch information"),
+               OPT_BOOLEAN(0, "branch", &s.show_branch, N_("show branch information")),
                OPT_SET_INT(0, "porcelain", &status_format,
-                           "machine-readable output", STATUS_FORMAT_PORCELAIN),
+                           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,
-                           "terminate entries with NUL"),
-               OPT_BOOLEAN(0, "amend", &amend, "amend previous commit"),
-               OPT_BOOLEAN(0, "no-post-rewrite", &no_post_rewrite, "bypass post-rewrite hook"),
-               { OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, "mode", "show untracked files, optional modes: all, normal, no. (Default: all)", PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
+                           N_("terminate entries with NUL")),
+               OPT_BOOLEAN(0, "amend", &amend, N_("amend previous commit")),
+               OPT_BOOLEAN(0, "no-post-rewrite", &no_post_rewrite, N_("bypass post-rewrite hook")),
+               { OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, N_("mode"), N_("show untracked files, optional modes: all, normal, no. (Default: all)"), PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
                /* end commit contents options */
 
                { OPTION_BOOLEAN, 0, "allow-empty", &allow_empty, NULL,
-                 "ok to record an empty change",
+                 N_("ok to record an empty change"),
                  PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
                { OPTION_BOOLEAN, 0, "allow-empty-message", &allow_empty_message, NULL,
-                 "ok to record a change with an empty message",
+                 N_("ok to record a change with an empty message"),
                  PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
 
                OPT_END()
@@ -1452,6 +1436,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
                usage_with_options(builtin_commit_usage, builtin_commit_options);
 
        wt_status_prepare(&s);
+       gitmodules_config();
        git_config(git_commit_config, &s);
        determine_whence(&s);
        s.colopts = 0;
index b44277c23e293f42186230cc7feb9099f2058b2b..e1c33e0691796601ac869278c155194d33ee8332 100644 (file)
@@ -4,7 +4,7 @@
 #include "parse-options.h"
 
 static const char *const builtin_config_usage[] = {
-       "git config [options]",
+       N_("git config [options]"),
        NULL
 };
 
@@ -49,33 +49,33 @@ static int respect_includes = -1;
 #define TYPE_PATH (1<<3)
 
 static struct option builtin_config_options[] = {
-       OPT_GROUP("Config file location"),
-       OPT_BOOLEAN(0, "global", &use_global_config, "use global config file"),
-       OPT_BOOLEAN(0, "system", &use_system_config, "use system config file"),
-       OPT_BOOLEAN(0, "local", &use_local_config, "use repository config file"),
-       OPT_STRING('f', "file", &given_config_file, "file", "use given config file"),
-       OPT_GROUP("Action"),
-       OPT_BIT(0, "get", &actions, "get value: name [value-regex]", ACTION_GET),
-       OPT_BIT(0, "get-all", &actions, "get all values: key [value-regex]", ACTION_GET_ALL),
-       OPT_BIT(0, "get-regexp", &actions, "get values for regexp: name-regex [value-regex]", ACTION_GET_REGEXP),
-       OPT_BIT(0, "replace-all", &actions, "replace all matching variables: name value [value_regex]", ACTION_REPLACE_ALL),
-       OPT_BIT(0, "add", &actions, "adds a new variable: name value", ACTION_ADD),
-       OPT_BIT(0, "unset", &actions, "removes a variable: name [value-regex]", ACTION_UNSET),
-       OPT_BIT(0, "unset-all", &actions, "removes all matches: name [value-regex]", ACTION_UNSET_ALL),
-       OPT_BIT(0, "rename-section", &actions, "rename section: old-name new-name", ACTION_RENAME_SECTION),
-       OPT_BIT(0, "remove-section", &actions, "remove a section: name", ACTION_REMOVE_SECTION),
-       OPT_BIT('l', "list", &actions, "list all", ACTION_LIST),
-       OPT_BIT('e', "edit", &actions, "opens an editor", ACTION_EDIT),
-       OPT_STRING(0, "get-color", &get_color_slot, "slot", "find the color configured: [default]"),
-       OPT_STRING(0, "get-colorbool", &get_colorbool_slot, "slot", "find the color setting: [stdout-is-tty]"),
-       OPT_GROUP("Type"),
-       OPT_BIT(0, "bool", &types, "value is \"true\" or \"false\"", TYPE_BOOL),
-       OPT_BIT(0, "int", &types, "value is decimal number", TYPE_INT),
-       OPT_BIT(0, "bool-or-int", &types, "value is --bool or --int", TYPE_BOOL_OR_INT),
-       OPT_BIT(0, "path", &types, "value is a path (file or directory name)", TYPE_PATH),
-       OPT_GROUP("Other"),
-       OPT_BOOLEAN('z', "null", &end_null, "terminate values with NUL byte"),
-       OPT_BOOL(0, "includes", &respect_includes, "respect include directives on lookup"),
+       OPT_GROUP(N_("Config file location")),
+       OPT_BOOLEAN(0, "global", &use_global_config, N_("use global config file")),
+       OPT_BOOLEAN(0, "system", &use_system_config, N_("use system config file")),
+       OPT_BOOLEAN(0, "local", &use_local_config, N_("use repository config file")),
+       OPT_STRING('f', "file", &given_config_file, N_("file"), N_("use given config file")),
+       OPT_GROUP(N_("Action")),
+       OPT_BIT(0, "get", &actions, N_("get value: name [value-regex]"), ACTION_GET),
+       OPT_BIT(0, "get-all", &actions, N_("get all values: key [value-regex]"), ACTION_GET_ALL),
+       OPT_BIT(0, "get-regexp", &actions, N_("get values for regexp: name-regex [value-regex]"), ACTION_GET_REGEXP),
+       OPT_BIT(0, "replace-all", &actions, N_("replace all matching variables: name value [value_regex]"), ACTION_REPLACE_ALL),
+       OPT_BIT(0, "add", &actions, N_("add a new variable: name value"), ACTION_ADD),
+       OPT_BIT(0, "unset", &actions, N_("remove a variable: name [value-regex]"), ACTION_UNSET),
+       OPT_BIT(0, "unset-all", &actions, N_("remove all matches: name [value-regex]"), ACTION_UNSET_ALL),
+       OPT_BIT(0, "rename-section", &actions, N_("rename section: old-name new-name"), ACTION_RENAME_SECTION),
+       OPT_BIT(0, "remove-section", &actions, N_("remove a section: name"), ACTION_REMOVE_SECTION),
+       OPT_BIT('l', "list", &actions, N_("list all"), ACTION_LIST),
+       OPT_BIT('e', "edit", &actions, N_("open an editor"), ACTION_EDIT),
+       OPT_STRING(0, "get-color", &get_color_slot, N_("slot"), N_("find the color configured: [default]")),
+       OPT_STRING(0, "get-colorbool", &get_colorbool_slot, N_("slot"), N_("find the color setting: [stdout-is-tty]")),
+       OPT_GROUP(N_("Type")),
+       OPT_BIT(0, "bool", &types, N_("value is \"true\" or \"false\""), TYPE_BOOL),
+       OPT_BIT(0, "int", &types, N_("value is decimal number"), TYPE_INT),
+       OPT_BIT(0, "bool-or-int", &types, N_("value is --bool or --int"), TYPE_BOOL_OR_INT),
+       OPT_BIT(0, "path", &types, N_("value is a path (file or directory name)"), TYPE_PATH),
+       OPT_GROUP(N_("Other")),
+       OPT_BOOLEAN('z', "null", &end_null, N_("terminate values with NUL byte")),
+       OPT_BOOL(0, "includes", &respect_includes, N_("respect include directives on lookup")),
        OPT_END(),
 };
 
@@ -161,7 +161,7 @@ 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, *repo_config = NULL;
+       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;
@@ -169,12 +169,10 @@ static int get_value(const char *key_, const char *regex_)
 
        local = given_config_file;
        if (!local) {
-               const char *home = getenv("HOME");
                local = repo_config = git_pathdup("config");
-               if (home)
-                       global = xstrdup(mkpath("%s/.gitconfig", home));
                if (git_config_system())
                        system_wide = git_etc_gitconfig();
+               home_config_paths(&global, &xdg, "config");
        }
 
        if (use_key_regexp) {
@@ -233,6 +231,8 @@ static int get_value(const char *key_, const char *regex_)
 
        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)
@@ -242,6 +242,8 @@ static int get_value(const char *key_, const char *regex_)
                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);
 
@@ -259,6 +261,7 @@ static int get_value(const char *key_, const char *regex_)
 free_strings:
        free(repo_config);
        free(global);
+       free(xdg);
        return ret;
 }
 
@@ -383,13 +386,25 @@ int cmd_config(int argc, const char **argv, const char *prefix)
        }
 
        if (use_global_config) {
-               char *home = getenv("HOME");
-               if (home) {
-                       char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
-                       given_config_file = user_config;
-               } else {
+               char *user_config = NULL;
+               char *xdg_config = NULL;
+
+               home_config_paths(&user_config, &xdg_config, "config");
+
+               if (!user_config)
+                       /*
+                        * It is unknown if HOME/.gitconfig exists, so
+                        * we do not know if we should write to XDG
+                        * location; error out even if XDG_CONFIG_HOME
+                        * is set and points at a sane location.
+                        */
                        die("$HOME not set");
-               }
+
+               if (access_or_warn(user_config, R_OK) &&
+                   xdg_config && !access_or_warn(xdg_config, R_OK))
+                       given_config_file = xdg_config;
+               else
+                       given_config_file = user_config;
        }
        else if (use_system_config)
                given_config_file = git_etc_gitconfig();
index c37cb98c31ddfaa90d38a0355d32cf3d6c404bff..9afaa88f776468a0de33dd153eadae7621cf6267 100644 (file)
@@ -66,7 +66,7 @@ static void count_objects(DIR *d, char *path, int len, int verbose,
 }
 
 static char const * const count_objects_usage[] = {
-       "git count-objects [-v]",
+       N_("git count-objects [-v]"),
        NULL
 };
 
@@ -79,7 +79,7 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix)
        unsigned long loose = 0, packed = 0, packed_loose = 0, garbage = 0;
        off_t loose_size = 0;
        struct option opts[] = {
-               OPT__VERBOSE(&verbose, "be verbose"),
+               OPT__VERBOSE(&verbose, N_("be verbose")),
                OPT_END(),
        };
 
diff --git a/builtin/credential.c b/builtin/credential.c
new file mode 100644 (file)
index 0000000..0412fa0
--- /dev/null
@@ -0,0 +1,31 @@
+#include "git-compat-util.h"
+#include "credential.h"
+#include "builtin.h"
+
+static const char usage_msg[] =
+       "git credential [fill|approve|reject]";
+
+int cmd_credential(int argc, const char **argv, const char *prefix)
+{
+       const char *op;
+       struct credential c = CREDENTIAL_INIT;
+
+       op = argv[1];
+       if (!op)
+               usage(usage_msg);
+
+       if (credential_read(&c, stdin) < 0)
+               die("unable to read credential from stdin");
+
+       if (!strcmp(op, "fill")) {
+               credential_fill(&c);
+               credential_write(&c, stdout);
+       } else if (!strcmp(op, "approve")) {
+               credential_approve(&c);
+       } else if (!strcmp(op, "reject")) {
+               credential_reject(&c);
+       } else {
+               usage(usage_msg);
+       }
+       return 0;
+}
index 9f63067f50a6f49d61d40474608535905bec905b..04c185b1fbdc51ba9958fdb83d1c6616bcb0c18e 100644 (file)
@@ -12,8 +12,8 @@
 #define MAX_TAGS       (FLAG_BITS - 1)
 
 static const char * const describe_usage[] = {
-       "git describe [options] <committish>*",
-       "git describe [options] --dirty",
+       N_("git describe [options] <committish>*"),
+       N_("git describe [options] --dirty"),
        NULL
 };
 
@@ -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);
@@ -400,22 +400,22 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
 {
        int contains = 0;
        struct option options[] = {
-               OPT_BOOLEAN(0, "contains",   &contains, "find the tag that comes after the commit"),
-               OPT_BOOLEAN(0, "debug",      &debug, "debug search strategy on stderr"),
-               OPT_BOOLEAN(0, "all",        &all, "use any ref in .git/refs"),
-               OPT_BOOLEAN(0, "tags",       &tags, "use any tag in .git/refs/tags"),
-               OPT_BOOLEAN(0, "long",       &longformat, "always use long format"),
+               OPT_BOOLEAN(0, "contains",   &contains, N_("find the tag that comes after the commit")),
+               OPT_BOOLEAN(0, "debug",      &debug, N_("debug search strategy on stderr")),
+               OPT_BOOLEAN(0, "all",        &all, N_("use any ref in .git/refs")),
+               OPT_BOOLEAN(0, "tags",       &tags, N_("use any tag in .git/refs/tags")),
+               OPT_BOOLEAN(0, "long",       &longformat, N_("always use long format")),
                OPT__ABBREV(&abbrev),
                OPT_SET_INT(0, "exact-match", &max_candidates,
-                           "only output exact matches", 0),
+                           N_("only output exact matches"), 0),
                OPT_INTEGER(0, "candidates", &max_candidates,
-                           "consider <n> most recent tags (default: 10)"),
-               OPT_STRING(0, "match",       &pattern, "pattern",
-                          "only consider tags matching <pattern>"),
+                           N_("consider <n> most recent tags (default: 10)")),
+               OPT_STRING(0, "match",       &pattern, N_("pattern"),
+                          N_("only consider tags matching <pattern>")),
                OPT_BOOLEAN(0, "always",     &always,
-                          "show abbreviated commit object as fallback"),
-               {OPTION_STRING, 0, "dirty",  &dirty, "mark",
-                          "append <mark> on dirty working tree (default: \"-dirty\")",
+                          N_("show abbreviated commit object as fallback")),
+               {OPTION_STRING, 0, "dirty",  &dirty, N_("mark"),
+                          N_("append <mark> on dirty working tree (default: \"-dirty\")"),
                 PARSE_OPT_OPTARG, NULL, (intptr_t) "-dirty"},
                OPT_END(),
        };
index 9ab6db3fb042d0cb7ee3a1919788b9a6cd26a3d6..12220ad8dac65acaa556c6524310d5540709f324 100644 (file)
@@ -19,7 +19,7 @@
 #include "quote.h"
 
 static const char *fast_export_usage[] = {
-       "git fast-export [rev-list-opts]",
+       N_("git fast-export [rev-list-opts]"),
        NULL
 };
 
@@ -632,24 +632,24 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
        char *export_filename = NULL, *import_filename = NULL;
        struct option options[] = {
                OPT_INTEGER(0, "progress", &progress,
-                           "show progress after <n> objects"),
-               OPT_CALLBACK(0, "signed-tags", &signed_tag_mode, "mode",
-                            "select handling of signed tags",
+                           N_("show progress after <n> objects")),
+               OPT_CALLBACK(0, "signed-tags", &signed_tag_mode, N_("mode"),
+                            N_("select handling of signed tags"),
                             parse_opt_signed_tag_mode),
-               OPT_CALLBACK(0, "tag-of-filtered-object", &tag_of_filtered_mode, "mode",
-                            "select handling of tags that tag filtered objects",
+               OPT_CALLBACK(0, "tag-of-filtered-object", &tag_of_filtered_mode, N_("mode"),
+                            N_("select handling of tags that tag filtered objects"),
                             parse_opt_tag_of_filtered_mode),
-               OPT_STRING(0, "export-marks", &export_filename, "file",
-                            "Dump marks to this file"),
-               OPT_STRING(0, "import-marks", &import_filename, "file",
-                            "Import marks from this file"),
+               OPT_STRING(0, "export-marks", &export_filename, N_("file"),
+                            N_("Dump marks to this file")),
+               OPT_STRING(0, "import-marks", &import_filename, N_("file"),
+                            N_("Import marks from this file")),
                OPT_BOOLEAN(0, "fake-missing-tagger", &fake_missing_tagger,
-                            "Fake a tagger when tags lack one"),
+                            N_("Fake a tagger when tags lack one")),
                OPT_BOOLEAN(0, "full-tree", &full_tree,
-                            "Output full tree for each commit"),
+                            N_("Output full tree for each commit")),
                OPT_BOOLEAN(0, "use-done-feature", &use_done_feature,
-                            "Use the done feature to terminate the stream"),
-               OPT_BOOL(0, "no-data", &no_data, "Skip output of blob data"),
+                            N_("Use the done feature to terminate the stream")),
+               OPT_BOOL(0, "no-data", &no_data, N_("Skip output of blob data")),
                OPT_END()
        };
 
index 149db88726b8b5f924e6d136828008ec952bc88e..e6443986b81050b01ebd7c57a7afd7abb5c65a45 100644 (file)
@@ -10,6 +10,7 @@
 #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;
@@ -18,6 +19,7 @@ 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",
 };
@@ -327,6 +329,8 @@ static int find_common(int fd[2], unsigned char *result_sha1,
                        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
@@ -521,72 +525,59 @@ static void mark_recent_complete_commits(unsigned long cutoff)
        }
 }
 
-static void filter_refs(struct ref **refs, int nr_match, char **match)
+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 **return_refs;
        struct ref *newlist = NULL;
        struct ref **newtail = &newlist;
        struct ref *ref, *next;
-       struct ref *fastarray[32];
-       int match_pos;
-
-       if (nr_match && !args.fetch_all) {
-               if (ARRAY_SIZE(fastarray) < nr_match)
-                       return_refs = xcalloc(nr_match, sizeof(struct ref *));
-               else {
-                       return_refs = fastarray;
-                       memset(return_refs, 0, sizeof(struct ref *) * nr_match);
-               }
-       }
-       else
-               return_refs = NULL;
+       int sought_pos;
 
-       match_pos = 0;
+       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 if (args.fetch_all &&
-                        (!args.depth || prefixcmp(ref->name, "refs/tags/") )) {
-                       *newtail = ref;
-                       ref->next = NULL;
-                       newtail = &ref->next;
-                       continue;
-               }
                else {
-                       int cmp = -1;
-                       while (match_pos < nr_match) {
-                               cmp = strcmp(ref->name, match[match_pos]);
-                               if (cmp < 0) /* definitely do not have it */
-                                       break;
-                               else if (cmp == 0) { /* definitely have it */
-                                       match[match_pos][0] = '\0';
-                                       return_refs[match_pos] = ref;
+                       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 /* might have it; keep looking */
-                                       match_pos++;
+                               else
+                                       sought_pos++; /* might have it; keep looking */
                        }
-                       if (!cmp)
-                               continue; /* we will link it later */
                }
-               free(ref);
-       }
 
-       if (!args.fetch_all) {
-               int i;
-               for (i = 0; i < nr_match; i++) {
-                       ref = return_refs[i];
-                       if (ref) {
-                               *newtail = ref;
-                               ref->next = NULL;
-                               newtail = &ref->next;
-                       }
+               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);
                }
-               if (return_refs != fastarray)
-                       free(return_refs);
        }
+
+       filter_string_list(sought, 0, non_matching_ref, NULL);
        *refs = newlist;
 }
 
@@ -595,7 +586,7 @@ 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, int nr_match, char **match)
+static int everything_local(struct ref **refs, struct string_list *sought)
 {
        struct ref *ref;
        int retval;
@@ -646,7 +637,7 @@ static int everything_local(struct ref **refs, int nr_match, char **match)
                }
        }
 
-       filter_refs(refs, nr_match, match);
+       filter_refs(refs, sought);
 
        for (retval = 1, ref = *refs; ref ; ref = ref->next) {
                const unsigned char *remote = ref->old_sha1;
@@ -777,12 +768,13 @@ static int get_pack(int xd[2], char **pack_lockfile)
 
 static struct ref *do_fetch_pack(int fd[2],
                const struct ref *orig_ref,
-               int nr_match,
-               char **match,
+               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);
 
@@ -814,12 +806,26 @@ static struct ref *do_fetch_pack(int fd[2],
                        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 (everything_local(&ref, nr_match, match)) {
+
+       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;
        }
@@ -839,19 +845,6 @@ static struct ref *do_fetch_pack(int fd[2],
        return ref;
 }
 
-static int remove_duplicates(int nr_heads, char **heads)
-{
-       int src, dst;
-
-       if (!nr_heads)
-               return 0;
-
-       for (src = dst = 1; src < nr_heads; src++)
-               if (strcmp(heads[src], heads[dst-1]))
-                       heads[dst++] = heads[src];
-       return dst;
-}
-
 static int fetch_pack_config(const char *var, const char *value, void *cb)
 {
        if (strcmp(var, "fetch.unpacklimit") == 0) {
@@ -902,8 +895,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
        int i, ret;
        struct ref *ref = NULL;
        const char *dest = NULL;
-       int alloc_heads = 0, nr_heads = 0;
-       char **heads = NULL;
+       struct string_list sought = STRING_LIST_INIT_DUP;
        int fd[2];
        char *pack_lockfile = NULL;
        char **pack_lockfile_ptr = NULL;
@@ -980,9 +972,8 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
         * Copy refs from cmdline to growable list, then append any
         * refs from the standard input:
         */
-       ALLOC_GROW(heads, argc - i, alloc_heads);
        for (; i < argc; i++)
-               heads[nr_heads++] = xstrdup(argv[i]);
+               string_list_append(&sought, xstrdup(argv[i]));
        if (args.stdin_refs) {
                if (args.stateless_rpc) {
                        /* in stateless RPC mode we use pkt-line to read
@@ -995,17 +986,14 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
                                        break;
                                if (line[n-1] == '\n')
                                        n--;
-                               ALLOC_GROW(heads, nr_heads + 1, alloc_heads);
-                               heads[nr_heads++] = xmemdupz(line, n);
+                               string_list_append(&sought, xmemdupz(line, n));
                        }
                }
                else {
                        /* read from stdin one ref per line, until EOF */
                        struct strbuf line = STRBUF_INIT;
-                       while (strbuf_getline(&line, stdin, '\n') != EOF) {
-                               ALLOC_GROW(heads, nr_heads + 1, alloc_heads);
-                               heads[nr_heads++] = strbuf_detach(&line, NULL);
-                       }
+                       while (strbuf_getline(&line, stdin, '\n') != EOF)
+                               string_list_append(&sought, strbuf_detach(&line, NULL));
                        strbuf_release(&line);
                }
        }
@@ -1022,7 +1010,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
        get_remote_heads(fd[0], &ref, 0, NULL);
 
        ref = fetch_pack(&args, fd, conn, ref, dest,
-               nr_heads, heads, pack_lockfile_ptr);
+                        &sought, pack_lockfile_ptr);
        if (pack_lockfile) {
                printf("lock %s\n", pack_lockfile);
                fflush(stdout);
@@ -1030,21 +1018,18 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
        close(fd[0]);
        close(fd[1]);
        if (finish_connect(conn))
-               ref = NULL;
-       ret = !ref;
-
-       if (!ret && nr_heads) {
-               /* If the heads to pull were given, we should have
-                * consumed all of them by matching the remote.
-                * Otherwise, 'git fetch remote no-such-ref' would
-                * silently succeed without issuing an error.
-                */
-               for (i = 0; i < nr_heads; i++)
-                       if (heads[i] && heads[i][0]) {
-                               error("no such remote ref %s", heads[i]);
-                               ret = 1;
-                       }
-       }
+               return 1;
+
+       ret = !ref || sought.nr;
+
+       /*
+        * If the heads to pull were given, we should have consumed
+        * all of them by matching the remote.  Otherwise, 'git fetch
+        * remote no-such-ref' would silently succeed without issuing
+        * an error.
+        */
+       for (i = 0; i < sought.nr; i++)
+               error("no such remote ref %s", sought.items[i].string);
        while (ref) {
                printf("%s %s\n",
                       sha1_to_hex(ref->old_sha1), ref->name);
@@ -1054,18 +1039,12 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
        return ret;
 }
 
-static int compare_heads(const void *a, const void *b)
-{
-       return strcmp(*(const char **)a, *(const char **)b);
-}
-
 struct ref *fetch_pack(struct fetch_pack_args *my_args,
                       int fd[], struct child_process *conn,
                       const struct ref *ref,
-               const char *dest,
-               int nr_heads,
-               char **heads,
-               char **pack_lockfile)
+                      const char *dest,
+                      struct string_list *sought,
+                      char **pack_lockfile)
 {
        struct stat st;
        struct ref *ref_cpy;
@@ -1078,16 +1057,16 @@ struct ref *fetch_pack(struct fetch_pack_args *my_args,
                        st.st_mtime = 0;
        }
 
-       if (heads && nr_heads) {
-               qsort(heads, nr_heads, sizeof(*heads), compare_heads);
-               nr_heads = remove_duplicates(nr_heads, heads);
+       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, nr_heads, heads, pack_lockfile);
+       ref_cpy = do_fetch_pack(fd, ref, sought, pack_lockfile);
 
        if (args.depth > 0) {
                struct cache_time mtime;
index bb9a0743ff565f3002eb0fede8e35b7f01a73b75..4b5a89839b66f201bda42f06cabdf781d44f0192 100644 (file)
 #include "transport.h"
 #include "submodule.h"
 #include "connected.h"
+#include "argv-array.h"
 
 static const char * const builtin_fetch_usage[] = {
-       "git fetch [<options>] [<repository> [<refspec>...]]",
-       "git fetch [<options>] <group>",
-       "git fetch --multiple [<options>] [(<repository> | <group>)...]",
-       "git fetch --all [<options>]",
+       N_("git fetch [<options>] [<repository> [<refspec>...]]"),
+       N_("git fetch [<options>] <group>"),
+       N_("git fetch --multiple [<options>] [(<repository> | <group>)...]"),
+       N_("git fetch --all [<options>]"),
        NULL
 };
 
@@ -56,36 +57,36 @@ static int option_parse_recurse_submodules(const struct option *opt,
 static struct option builtin_fetch_options[] = {
        OPT__VERBOSITY(&verbosity),
        OPT_BOOLEAN(0, "all", &all,
-                   "fetch from all remotes"),
+                   N_("fetch from all remotes")),
        OPT_BOOLEAN('a', "append", &append,
-                   "append to .git/FETCH_HEAD instead of overwriting"),
-       OPT_STRING(0, "upload-pack", &upload_pack, "path",
-                  "path to upload pack on remote end"),
-       OPT__FORCE(&force, "force overwrite of local branch"),
+                   N_("append to .git/FETCH_HEAD instead of overwriting")),
+       OPT_STRING(0, "upload-pack", &upload_pack, N_("path"),
+                  N_("path to upload pack on remote end")),
+       OPT__FORCE(&force, N_("force overwrite of local branch")),
        OPT_BOOLEAN('m', "multiple", &multiple,
-                   "fetch from multiple remotes"),
+                   N_("fetch from multiple remotes")),
        OPT_SET_INT('t', "tags", &tags,
-                   "fetch all tags and associated objects", TAGS_SET),
+                   N_("fetch all tags and associated objects"), TAGS_SET),
        OPT_SET_INT('n', NULL, &tags,
-                   "do not fetch all tags (--no-tags)", TAGS_UNSET),
+                   N_("do not fetch all tags (--no-tags)"), TAGS_UNSET),
        OPT_BOOLEAN('p', "prune", &prune,
-                   "prune remote-tracking branches no longer on remote"),
-       { OPTION_CALLBACK, 0, "recurse-submodules", NULL, "on-demand",
-                   "control recursive fetching of submodules",
+                   N_("prune remote-tracking branches no longer on remote")),
+       { OPTION_CALLBACK, 0, "recurse-submodules", NULL, N_("on-demand"),
+                   N_("control recursive fetching of submodules"),
                    PARSE_OPT_OPTARG, option_parse_recurse_submodules },
        OPT_BOOLEAN(0, "dry-run", &dry_run,
-                   "dry run"),
-       OPT_BOOLEAN('k', "keep", &keep, "keep downloaded pack"),
+                   N_("dry run")),
+       OPT_BOOLEAN('k', "keep", &keep, N_("keep downloaded pack")),
        OPT_BOOLEAN('u', "update-head-ok", &update_head_ok,
-                   "allow updating of HEAD ref"),
-       OPT_BOOL(0, "progress", &progress, "force progress reporting"),
-       OPT_STRING(0, "depth", &depth, "depth",
-                  "deepen history of shallow clone"),
-       { OPTION_STRING, 0, "submodule-prefix", &submodule_prefix, "dir",
-                  "prepend this to submodule path output", PARSE_OPT_HIDDEN },
+                   N_("allow updating of HEAD ref")),
+       OPT_BOOL(0, "progress", &progress, N_("force progress reporting")),
+       OPT_STRING(0, "depth", &depth, N_("depth"),
+                  N_("deepen history of shallow clone")),
+       { OPTION_STRING, 0, "submodule-prefix", &submodule_prefix, N_("dir"),
+                  N_("prepend this to submodule path output"), PARSE_OPT_HIDDEN },
        { OPTION_STRING, 0, "recurse-submodules-default",
                   &recurse_submodules_default, NULL,
-                  "default mode for recursion", PARSE_OPT_HIDDEN },
+                  N_("default mode for recursion"), PARSE_OPT_HIDDEN },
        OPT_END()
 };
 
@@ -255,9 +256,8 @@ static int update_local_ref(struct ref *ref,
        if (!hashcmp(ref->old_sha1, ref->new_sha1)) {
                if (verbosity > 0)
                        strbuf_addf(display, "= %-*s %-*s -> %s",
-                                   TRANSPORT_SUMMARY_WIDTH,
-                                   _("[up to date]"), REFCOL_WIDTH,
-                                   remote, pretty_ref);
+                                   TRANSPORT_SUMMARY(_("[up to date]")),
+                                   REFCOL_WIDTH, remote, pretty_ref);
                return 0;
        }
 
@@ -271,7 +271,7 @@ static int update_local_ref(struct ref *ref,
                 */
                strbuf_addf(display,
                            _("! %-*s %-*s -> %s  (can't fetch in current branch)"),
-                           TRANSPORT_SUMMARY_WIDTH, _("[rejected]"),
+                           TRANSPORT_SUMMARY(_("[rejected]")),
                            REFCOL_WIDTH, remote, pretty_ref);
                return 1;
        }
@@ -282,7 +282,7 @@ static int update_local_ref(struct ref *ref,
                r = s_update_ref("updating tag", ref, 0);
                strbuf_addf(display, "%c %-*s %-*s -> %s%s",
                            r ? '!' : '-',
-                           TRANSPORT_SUMMARY_WIDTH, _("[tag update]"),
+                           TRANSPORT_SUMMARY(_("[tag update]")),
                            REFCOL_WIDTH, remote, pretty_ref,
                            r ? _("  (unable to update local ref)") : "");
                return r;
@@ -317,13 +317,13 @@ static int update_local_ref(struct ref *ref,
                r = s_update_ref(msg, ref, 0);
                strbuf_addf(display, "%c %-*s %-*s -> %s%s",
                            r ? '!' : '*',
-                           TRANSPORT_SUMMARY_WIDTH, what,
+                           TRANSPORT_SUMMARY(what),
                            REFCOL_WIDTH, remote, pretty_ref,
                            r ? _("  (unable to update local ref)") : "");
                return r;
        }
 
-       if (in_merge_bases(current, &updated, 1)) {
+       if (in_merge_bases(current, updated)) {
                char quickref[83];
                int r;
                strcpy(quickref, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV));
@@ -357,7 +357,7 @@ static int update_local_ref(struct ref *ref,
                return r;
        } else {
                strbuf_addf(display, "! %-*s %-*s -> %s  %s",
-                           TRANSPORT_SUMMARY_WIDTH, _("[rejected]"),
+                           TRANSPORT_SUMMARY(_("[rejected]")),
                            REFCOL_WIDTH, remote, pretty_ref,
                            _("(non-fast-forward)"));
                return 1;
@@ -554,7 +554,7 @@ static int prune_refs(struct refspec *refs, int ref_count, struct ref *ref_map)
                        result |= delete_ref(ref->name, NULL, 0);
                if (verbosity >= 0) {
                        fprintf(stderr, " x %-*s %-*s -> %s\n",
-                               TRANSPORT_SUMMARY_WIDTH, _("[deleted]"),
+                               TRANSPORT_SUMMARY(_("[deleted]")),
                                REFCOL_WIDTH, _("(none)"), prettify_refname(ref->name));
                        warn_dangling_symref(stderr, dangling_msg, ref->name);
                }
@@ -841,38 +841,39 @@ static int add_remote_or_group(const char *name, struct string_list *list)
        return 1;
 }
 
-static void add_options_to_argv(int *argc, const char **argv)
+static void add_options_to_argv(struct argv_array *argv)
 {
        if (dry_run)
-               argv[(*argc)++] = "--dry-run";
+               argv_array_push(argv, "--dry-run");
        if (prune)
-               argv[(*argc)++] = "--prune";
+               argv_array_push(argv, "--prune");
        if (update_head_ok)
-               argv[(*argc)++] = "--update-head-ok";
+               argv_array_push(argv, "--update-head-ok");
        if (force)
-               argv[(*argc)++] = "--force";
+               argv_array_push(argv, "--force");
        if (keep)
-               argv[(*argc)++] = "--keep";
+               argv_array_push(argv, "--keep");
        if (recurse_submodules == RECURSE_SUBMODULES_ON)
-               argv[(*argc)++] = "--recurse-submodules";
+               argv_array_push(argv, "--recurse-submodules");
        else if (recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND)
-               argv[(*argc)++] = "--recurse-submodules=on-demand";
+               argv_array_push(argv, "--recurse-submodules=on-demand");
+       if (tags == TAGS_SET)
+               argv_array_push(argv, "--tags");
+       else if (tags == TAGS_UNSET)
+               argv_array_push(argv, "--no-tags");
        if (verbosity >= 2)
-               argv[(*argc)++] = "-v";
+               argv_array_push(argv, "-v");
        if (verbosity >= 1)
-               argv[(*argc)++] = "-v";
+               argv_array_push(argv, "-v");
        else if (verbosity < 0)
-               argv[(*argc)++] = "-q";
+               argv_array_push(argv, "-q");
 
 }
 
 static int fetch_multiple(struct string_list *list)
 {
        int i, result = 0;
-       const char *argv[12] = { "fetch", "--append" };
-       int argc = 2;
-
-       add_options_to_argv(&argc, argv);
+       struct argv_array argv = ARGV_ARRAY_INIT;
 
        if (!append && !dry_run) {
                int errcode = truncate_fetch_head();
@@ -880,18 +881,22 @@ static int fetch_multiple(struct string_list *list)
                        return errcode;
        }
 
+       argv_array_pushl(&argv, "fetch", "--append", NULL);
+       add_options_to_argv(&argv);
+
        for (i = 0; i < list->nr; i++) {
                const char *name = list->items[i].string;
-               argv[argc] = name;
-               argv[argc + 1] = NULL;
+               argv_array_push(&argv, name);
                if (verbosity >= 0)
                        printf(_("Fetching %s\n"), name);
-               if (run_command_v_opt(argv, RUN_GIT_CMD)) {
+               if (run_command_v_opt(argv.argv, RUN_GIT_CMD)) {
                        error(_("Could not fetch %s"), name);
                        result = 1;
                }
+               argv_array_pop(&argv);
        }
 
+       argv_array_clear(&argv);
        return result;
 }
 
@@ -1007,13 +1012,14 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
        }
 
        if (!result && (recurse_submodules != RECURSE_SUBMODULES_OFF)) {
-               const char *options[10];
-               int num_options = 0;
-               add_options_to_argv(&num_options, options);
-               result = fetch_populated_submodules(num_options, options,
+               struct argv_array options = ARGV_ARRAY_INIT;
+
+               add_options_to_argv(&options);
+               result = fetch_populated_submodules(&options,
                                                    submodule_prefix,
                                                    recurse_submodules,
                                                    verbosity < 0);
+               argv_array_clear(&options);
        }
 
        /* All names were strdup()ed or strndup()ed */
index 2c4d435da111770bcb3271de4c46e806f3a693b4..e2e27b2c404a1c451a20e396a7aa03dece722dad 100644 (file)
@@ -10,7 +10,7 @@
 #include "gpg-interface.h"
 
 static const char * const fmt_merge_msg_usage[] = {
-       "git fmt-merge-msg [-m <message>] [--log[=<n>]|--no-log] [--file <file>]",
+       N_("git fmt-merge-msg [-m <message>] [--log[=<n>]|--no-log] [--file <file>]"),
        NULL
 };
 
@@ -650,16 +650,16 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
        const char *message = NULL;
        int shortlog_len = -1;
        struct option options[] = {
-               { OPTION_INTEGER, 0, "log", &shortlog_len, "n",
-                 "populate log with at most <n> entries from shortlog",
+               { OPTION_INTEGER, 0, "log", &shortlog_len, N_("n"),
+                 N_("populate log with at most <n> entries from shortlog"),
                  PARSE_OPT_OPTARG, NULL, DEFAULT_MERGE_LOG_LEN },
-               { OPTION_INTEGER, 0, "summary", &shortlog_len, "n",
-                 "alias for --log (deprecated)",
+               { OPTION_INTEGER, 0, "summary", &shortlog_len, N_("n"),
+                 N_("alias for --log (deprecated)"),
                  PARSE_OPT_OPTARG | PARSE_OPT_HIDDEN, NULL,
                  DEFAULT_MERGE_LOG_LEN },
-               OPT_STRING('m', "message", &message, "text",
-                       "use <text> as start of message"),
-               OPT_FILENAME('F', "file", &inpath, "file to read from"),
+               OPT_STRING('m', "message", &message, N_("text"),
+                       N_("use <text> as start of message")),
+               OPT_FILENAME('F', "file", &inpath, N_("file to read from")),
                OPT_END()
        };
 
index 0c5294e5e8fb92ca4757929a4bdf4bc49ca659bb..7f059c31dfbd11f77c891134ccc34cdc1f65bcb8 100644 (file)
@@ -976,7 +976,7 @@ static int opt_parse_sort(const struct option *opt, const char *arg, int unset)
 }
 
 static char const * const for_each_ref_usage[] = {
-       "git for-each-ref [options] [<pattern>]",
+       N_("git for-each-ref [options] [<pattern>]"),
        NULL
 };
 
@@ -991,19 +991,19 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
 
        struct option opts[] = {
                OPT_BIT('s', "shell", &quote_style,
-                       "quote placeholders suitably for shells", QUOTE_SHELL),
+                       N_("quote placeholders suitably for shells"), QUOTE_SHELL),
                OPT_BIT('p', "perl",  &quote_style,
-                       "quote placeholders suitably for perl", QUOTE_PERL),
+                       N_("quote placeholders suitably for perl"), QUOTE_PERL),
                OPT_BIT(0 , "python", &quote_style,
-                       "quote placeholders suitably for python", QUOTE_PYTHON),
+                       N_("quote placeholders suitably for python"), QUOTE_PYTHON),
                OPT_BIT(0 , "tcl",  &quote_style,
-                       "quote placeholders suitably for tcl", QUOTE_TCL),
+                       N_("quote placeholders suitably for tcl"), QUOTE_TCL),
 
                OPT_GROUP(""),
-               OPT_INTEGER( 0 , "count", &maxcount, "show only <n> matched refs"),
-               OPT_STRING(  0 , "format", &format, "format", "format to use for the output"),
-               OPT_CALLBACK(0 , "sort", sort_tail, "key",
-                           "field name to sort on", &opt_parse_sort),
+               OPT_INTEGER( 0 , "count", &maxcount, N_("show only <n> matched refs")),
+               OPT_STRING(  0 , "format", &format, N_("format"), N_("format to use for the output")),
+               OPT_CALLBACK(0 , "sort", sort_tail, N_("key"),
+                           N_("field name to sort on"), &opt_parse_sort),
                OPT_END(),
        };
 
index a710227a64a9862c0a70f3022f901fc65b0c7f90..bb9a2cd44722dc27d54aa5451278a10f512becb8 100644 (file)
@@ -605,23 +605,23 @@ static int fsck_cache_tree(struct cache_tree *it)
 }
 
 static char const * const fsck_usage[] = {
-       "git fsck [options] [<object>...]",
+       N_("git fsck [options] [<object>...]"),
        NULL
 };
 
 static struct option fsck_opts[] = {
-       OPT__VERBOSE(&verbose, "be verbose"),
-       OPT_BOOLEAN(0, "unreachable", &show_unreachable, "show unreachable objects"),
-       OPT_BOOL(0, "dangling", &show_dangling, "show dangling objects"),
-       OPT_BOOLEAN(0, "tags", &show_tags, "report tags"),
-       OPT_BOOLEAN(0, "root", &show_root, "report root nodes"),
-       OPT_BOOLEAN(0, "cache", &keep_cache_objects, "make index objects head nodes"),
-       OPT_BOOLEAN(0, "reflogs", &include_reflogs, "make reflogs head nodes (default)"),
-       OPT_BOOLEAN(0, "full", &check_full, "also consider packs and alternate objects"),
-       OPT_BOOLEAN(0, "strict", &check_strict, "enable more strict checking"),
+       OPT__VERBOSE(&verbose, N_("be verbose")),
+       OPT_BOOLEAN(0, "unreachable", &show_unreachable, N_("show unreachable objects")),
+       OPT_BOOL(0, "dangling", &show_dangling, N_("show dangling objects")),
+       OPT_BOOLEAN(0, "tags", &show_tags, N_("report tags")),
+       OPT_BOOLEAN(0, "root", &show_root, N_("report root nodes")),
+       OPT_BOOLEAN(0, "cache", &keep_cache_objects, N_("make index objects head nodes")),
+       OPT_BOOLEAN(0, "reflogs", &include_reflogs, N_("make reflogs head nodes (default)")),
+       OPT_BOOLEAN(0, "full", &check_full, N_("also consider packs and alternate objects")),
+       OPT_BOOLEAN(0, "strict", &check_strict, N_("enable more strict checking")),
        OPT_BOOLEAN(0, "lost-found", &write_lost_and_found,
-                               "write dangling objects in .git/lost-found"),
-       OPT_BOOL(0, "progress", &show_progress, "show progress"),
+                               N_("write dangling objects in .git/lost-found")),
+       OPT_BOOL(0, "progress", &show_progress, N_("show progress")),
        OPT_END(),
 };
 
index 9b4232c8f30715327342c3d86c027d04c2a44c94..6be6c8d65b26c9149aac2b6c1de6e3217c6ceea7 100644 (file)
@@ -19,7 +19,7 @@
 #define FAILED_RUN "failed to run %s"
 
 static const char * const builtin_gc_usage[] = {
-       "git gc [options]",
+       N_("git gc [options]"),
        NULL
 };
 
@@ -174,12 +174,12 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
        int quiet = 0;
 
        struct option builtin_gc_options[] = {
-               OPT__QUIET(&quiet, "suppress progress reporting"),
-               { OPTION_STRING, 0, "prune", &prune_expire, "date",
-                       "prune unreferenced objects",
+               OPT__QUIET(&quiet, N_("suppress progress reporting")),
+               { OPTION_STRING, 0, "prune", &prune_expire, N_("date"),
+                       N_("prune unreferenced objects"),
                        PARSE_OPT_OPTARG, NULL, (intptr_t)prune_expire },
-               OPT_BOOLEAN(0, "aggressive", &aggressive, "be more thorough (increased runtime)"),
-               OPT_BOOLEAN(0, "auto", &auto_gc, "enable auto-gc mode"),
+               OPT_BOOLEAN(0, "aggressive", &aggressive, N_("be more thorough (increased runtime)")),
+               OPT_BOOLEAN(0, "auto", &auto_gc, N_("enable auto-gc mode")),
                OPT_END()
        };
 
@@ -217,9 +217,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
                 */
                if (!need_to_gc())
                        return 0;
-               if (quiet)
-                       fprintf(stderr, _("Auto packing the repository for optimum performance.\n"));
-               else
+               if (!quiet)
                        fprintf(stderr,
                                        _("Auto packing the repository for optimum performance. You may also\n"
                                        "run \"git gc\" manually. See "
index 29adb0ac9399002b07942711863fa3b353926468..0e1b6c860e18c6c47f343fad885cbd24f641862e 100644 (file)
@@ -19,7 +19,7 @@
 #include "dir.h"
 
 static char const * const grep_usage[] = {
-       "git grep [options] [-e] <pattern> [<rev>...] [[--] <path>...]",
+       N_("git grep [options] [-e] <pattern> [<rev>...] [[--] <path>...]"),
        NULL
 };
 
@@ -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;
@@ -209,6 +209,7 @@ static void start_threads(struct grep_opt *opt)
                int err;
                struct grep_opt *o = grep_opt_dup(opt);
                o->output = strbuf_out;
+               o->debug = 0;
                compile_grep_patterns(o);
                err = pthread_create(&threads[i], NULL, run, o);
 
@@ -260,51 +261,12 @@ static int wait_all(void)
 }
 #endif
 
-static int grep_config(const char *var, const char *value, void *cb)
+static int grep_cmd_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->regflags |= REG_EXTENDED;
-               else
-                       opt->regflags &= ~REG_EXTENDED;
-               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)
@@ -318,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;
 
@@ -332,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
@@ -341,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);
 
@@ -361,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
@@ -370,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);
 
@@ -426,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);
@@ -444,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;
@@ -465,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;
@@ -480,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);
@@ -495,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;
@@ -518,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;
@@ -669,95 +636,88 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
        int i;
        int dummy;
        int use_index = 1;
-       enum {
-               pattern_type_unspecified = 0,
-               pattern_type_bre,
-               pattern_type_ere,
-               pattern_type_fixed,
-               pattern_type_pcre,
-       };
-       int pattern_type = pattern_type_unspecified;
+       int pattern_type_arg = GREP_PATTERN_TYPE_UNSPECIFIED;
 
        struct option options[] = {
                OPT_BOOLEAN(0, "cached", &cached,
-                       "search in index instead of in the work tree"),
+                       N_("search in index instead of in the work tree")),
                OPT_NEGBIT(0, "no-index", &use_index,
-                        "finds in contents not managed by git", 1),
+                        N_("find in contents not managed by git"), 1),
                OPT_BOOLEAN(0, "untracked", &untracked,
-                       "search in both tracked and untracked files"),
+                       N_("search in both tracked and untracked files")),
                OPT_SET_INT(0, "exclude-standard", &opt_exclude,
-                           "search also in ignored files", 1),
+                           N_("search also in ignored files"), 1),
                OPT_GROUP(""),
                OPT_BOOLEAN('v', "invert-match", &opt.invert,
-                       "show non-matching lines"),
+                       N_("show non-matching lines")),
                OPT_BOOLEAN('i', "ignore-case", &opt.ignore_case,
-                       "case insensitive matching"),
+                       N_("case insensitive matching")),
                OPT_BOOLEAN('w', "word-regexp", &opt.word_regexp,
-                       "match patterns only at word boundaries"),
+                       N_("match patterns only at word boundaries")),
                OPT_SET_INT('a', "text", &opt.binary,
-                       "process binary files as text", GREP_BINARY_TEXT),
+                       N_("process binary files as text"), GREP_BINARY_TEXT),
                OPT_SET_INT('I', NULL, &opt.binary,
-                       "don't match patterns in binary files",
+                       N_("don't match patterns in binary files"),
                        GREP_BINARY_NOMATCH),
-               { OPTION_INTEGER, 0, "max-depth", &opt.max_depth, "depth",
-                       "descend at most <depth> levels", PARSE_OPT_NONEG,
+               { OPTION_INTEGER, 0, "max-depth", &opt.max_depth, N_("depth"),
+                       N_("descend at most <depth> levels"), PARSE_OPT_NONEG,
                        NULL, 1 },
                OPT_GROUP(""),
-               OPT_SET_INT('E', "extended-regexp", &pattern_type,
-                           "use extended POSIX regular expressions",
-                           pattern_type_ere),
-               OPT_SET_INT('G', "basic-regexp", &pattern_type,
-                           "use basic POSIX regular expressions (default)",
-                           pattern_type_bre),
-               OPT_SET_INT('F', "fixed-strings", &pattern_type,
-                           "interpret patterns as fixed strings",
-                           pattern_type_fixed),
-               OPT_SET_INT('P', "perl-regexp", &pattern_type,
-                           "use Perl-compatible regular expressions",
-                           pattern_type_pcre),
+               OPT_SET_INT('E', "extended-regexp", &pattern_type_arg,
+                           N_("use extended POSIX regular expressions"),
+                           GREP_PATTERN_TYPE_ERE),
+               OPT_SET_INT('G', "basic-regexp", &pattern_type_arg,
+                           N_("use basic POSIX regular expressions (default)"),
+                           GREP_PATTERN_TYPE_BRE),
+               OPT_SET_INT('F', "fixed-strings", &pattern_type_arg,
+                           N_("interpret patterns as fixed strings"),
+                           GREP_PATTERN_TYPE_FIXED),
+               OPT_SET_INT('P', "perl-regexp", &pattern_type_arg,
+                           N_("use Perl-compatible regular expressions"),
+                           GREP_PATTERN_TYPE_PCRE),
                OPT_GROUP(""),
-               OPT_BOOLEAN('n', "line-number", &opt.linenum, "show line numbers"),
-               OPT_NEGBIT('h', NULL, &opt.pathname, "don't show filenames", 1),
-               OPT_BIT('H', NULL, &opt.pathname, "show filenames", 1),
+               OPT_BOOLEAN('n', "line-number", &opt.linenum, N_("show line numbers")),
+               OPT_NEGBIT('h', NULL, &opt.pathname, N_("don't show filenames"), 1),
+               OPT_BIT('H', NULL, &opt.pathname, N_("show filenames"), 1),
                OPT_NEGBIT(0, "full-name", &opt.relative,
-                       "show filenames relative to top directory", 1),
+                       N_("show filenames relative to top directory"), 1),
                OPT_BOOLEAN('l', "files-with-matches", &opt.name_only,
-                       "show only filenames instead of matching lines"),
+                       N_("show only filenames instead of matching lines")),
                OPT_BOOLEAN(0, "name-only", &opt.name_only,
-                       "synonym for --files-with-matches"),
+                       N_("synonym for --files-with-matches")),
                OPT_BOOLEAN('L', "files-without-match",
                        &opt.unmatch_name_only,
-                       "show only the names of files without match"),
+                       N_("show only the names of files without match")),
                OPT_BOOLEAN('z', "null", &opt.null_following_name,
-                       "print NUL after filenames"),
+                       N_("print NUL after filenames")),
                OPT_BOOLEAN('c', "count", &opt.count,
-                       "show the number of matches instead of matching lines"),
-               OPT__COLOR(&opt.color, "highlight matches"),
+                       N_("show the number of matches instead of matching lines")),
+               OPT__COLOR(&opt.color, N_("highlight matches")),
                OPT_BOOLEAN(0, "break", &opt.file_break,
-                       "print empty line between matches from different files"),
+                       N_("print empty line between matches from different files")),
                OPT_BOOLEAN(0, "heading", &opt.heading,
-                       "show filename only once above matches from same file"),
+                       N_("show filename only once above matches from same file")),
                OPT_GROUP(""),
-               OPT_CALLBACK('C', "context", &opt, "n",
-                       "show <n> context lines before and after matches",
+               OPT_CALLBACK('C', "context", &opt, N_("n"),
+                       N_("show <n> context lines before and after matches"),
                        context_callback),
                OPT_INTEGER('B', "before-context", &opt.pre_context,
-                       "show <n> context lines before matches"),
+                       N_("show <n> context lines before matches")),
                OPT_INTEGER('A', "after-context", &opt.post_context,
-                       "show <n> context lines after matches"),
-               OPT_NUMBER_CALLBACK(&opt, "shortcut for -C NUM",
+                       N_("show <n> context lines after matches")),
+               OPT_NUMBER_CALLBACK(&opt, N_("shortcut for -C NUM"),
                        context_callback),
                OPT_BOOLEAN('p', "show-function", &opt.funcname,
-                       "show a line with the function name before matches"),
+                       N_("show a line with the function name before matches")),
                OPT_BOOLEAN('W', "function-context", &opt.funcbody,
-                       "show the surrounding function"),
+                       N_("show the surrounding function")),
                OPT_GROUP(""),
-               OPT_CALLBACK('f', NULL, &opt, "file",
-                       "read patterns from file", file_callback),
-               { OPTION_CALLBACK, 'e', NULL, &opt, "pattern",
-                       "match <pattern>", PARSE_OPT_NONEG, pattern_callback },
+               OPT_CALLBACK('f', NULL, &opt, N_("file"),
+                       N_("read patterns from file"), file_callback),
+               { OPTION_CALLBACK, 'e', NULL, &opt, N_("pattern"),
+                       N_("match <pattern>"), PARSE_OPT_NONEG, pattern_callback },
                { OPTION_CALLBACK, 0, "and", &opt, NULL,
-                 "combine patterns specified with -e",
+                 N_("combine patterns specified with -e"),
                  PARSE_OPT_NOARG | PARSE_OPT_NONEG, and_callback },
                OPT_BOOLEAN(0, "or", &dummy, ""),
                { OPTION_CALLBACK, 0, "not", &opt, NULL, "",
@@ -769,16 +729,19 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
                  PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH,
                  close_callback },
                OPT__QUIET(&opt.status_only,
-                          "indicate hit with exit status without output"),
+                          N_("indicate hit with exit status without output")),
                OPT_BOOLEAN(0, "all-match", &opt.all_match,
-                       "show only matches from files that match all patterns"),
+                       N_("show only matches from files that match all patterns")),
+               { OPTION_SET_INT, 0, "debug", &opt.debug, NULL,
+                 N_("show parse tree for grep expression"),
+                 PARSE_OPT_NOARG | PARSE_OPT_HIDDEN, NULL, 1 },
                OPT_GROUP(""),
                { OPTION_STRING, 'O', "open-files-in-pager", &show_in_pager,
-                       "pager", "show matching files in the pager",
+                       N_("pager"), N_("show matching files in the pager"),
                        PARSE_OPT_OPTARG, NULL, (intptr_t)default_pager },
                OPT_BOOLEAN(0, "ext-grep", &external_grep_allowed__ignored,
-                           "allow calling of grep(1) (ignored by this build)"),
-               { OPTION_CALLBACK, 0, "help-all", &options, NULL, "show usage",
+                           N_("allow calling of grep(1) (ignored by this build)")),
+               { OPTION_CALLBACK, 0, "help-all", &options, NULL, N_("show usage"),
                  PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, help_callback },
                OPT_END()
        };
@@ -790,25 +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;
-
-       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
@@ -824,28 +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);
-       switch (pattern_type) {
-       case pattern_type_fixed:
-               opt.fixed = 1;
-               opt.pcre = 0;
-               break;
-       case pattern_type_bre:
-               opt.fixed = 0;
-               opt.pcre = 0;
-               opt.regflags &= ~REG_EXTENDED;
-               break;
-       case pattern_type_ere:
-               opt.fixed = 0;
-               opt.pcre = 0;
-               opt.regflags |= REG_EXTENDED;
-               break;
-       case pattern_type_pcre:
-               opt.fixed = 0;
-               opt.pcre = 1;
-               break;
-       default:
-               break; /* nothing */
-       }
+       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 33911fd5e9325210dae63b3252fa3b56d42b545c..8d184f1a99120b1ebccac4f5e1d4fdb0a692b3c9 100644 (file)
@@ -57,8 +57,8 @@ static void hash_stdin_paths(const char *type, int write_objects)
 }
 
 static const char * const hash_object_usage[] = {
-       "git hash-object [-t <type>] [-w] [--path=<file>|--no-filters] [--stdin] [--] <file>...",
-       "git hash-object  --stdin-paths < <list-of-paths>",
+       N_("git hash-object [-t <type>] [-w] [--path=<file>|--no-filters] [--stdin] [--] <file>..."),
+       N_("git hash-object  --stdin-paths < <list-of-paths>"),
        NULL
 };
 
@@ -69,12 +69,12 @@ static int stdin_paths;
 static const char *vpath;
 
 static const struct option hash_object_options[] = {
-       OPT_STRING('t', NULL, &type, "type", "object type"),
-       OPT_BOOLEAN('w', NULL, &write_object, "write the object into the object database"),
-       OPT_BOOLEAN( 0 , "stdin", &hashstdin, "read the object from stdin"),
-       OPT_BOOLEAN( 0 , "stdin-paths", &stdin_paths, "read file names from stdin"),
-       OPT_BOOLEAN( 0 , "no-filters", &no_filters, "store file as is without filters"),
-       OPT_STRING( 0 , "path", &vpath, "file", "process file as it were from this path"),
+       OPT_STRING('t', NULL, &type, N_("type"), N_("object type")),
+       OPT_BOOLEAN('w', NULL, &write_object, N_("write the object into the object database")),
+       OPT_BOOLEAN( 0 , "stdin", &hashstdin, N_("read the object from stdin")),
+       OPT_BOOLEAN( 0 , "stdin-paths", &stdin_paths, N_("read file names from stdin")),
+       OPT_BOOLEAN( 0 , "no-filters", &no_filters, N_("store file as is without filters")),
+       OPT_STRING( 0 , "path", &vpath, N_("file"), N_("process file as it were from this path")),
        OPT_END()
 };
 
index 43d3c84449a57ec7028acb663d4ab4bea134c97e..bd86253d835fce671ed19676e5efeb59a6fc261d 100644 (file)
 #include "column.h"
 #include "help.h"
 
+#ifndef DEFAULT_HELP_FORMAT
+#define DEFAULT_HELP_FORMAT "man"
+#endif
+
 static struct man_viewer_list {
        struct man_viewer_list *next;
        char name[FLEX_ARRAY];
@@ -30,21 +34,23 @@ enum help_format {
        HELP_FORMAT_WEB
 };
 
+static const char *html_path;
+
 static int show_all = 0;
 static unsigned int colopts;
 static enum help_format help_format = HELP_FORMAT_NONE;
 static struct option builtin_help_options[] = {
-       OPT_BOOLEAN('a', "all", &show_all, "print all available commands"),
-       OPT_SET_INT('m', "man", &help_format, "show man page", HELP_FORMAT_MAN),
-       OPT_SET_INT('w', "web", &help_format, "show manual in web browser",
+       OPT_BOOLEAN('a', "all", &show_all, N_("print all available commands")),
+       OPT_SET_INT('m', "man", &help_format, N_("show man page"), HELP_FORMAT_MAN),
+       OPT_SET_INT('w', "web", &help_format, N_("show manual in web browser"),
                        HELP_FORMAT_WEB),
-       OPT_SET_INT('i', "info", &help_format, "show info page",
+       OPT_SET_INT('i', "info", &help_format, N_("show info page"),
                        HELP_FORMAT_INFO),
        OPT_END(),
 };
 
 static const char * const builtin_help_usage[] = {
-       "git help [--all] [--man|--web|--info] [command]",
+       N_("git help [--all] [--man|--web|--info] [command]"),
        NULL
 };
 
@@ -261,6 +267,12 @@ static int git_help_config(const char *var, const char *value, void *cb)
                help_format = parse_help_format(value);
                return 0;
        }
+       if (!strcmp(var, "help.htmlpath")) {
+               if (!value)
+                       return config_error_nonbool(var);
+               html_path = xstrdup(value);
+               return 0;
+       }
        if (!strcmp(var, "man.viewer")) {
                if (!value)
                        return config_error_nonbool(var);
@@ -383,12 +395,15 @@ static void show_info_page(const char *git_cmd)
 static void get_html_page_path(struct strbuf *page_path, const char *page)
 {
        struct stat st;
-       const char *html_path = system_path(GIT_HTML_PATH);
+       if (!html_path)
+               html_path = system_path(GIT_HTML_PATH);
 
        /* Check that we have a git documentation directory. */
-       if (stat(mkpath("%s/git.html", html_path), &st)
-           || !S_ISREG(st.st_mode))
-               die(_("'%s': not a documentation directory."), html_path);
+       if (!strstr(html_path, "://")) {
+               if (stat(mkpath("%s/git.html", html_path), &st)
+                   || !S_ISREG(st.st_mode))
+                       die("'%s': not a documentation directory.", html_path);
+       }
 
        strbuf_init(page_path, 0);
        strbuf_addf(page_path, "%s/%s.html", html_path, page);
@@ -447,6 +462,8 @@ int cmd_help(int argc, const char **argv, const char *prefix)
 
        if (parsed_help_format != HELP_FORMAT_NONE)
                help_format = parsed_help_format;
+       if (help_format == HELP_FORMAT_NONE)
+               help_format = parse_help_format(DEFAULT_HELP_FORMAT);
 
        alias = alias_lookup(argv[0]);
        if (alias && !is_git_command(argv[0])) {
index 470547835ca41888817b85dc4b7ed39273ede784..43d364b8d5e5b0cb4b78be517e78d64c96da4304 100644 (file)
@@ -9,6 +9,7 @@
 #include "progress.h"
 #include "fsck.h"
 #include "exec_cmd.h"
+#include "streaming.h"
 #include "thread-utils.h"
 
 static const char index_pack_usage[] =
@@ -290,7 +291,7 @@ static void parse_pack_header(void)
        if (hdr->hdr_signature != htonl(PACK_SIGNATURE))
                die(_("pack signature mismatch"));
        if (!pack_version_ok(hdr->hdr_version))
-               die("pack version %"PRIu32" unsupported",
+               die(_("pack version %"PRIu32" unsupported"),
                        ntohl(hdr->hdr_version));
 
        nr_objects = ntohl(hdr->hdr_entries);
@@ -384,30 +385,62 @@ static void unlink_base_data(struct base_data *c)
        free_base_data(c);
 }
 
-static void *unpack_entry_data(unsigned long offset, unsigned long size)
+static int is_delta_type(enum object_type type)
+{
+       return (type == OBJ_REF_DELTA || type == OBJ_OFS_DELTA);
+}
+
+static void *unpack_entry_data(unsigned long offset, unsigned long size,
+                              enum object_type type, unsigned char *sha1)
 {
+       static char fixed_buf[8192];
        int status;
        git_zstream stream;
-       void *buf = xmalloc(size);
+       void *buf;
+       git_SHA_CTX c;
+       char hdr[32];
+       int hdrlen;
+
+       if (!is_delta_type(type)) {
+               hdrlen = sprintf(hdr, "%s %lu", typename(type), size) + 1;
+               git_SHA1_Init(&c);
+               git_SHA1_Update(&c, hdr, hdrlen);
+       } else
+               sha1 = NULL;
+       if (type == OBJ_BLOB && size > big_file_threshold)
+               buf = fixed_buf;
+       else
+               buf = xmalloc(size);
 
        memset(&stream, 0, sizeof(stream));
        git_inflate_init(&stream);
        stream.next_out = buf;
-       stream.avail_out = size;
+       stream.avail_out = buf == fixed_buf ? sizeof(fixed_buf) : size;
 
        do {
+               unsigned char *last_out = stream.next_out;
                stream.next_in = fill(1);
                stream.avail_in = input_len;
                status = git_inflate(&stream, 0);
                use(input_len - stream.avail_in);
+               if (sha1)
+                       git_SHA1_Update(&c, last_out, stream.next_out - last_out);
+               if (buf == fixed_buf) {
+                       stream.next_out = buf;
+                       stream.avail_out = sizeof(fixed_buf);
+               }
        } while (status == Z_OK);
        if (stream.total_out != size || status != Z_STREAM_END)
                bad_object(offset, _("inflate returned %d"), status);
        git_inflate_end(&stream);
-       return buf;
+       if (sha1)
+               git_SHA1_Final(sha1, &c);
+       return buf == fixed_buf ? NULL : buf;
 }
 
-static void *unpack_raw_entry(struct object_entry *obj, union delta_base *delta_base)
+static void *unpack_raw_entry(struct object_entry *obj,
+                             union delta_base *delta_base,
+                             unsigned char *sha1)
 {
        unsigned char *p;
        unsigned long size, c;
@@ -467,12 +500,14 @@ static void *unpack_raw_entry(struct object_entry *obj, union delta_base *delta_
        }
        obj->hdr_size = consumed_bytes - obj->idx.offset;
 
-       data = unpack_entry_data(obj->idx.offset, obj->size);
+       data = unpack_entry_data(obj->idx.offset, obj->size, obj->type, sha1);
        obj->idx.crc32 = input_crc32;
        return data;
 }
 
-static void *get_data_from_pack(struct object_entry *obj)
+static void *unpack_data(struct object_entry *obj,
+                        int (*consume)(const unsigned char *, unsigned long, void *),
+                        void *cb_data)
 {
        off_t from = obj[0].idx.offset + obj[0].hdr_size;
        unsigned long len = obj[1].idx.offset - from;
@@ -480,13 +515,13 @@ static void *get_data_from_pack(struct object_entry *obj)
        git_zstream stream;
        int status;
 
-       data = xmalloc(obj->size);
+       data = xmalloc(consume ? 64*1024 : obj->size);
        inbuf = xmalloc((len < 64*1024) ? len : 64*1024);
 
        memset(&stream, 0, sizeof(stream));
        git_inflate_init(&stream);
        stream.next_out = data;
-       stream.avail_out = obj->size;
+       stream.avail_out = consume ? 64*1024 : obj->size;
 
        do {
                ssize_t n = (len < 64*1024) ? len : 64*1024;
@@ -502,7 +537,20 @@ static void *get_data_from_pack(struct object_entry *obj)
                len -= n;
                stream.next_in = inbuf;
                stream.avail_in = n;
-               status = git_inflate(&stream, 0);
+               if (!consume)
+                       status = git_inflate(&stream, 0);
+               else {
+                       do {
+                               status = git_inflate(&stream, 0);
+                               if (consume(data, stream.next_out - data, cb_data)) {
+                                       free(inbuf);
+                                       free(data);
+                                       return NULL;
+                               }
+                               stream.next_out = data;
+                               stream.avail_out = 64*1024;
+                       } while (status == Z_OK && stream.avail_in);
+               }
        } while (len && status == Z_OK && !stream.avail_in);
 
        /* This has been inflated OK when first encountered, so... */
@@ -511,9 +559,18 @@ static void *get_data_from_pack(struct object_entry *obj)
 
        git_inflate_end(&stream);
        free(inbuf);
+       if (consume) {
+               free(data);
+               data = NULL;
+       }
        return data;
 }
 
+static void *get_data_from_pack(struct object_entry *obj)
+{
+       return unpack_data(obj, NULL, NULL);
+}
+
 static int compare_delta_bases(const union delta_base *base1,
                               const union delta_base *base2,
                               enum object_type type1,
@@ -568,25 +625,102 @@ static void find_delta_children(const union delta_base *base,
        *last_index = last;
 }
 
-static void sha1_object(const void *data, unsigned long size,
-                       enum object_type type, unsigned char *sha1)
+struct compare_data {
+       struct object_entry *entry;
+       struct git_istream *st;
+       unsigned char *buf;
+       unsigned long buf_size;
+};
+
+static int compare_objects(const unsigned char *buf, unsigned long size,
+                          void *cb_data)
+{
+       struct compare_data *data = cb_data;
+
+       if (data->buf_size < size) {
+               free(data->buf);
+               data->buf = xmalloc(size);
+               data->buf_size = size;
+       }
+
+       while (size) {
+               ssize_t len = read_istream(data->st, data->buf, size);
+               if (len == 0)
+                       die(_("SHA1 COLLISION FOUND WITH %s !"),
+                           sha1_to_hex(data->entry->idx.sha1));
+               if (len < 0)
+                       die(_("unable to read %s"),
+                           sha1_to_hex(data->entry->idx.sha1));
+               if (memcmp(buf, data->buf, len))
+                       die(_("SHA1 COLLISION FOUND WITH %s !"),
+                           sha1_to_hex(data->entry->idx.sha1));
+               size -= len;
+               buf += len;
+       }
+       return 0;
+}
+
+static int check_collison(struct object_entry *entry)
+{
+       struct compare_data data;
+       enum object_type type;
+       unsigned long size;
+
+       if (entry->size <= big_file_threshold || entry->type != OBJ_BLOB)
+               return -1;
+
+       memset(&data, 0, sizeof(data));
+       data.entry = entry;
+       data.st = open_istream(entry->idx.sha1, &type, &size, NULL);
+       if (!data.st)
+               return -1;
+       if (size != entry->size || type != entry->type)
+               die(_("SHA1 COLLISION FOUND WITH %s !"),
+                   sha1_to_hex(entry->idx.sha1));
+       unpack_data(entry, compare_objects, &data);
+       close_istream(data.st);
+       free(data.buf);
+       return 0;
+}
+
+static void sha1_object(const void *data, struct object_entry *obj_entry,
+                       unsigned long size, enum object_type type,
+                       const unsigned char *sha1)
 {
-       hash_sha1_file(data, size, typename(type), sha1);
+       void *new_data = NULL;
+       int collision_test_needed;
+
+       assert(data || obj_entry);
+
        read_lock();
-       if (has_sha1_file(sha1)) {
+       collision_test_needed = has_sha1_file(sha1);
+       read_unlock();
+
+       if (collision_test_needed && !data) {
+               read_lock();
+               if (!check_collison(obj_entry))
+                       collision_test_needed = 0;
+               read_unlock();
+       }
+       if (collision_test_needed) {
                void *has_data;
                enum object_type has_type;
                unsigned long has_size;
+               read_lock();
+               has_type = sha1_object_info(sha1, &has_size);
+               if (has_type != type || has_size != size)
+                       die(_("SHA1 COLLISION FOUND WITH %s !"), sha1_to_hex(sha1));
                has_data = read_sha1_file(sha1, &has_type, &has_size);
                read_unlock();
+               if (!data)
+                       data = new_data = get_data_from_pack(obj_entry);
                if (!has_data)
                        die(_("cannot read existing object %s"), sha1_to_hex(sha1));
                if (size != has_size || type != has_type ||
                    memcmp(data, has_data, size) != 0)
                        die(_("SHA1 COLLISION FOUND WITH %s !"), sha1_to_hex(sha1));
                free(has_data);
-       } else
-               read_unlock();
+       }
 
        if (strict) {
                read_lock();
@@ -601,6 +735,9 @@ static void sha1_object(const void *data, unsigned long size,
                        int eaten;
                        void *buf = (void *) data;
 
+                       if (!buf)
+                               buf = new_data = get_data_from_pack(obj_entry);
+
                        /*
                         * we do not need to free the memory here, as the
                         * buf is deleted by the caller.
@@ -625,11 +762,8 @@ static void sha1_object(const void *data, unsigned long size,
                }
                read_unlock();
        }
-}
 
-static int is_delta_type(enum object_type type)
-{
-       return (type == OBJ_REF_DELTA || type == OBJ_OFS_DELTA);
+       free(new_data);
 }
 
 /*
@@ -711,7 +845,9 @@ static void resolve_delta(struct object_entry *delta_obj,
        free(delta_data);
        if (!result->data)
                bad_object(delta_obj->idx.offset, _("failed to apply delta"));
-       sha1_object(result->data, result->size, delta_obj->real_type,
+       hash_sha1_file(result->data, result->size,
+                      typename(delta_obj->real_type), delta_obj->idx.sha1);
+       sha1_object(result->data, NULL, result->size, delta_obj->real_type,
                    delta_obj->idx.sha1);
        counter_lock();
        nr_resolved_deltas++;
@@ -841,7 +977,7 @@ static void *threaded_second_pass(void *data)
  */
 static void parse_pack_objects(unsigned char *sha1)
 {
-       int i;
+       int i, nr_delays = 0;
        struct delta_entry *delta = deltas;
        struct stat st;
 
@@ -851,14 +987,18 @@ static void parse_pack_objects(unsigned char *sha1)
                                nr_objects);
        for (i = 0; i < nr_objects; i++) {
                struct object_entry *obj = &objects[i];
-               void *data = unpack_raw_entry(obj, &delta->base);
+               void *data = unpack_raw_entry(obj, &delta->base, obj->idx.sha1);
                obj->real_type = obj->type;
                if (is_delta_type(obj->type)) {
                        nr_deltas++;
                        delta->obj_no = i;
                        delta++;
+               } else if (!data) {
+                       /* large blobs, check later */
+                       obj->real_type = OBJ_BAD;
+                       nr_delays++;
                } else
-                       sha1_object(data, obj->size, obj->type, obj->idx.sha1);
+                       sha1_object(data, NULL, obj->size, obj->type, obj->idx.sha1);
                free(data);
                display_progress(progress, i+1);
        }
@@ -878,6 +1018,17 @@ static void parse_pack_objects(unsigned char *sha1)
        if (S_ISREG(st.st_mode) &&
                        lseek(input_fd, 0, SEEK_CUR) - input_len != st.st_size)
                die(_("pack has junk at the end"));
+
+       for (i = 0; i < nr_objects; i++) {
+               struct object_entry *obj = &objects[i];
+               if (obj->real_type != OBJ_BAD)
+                       continue;
+               obj->real_type = obj->type;
+               sha1_object(NULL, obj, obj->size, obj->type, obj->idx.sha1);
+               nr_delays--;
+       }
+       if (nr_delays)
+               die(_("confusion beyond insanity in parse_pack_objects()"));
 }
 
 /*
@@ -910,7 +1061,8 @@ static void resolve_deltas(void)
                        int ret = pthread_create(&thread_data[i].thread, NULL,
                                                 threaded_second_pass, thread_data + i);
                        if (ret)
-                               die("unable to create thread: %s", strerror(ret));
+                               die(_("unable to create thread: %s"),
+                                   strerror(ret));
                }
                for (i = 0; i < nr_threads; i++)
                        pthread_join(thread_data[i].thread, NULL);
@@ -957,7 +1109,7 @@ static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned cha
                                   * sizeof(*objects));
                f = sha1fd(output_fd, curr_pack);
                fix_unresolved_deltas(f, nr_unresolved);
-               sprintf(msg, "completed with %d local objects",
+               sprintf(msg, _("completed with %d local objects"),
                        nr_objects - nr_objects_initial);
                stop_progress_msg(&progress, msg);
                sha1close(f, tail_sha1, 0);
@@ -966,8 +1118,8 @@ static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned cha
                                         curr_pack, nr_objects,
                                         read_sha1, consumed_bytes-20);
                if (hashcmp(read_sha1, tail_sha1) != 0)
-                       die("Unexpected tail checksum for %s "
-                           "(disk corruption?)", curr_pack);
+                       die(_("Unexpected tail checksum for %s "
+                             "(disk corruption?)"), curr_pack);
        }
        if (nr_deltas != nr_resolved_deltas)
                die(Q_("pack has %d unresolved delta",
@@ -1176,17 +1328,17 @@ static int git_index_pack_config(const char *k, const char *v, void *cb)
        if (!strcmp(k, "pack.indexversion")) {
                opts->version = git_config_int(k, v);
                if (opts->version > 2)
-                       die("bad pack.indexversion=%"PRIu32, opts->version);
+                       die(_("bad pack.indexversion=%"PRIu32), opts->version);
                return 0;
        }
        if (!strcmp(k, "pack.threads")) {
                nr_threads = git_config_int(k, v);
                if (nr_threads < 0)
-                       die("invalid number of threads specified (%d)",
+                       die(_("invalid number of threads specified (%d)"),
                            nr_threads);
 #ifdef NO_PTHREADS
                if (nr_threads != 1)
-                       warning("no threads support, ignoring %s", k);
+                       warning(_("no threads support, ignoring %s"), k);
                nr_threads = 1;
 #endif
                return 0;
@@ -1359,8 +1511,8 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
                                        usage(index_pack_usage);
 #ifdef NO_PTHREADS
                                if (nr_threads != 1)
-                                       warning("no threads support, "
-                                               "ignoring %s", arg);
+                                       warning(_("no threads support, "
+                                                 "ignoring %s"), arg);
                                nr_threads = 1;
 #endif
                        } else if (!prefixcmp(arg, "--pack_header=")) {
index 0dacb8b79c57cae2b789eb84d7cfbdb1654ba52f..78aa3872dddbba8988b61c49996f9e63719bac75 100644 (file)
@@ -290,6 +290,7 @@ static int create_default_files(const char *template_path)
                strcpy(path + len, "CoNfIg");
                if (!access(path, F_OK))
                        git_config_set("core.ignorecase", "true");
+               probe_utf8_pathname_composition(path, len);
        }
 
        return reinit;
@@ -463,7 +464,7 @@ static int shared_callback(const struct option *opt, const char *arg, int unset)
 }
 
 static const char *const init_db_usage[] = {
-       "git init [-q | --quiet] [--bare] [--template=<template-directory>] [--shared[=<permissions>]] [directory]",
+       N_("git init [-q | --quiet] [--bare] [--template=<template-directory>] [--shared[=<permissions>]] [directory]"),
        NULL
 };
 
@@ -481,17 +482,17 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
        const char *template_dir = NULL;
        unsigned int flags = 0;
        const struct option init_db_options[] = {
-               OPT_STRING(0, "template", &template_dir, "template-directory",
-                               "directory from which templates will be used"),
+               OPT_STRING(0, "template", &template_dir, N_("template-directory"),
+                               N_("directory from which templates will be used")),
                OPT_SET_INT(0, "bare", &is_bare_repository_cfg,
-                               "create a bare repository", 1),
+                               N_("create a bare repository"), 1),
                { OPTION_CALLBACK, 0, "shared", &init_shared_repository,
-                       "permissions",
-                       "specify that the git repository is to be shared amongst several users",
+                       N_("permissions"),
+                       N_("specify that the git repository is to be shared amongst several users"),
                        PARSE_OPT_OPTARG | PARSE_OPT_NONEG, shared_callback, 0},
-               OPT_BIT('q', "quiet", &flags, "be quiet", INIT_DB_QUIET),
-               OPT_STRING(0, "separate-git-dir", &real_git_dir, "gitdir",
-                          "separate git dir from working tree"),
+               OPT_BIT('q', "quiet", &flags, N_("be quiet"), INIT_DB_QUIET),
+               OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"),
+                          N_("separate git dir from working tree")),
                OPT_END()
        };
 
index a8249d3c0137208be8c01c983784bf2b4a130a74..e7b7db1cacf1934a9bb0b96beb98ddda15a66074 100644 (file)
@@ -21,6 +21,7 @@
 #include "parse-options.h"
 #include "branch.h"
 #include "streaming.h"
+#include "version.h"
 
 /* Set a default date-time format for git log ("log.date" config variable) */
 static const char *default_date_mode = NULL;
@@ -33,8 +34,8 @@ static const char *fmt_patch_subject_prefix = "PATCH";
 static const char *fmt_pretty;
 
 static const char * const builtin_log_usage[] = {
-       "git log [<options>] [<since>..<until>] [[--] <path>...]\n"
-       "   or: git show [options] <object>...",
+       N_("git log [<options>] [<since>..<until>] [[--] <path>...]\n")
+       N_("   or: git show [options] <object>..."),
        NULL
 };
 
@@ -96,9 +97,9 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
        int quiet = 0, source = 0;
 
        const struct option builtin_log_options[] = {
-               OPT_BOOLEAN(0, "quiet", &quiet, "suppress diff output"),
-               OPT_BOOLEAN(0, "source", &source, "show source"),
-               { OPTION_CALLBACK, 0, "decorate", NULL, NULL, "decorate options",
+               OPT_BOOLEAN(0, "quiet", &quiet, N_("suppress diff output")),
+               OPT_BOOLEAN(0, "source", &source, N_("show source")),
+               { OPTION_CALLBACK, 0, "decorate", NULL, NULL, N_("decorate options"),
                  PARSE_OPT_OPTARG, decorate_callback},
                OPT_END()
        };
@@ -350,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);
 }
 
@@ -359,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);
@@ -366,6 +369,7 @@ int cmd_whatchanged(int argc, const char **argv, const char *prefix)
        rev.simplify_history = 0;
        memset(&opt, 0, sizeof(opt));
        opt.def = "HEAD";
+       opt.revarg_opt = REVARG_COMMITTISH;
        cmd_log_init(argc, argv, prefix, &rev, &opt);
        if (!rev.diffopt.output_format)
                rev.diffopt.output_format = DIFF_FORMAT_RAW;
@@ -448,13 +452,14 @@ 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);
        init_revisions(&rev, prefix);
        rev.diff = 1;
        rev.always_show_header = 1;
-       rev.no_walk = 1;
+       rev.no_walk = REVISION_WALK_NO_WALK_SORTED;
        rev.diffopt.stat_width = -1;    /* Scale to real terminal size */
 
        memset(&opt, 0, sizeof(opt));
@@ -528,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);
@@ -550,12 +556,14 @@ 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);
        rev.always_show_header = 1;
        memset(&opt, 0, sizeof(opt));
        opt.def = "HEAD";
+       opt.revarg_opt = REVARG_COMMITTISH;
        cmd_log_init(argc, argv, prefix, &rev, &opt);
        return cmd_log_walk(&rev);
 }
@@ -693,7 +701,7 @@ static int reopen_stdout(struct commit *commit, const char *subject,
        return 0;
 }
 
-static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids, const char *prefix)
+static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids)
 {
        struct rev_info check_rev;
        struct commit *commit;
@@ -714,7 +722,8 @@ static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids, const cha
        init_patch_ids(ids);
 
        /* given a range a..b get all patch ids for b..a */
-       init_revisions(&check_rev, prefix);
+       init_revisions(&check_rev, rev->prefix);
+       check_rev.max_parents = 1;
        o1->flags ^= UNINTERESTING;
        o2->flags ^= UNINTERESTING;
        add_pending_object(&check_rev, o1, "o1");
@@ -723,10 +732,6 @@ static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids, const cha
                die(_("revision walk setup failed"));
 
        while ((commit = get_revision(&check_rev)) != NULL) {
-               /* ignore merges */
-               if (commit->parents && commit->parents->next)
-                       continue;
-
                add_commit_patch_id(commit, ids);
        }
 
@@ -887,7 +892,7 @@ static const char *set_outdir(const char *prefix, const char *output_directory)
 }
 
 static const char * const builtin_format_patch_usage[] = {
-       "git format-patch [options] [<since> | <revision range>]",
+       N_("git format-patch [options] [<since> | <revision range>]"),
        NULL
 };
 
@@ -1060,67 +1065,68 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
        char *branch_name = NULL;
        const struct option builtin_format_patch_options[] = {
                { OPTION_CALLBACK, 'n', "numbered", &numbered, NULL,
-                           "use [PATCH n/m] even with a single patch",
+                           N_("use [PATCH n/m] even with a single patch"),
                            PARSE_OPT_NOARG, numbered_callback },
                { OPTION_CALLBACK, 'N', "no-numbered", &numbered, NULL,
-                           "use [PATCH] even with multiple patches",
+                           N_("use [PATCH] even with multiple patches"),
                            PARSE_OPT_NOARG, no_numbered_callback },
-               OPT_BOOLEAN('s', "signoff", &do_signoff, "add Signed-off-by:"),
+               OPT_BOOLEAN('s', "signoff", &do_signoff, N_("add Signed-off-by:")),
                OPT_BOOLEAN(0, "stdout", &use_stdout,
-                           "print patches to standard out"),
+                           N_("print patches to standard out")),
                OPT_BOOLEAN(0, "cover-letter", &cover_letter,
-                           "generate a cover letter"),
+                           N_("generate a cover letter")),
                OPT_BOOLEAN(0, "numbered-files", &numbered_files,
-                           "use simple number sequence for output file names"),
-               OPT_STRING(0, "suffix", &fmt_patch_suffix, "sfx",
-                           "use <sfx> instead of '.patch'"),
+                           N_("use simple number sequence for output file names")),
+               OPT_STRING(0, "suffix", &fmt_patch_suffix, N_("sfx"),
+                           N_("use <sfx> instead of '.patch'")),
                OPT_INTEGER(0, "start-number", &start_number,
-                           "start numbering patches at <n> instead of 1"),
-               { OPTION_CALLBACK, 0, "subject-prefix", &rev, "prefix",
-                           "Use [<prefix>] instead of [PATCH]",
+                           N_("start numbering patches at <n> instead of 1")),
+               { OPTION_CALLBACK, 0, "subject-prefix", &rev, N_("prefix"),
+                           N_("Use [<prefix>] instead of [PATCH]"),
                            PARSE_OPT_NONEG, subject_prefix_callback },
                { OPTION_CALLBACK, 'o', "output-directory", &output_directory,
-                           "dir", "store resulting files in <dir>",
+                           N_("dir"), N_("store resulting files in <dir>"),
                            PARSE_OPT_NONEG, output_directory_callback },
                { OPTION_CALLBACK, 'k', "keep-subject", &rev, NULL,
-                           "don't strip/add [PATCH]",
+                           N_("don't strip/add [PATCH]"),
                            PARSE_OPT_NOARG | PARSE_OPT_NONEG, keep_callback },
                OPT_BOOLEAN(0, "no-binary", &no_binary_diff,
-                           "don't output binary diffs"),
+                           N_("don't output binary diffs")),
                OPT_BOOLEAN(0, "ignore-if-in-upstream", &ignore_if_in_upstream,
-                           "don't include a patch matching a commit upstream"),
+                           N_("don't include a patch matching a commit upstream")),
                { OPTION_BOOLEAN, 'p', "no-stat", &use_patch_format, NULL,
-                 "show patch format instead of default (patch + stat)",
+                 N_("show patch format instead of default (patch + stat)"),
                  PARSE_OPT_NONEG | PARSE_OPT_NOARG },
-               OPT_GROUP("Messaging"),
-               { OPTION_CALLBACK, 0, "add-header", NULL, "header",
-                           "add email header", 0, header_callback },
-               { OPTION_CALLBACK, 0, "to", NULL, "email", "add To: header",
+               OPT_GROUP(N_("Messaging")),
+               { OPTION_CALLBACK, 0, "add-header", NULL, N_("header"),
+                           N_("add email header"), 0, header_callback },
+               { OPTION_CALLBACK, 0, "to", NULL, N_("email"), N_("add To: header"),
                            0, to_callback },
-               { OPTION_CALLBACK, 0, "cc", NULL, "email", "add Cc: header",
+               { OPTION_CALLBACK, 0, "cc", NULL, N_("email"), N_("add Cc: header"),
                            0, cc_callback },
-               OPT_STRING(0, "in-reply-to", &in_reply_to, "message-id",
-                           "make first mail a reply to <message-id>"),
-               { OPTION_CALLBACK, 0, "attach", &rev, "boundary",
-                           "attach the patch", PARSE_OPT_OPTARG,
+               OPT_STRING(0, "in-reply-to", &in_reply_to, N_("message-id"),
+                           N_("make first mail a reply to <message-id>")),
+               { OPTION_CALLBACK, 0, "attach", &rev, N_("boundary"),
+                           N_("attach the patch"), PARSE_OPT_OPTARG,
                            attach_callback },
-               { OPTION_CALLBACK, 0, "inline", &rev, "boundary",
-                           "inline the patch",
+               { OPTION_CALLBACK, 0, "inline", &rev, N_("boundary"),
+                           N_("inline the patch"),
                            PARSE_OPT_OPTARG | PARSE_OPT_NONEG,
                            inline_callback },
-               { OPTION_CALLBACK, 0, "thread", &thread, "style",
-                           "enable message threading, styles: shallow, deep",
+               { OPTION_CALLBACK, 0, "thread", &thread, N_("style"),
+                           N_("enable message threading, styles: shallow, deep"),
                            PARSE_OPT_OPTARG, thread_callback },
-               OPT_STRING(0, "signature", &signature, "signature",
-                           "add a signature"),
+               OPT_STRING(0, "signature", &signature, N_("signature"),
+                           N_("add a signature")),
                OPT_BOOLEAN(0, "quiet", &quiet,
-                           "don't print the patch filenames"),
+                           N_("don't print the patch filenames")),
                OPT_END()
        };
 
        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;
@@ -1131,6 +1137,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
        rev.subject_prefix = fmt_patch_subject_prefix;
        memset(&s_r_opt, 0, sizeof(s_r_opt));
        s_r_opt.def = "HEAD";
+       s_r_opt.revarg_opt = REVARG_COMMITTISH;
 
        if (default_attach) {
                rev.mime_boundary = default_attach;
@@ -1302,7 +1309,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                        if (hashcmp(o[0].item->sha1, o[1].item->sha1) == 0)
                                return 0;
                }
-               get_patch_ids(&rev, &ids, prefix);
+               get_patch_ids(&rev, &ids);
        }
 
        if (!use_stdout)
@@ -1439,7 +1446,7 @@ static int add_pending_commit(const char *arg, struct rev_info *revs, int flags)
 }
 
 static const char * const cherry_usage[] = {
-       "git cherry [-v] [<upstream> [<head> [<limit>]]]",
+       N_("git cherry [-v] [<upstream> [<head> [<limit>]]]"),
        NULL
 };
 
@@ -1473,7 +1480,7 @@ int cmd_cherry(int argc, const char **argv, const char *prefix)
 
        struct option options[] = {
                OPT__ABBREV(&abbrev),
-               OPT__VERBOSE(&verbose, "be verbose"),
+               OPT__VERBOSE(&verbose, N_("be verbose")),
                OPT_END()
        };
 
@@ -1504,10 +1511,7 @@ int cmd_cherry(int argc, const char **argv, const char *prefix)
        }
 
        init_revisions(&revs, prefix);
-       revs.diff = 1;
-       revs.combine_merges = 0;
-       revs.ignore_merges = 1;
-       DIFF_OPT_SET(&revs.diffopt, RECURSIVE);
+       revs.max_parents = 1;
 
        if (add_pending_commit(head, &revs, 0))
                die(_("Unknown commit %s"), head);
@@ -1521,7 +1525,7 @@ int cmd_cherry(int argc, const char **argv, const char *prefix)
                        return 0;
        }
 
-       get_patch_ids(&revs, &ids, prefix);
+       get_patch_ids(&revs, &ids);
 
        if (limit && add_pending_commit(limit, &revs, UNINTERESTING))
                die(_("Unknown commit %s"), limit);
@@ -1530,10 +1534,6 @@ int cmd_cherry(int argc, const char **argv, const char *prefix)
        if (prepare_revision_walk(&revs))
                die(_("revision walk setup failed"));
        while ((commit = get_revision(&revs)) != NULL) {
-               /* ignore merges */
-               if (commit->parents && commit->parents->next)
-                       continue;
-
                commit_list_insert(commit, &list);
        }
 
index 31b3f2d9006e0f5703ca9fb37bea247012581c0e..b5434af0c87741f3160388cf86904c6e3f903527 100644 (file)
@@ -405,7 +405,7 @@ int report_path_error(const char *ps_matched, const char **pathspec, const char
 }
 
 static const char * const ls_files_usage[] = {
-       "git ls-files [options] [<file>...]",
+       N_("git ls-files [options] [<file>...]"),
        NULL
 };
 
@@ -457,57 +457,57 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
        struct dir_struct dir;
        struct option builtin_ls_files_options[] = {
                { OPTION_CALLBACK, 'z', NULL, NULL, NULL,
-                       "paths are separated with NUL character",
+                       N_("paths are separated with NUL character"),
                        PARSE_OPT_NOARG, option_parse_z },
                OPT_BOOLEAN('t', NULL, &show_tag,
-                       "identify the file status with tags"),
+                       N_("identify the file status with tags")),
                OPT_BOOLEAN('v', NULL, &show_valid_bit,
-                       "use lowercase letters for 'assume unchanged' files"),
+                       N_("use lowercase letters for 'assume unchanged' files")),
                OPT_BOOLEAN('c', "cached", &show_cached,
-                       "show cached files in the output (default)"),
+                       N_("show cached files in the output (default)")),
                OPT_BOOLEAN('d', "deleted", &show_deleted,
-                       "show deleted files in the output"),
+                       N_("show deleted files in the output")),
                OPT_BOOLEAN('m', "modified", &show_modified,
-                       "show modified files in the output"),
+                       N_("show modified files in the output")),
                OPT_BOOLEAN('o', "others", &show_others,
-                       "show other files in the output"),
+                       N_("show other files in the output")),
                OPT_BIT('i', "ignored", &dir.flags,
-                       "show ignored files in the output",
+                       N_("show ignored files in the output"),
                        DIR_SHOW_IGNORED),
                OPT_BOOLEAN('s', "stage", &show_stage,
-                       "show staged contents' object name in the output"),
+                       N_("show staged contents' object name in the output")),
                OPT_BOOLEAN('k', "killed", &show_killed,
-                       "show files on the filesystem that need to be removed"),
+                       N_("show files on the filesystem that need to be removed")),
                OPT_BIT(0, "directory", &dir.flags,
-                       "show 'other' directories' name only",
+                       N_("show 'other' directories' name only"),
                        DIR_SHOW_OTHER_DIRECTORIES),
                OPT_NEGBIT(0, "empty-directory", &dir.flags,
-                       "don't show empty directories",
+                       N_("don't show empty directories"),
                        DIR_HIDE_EMPTY_DIRECTORIES),
                OPT_BOOLEAN('u', "unmerged", &show_unmerged,
-                       "show unmerged files in the output"),
+                       N_("show unmerged files in the output")),
                OPT_BOOLEAN(0, "resolve-undo", &show_resolve_undo,
-                           "show resolve-undo information"),
-               { OPTION_CALLBACK, 'x', "exclude", &dir.exclude_list[EXC_CMDL], "pattern",
-                       "skip files matching pattern",
+                           N_("show resolve-undo information")),
+               { OPTION_CALLBACK, 'x', "exclude", &dir.exclude_list[EXC_CMDL], N_("pattern"),
+                       N_("skip files matching pattern"),
                        0, option_parse_exclude },
-               { OPTION_CALLBACK, 'X', "exclude-from", &dir, "file",
-                       "exclude patterns are read from <file>",
+               { OPTION_CALLBACK, 'X', "exclude-from", &dir, N_("file"),
+                       N_("exclude patterns are read from <file>"),
                        0, option_parse_exclude_from },
-               OPT_STRING(0, "exclude-per-directory", &dir.exclude_per_dir, "file",
-                       "read additional per-directory exclude patterns in <file>"),
+               OPT_STRING(0, "exclude-per-directory", &dir.exclude_per_dir, N_("file"),
+                       N_("read additional per-directory exclude patterns in <file>")),
                { OPTION_CALLBACK, 0, "exclude-standard", &dir, NULL,
-                       "add the standard git exclusions",
+                       N_("add the standard git exclusions"),
                        PARSE_OPT_NOARG, option_parse_exclude_standard },
                { OPTION_SET_INT, 0, "full-name", &prefix_len, NULL,
-                       "make the output relative to the project top directory",
+                       N_("make the output relative to the project top directory"),
                        PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL },
                OPT_BOOLEAN(0, "error-unmatch", &error_unmatch,
-                       "if any <file> is not in the index, treat this as an error"),
-               OPT_STRING(0, "with-tree", &with_tree, "tree-ish",
-                       "pretend that paths removed since <tree-ish> are still present"),
+                       N_("if any <file> is not in the index, treat this as an error")),
+               OPT_STRING(0, "with-tree", &with_tree, N_("tree-ish"),
+                       N_("pretend that paths removed since <tree-ish> are still present")),
                OPT__ABBREV(&abbrev),
-               OPT_BOOLEAN(0, "debug", &debug_mode, "show debugging data"),
+               OPT_BOOLEAN(0, "debug", &debug_mode, N_("show debugging data")),
                OPT_END()
        };
 
index 41c88a98a2de1ce817351243f9aa9e2811604097..25e83cfe9de3dc3cee19f03f82b56396eb6b65de 100644 (file)
@@ -5,7 +5,7 @@
 
 static const char ls_remote_usage[] =
 "git ls-remote [--heads] [--tags]  [-u <exec> | --upload-pack <exec>]\n"
-"                     [-q|--quiet] [--exit-code] [<repository> [<refs>...]]";
+"                     [-q|--quiet] [--exit-code] [--get-url] [<repository> [<refs>...]]";
 
 /*
  * Is there one among the list of patterns that match the tail part
index 6b666e1e87017f41d2f53c50b157f280b3a5f282..235c17cc015acfb73358bc5ee5bde712fa2b0fa9 100644 (file)
@@ -24,7 +24,7 @@ static int chomp_prefix;
 static const char *ls_tree_prefix;
 
 static const  char * const ls_tree_usage[] = {
-       "git ls-tree [<options>] <tree-ish> [<path>...]",
+       N_("git ls-tree [<options>] <tree-ish> [<path>...]"),
        NULL
 };
 
@@ -122,25 +122,25 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
        struct tree *tree;
        int i, full_tree = 0;
        const struct option ls_tree_options[] = {
-               OPT_BIT('d', NULL, &ls_options, "only show trees",
+               OPT_BIT('d', NULL, &ls_options, N_("only show trees"),
                        LS_TREE_ONLY),
-               OPT_BIT('r', NULL, &ls_options, "recurse into subtrees",
+               OPT_BIT('r', NULL, &ls_options, N_("recurse into subtrees"),
                        LS_RECURSIVE),
-               OPT_BIT('t', NULL, &ls_options, "show trees when recursing",
+               OPT_BIT('t', NULL, &ls_options, N_("show trees when recursing"),
                        LS_SHOW_TREES),
                OPT_SET_INT('z', NULL, &line_termination,
-                           "terminate entries with NUL byte", 0),
-               OPT_BIT('l', "long", &ls_options, "include object size",
+                           N_("terminate entries with NUL byte"), 0),
+               OPT_BIT('l', "long", &ls_options, N_("include object size"),
                        LS_SHOW_SIZE),
-               OPT_BIT(0, "name-only", &ls_options, "list only filenames",
+               OPT_BIT(0, "name-only", &ls_options, N_("list only filenames"),
                        LS_NAME_ONLY),
-               OPT_BIT(0, "name-status", &ls_options, "list only filenames",
+               OPT_BIT(0, "name-status", &ls_options, N_("list only filenames"),
                        LS_NAME_ONLY),
                OPT_SET_INT(0, "full-name", &chomp_prefix,
-                           "use full path names", 0),
+                           N_("use full path names"), 0),
                OPT_BOOLEAN(0, "full-tree", &full_tree,
-                           "list entire tree; not just current directory "
-                           "(implies --full-name)"),
+                           N_("list entire tree; not just current directory "
+                              "(implies --full-name)")),
                OPT__ABBREV(&abbrev),
                OPT_END()
        };
index eaf9e157a3897c2442756911b906ff9d3ee2be90..da231400b327b86a18a054075f6aee4749846932 100644 (file)
@@ -19,9 +19,6 @@ static struct strbuf email = STRBUF_INIT;
 static enum  {
        TE_DONTCARE, TE_QP, TE_BASE64
 } transfer_encoding;
-static enum  {
-       TYPE_TEXT, TYPE_OTHER
-} message_type;
 
 static struct strbuf charset = STRBUF_INIT;
 static int patch_lines;
@@ -160,10 +157,9 @@ static int slurp_attr(const char *line, const char *name, struct strbuf *attr)
        const char *ends, *ap = strcasestr(line, name);
        size_t sz;
 
-       if (!ap) {
-               strbuf_setlen(attr, 0);
+       strbuf_setlen(attr, 0);
+       if (!ap)
                return 0;
-       }
        ap += strlen(name);
        if (*ap == '"') {
                ap++;
@@ -185,8 +181,6 @@ static void handle_content_type(struct strbuf *line)
        struct strbuf *boundary = xmalloc(sizeof(struct strbuf));
        strbuf_init(boundary, line->len);
 
-       if (!strcasestr(line->buf, "text/"))
-                message_type = TYPE_OTHER;
        if (slurp_attr(line->buf, "boundary=", boundary)) {
                strbuf_insert(boundary, 0, "--", 2);
                if (++content_top > &content[MAX_BOUNDARIES]) {
@@ -232,7 +226,9 @@ static void cleanup_subject(struct strbuf *subject)
                case 'r': case 'R':
                        if (subject->len <= at + 3)
                                break;
-                       if (!memcmp(subject->buf + at + 1, "e:", 2)) {
+                       if ((subject->buf[at + 1] == 'e' ||
+                            subject->buf[at + 1] == 'E') &&
+                           subject->buf[at + 2] == ':') {
                                strbuf_remove(subject, at, 3);
                                continue;
                        }
@@ -481,36 +477,12 @@ static struct strbuf *decode_b_segment(const struct strbuf *b_seg)
        return out;
 }
 
-/*
- * When there is no known charset, guess.
- *
- * Right now we assume that if the target is UTF-8 (the default),
- * and it already looks like UTF-8 (which includes US-ASCII as its
- * subset, of course) then that is what it is and there is nothing
- * to do.
- *
- * Otherwise, we default to assuming it is Latin1 for historical
- * reasons.
- */
-static const char *guess_charset(const struct strbuf *line, const char *target_charset)
-{
-       if (is_encoding_utf8(target_charset)) {
-               if (is_utf8(line->buf))
-                       return NULL;
-       }
-       return "ISO8859-1";
-}
-
 static void convert_to_utf8(struct strbuf *line, const char *charset)
 {
        char *out;
 
-       if (!charset || !*charset) {
-               charset = guess_charset(line, metainfo_charset);
-               if (!charset)
-                       return;
-       }
-
+       if (!charset || !*charset)
+               return;
        if (!strcasecmp(metainfo_charset, charset))
                return;
        out = reencode_string(line->buf, metainfo_charset, charset);
@@ -680,7 +652,6 @@ again:
        /* set some defaults */
        transfer_encoding = TE_DONTCARE;
        strbuf_reset(&charset);
-       message_type = TYPE_TEXT;
 
        /* slurp in this section's info */
        while (read_one_header_line(&line, fin))
@@ -894,11 +865,6 @@ static void handle_body(void)
                        strbuf_insert(&line, 0, prev.buf, prev.len);
                        strbuf_reset(&prev);
 
-                       /* binary data most likely doesn't have newlines */
-                       if (message_type != TYPE_TEXT) {
-                               handle_filter(&line);
-                               break;
-                       }
                        /*
                         * This is a decoded line that may contain
                         * multiple new lines.  Pass only one chunk
index 4f30f1b0c8b14e78e272ec54a86584d66501f754..1bc79910481e6ee04b470620da5609c1c6fbcac4 100644 (file)
@@ -23,9 +23,10 @@ static int show_merge_base(struct commit **rev, int rev_nr, int show_all)
 }
 
 static const char * const merge_base_usage[] = {
-       "git merge-base [-a|--all] <commit> <commit>...",
-       "git merge-base [-a|--all] --octopus <commit>...",
-       "git merge-base --independent <commit>...",
+       N_("git merge-base [-a|--all] <commit> <commit>..."),
+       N_("git merge-base [-a|--all] --octopus <commit>..."),
+       N_("git merge-base --independent <commit>..."),
+       N_("git merge-base --is-ancestor <commit> <commit>"),
        NULL
 };
 
@@ -70,6 +71,20 @@ static int handle_octopus(int count, const char **args, int reduce, int show_all
        return 0;
 }
 
+static int handle_is_ancestor(int argc, const char **argv)
+{
+       struct commit *one, *two;
+
+       if (argc != 2)
+               die("--is-ancestor takes exactly two commits");
+       one = get_commit_reference(argv[0]);
+       two = get_commit_reference(argv[1]);
+       if (in_merge_bases(one, two))
+               return 0;
+       else
+               return 1;
+}
+
 int cmd_merge_base(int argc, const char **argv, const char *prefix)
 {
        struct commit **rev;
@@ -77,11 +92,14 @@ int cmd_merge_base(int argc, const char **argv, const char *prefix)
        int show_all = 0;
        int octopus = 0;
        int reduce = 0;
+       int is_ancestor = 0;
 
        struct option options[] = {
-               OPT_BOOLEAN('a', "all", &show_all, "output all common ancestors"),
-               OPT_BOOLEAN(0, "octopus", &octopus, "find ancestors for a single n-way merge"),
-               OPT_BOOLEAN(0, "independent", &reduce, "list revs not reachable from others"),
+               OPT_BOOLEAN('a', "all", &show_all, N_("output all common ancestors")),
+               OPT_BOOLEAN(0, "octopus", &octopus, N_("find ancestors for a single n-way merge")),
+               OPT_BOOLEAN(0, "independent", &reduce, N_("list revs not reachable from others")),
+               OPT_BOOLEAN(0, "is-ancestor", &is_ancestor,
+                           N_("is the first one ancestor of the other?")),
                OPT_END()
        };
 
@@ -89,6 +107,10 @@ int cmd_merge_base(int argc, const char **argv, const char *prefix)
        argc = parse_options(argc, argv, prefix, options, merge_base_usage, 0);
        if (!octopus && !reduce && argc < 2)
                usage_with_options(merge_base_usage, options);
+       if (is_ancestor && (show_all | octopus | reduce))
+               die("--is-ancestor cannot be used with other options");
+       if (is_ancestor)
+               return handle_is_ancestor(argc, argv);
        if (reduce && (show_all || octopus))
                die("--independent cannot be used with other options");
 
index 6f0efef43c5b93c87fa8f586319cd03c8018bd55..c0570f24072a8e29a13e00a2f4fe1b5054ebac7c 100644 (file)
@@ -5,7 +5,7 @@
 #include "parse-options.h"
 
 static const char *const merge_file_usage[] = {
-       "git merge-file [options] [-L name1 [-L orig [-L name2]]] file1 orig_file file2",
+       N_("git merge-file [options] [-L name1 [-L orig [-L name2]]] file1 orig_file file2"),
        NULL
 };
 
@@ -30,19 +30,19 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
        int quiet = 0;
        int prefixlen = 0;
        struct option options[] = {
-               OPT_BOOLEAN('p', "stdout", &to_stdout, "send results to standard output"),
-               OPT_SET_INT(0, "diff3", &xmp.style, "use a diff3 based merge", XDL_MERGE_DIFF3),
-               OPT_SET_INT(0, "ours", &xmp.favor, "for conflicts, use our version",
+               OPT_BOOLEAN('p', "stdout", &to_stdout, N_("send results to standard output")),
+               OPT_SET_INT(0, "diff3", &xmp.style, N_("use a diff3 based merge"), XDL_MERGE_DIFF3),
+               OPT_SET_INT(0, "ours", &xmp.favor, N_("for conflicts, use our version"),
                            XDL_MERGE_FAVOR_OURS),
-               OPT_SET_INT(0, "theirs", &xmp.favor, "for conflicts, use their version",
+               OPT_SET_INT(0, "theirs", &xmp.favor, N_("for conflicts, use their version"),
                            XDL_MERGE_FAVOR_THEIRS),
-               OPT_SET_INT(0, "union", &xmp.favor, "for conflicts, use a union version",
+               OPT_SET_INT(0, "union", &xmp.favor, N_("for conflicts, use a union version"),
                            XDL_MERGE_FAVOR_UNION),
                OPT_INTEGER(0, "marker-size", &xmp.marker_size,
-                           "for conflicts, use this marker size"),
-               OPT__QUIET(&quiet, "do not warn about conflicts"),
-               OPT_CALLBACK('L', NULL, names, "name",
-                            "set labels for file1/orig_file/file2", &label_cb),
+                           N_("for conflicts, use this marker size")),
+               OPT__QUIET(&quiet, N_("do not warn about conflicts")),
+               OPT_CALLBACK('L', NULL, names, N_("name"),
+                            N_("set labels for file1/orig_file/file2"), &label_cb),
                OPT_END(),
        };
 
index e81fde6d79e8896235c4a3901bc303f6094a9e55..0ec8f0d449e505a52166b560f43f30d8c30cfbaf 100644 (file)
@@ -40,9 +40,9 @@ struct strategy {
 };
 
 static const char * const builtin_merge_usage[] = {
-       "git merge [options] [<commit>...]",
-       "git merge [options] <msg> HEAD <commit>",
-       "git merge --abort",
+       N_("git merge [options] [<commit>...]"),
+       N_("git merge [options] <msg> HEAD <commit>"),
+       N_("git merge --abort"),
        NULL
 };
 
@@ -180,39 +180,39 @@ static int option_parse_n(const struct option *opt,
 
 static struct option builtin_merge_options[] = {
        { OPTION_CALLBACK, 'n', NULL, NULL, NULL,
-               "do not show a diffstat at the end of the merge",
+               N_("do not show a diffstat at the end of the merge"),
                PARSE_OPT_NOARG, option_parse_n },
        OPT_BOOLEAN(0, "stat", &show_diffstat,
-               "show a diffstat at the end of the merge"),
-       OPT_BOOLEAN(0, "summary", &show_diffstat, "(synonym to --stat)"),
-       { OPTION_INTEGER, 0, "log", &shortlog_len, "n",
-         "add (at most <n>) entries from shortlog to merge commit message",
+               N_("show a diffstat at the end of the merge")),
+       OPT_BOOLEAN(0, "summary", &show_diffstat, N_("(synonym to --stat)")),
+       { OPTION_INTEGER, 0, "log", &shortlog_len, N_("n"),
+         N_("add (at most <n>) entries from shortlog to merge commit message"),
          PARSE_OPT_OPTARG, NULL, DEFAULT_MERGE_LOG_LEN },
        OPT_BOOLEAN(0, "squash", &squash,
-               "create a single commit instead of doing a merge"),
+               N_("create a single commit instead of doing a merge")),
        OPT_BOOLEAN(0, "commit", &option_commit,
-               "perform a commit if the merge succeeds (default)"),
+               N_("perform a commit if the merge succeeds (default)")),
        OPT_BOOL('e', "edit", &option_edit,
-               "edit message before committing"),
+               N_("edit message before committing")),
        OPT_BOOLEAN(0, "ff", &allow_fast_forward,
-               "allow fast-forward (default)"),
+               N_("allow fast-forward (default)")),
        OPT_BOOLEAN(0, "ff-only", &fast_forward_only,
-               "abort if fast-forward is not possible"),
+               N_("abort if fast-forward is not possible")),
        OPT_RERERE_AUTOUPDATE(&allow_rerere_auto),
-       OPT_CALLBACK('s', "strategy", &use_strategies, "strategy",
-               "merge strategy to use", option_parse_strategy),
-       OPT_CALLBACK('X', "strategy-option", &xopts, "option=value",
-               "option for selected merge strategy", option_parse_x),
-       OPT_CALLBACK('m', "message", &merge_msg, "message",
-               "merge commit message (for a non-fast-forward merge)",
+       OPT_CALLBACK('s', "strategy", &use_strategies, N_("strategy"),
+               N_("merge strategy to use"), option_parse_strategy),
+       OPT_CALLBACK('X', "strategy-option", &xopts, N_("option=value"),
+               N_("option for selected merge strategy"), option_parse_x),
+       OPT_CALLBACK('m', "message", &merge_msg, N_("message"),
+               N_("merge commit message (for a non-fast-forward merge)"),
                option_parse_message),
        OPT__VERBOSITY(&verbosity),
        OPT_BOOLEAN(0, "abort", &abort_current_merge,
-               "abort the current in-progress merge"),
-       OPT_SET_INT(0, "progress", &show_progress, "force progress reporting", 1),
-       { OPTION_STRING, 'S', "gpg-sign", &sign_commit, "key id",
-         "GPG sign commit", PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
-       OPT_BOOLEAN(0, "overwrite-ignore", &overwrite_ignore, "update ignored files (default)"),
+               N_("abort the current in-progress merge")),
+       OPT_SET_INT(0, "progress", &show_progress, N_("force progress reporting"), 1),
+       { OPTION_STRING, 'S', "gpg-sign", &sign_commit, N_("key id"),
+         N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
+       OPT_BOOLEAN(0, "overwrite-ignore", &overwrite_ignore, N_("update ignored files (default)")),
        OPT_END()
 };
 
index 4ae1c412d47bd581f22ec8b821a1111224dddd28..f92ba404abd5cea0cde344936f697e46c1a46045 100644 (file)
@@ -64,7 +64,7 @@ static void write_tree(unsigned char *sha1)
 }
 
 static const char *mktree_usage[] = {
-       "git mktree [-z] [--missing] [--batch]",
+       N_("git mktree [-z] [--missing] [--batch]"),
        NULL
 };
 
@@ -150,9 +150,9 @@ int cmd_mktree(int ac, const char **av, const char *prefix)
        int got_eof = 0;
 
        const struct option option[] = {
-               OPT_SET_INT('z', NULL, &line_termination, "input is NUL terminated", '\0'),
-               OPT_SET_INT( 0 , "missing", &allow_missing, "allow missing objects", 1),
-               OPT_SET_INT( 0 , "batch", &is_batch_mode, "allow creation of more than one tree", 1),
+               OPT_SET_INT('z', NULL, &line_termination, N_("input is NUL terminated"), '\0'),
+               OPT_SET_INT( 0 , "missing", &allow_missing, N_("allow missing objects"), 1),
+               OPT_SET_INT( 0 , "batch", &is_batch_mode, N_("allow creation of more than one tree"), 1),
                OPT_END()
        };
 
index 2a144b011caa8ecb70f55976bdec60cae89fad9e..034fec92a11d79f28d80171ca86394817084ee09 100644 (file)
@@ -11,7 +11,7 @@
 #include "parse-options.h"
 
 static const char * const builtin_mv_usage[] = {
-       "git mv [options] <source>... <destination>",
+       N_("git mv [options] <source>... <destination>"),
        NULL
 };
 
@@ -59,10 +59,10 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
        int i, newfd;
        int verbose = 0, show_only = 0, force = 0, ignore_errors = 0;
        struct option builtin_mv_options[] = {
-               OPT__VERBOSE(&verbose, "be verbose"),
-               OPT__DRY_RUN(&show_only, "dry run"),
-               OPT__FORCE(&force, "force move/rename even if target exists"),
-               OPT_BOOLEAN('k', NULL, &ignore_errors, "skip move/rename errors"),
+               OPT__VERBOSE(&verbose, N_("be verbose")),
+               OPT__DRY_RUN(&show_only, N_("dry run")),
+               OPT__FORCE(&force, N_("force move/rename even if target exists")),
+               OPT_BOOLEAN('k', NULL, &ignore_errors, N_("skip move/rename errors")),
                OPT_END(),
        };
        const char **source, **destination, **dest_path;
index 1b374583c2751801dfae1d0d1861d28f81c7ad7b..62382479749909d449b718fc2f3bef36906caa4b 100644 (file)
@@ -172,9 +172,9 @@ static void show_name(const struct object *obj,
 }
 
 static char const * const name_rev_usage[] = {
-       "git name-rev [options] <commit>...",
-       "git name-rev [options] --all",
-       "git name-rev [options] --stdin",
+       N_("git name-rev [options] <commit>..."),
+       N_("git name-rev [options] --all"),
+       N_("git name-rev [options] --stdin"),
        NULL
 };
 
@@ -226,16 +226,16 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
        int all = 0, transform_stdin = 0, allow_undefined = 1, always = 0;
        struct name_ref_data data = { 0, 0, NULL };
        struct option opts[] = {
-               OPT_BOOLEAN(0, "name-only", &data.name_only, "print only names (no SHA-1)"),
-               OPT_BOOLEAN(0, "tags", &data.tags_only, "only use tags to name the commits"),
-               OPT_STRING(0, "refs", &data.ref_filter, "pattern",
-                                  "only use refs matching <pattern>"),
+               OPT_BOOLEAN(0, "name-only", &data.name_only, N_("print only names (no SHA-1)")),
+               OPT_BOOLEAN(0, "tags", &data.tags_only, N_("only use tags to name the commits")),
+               OPT_STRING(0, "refs", &data.ref_filter, N_("pattern"),
+                                  N_("only use refs matching <pattern>")),
                OPT_GROUP(""),
-               OPT_BOOLEAN(0, "all", &all, "list all commits reachable from all refs"),
-               OPT_BOOLEAN(0, "stdin", &transform_stdin, "read from stdin"),
-               OPT_BOOLEAN(0, "undefined", &allow_undefined, "allow to print `undefined` names"),
+               OPT_BOOLEAN(0, "all", &all, N_("list all commits reachable from all refs")),
+               OPT_BOOLEAN(0, "stdin", &transform_stdin, N_("read from stdin")),
+               OPT_BOOLEAN(0, "undefined", &allow_undefined, N_("allow to print `undefined` names")),
                OPT_BOOLEAN(0, "always",     &always,
-                          "show abbreviated commit object as fallback"),
+                          N_("show abbreviated commit object as fallback")),
                OPT_END(),
        };
 
index 3644d140ece9f2cfc6381e1a60c5b4fc8f645e2a..453457adb9dedac510c5a95e0e07cb0b4b46c80e 100644 (file)
 #include "string-list.h"
 #include "notes-merge.h"
 
+static void commit_notes(struct notes_tree *t, const char *msg);
+static combine_notes_fn parse_combine_notes_fn(const char *v);
+
 static const char * const git_notes_usage[] = {
-       "git notes [--ref <notes_ref>] [list [<object>]]",
-       "git notes [--ref <notes_ref>] add [-f] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]",
-       "git notes [--ref <notes_ref>] copy [-f] <from-object> <to-object>",
-       "git notes [--ref <notes_ref>] append [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]",
-       "git notes [--ref <notes_ref>] edit [<object>]",
-       "git notes [--ref <notes_ref>] show [<object>]",
-       "git notes [--ref <notes_ref>] merge [-v | -q] [-s <strategy> ] <notes_ref>",
-       "git notes merge --commit [-v | -q]",
-       "git notes merge --abort [-v | -q]",
-       "git notes [--ref <notes_ref>] remove [<object>...]",
-       "git notes [--ref <notes_ref>] prune [-n | -v]",
-       "git notes [--ref <notes_ref>] get-ref",
+       N_("git notes [--ref <notes_ref>] [list [<object>]]"),
+       N_("git notes [--ref <notes_ref>] add [-f] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
+       N_("git notes [--ref <notes_ref>] copy [-f] <from-object> <to-object>"),
+       N_("git notes [--ref <notes_ref>] append [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
+       N_("git notes [--ref <notes_ref>] edit [<object>]"),
+       N_("git notes [--ref <notes_ref>] show [<object>]"),
+       N_("git notes [--ref <notes_ref>] merge [-v | -q] [-s <strategy> ] <notes_ref>"),
+       N_("git notes merge --commit [-v | -q]"),
+       N_("git notes merge --abort [-v | -q]"),
+       N_("git notes [--ref <notes_ref>] remove [<object>...]"),
+       N_("git notes [--ref <notes_ref>] prune [-n | -v]"),
+       N_("git notes [--ref <notes_ref>] get-ref"),
        NULL
 };
 
 static const char * const git_notes_list_usage[] = {
-       "git notes [list [<object>]]",
+       N_("git notes [list [<object>]]"),
        NULL
 };
 
 static const char * const git_notes_add_usage[] = {
-       "git notes add [<options>] [<object>]",
+       N_("git notes add [<options>] [<object>]"),
        NULL
 };
 
 static const char * const git_notes_copy_usage[] = {
-       "git notes copy [<options>] <from-object> <to-object>",
-       "git notes copy --stdin [<from-object> <to-object>]...",
+       N_("git notes copy [<options>] <from-object> <to-object>"),
+       N_("git notes copy --stdin [<from-object> <to-object>]..."),
        NULL
 };
 
 static const char * const git_notes_append_usage[] = {
-       "git notes append [<options>] [<object>]",
+       N_("git notes append [<options>] [<object>]"),
        NULL
 };
 
 static const char * const git_notes_edit_usage[] = {
-       "git notes edit [<object>]",
+       N_("git notes edit [<object>]"),
        NULL
 };
 
 static const char * const git_notes_show_usage[] = {
-       "git notes show [<object>]",
+       N_("git notes show [<object>]"),
        NULL
 };
 
 static const char * const git_notes_merge_usage[] = {
-       "git notes merge [<options>] <notes_ref>",
-       "git notes merge --commit [<options>]",
-       "git notes merge --abort [<options>]",
+       N_("git notes merge [<options>] <notes_ref>"),
+       N_("git notes merge --commit [<options>]"),
+       N_("git notes merge --abort [<options>]"),
        NULL
 };
 
 static const char * const git_notes_remove_usage[] = {
-       "git notes remove [<object>]",
+       N_("git notes remove [<object>]"),
        NULL
 };
 
 static const char * const git_notes_prune_usage[] = {
-       "git notes prune [<options>]",
+       N_("git notes prune [<options>]"),
        NULL
 };
 
 static const char * const git_notes_get_ref_usage[] = {
-       "git notes get-ref",
+       N_("git notes get-ref"),
        NULL
 };
 
@@ -288,7 +291,7 @@ static int parse_reedit_arg(const struct option *opt, const char *arg, int unset
        return parse_reuse_arg(opt, arg, unset);
 }
 
-void commit_notes(struct notes_tree *t, const char *msg)
+static void commit_notes(struct notes_tree *t, const char *msg)
 {
        struct strbuf buf = STRBUF_INIT;
        unsigned char commit_sha1[20];
@@ -312,7 +315,7 @@ void commit_notes(struct notes_tree *t, const char *msg)
        strbuf_release(&buf);
 }
 
-combine_notes_fn parse_combine_notes_fn(const char *v)
+static combine_notes_fn parse_combine_notes_fn(const char *v)
 {
        if (!strcasecmp(v, "overwrite"))
                return combine_notes_overwrite;
@@ -531,19 +534,19 @@ static int add(int argc, const char **argv, const char *prefix)
        const unsigned char *note;
        struct msg_arg msg = { 0, 0, STRBUF_INIT };
        struct option options[] = {
-               { OPTION_CALLBACK, 'm', "message", &msg, "msg",
-                       "note contents as a string", PARSE_OPT_NONEG,
+               { OPTION_CALLBACK, 'm', "message", &msg, N_("message"),
+                       N_("note contents as a string"), PARSE_OPT_NONEG,
                        parse_msg_arg},
-               { OPTION_CALLBACK, 'F', "file", &msg, "file",
-                       "note contents in a file", PARSE_OPT_NONEG,
+               { OPTION_CALLBACK, 'F', "file", &msg, N_("file"),
+                       N_("note contents in a file"), PARSE_OPT_NONEG,
                        parse_file_arg},
-               { OPTION_CALLBACK, 'c', "reedit-message", &msg, "object",
-                       "reuse and edit specified note object", PARSE_OPT_NONEG,
+               { OPTION_CALLBACK, 'c', "reedit-message", &msg, N_("object"),
+                       N_("reuse and edit specified note object"), PARSE_OPT_NONEG,
                        parse_reedit_arg},
-               { OPTION_CALLBACK, 'C', "reuse-message", &msg, "object",
-                       "reuse specified note object", PARSE_OPT_NONEG,
+               { OPTION_CALLBACK, 'C', "reuse-message", &msg, N_("object"),
+                       N_("reuse specified note object"), PARSE_OPT_NONEG,
                        parse_reuse_arg},
-               OPT__FORCE(&force, "replace existing notes"),
+               OPT__FORCE(&force, N_("replace existing notes")),
                OPT_END()
        };
 
@@ -611,11 +614,11 @@ static int copy(int argc, const char **argv, const char *prefix)
        struct notes_tree *t;
        const char *rewrite_cmd = NULL;
        struct option options[] = {
-               OPT__FORCE(&force, "replace existing notes"),
-               OPT_BOOLEAN(0, "stdin", &from_stdin, "read objects from stdin"),
-               OPT_STRING(0, "for-rewrite", &rewrite_cmd, "command",
-                          "load rewriting config for <command> (implies "
-                          "--stdin)"),
+               OPT__FORCE(&force, N_("replace existing notes")),
+               OPT_BOOLEAN(0, "stdin", &from_stdin, N_("read objects from stdin")),
+               OPT_STRING(0, "for-rewrite", &rewrite_cmd, N_("command"),
+                          N_("load rewriting config for <command> (implies "
+                             "--stdin)")),
                OPT_END()
        };
 
@@ -688,17 +691,17 @@ static int append_edit(int argc, const char **argv, const char *prefix)
        const char * const *usage;
        struct msg_arg msg = { 0, 0, STRBUF_INIT };
        struct option options[] = {
-               { OPTION_CALLBACK, 'm', "message", &msg, "msg",
-                       "note contents as a string", PARSE_OPT_NONEG,
+               { OPTION_CALLBACK, 'm', "message", &msg, N_("message"),
+                       N_("note contents as a string"), PARSE_OPT_NONEG,
                        parse_msg_arg},
-               { OPTION_CALLBACK, 'F', "file", &msg, "file",
-                       "note contents in a file", PARSE_OPT_NONEG,
+               { OPTION_CALLBACK, 'F', "file", &msg, N_("file"),
+                       N_("note contents in a file"), PARSE_OPT_NONEG,
                        parse_file_arg},
-               { OPTION_CALLBACK, 'c', "reedit-message", &msg, "object",
-                       "reuse and edit specified note object", PARSE_OPT_NONEG,
+               { OPTION_CALLBACK, 'c', "reedit-message", &msg, N_("object"),
+                       N_("reuse and edit specified note object"), PARSE_OPT_NONEG,
                        parse_reedit_arg},
-               { OPTION_CALLBACK, 'C', "reuse-message", &msg, "object",
-                       "reuse specified note object", PARSE_OPT_NONEG,
+               { OPTION_CALLBACK, 'C', "reuse-message", &msg, N_("object"),
+                       N_("reuse specified note object"), PARSE_OPT_NONEG,
                        parse_reuse_arg},
                OPT_END()
        };
@@ -861,19 +864,19 @@ static int merge(int argc, const char **argv, const char *prefix)
        int verbosity = 0, result;
        const char *strategy = NULL;
        struct option options[] = {
-               OPT_GROUP("General options"),
+               OPT_GROUP(N_("General options")),
                OPT__VERBOSITY(&verbosity),
-               OPT_GROUP("Merge options"),
-               OPT_STRING('s', "strategy", &strategy, "strategy",
-                          "resolve notes conflicts using the given strategy "
-                          "(manual/ours/theirs/union/cat_sort_uniq)"),
-               OPT_GROUP("Committing unmerged notes"),
+               OPT_GROUP(N_("Merge options")),
+               OPT_STRING('s', "strategy", &strategy, N_("strategy"),
+                          N_("resolve notes conflicts using the given strategy "
+                             "(manual/ours/theirs/union/cat_sort_uniq)")),
+               OPT_GROUP(N_("Committing unmerged notes")),
                { OPTION_BOOLEAN, 0, "commit", &do_commit, NULL,
-                       "finalize notes merge by committing unmerged notes",
+                       N_("finalize notes merge by committing unmerged notes"),
                        PARSE_OPT_NOARG | PARSE_OPT_NONEG },
-               OPT_GROUP("Aborting notes merge resolution"),
+               OPT_GROUP(N_("Aborting notes merge resolution")),
                { OPTION_BOOLEAN, 0, "abort", &do_abort, NULL,
-                       "abort notes merge",
+                       N_("abort notes merge"),
                        PARSE_OPT_NOARG | PARSE_OPT_NONEG },
                OPT_END()
        };
@@ -980,10 +983,10 @@ static int remove_cmd(int argc, const char **argv, const char *prefix)
        int from_stdin = 0;
        struct option options[] = {
                OPT_BIT(0, "ignore-missing", &flag,
-                       "attempt to remove non-existent note is not an error",
+                       N_("attempt to remove non-existent note is not an error"),
                        IGNORE_MISSING),
                OPT_BOOLEAN(0, "stdin", &from_stdin,
-                           "read object names from the standard input"),
+                           N_("read object names from the standard input")),
                OPT_END()
        };
        struct notes_tree *t;
@@ -1064,8 +1067,8 @@ int cmd_notes(int argc, const char **argv, const char *prefix)
        int result;
        const char *override_notes_ref = NULL;
        struct option options[] = {
-               OPT_STRING(0, "ref", &override_notes_ref, "notes_ref",
-                          "use notes from <notes_ref>"),
+               OPT_STRING(0, "ref", &override_notes_ref, N_("notes_ref"),
+                          N_("use notes from <notes_ref>")),
                OPT_END()
        };
 
index ccfcbad14647eff80131cd99c22a18f13016b4af..f069462cb03bbae46dae8d6b97420b3726690c47 100644 (file)
 #include "list-objects.h"
 #include "progress.h"
 #include "refs.h"
+#include "streaming.h"
 #include "thread-utils.h"
 
 static const char *pack_usage[] = {
-       "git pack-objects --stdout [options...] [< ref-list | < object-list]",
-       "git pack-objects [options...] base-name [< ref-list | < object-list]",
+       N_("git pack-objects --stdout [options...] [< ref-list | < object-list]"),
+       N_("git pack-objects [options...] base-name [< ref-list | < object-list]"),
        NULL
 };
 
@@ -150,6 +151,46 @@ static unsigned long do_compress(void **pptr, unsigned long size)
        return stream.total_out;
 }
 
+static unsigned long write_large_blob_data(struct git_istream *st, struct sha1file *f,
+                                          const unsigned char *sha1)
+{
+       git_zstream stream;
+       unsigned char ibuf[1024 * 16];
+       unsigned char obuf[1024 * 16];
+       unsigned long olen = 0;
+
+       memset(&stream, 0, sizeof(stream));
+       git_deflate_init(&stream, pack_compression_level);
+
+       for (;;) {
+               ssize_t readlen;
+               int zret = Z_OK;
+               readlen = read_istream(st, ibuf, sizeof(ibuf));
+               if (readlen == -1)
+                       die(_("unable to read %s"), sha1_to_hex(sha1));
+
+               stream.next_in = ibuf;
+               stream.avail_in = readlen;
+               while ((stream.avail_in || readlen == 0) &&
+                      (zret == Z_OK || zret == Z_BUF_ERROR)) {
+                       stream.next_out = obuf;
+                       stream.avail_out = sizeof(obuf);
+                       zret = git_deflate(&stream, readlen ? 0 : Z_FINISH);
+                       sha1write(f, obuf, stream.next_out - obuf);
+                       olen += stream.next_out - obuf;
+               }
+               if (stream.avail_in)
+                       die(_("deflate error (%d)"), zret);
+               if (readlen == 0) {
+                       if (zret != Z_STREAM_END)
+                               die(_("deflate error (%d)"), zret);
+                       break;
+               }
+       }
+       git_deflate_end(&stream);
+       return olen;
+}
+
 /*
  * we are going to reuse the existing object data as is.  make
  * sure it is not corrupt.
@@ -208,11 +249,18 @@ static unsigned long write_no_reuse_object(struct sha1file *f, struct object_ent
        unsigned hdrlen;
        enum object_type type;
        void *buf;
+       struct git_istream *st = NULL;
 
        if (!usable_delta) {
-               buf = read_sha1_file(entry->idx.sha1, &type, &size);
-               if (!buf)
-                       die("unable to read %s", sha1_to_hex(entry->idx.sha1));
+               if (entry->type == OBJ_BLOB &&
+                   entry->size > big_file_threshold &&
+                   (st = open_istream(entry->idx.sha1, &type, &size, NULL)) != NULL)
+                       buf = NULL;
+               else {
+                       buf = read_sha1_file(entry->idx.sha1, &type, &size);
+                       if (!buf)
+                               die(_("unable to read %s"), sha1_to_hex(entry->idx.sha1));
+               }
                /*
                 * make sure no cached delta data remains from a
                 * previous attempt before a pack split occurred.
@@ -233,7 +281,9 @@ static unsigned long write_no_reuse_object(struct sha1file *f, struct object_ent
                        OBJ_OFS_DELTA : OBJ_REF_DELTA;
        }
 
-       if (entry->z_delta_size)
+       if (st) /* large blob case, just assume we don't compress well */
+               datalen = size;
+       else if (entry->z_delta_size)
                datalen = entry->z_delta_size;
        else
                datalen = do_compress(&buf, size);
@@ -256,6 +306,8 @@ static unsigned long write_no_reuse_object(struct sha1file *f, struct object_ent
                while (ofs >>= 7)
                        dheader[--pos] = 128 | (--ofs & 127);
                if (limit && hdrlen + sizeof(dheader) - pos + datalen + 20 >= limit) {
+                       if (st)
+                               close_istream(st);
                        free(buf);
                        return 0;
                }
@@ -268,6 +320,8 @@ static unsigned long write_no_reuse_object(struct sha1file *f, struct object_ent
                 * an additional 20 bytes for the base sha1.
                 */
                if (limit && hdrlen + 20 + datalen + 20 >= limit) {
+                       if (st)
+                               close_istream(st);
                        free(buf);
                        return 0;
                }
@@ -276,13 +330,20 @@ static unsigned long write_no_reuse_object(struct sha1file *f, struct object_ent
                hdrlen += 20;
        } else {
                if (limit && hdrlen + datalen + 20 >= limit) {
+                       if (st)
+                               close_istream(st);
                        free(buf);
                        return 0;
                }
                sha1write(f, header, hdrlen);
        }
-       sha1write(f, buf, datalen);
-       free(buf);
+       if (st) {
+               datalen = write_large_blob_data(st, f, entry->idx.sha1);
+               close_istream(st);
+       } else {
+               sha1write(f, buf, datalen);
+               free(buf);
+       }
 
        return hdrlen + datalen;
 }
@@ -1972,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;
@@ -2312,7 +2372,7 @@ static void get_object_list(int ac, const char **av)
                        }
                        die("not a rev '%s'", line);
                }
-               if (handle_revision_arg(line, &revs, flags, 1))
+               if (handle_revision_arg(line, &revs, flags, REVARG_CANNOT_BE_FILENAME))
                        die("bad revision '%s'", line);
        }
 
@@ -2384,67 +2444,67 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
        int rev_list_unpacked = 0, rev_list_all = 0, rev_list_reflog = 0;
        struct option pack_objects_options[] = {
                OPT_SET_INT('q', "quiet", &progress,
-                           "do not show progress meter", 0),
+                           N_("do not show progress meter"), 0),
                OPT_SET_INT(0, "progress", &progress,
-                           "show progress meter", 1),
+                           N_("show progress meter"), 1),
                OPT_SET_INT(0, "all-progress", &progress,
-                           "show progress meter during object writing phase", 2),
+                           N_("show progress meter during object writing phase"), 2),
                OPT_BOOL(0, "all-progress-implied",
                         &all_progress_implied,
-                        "similar to --all-progress when progress meter is shown"),
-               { OPTION_CALLBACK, 0, "index-version", NULL, "version[,offset]",
-                 "write the pack index file in the specified idx format version",
+                        N_("similar to --all-progress when progress meter is shown")),
+               { OPTION_CALLBACK, 0, "index-version", NULL, N_("version[,offset]"),
+                 N_("write the pack index file in the specified idx format version"),
                  0, option_parse_index_version },
                OPT_ULONG(0, "max-pack-size", &pack_size_limit,
-                         "maximum size of each output pack file"),
+                         N_("maximum size of each output pack file")),
                OPT_BOOL(0, "local", &local,
-                        "ignore borrowed objects from alternate object store"),
+                        N_("ignore borrowed objects from alternate object store")),
                OPT_BOOL(0, "incremental", &incremental,
-                        "ignore packed objects"),
+                        N_("ignore packed objects")),
                OPT_INTEGER(0, "window", &window,
-                           "limit pack window by objects"),
+                           N_("limit pack window by objects")),
                OPT_ULONG(0, "window-memory", &window_memory_limit,
-                         "limit pack window by memory in addition to object limit"),
+                         N_("limit pack window by memory in addition to object limit")),
                OPT_INTEGER(0, "depth", &depth,
-                           "maximum length of delta chain allowed in the resulting pack"),
+                           N_("maximum length of delta chain allowed in the resulting pack")),
                OPT_BOOL(0, "reuse-delta", &reuse_delta,
-                        "reuse existing deltas"),
+                        N_("reuse existing deltas")),
                OPT_BOOL(0, "reuse-object", &reuse_object,
-                        "reuse existing objects"),
+                        N_("reuse existing objects")),
                OPT_BOOL(0, "delta-base-offset", &allow_ofs_delta,
-                        "use OFS_DELTA objects"),
+                        N_("use OFS_DELTA objects")),
                OPT_INTEGER(0, "threads", &delta_search_threads,
-                           "use threads when searching for best delta matches"),
+                           N_("use threads when searching for best delta matches")),
                OPT_BOOL(0, "non-empty", &non_empty,
-                        "do not create an empty pack output"),
+                        N_("do not create an empty pack output")),
                OPT_BOOL(0, "revs", &use_internal_rev_list,
-                        "read revision arguments from standard input"),
+                        N_("read revision arguments from standard input")),
                { OPTION_SET_INT, 0, "unpacked", &rev_list_unpacked, NULL,
-                 "limit the objects to those that are not yet packed",
+                 N_("limit the objects to those that are not yet packed"),
                  PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 },
                { OPTION_SET_INT, 0, "all", &rev_list_all, NULL,
-                 "include objects reachable from any reference",
+                 N_("include objects reachable from any reference"),
                  PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 },
                { OPTION_SET_INT, 0, "reflog", &rev_list_reflog, NULL,
-                 "include objects referred by reflog entries",
+                 N_("include objects referred by reflog entries"),
                  PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 },
                OPT_BOOL(0, "stdout", &pack_to_stdout,
-                        "output pack to stdout"),
+                        N_("output pack to stdout")),
                OPT_BOOL(0, "include-tag", &include_tag,
-                        "include tag objects that refer to objects to be packed"),
+                        N_("include tag objects that refer to objects to be packed")),
                OPT_BOOL(0, "keep-unreachable", &keep_unreachable,
-                        "keep unreachable objects"),
-               { OPTION_CALLBACK, 0, "unpack-unreachable", NULL, "time",
-                 "unpack unreachable objects newer than <time>",
+                        N_("keep unreachable objects")),
+               { OPTION_CALLBACK, 0, "unpack-unreachable", NULL, N_("time"),
+                 N_("unpack unreachable objects newer than <time>"),
                  PARSE_OPT_OPTARG, option_parse_unpack_unreachable },
                OPT_BOOL(0, "thin", &thin,
-                        "create thin packs"),
+                        N_("create thin packs")),
                OPT_BOOL(0, "honor-pack-keep", &ignore_packed_keep,
-                        "ignore packs that have companion .keep file"),
+                        N_("ignore packs that have companion .keep file")),
                OPT_INTEGER(0, "compression", &pack_compression_level,
-                           "pack compression level"),
+                           N_("pack compression level")),
                OPT_SET_INT(0, "keep-true-parents", &grafts_replace_parents,
-                           "do not hide commits by grafts", 0),
+                           N_("do not hide commits by grafts"), 0),
                OPT_END(),
        };
 
index 39a9d89fbdf322a8ef42a62e41ac36af934ff638..b5a0f88eb8c5641b41bfe95bd342fb180e7fadad 100644 (file)
@@ -3,7 +3,7 @@
 #include "pack-refs.h"
 
 static char const * const pack_refs_usage[] = {
-       "git pack-refs [options]",
+       N_("git pack-refs [options]"),
        NULL
 };
 
@@ -11,8 +11,8 @@ int cmd_pack_refs(int argc, const char **argv, const char *prefix)
 {
        unsigned int flags = PACK_REFS_PRUNE;
        struct option opts[] = {
-               OPT_BIT(0, "all",   &flags, "pack everything", PACK_REFS_ALL),
-               OPT_BIT(0, "prune", &flags, "prune loose refs (default)", PACK_REFS_PRUNE),
+               OPT_BIT(0, "all",   &flags, N_("pack everything"), PACK_REFS_ALL),
+               OPT_BIT(0, "prune", &flags, N_("prune loose refs (default)"), PACK_REFS_PRUNE),
                OPT_END(),
        };
        if (parse_options(argc, argv, prefix, opts, pack_refs_usage, 0))
index b58a2e1eb28d0eb94cc6863c64af7e0ac816caea..83382c1fe13e1f99aad4736993c08877c989a748 100644 (file)
@@ -4,7 +4,7 @@
 #include "parse-options.h"
 
 static const char * const prune_packed_usage[] = {
-       "git prune-packed [-n|--dry-run] [-q|--quiet]",
+       N_("git prune-packed [-n|--dry-run] [-q|--quiet]"),
        NULL
 };
 
@@ -73,8 +73,8 @@ int cmd_prune_packed(int argc, const char **argv, const char *prefix)
 {
        int opts = isatty(2) ? VERBOSE : 0;
        const struct option prune_packed_options[] = {
-               OPT_BIT('n', "dry-run", &opts, "dry run", DRY_RUN),
-               OPT_NEGBIT('q', "quiet", &opts, "be quiet", VERBOSE),
+               OPT_BIT('n', "dry-run", &opts, N_("dry run"), DRY_RUN),
+               OPT_NEGBIT('q', "quiet", &opts, N_("be quiet"), VERBOSE),
                OPT_END()
        };
 
index b99b635e44f6145395b5c761505099c0a0f5b6cc..8cb8b9186a3a268630680e4b224d3767017e1e38 100644 (file)
@@ -9,7 +9,7 @@
 #include "dir.h"
 
 static const char * const prune_usage[] = {
-       "git prune [-n] [-v] [--expire <time>] [--] [<head>...]",
+       N_("git prune [-n] [-v] [--expire <time>] [--] [<head>...]"),
        NULL
 };
 static int show_only;
@@ -25,7 +25,8 @@ static int prune_tmp_object(const char *path, const char *filename)
                return error("Could not stat '%s'", fullpath);
        if (st.st_mtime > expire)
                return 0;
-       printf("Removing stale temporary file %s\n", fullpath);
+       if (show_only || verbose)
+               printf("Removing stale temporary file %s\n", fullpath);
        if (!show_only)
                unlink_or_warn(fullpath);
        return 0;
@@ -128,11 +129,11 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
        struct rev_info revs;
        struct progress *progress = NULL;
        const struct option options[] = {
-               OPT__DRY_RUN(&show_only, "do not remove, show only"),
-               OPT__VERBOSE(&verbose, "report pruned objects"),
-               OPT_BOOL(0, "progress", &show_progress, "show progress"),
+               OPT__DRY_RUN(&show_only, N_("do not remove, show only")),
+               OPT__VERBOSE(&verbose, N_("report pruned objects")),
+               OPT_BOOL(0, "progress", &show_progress, N_("show progress")),
                OPT_DATE(0, "expire", &expire,
-                        "expire objects older than <time>"),
+                        N_("expire objects older than <time>")),
                OPT_END()
        };
        char *s;
@@ -168,7 +169,7 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
 
        prune_packed_objects(show_only);
        remove_temporary_files(get_object_directory());
-       s = xstrdup(mkpath("%s/pack", get_object_directory()));
+       s = mkpathdup("%s/pack", get_object_directory());
        remove_temporary_files(s);
        free(s);
        return 0;
index fdfcc6c71607a7412666b7cc647db98e1b85c8c1..db9ba30b08c221ac2290b1ffc939713fe378e666 100644 (file)
@@ -11,7 +11,7 @@
 #include "submodule.h"
 
 static const char * const push_usage[] = {
-       "git push [<options>] [<repository> [<refspec>...]]",
+       N_("git push [<options>] [<repository> [<refspec>...]]"),
        NULL,
 };
 
@@ -147,12 +147,37 @@ static void setup_push_upstream(struct remote *remote, int simple)
        add_refspec(refspec.buf);
 }
 
+static char warn_unspecified_push_default_msg[] =
+N_("push.default is unset; its implicit value is changing in\n"
+   "Git 2.0 from 'matching' to 'simple'. To squelch this message\n"
+   "and maintain the current behavior after the default changes, use:\n"
+   "\n"
+   "  git config --global push.default matching\n"
+   "\n"
+   "To squelch this message and adopt the new behavior now, use:\n"
+   "\n"
+   "  git config --global push.default simple\n"
+   "\n"
+   "See 'git help config' and search for 'push.default' for further information.\n"
+   "(the 'simple' mode was introduced in Git 1.7.11. Use the similar mode\n"
+   "'current' instead of 'simple' if you sometimes use older versions of Git)");
+
+static void warn_unspecified_push_default_configuration(void)
+{
+       static int warn_once;
+
+       if (warn_once++)
+               return;
+       warning("%s\n", _(warn_unspecified_push_default_msg));
+}
+
 static void setup_default_push_refspecs(struct remote *remote)
 {
        switch (push_default) {
        default:
        case PUSH_DEFAULT_UNSPECIFIED:
                default_matching_used = 1;
+               warn_unspecified_push_default_configuration();
                /* fallthru */
        case PUSH_DEFAULT_MATCHING:
                add_refspec(":");
@@ -186,8 +211,8 @@ static const char message_advice_pull_before_push[] =
 static const char message_advice_use_upstream[] =
        N_("Updates were rejected because a pushed branch tip is behind its remote\n"
           "counterpart. If you did not intend to push that branch, you may want to\n"
-          "specify branches to push or set the 'push.default' configuration\n"
-          "variable to 'current' or 'upstream' to push only the current branch.");
+          "specify branches to push or set the 'push.default' configuration variable\n"
+          "to 'simple', 'current' or 'upstream' to push only the current branch.");
 
 static const char message_advice_checkout_pull_push[] =
        N_("Updates were rejected because a pushed branch tip is behind its remote\n"
@@ -354,25 +379,25 @@ int cmd_push(int argc, const char **argv, const char *prefix)
        const char *repo = NULL;        /* default repository */
        struct option options[] = {
                OPT__VERBOSITY(&verbosity),
-               OPT_STRING( 0 , "repo", &repo, "repository", "repository"),
-               OPT_BIT( 0 , "all", &flags, "push all refs", TRANSPORT_PUSH_ALL),
-               OPT_BIT( 0 , "mirror", &flags, "mirror all refs",
+               OPT_STRING( 0 , "repo", &repo, N_("repository"), N_("repository")),
+               OPT_BIT( 0 , "all", &flags, N_("push all refs"), TRANSPORT_PUSH_ALL),
+               OPT_BIT( 0 , "mirror", &flags, N_("mirror all refs"),
                            (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE)),
-               OPT_BOOLEAN( 0, "delete", &deleterefs, "delete refs"),
-               OPT_BOOLEAN( 0 , "tags", &tags, "push tags (can't be used with --all or --mirror)"),
-               OPT_BIT('n' , "dry-run", &flags, "dry run", TRANSPORT_PUSH_DRY_RUN),
-               OPT_BIT( 0,  "porcelain", &flags, "machine-readable output", TRANSPORT_PUSH_PORCELAIN),
-               OPT_BIT('f', "force", &flags, "force updates", TRANSPORT_PUSH_FORCE),
-               { OPTION_CALLBACK, 0, "recurse-submodules", &flags, "check",
-                       "controls recursive pushing of submodules",
+               OPT_BOOLEAN( 0, "delete", &deleterefs, N_("delete refs")),
+               OPT_BOOLEAN( 0 , "tags", &tags, N_("push tags (can't be used with --all or --mirror)")),
+               OPT_BIT('n' , "dry-run", &flags, N_("dry run"), TRANSPORT_PUSH_DRY_RUN),
+               OPT_BIT( 0,  "porcelain", &flags, N_("machine-readable output"), TRANSPORT_PUSH_PORCELAIN),
+               OPT_BIT('f', "force", &flags, N_("force updates"), TRANSPORT_PUSH_FORCE),
+               { OPTION_CALLBACK, 0, "recurse-submodules", &flags, N_("check"),
+                       N_("control recursive pushing of submodules"),
                        PARSE_OPT_OPTARG, option_parse_recurse_submodules },
-               OPT_BOOLEAN( 0 , "thin", &thin, "use thin pack"),
-               OPT_STRING( 0 , "receive-pack", &receivepack, "receive-pack", "receive pack program"),
-               OPT_STRING( 0 , "exec", &receivepack, "receive-pack", "receive pack program"),
-               OPT_BIT('u', "set-upstream", &flags, "set upstream for git pull/status",
+               OPT_BOOLEAN( 0 , "thin", &thin, N_("use thin pack")),
+               OPT_STRING( 0 , "receive-pack", &receivepack, "receive-pack", N_("receive pack program")),
+               OPT_STRING( 0 , "exec", &receivepack, "receive-pack", N_("receive pack program")),
+               OPT_BIT('u', "set-upstream", &flags, N_("set upstream for git pull/status"),
                        TRANSPORT_PUSH_SET_UPSTREAM),
-               OPT_BOOL(0, "progress", &progress, "force progress reporting"),
-               OPT_BIT(0, "prune", &flags, "prune locally removed refs",
+               OPT_BOOL(0, "progress", &progress, N_("force progress reporting")),
+               OPT_BIT(0, "prune", &flags, N_("prune locally removed refs"),
                        TRANSPORT_PUSH_PRUNE),
                OPT_END()
        };
index df6c4c8819e7903f34cd6dc6bb0078a6cddac310..042ac1b84f22257d1a8a4d32d34124b6dc372f16 100644 (file)
@@ -33,7 +33,7 @@ static int list_tree(unsigned char *sha1)
 }
 
 static const char * const read_tree_usage[] = {
-       "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>]])",
+       N_("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>]])"),
        NULL
 };
 
@@ -104,37 +104,37 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
        struct unpack_trees_options opts;
        int prefix_set = 0;
        const struct option read_tree_options[] = {
-               { OPTION_CALLBACK, 0, "index-output", NULL, "file",
-                 "write resulting index to <file>",
+               { OPTION_CALLBACK, 0, "index-output", NULL, N_("file"),
+                 N_("write resulting index to <file>"),
                  PARSE_OPT_NONEG, index_output_cb },
                OPT_SET_INT(0, "empty", &read_empty,
-                           "only empty the index", 1),
-               OPT__VERBOSE(&opts.verbose_update, "be verbose"),
-               OPT_GROUP("Merging"),
+                           N_("only empty the index"), 1),
+               OPT__VERBOSE(&opts.verbose_update, N_("be verbose")),
+               OPT_GROUP(N_("Merging")),
                OPT_SET_INT('m', NULL, &opts.merge,
-                           "perform a merge in addition to a read", 1),
+                           N_("perform a merge in addition to a read"), 1),
                OPT_SET_INT(0, "trivial", &opts.trivial_merges_only,
-                           "3-way merge if no file level merging required", 1),
+                           N_("3-way merge if no file level merging required"), 1),
                OPT_SET_INT(0, "aggressive", &opts.aggressive,
-                           "3-way merge in presence of adds and removes", 1),
+                           N_("3-way merge in presence of adds and removes"), 1),
                OPT_SET_INT(0, "reset", &opts.reset,
-                           "same as -m, but discard unmerged entries", 1),
-               { OPTION_STRING, 0, "prefix", &opts.prefix, "<subdirectory>/",
-                 "read the tree into the index under <subdirectory>/",
+                           N_("same as -m, but discard unmerged entries"), 1),
+               { OPTION_STRING, 0, "prefix", &opts.prefix, N_("<subdirectory>/"),
+                 N_("read the tree into the index under <subdirectory>/"),
                  PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP },
                OPT_SET_INT('u', NULL, &opts.update,
-                           "update working tree with merge result", 1),
+                           N_("update working tree with merge result"), 1),
                { OPTION_CALLBACK, 0, "exclude-per-directory", &opts,
-                 "gitignore",
-                 "allow explicitly ignored files to be overwritten",
+                 N_("gitignore"),
+                 N_("allow explicitly ignored files to be overwritten"),
                  PARSE_OPT_NONEG, exclude_per_directory_cb },
                OPT_SET_INT('i', NULL, &opts.index_only,
-                           "don't check the working tree after merging", 1),
-               OPT__DRY_RUN(&opts.dry_run, "don't update the index or the work tree"),
+                           N_("don't check the working tree after merging"), 1),
+               OPT__DRY_RUN(&opts.dry_run, N_("don't update the index or the work tree")),
                OPT_SET_INT(0, "no-sparse-checkout", &opts.skip_sparse_checkout,
-                           "skip applying sparse checkout filter", 1),
+                           N_("skip applying sparse checkout filter"), 1),
                OPT_SET_INT(0, "debug-unpack", &opts.debug_unpack,
-                           "debug unpack-trees", 1),
+                           N_("debug unpack-trees"), 1),
                OPT_END()
        };
 
index 3f05d971ec2f8b047b2ef3a32c91f039d686d91a..ff781febcad92dfccd8a3d97d0414526ded36943 100644 (file)
@@ -12,6 +12,7 @@
 #include "string-list.h"
 #include "sha1-array.h"
 #include "connected.h"
+#include "version.h"
 
 static const char receive_pack_usage[] = "git receive-pack <git-dir>";
 
@@ -121,10 +122,11 @@ static void show_ref(const char *path, const unsigned char *sha1)
        if (sent_capabilities)
                packet_write(1, "%s %s\n", sha1_to_hex(sha1), path);
        else
-               packet_write(1, "%s %s%c%s%s\n",
+               packet_write(1, "%s %s%c%s%s agent=%s\n",
                             sha1_to_hex(sha1), path, 0,
                             " report-status delete-refs side-band-64k quiet",
-                            prefer_ofs_delta ? " ofs-delta" : "");
+                            prefer_ofs_delta ? " ofs-delta" : "",
+                            git_user_agent_sanitized());
        sent_capabilities = 1;
 }
 
@@ -478,7 +480,6 @@ static const char *update(struct command *cmd)
            !prefixcmp(name, "refs/heads/")) {
                struct object *old_object, *new_object;
                struct commit *old_commit, *new_commit;
-               struct commit_list *bases, *ent;
 
                old_object = parse_object(old_sha1);
                new_object = parse_object(new_sha1);
@@ -491,12 +492,7 @@ static const char *update(struct command *cmd)
                }
                old_commit = (struct commit *)old_object;
                new_commit = (struct commit *)new_object;
-               bases = get_merge_bases(old_commit, new_commit, 1);
-               for (ent = bases; ent; ent = ent->next)
-                       if (!hashcmp(old_sha1, ent->item->object.sha1))
-                               break;
-               free_commit_list(bases);
-               if (!ent) {
+               if (!in_merge_bases(old_commit, new_commit)) {
                        rp_error("denying non-fast-forward %s"
                                 " (you should pull first)", name);
                        return "non-fast-forward";
@@ -699,7 +695,7 @@ static void execute_commands(struct command *commands, const char *unpacker_erro
 
        if (unpacker_error) {
                for (cmd = commands; cmd; cmd = cmd->next)
-                       cmd->error_string = "n/a (unpacker error)";
+                       cmd->error_string = "unpacker error";
                return;
        }
 
@@ -799,7 +795,7 @@ static const char *parse_pack_header(struct pack_header *hdr)
 
 static const char *pack_lockfile;
 
-static const char *unpack(void)
+static const char *unpack(int err_fd)
 {
        struct pack_header hdr;
        const char *hdr_err;
@@ -819,6 +815,7 @@ static const char *unpack(void)
 
        if (ntohl(hdr.hdr_entries) < unpack_limit) {
                int code, i = 0;
+               struct child_process child;
                const char *unpacker[5];
                unpacker[i++] = "unpack-objects";
                if (quiet)
@@ -827,7 +824,12 @@ static const char *unpack(void)
                        unpacker[i++] = "--strict";
                unpacker[i++] = hdr_arg;
                unpacker[i++] = NULL;
-               code = run_command_v_opt(unpacker, RUN_GIT_CMD);
+               memset(&child, 0, sizeof(child));
+               child.argv = unpacker;
+               child.no_stdout = 1;
+               child.err = err_fd;
+               child.git_cmd = 1;
+               code = run_command(&child);
                if (!code)
                        return NULL;
                return "unpack-objects abnormal exit";
@@ -852,6 +854,7 @@ static const char *unpack(void)
                memset(&ip, 0, sizeof(ip));
                ip.argv = keeper;
                ip.out = -1;
+               ip.err = err_fd;
                ip.git_cmd = 1;
                status = start_command(&ip);
                if (status) {
@@ -868,6 +871,26 @@ static const char *unpack(void)
        }
 }
 
+static const char *unpack_with_sideband(void)
+{
+       struct async muxer;
+       const char *ret;
+
+       if (!use_sideband)
+               return unpack(0);
+
+       memset(&muxer, 0, sizeof(muxer));
+       muxer.proc = copy_to_sideband;
+       muxer.in = -1;
+       if (start_async(&muxer))
+               return NULL;
+
+       ret = unpack(muxer.in);
+
+       finish_async(&muxer);
+       return ret;
+}
+
 static void report(struct command *commands, const char *unpack_status)
 {
        struct command *cmd;
@@ -965,7 +988,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
                const char *unpack_status = NULL;
 
                if (!delete_only(commands))
-                       unpack_status = unpack();
+                       unpack_status = unpack_with_sideband();
                execute_commands(commands, unpack_status);
                if (pack_lockfile)
                        unlink_or_warn(pack_lockfile);
index 062d7dad1b5af720e70adcaa05b60bf68977b05c..b3c9e27bde653bf01acc6126deeb5f508fa0b26e 100644 (file)
@@ -330,8 +330,10 @@ static int expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
                printf("keep %s", message);
        return 0;
  prune:
-       if (!cb->newlog || cb->cmd->verbose)
-               printf("%sprune %s", cb->newlog ? "" : "would ", message);
+       if (!cb->newlog)
+               printf("would prune %s", message);
+       else if (cb->cmd->verbose)
+               printf("prune %s", message);
        return 0;
 }
 
index 920262d76ec9bdc40a8ad7703cf1eb972a40eb9e..a5a4b232310a27c1d67dd6a1bce252cd62cfa52d 100644 (file)
@@ -8,66 +8,66 @@
 #include "refs.h"
 
 static const char * const builtin_remote_usage[] = {
-       "git remote [-v | --verbose]",
-       "git remote add [-t <branch>] [-m <master>] [-f] [--tags|--no-tags] [--mirror=<fetch|push>] <name> <url>",
-       "git remote rename <old> <new>",
-       "git remote rm <name>",
-       "git remote set-head <name> (-a | -d | <branch>)",
-       "git remote [-v | --verbose] show [-n] <name>",
-       "git remote prune [-n | --dry-run] <name>",
-       "git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]",
-       "git remote set-branches [--add] <name> <branch>...",
-       "git remote set-url [--push] <name> <newurl> [<oldurl>]",
-       "git remote set-url --add <name> <newurl>",
-       "git remote set-url --delete <name> <url>",
+       N_("git remote [-v | --verbose]"),
+       N_("git remote add [-t <branch>] [-m <master>] [-f] [--tags|--no-tags] [--mirror=<fetch|push>] <name> <url>"),
+       N_("git remote rename <old> <new>"),
+       N_("git remote remove <name>"),
+       N_("git remote set-head <name> (-a | -d | <branch>)"),
+       N_("git remote [-v | --verbose] show [-n] <name>"),
+       N_("git remote prune [-n | --dry-run] <name>"),
+       N_("git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]"),
+       N_("git remote set-branches [--add] <name> <branch>..."),
+       N_("git remote set-url [--push] <name> <newurl> [<oldurl>]"),
+       N_("git remote set-url --add <name> <newurl>"),
+       N_("git remote set-url --delete <name> <url>"),
        NULL
 };
 
 static const char * const builtin_remote_add_usage[] = {
-       "git remote add [<options>] <name> <url>",
+       N_("git remote add [<options>] <name> <url>"),
        NULL
 };
 
 static const char * const builtin_remote_rename_usage[] = {
-       "git remote rename <old> <new>",
+       N_("git remote rename <old> <new>"),
        NULL
 };
 
 static const char * const builtin_remote_rm_usage[] = {
-       "git remote rm <name>",
+       N_("git remote remove <name>"),
        NULL
 };
 
 static const char * const builtin_remote_sethead_usage[] = {
-       "git remote set-head <name> (-a | -d | <branch>])",
+       N_("git remote set-head <name> (-a | -d | <branch>])"),
        NULL
 };
 
 static const char * const builtin_remote_setbranches_usage[] = {
-       "git remote set-branches <name> <branch>...",
-       "git remote set-branches --add <name> <branch>...",
+       N_("git remote set-branches <name> <branch>..."),
+       N_("git remote set-branches --add <name> <branch>..."),
        NULL
 };
 
 static const char * const builtin_remote_show_usage[] = {
-       "git remote show [<options>] <name>",
+       N_("git remote show [<options>] <name>"),
        NULL
 };
 
 static const char * const builtin_remote_prune_usage[] = {
-       "git remote prune [<options>] <name>",
+       N_("git remote prune [<options>] <name>"),
        NULL
 };
 
 static const char * const builtin_remote_update_usage[] = {
-       "git remote update [<options>] [<group> | <remote>]...",
+       N_("git remote update [<options>] [<group> | <remote>]..."),
        NULL
 };
 
 static const char * const builtin_remote_seturl_usage[] = {
-       "git remote set-url [--push] <name> <newurl> [<oldurl>]",
-       "git remote set-url --add <name> <newurl>",
-       "git remote set-url --delete <name> <url>",
+       N_("git remote set-url [--push] <name> <newurl> [<oldurl>]"),
+       N_("git remote set-url --add <name> <newurl>"),
+       N_("git remote set-url --delete <name> <url>"),
        NULL
 };
 
@@ -160,17 +160,17 @@ static int add(int argc, const char **argv)
        int i;
 
        struct option options[] = {
-               OPT_BOOLEAN('f', "fetch", &fetch, "fetch the remote branches"),
+               OPT_BOOLEAN('f', "fetch", &fetch, N_("fetch the remote branches")),
                OPT_SET_INT(0, "tags", &fetch_tags,
-                           "import all tags and associated objects when fetching",
+                           N_("import all tags and associated objects when fetching"),
                            TAGS_SET),
                OPT_SET_INT(0, NULL, &fetch_tags,
-                           "or do not fetch any tag at all (--no-tags)", TAGS_UNSET),
-               OPT_STRING_LIST('t', "track", &track, "branch",
-                               "branch(es) to track"),
-               OPT_STRING('m', "master", &master, "branch", "master branch"),
-               { OPTION_CALLBACK, 0, "mirror", &mirror, "push|fetch",
-                       "set up remote as a mirror to push to or fetch from",
+                           N_("or do not fetch any tag at all (--no-tags)"), TAGS_UNSET),
+               OPT_STRING_LIST('t', "track", &track, N_("branch"),
+                               N_("branch(es) to track")),
+               OPT_STRING('m', "master", &master, N_("branch"), N_("master branch")),
+               { OPTION_CALLBACK, 0, "mirror", &mirror, N_("push|fetch"),
+                       N_("set up remote as a mirror to push to or fetch from"),
                        PARSE_OPT_OPTARG, parse_mirror_opt },
                OPT_END()
        };
@@ -1088,7 +1088,7 @@ static int show(int argc, const char **argv)
 {
        int no_query = 0, result = 0, query_flag = 0;
        struct option options[] = {
-               OPT_BOOLEAN('n', NULL, &no_query, "do not query remotes"),
+               OPT_BOOLEAN('n', NULL, &no_query, N_("do not query remotes")),
                OPT_END()
        };
        struct ref_states states;
@@ -1196,9 +1196,9 @@ static int set_head(int argc, const char **argv)
 
        struct option options[] = {
                OPT_BOOLEAN('a', "auto", &opt_a,
-                           "set refs/remotes/<name>/HEAD according to remote"),
+                           N_("set refs/remotes/<name>/HEAD according to remote")),
                OPT_BOOLEAN('d', "delete", &opt_d,
-                           "delete refs/remotes/<name>/HEAD"),
+                           N_("delete refs/remotes/<name>/HEAD")),
                OPT_END()
        };
        argc = parse_options(argc, argv, NULL, options, builtin_remote_sethead_usage,
@@ -1250,7 +1250,7 @@ static int prune(int argc, const char **argv)
 {
        int dry_run = 0, result = 0;
        struct option options[] = {
-               OPT__DRY_RUN(&dry_run, "dry run"),
+               OPT__DRY_RUN(&dry_run, N_("dry run")),
                OPT_END()
        };
 
@@ -1318,7 +1318,7 @@ static int update(int argc, const char **argv)
        int i, prune = 0;
        struct option options[] = {
                OPT_BOOLEAN('p', "prune", &prune,
-                           "prune remotes after fetching"),
+                           N_("prune remotes after fetching")),
                OPT_END()
        };
        const char **fetch_argv;
@@ -1404,7 +1404,7 @@ static int set_branches(int argc, const char **argv)
 {
        int add_mode = 0;
        struct option options[] = {
-               OPT_BOOLEAN('\0', "add", &add_mode, "add branch"),
+               OPT_BOOLEAN('\0', "add", &add_mode, N_("add branch")),
                OPT_END()
        };
 
@@ -1433,11 +1433,11 @@ static int set_url(int argc, const char **argv)
        struct strbuf name_buf = STRBUF_INIT;
        struct option options[] = {
                OPT_BOOLEAN('\0', "push", &push_mode,
-                           "manipulate push URLs"),
+                           N_("manipulate push URLs")),
                OPT_BOOLEAN('\0', "add", &add_mode,
-                           "add URL"),
+                           N_("add URL")),
                OPT_BOOLEAN('\0', "delete", &delete_mode,
-                           "delete URLs"),
+                           N_("delete URLs")),
                OPT_END()
        };
        argc = parse_options(argc, argv, NULL, options, builtin_remote_seturl_usage,
@@ -1566,7 +1566,7 @@ static int show_all(void)
 int cmd_remote(int argc, const char **argv, const char *prefix)
 {
        struct option options[] = {
-               OPT__VERBOSE(&verbose, "be verbose; must be placed before a subcommand"),
+               OPT__VERBOSE(&verbose, N_("be verbose; must be placed before a subcommand")),
                OPT_END()
        };
        int result;
@@ -1580,7 +1580,7 @@ int cmd_remote(int argc, const char **argv, const char *prefix)
                result = add(argc, argv);
        else if (!strcmp(argv[0], "rename"))
                result = mv(argc, argv);
-       else if (!strcmp(argv[0], "rm"))
+       else if (!strcmp(argv[0], "rm") || !strcmp(argv[0], "remove"))
                result = rm(argc, argv);
        else if (!strcmp(argv[0], "set-head"))
                result = set_head(argc, argv);
index 4a8970e9c95c1e07c1ed919d40f33238dcd05588..e3aaf70203d4f5b6f099ed538d3366fb0a7747ce 100644 (file)
@@ -14,9 +14,9 @@
 #include "parse-options.h"
 
 static const char * const git_replace_usage[] = {
-       "git replace [-f] <object> <replacement>",
-       "git replace -d <object>...",
-       "git replace -l [<pattern>]",
+       N_("git replace [-f] <object> <replacement>"),
+       N_("git replace -d <object>..."),
+       N_("git replace -l [<pattern>]"),
        NULL
 };
 
@@ -115,9 +115,9 @@ int cmd_replace(int argc, const char **argv, const char *prefix)
 {
        int list = 0, delete = 0, force = 0;
        struct option options[] = {
-               OPT_BOOLEAN('l', NULL, &list, "list replace refs"),
-               OPT_BOOLEAN('d', NULL, &delete, "delete replace refs"),
-               OPT_BOOLEAN('f', NULL, &force, "replace the ref if it exists"),
+               OPT_BOOLEAN('l', NULL, &list, N_("list replace refs")),
+               OPT_BOOLEAN('d', NULL, &delete, N_("delete replace refs")),
+               OPT_BOOLEAN('f', NULL, &force, N_("replace the ref if it exists")),
                OPT_END()
        };
 
index 08213c7c0bc6fa5d649a38520dc87222019babe2..dc1708e6d6de54b5aaec36d5ff4242bd60183f0a 100644 (file)
@@ -8,7 +8,7 @@
 #include "xdiff-interface.h"
 
 static const char * const rerere_usage[] = {
-       "git rerere [clear | forget path... | status | remaining | diff | gc]",
+       N_("git rerere [clear | forget path... | status | remaining | diff | gc]"),
        NULL,
 };
 
@@ -53,7 +53,7 @@ int cmd_rerere(int argc, const char **argv, const char *prefix)
 
        struct option options[] = {
                OPT_SET_INT(0, "rerere-autoupdate", &autoupdate,
-                       "register clean resolutions in index", 1),
+                       N_("register clean resolutions in index"), 1),
                OPT_END(),
        };
 
index 4cc34c908446fe2d3db5acf315e47f2768ba07bd..915cc9f86f855d517abaa55d31c502899fb77220 100644 (file)
@@ -22,9 +22,9 @@
 #include "cache-tree.h"
 
 static const char * const git_reset_usage[] = {
-       "git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]",
-       "git reset [-q] <commit> [--] <paths>...",
-       "git reset --patch [<commit>] [--] [<paths>...]",
+       N_("git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]"),
+       N_("git reset [-q] <commit> [--] <paths>..."),
+       N_("git reset --patch [<commit>] [--] [<paths>...]"),
        NULL
 };
 
@@ -235,17 +235,17 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
        struct commit *commit;
        struct strbuf msg = STRBUF_INIT;
        const struct option options[] = {
-               OPT__QUIET(&quiet, "be quiet, only report errors"),
+               OPT__QUIET(&quiet, N_("be quiet, only report errors")),
                OPT_SET_INT(0, "mixed", &reset_type,
-                                               "reset HEAD and index", MIXED),
-               OPT_SET_INT(0, "soft", &reset_type, "reset only HEAD", SOFT),
+                                               N_("reset HEAD and index"), MIXED),
+               OPT_SET_INT(0, "soft", &reset_type, N_("reset only HEAD"), SOFT),
                OPT_SET_INT(0, "hard", &reset_type,
-                               "reset HEAD, index and working tree", HARD),
+                               N_("reset HEAD, index and working tree"), HARD),
                OPT_SET_INT(0, "merge", &reset_type,
-                               "reset HEAD, index and working tree", MERGE),
+                               N_("reset HEAD, index and working tree"), MERGE),
                OPT_SET_INT(0, "keep", &reset_type,
-                               "reset HEAD but keep local changes", KEEP),
-               OPT_BOOLEAN('p', "patch", &patch_mode, "select hunks interactively"),
+                               N_("reset HEAD but keep local changes"), KEEP),
+               OPT_BOOLEAN('p', "patch", &patch_mode, N_("select hunks interactively")),
                OPT_END()
        };
 
@@ -276,7 +276,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
                 * Otherwise, argv[i] could be either <rev> or <paths> and
                 * has to be unambiguous.
                 */
-               else if (!get_sha1(argv[i], sha1)) {
+               else if (!get_sha1_committish(argv[i], sha1)) {
                        /*
                         * Ok, argv[i] looks like a rev; it should not
                         * be a filename.
@@ -289,9 +289,15 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
                }
        }
 
-       if (get_sha1(rev, sha1))
+       if (get_sha1_committish(rev, sha1))
                die(_("Failed to resolve '%s' as a valid ref."), rev);
 
+       /*
+        * NOTE: As "git reset $treeish -- $path" should be usable on
+        * any tree-ish, this is not strictly correct. We are not
+        * moving the HEAD to any commit; we are merely resetting the
+        * entries in the index to that of a treeish.
+        */
        commit = lookup_commit_reference(sha1);
        if (!commit)
                die(_("Could not parse object '%s'."), rev);
index 47b4e7adb956517c22edc580892d63a99d9f219a..f267a1d3b57c1f1ab44c83a197f46051f4f13060 100644 (file)
@@ -195,6 +195,12 @@ static int anti_reference(const char *refname, const unsigned char *sha1, int fl
        return 0;
 }
 
+static int show_abbrev(const unsigned char *sha1, void *cb_data)
+{
+       show_rev(NORMAL, sha1, NULL);
+       return 0;
+}
+
 static void show_datestring(const char *flag, const char *datestr)
 {
        static char buffer[100];
@@ -250,7 +256,7 @@ static int try_difference(const char *arg)
                return 0;
        }
 
-       if (!get_sha1(this, sha1) && !get_sha1(next, end)) {
+       if (!get_sha1_committish(this, sha1) && !get_sha1_committish(next, end)) {
                show_rev(NORMAL, end, next);
                show_rev(symmetric ? NORMAL : REVERSED, sha1, this);
                if (symmetric) {
@@ -290,7 +296,7 @@ static int try_parent_shorthands(const char *arg)
                return 0;
 
        *dotdot = 0;
-       if (get_sha1(arg, sha1))
+       if (get_sha1_committish(arg, sha1))
                return 0;
 
        if (!parents_only)
@@ -330,15 +336,15 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)
 {
        static int keep_dashdash = 0, stop_at_non_option = 0;
        static char const * const parseopt_usage[] = {
-               "git rev-parse --parseopt [options] -- [<args>...]",
+               N_("git rev-parse --parseopt [options] -- [<args>...]"),
                NULL
        };
        static struct option parseopt_opts[] = {
                OPT_BOOLEAN(0, "keep-dashdash", &keep_dashdash,
-                                       "keep the `--` passed as an arg"),
+                                       N_("keep the `--` passed as an arg")),
                OPT_BOOLEAN(0, "stop-at-non-option", &stop_at_non_option,
-                                       "stop parsing after the "
-                                       "first non-option argument"),
+                                       N_("stop parsing after the "
+                                          "first non-option argument")),
                OPT_END(),
        };
 
@@ -455,11 +461,11 @@ static void die_no_single_rev(int quiet)
 }
 
 static const char builtin_rev_parse_usage[] =
-"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.";
+N_("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.");
 
 int cmd_rev_parse(int argc, const char **argv, const char *prefix)
 {
@@ -601,6 +607,10 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
                                for_each_ref(show_reference, NULL);
                                continue;
                        }
+                       if (!prefixcmp(arg, "--disambiguate=")) {
+                               for_each_abbrev(arg + 15, show_abbrev, NULL);
+                               continue;
+                       }
                        if (!strcmp(arg, "--bisect")) {
                                for_each_ref_in("refs/bisect/bad", show_reference, NULL);
                                for_each_ref_in("refs/bisect/good", anti_reference, NULL);
index 82d1bf844b996d5d121169f244358964fd36fd19..c5e36b94c080212ec9241146c20ef2e323663bea 100644 (file)
  */
 
 static const char * const revert_usage[] = {
-       "git revert [options] <commit-ish>",
-       "git revert <subcommand>",
+       N_("git revert [options] <commit-ish>"),
+       N_("git revert <subcommand>"),
        NULL
 };
 
 static const char * const cherry_pick_usage[] = {
-       "git cherry-pick [options] <commit-ish>",
-       "git cherry-pick <subcommand>",
+       N_("git cherry-pick [options] <commit-ish>"),
+       N_("git cherry-pick <subcommand>"),
        NULL
 };
 
@@ -100,18 +100,19 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
        int contin = 0;
        int rollback = 0;
        struct option options[] = {
-               OPT_BOOLEAN(0, "quit", &remove_state, "end revert or cherry-pick sequence"),
-               OPT_BOOLEAN(0, "continue", &contin, "resume revert or cherry-pick sequence"),
-               OPT_BOOLEAN(0, "abort", &rollback, "cancel revert or cherry-pick sequence"),
-               OPT_BOOLEAN('n', "no-commit", &opts->no_commit, "don't automatically commit"),
-               OPT_BOOLEAN('e', "edit", &opts->edit, "edit the commit message"),
+               OPT_BOOLEAN(0, "quit", &remove_state, N_("end revert or cherry-pick sequence")),
+               OPT_BOOLEAN(0, "continue", &contin, N_("resume revert or cherry-pick sequence")),
+               OPT_BOOLEAN(0, "abort", &rollback, N_("cancel revert or cherry-pick sequence")),
+               OPT_BOOLEAN('n', "no-commit", &opts->no_commit, N_("don't automatically commit")),
+               OPT_BOOLEAN('e', "edit", &opts->edit, N_("edit the commit message")),
                OPT_NOOP_NOARG('r', NULL),
-               OPT_BOOLEAN('s', "signoff", &opts->signoff, "add Signed-off-by:"),
-               OPT_INTEGER('m', "mainline", &opts->mainline, "parent number"),
+               OPT_BOOLEAN('s', "signoff", &opts->signoff, N_("add Signed-off-by:")),
+               OPT_INTEGER('m', "mainline", &opts->mainline, N_("parent number")),
                OPT_RERERE_AUTOUPDATE(&opts->allow_rerere_auto),
-               OPT_STRING(0, "strategy", &opts->strategy, "strategy", "merge strategy"),
-               OPT_CALLBACK('X', "strategy-option", &opts, "option",
-                       "option for merge strategy", option_parse_x),
+               OPT_STRING(0, "strategy", &opts->strategy, N_("strategy"), N_("merge strategy")),
+               OPT_CALLBACK('X', "strategy-option", &opts, N_("option"),
+                       N_("option for merge strategy"), option_parse_x),
+               OPT_END(),
                OPT_END(),
                OPT_END(),
                OPT_END(),
@@ -121,10 +122,11 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
 
        if (opts->action == REPLAY_PICK) {
                struct option cp_extra[] = {
-                       OPT_BOOLEAN('x', NULL, &opts->record_origin, "append commit name"),
-                       OPT_BOOLEAN(0, "ff", &opts->allow_ff, "allow fast-forward"),
-                       OPT_BOOLEAN(0, "allow-empty", &opts->allow_empty, "preserve initially empty commits"),
-                       OPT_BOOLEAN(0, "keep-redundant-commits", &opts->keep_redundant_commits, "keep redundant, empty commits"),
+                       OPT_BOOLEAN('x', NULL, &opts->record_origin, N_("append commit name")),
+                       OPT_BOOLEAN(0, "ff", &opts->allow_ff, N_("allow fast-forward")),
+                       OPT_BOOLEAN(0, "allow-empty", &opts->allow_empty, N_("preserve initially empty commits")),
+                       OPT_BOOLEAN(0, "allow-empty-message", &opts->allow_empty_message, N_("allow commits with empty messages")),
+                       OPT_BOOLEAN(0, "keep-redundant-commits", &opts->keep_redundant_commits, N_("keep redundant, empty commits")),
                        OPT_END(),
                };
                if (parse_options_concat(options, ARRAY_SIZE(options), cp_extra))
@@ -193,7 +195,7 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
                struct setup_revision_opt s_r_opt;
                opts->revs = xmalloc(sizeof(*opts->revs));
                init_revisions(opts->revs, NULL);
-               opts->revs->no_walk = 1;
+               opts->revs->no_walk = REVISION_WALK_NO_WALK_UNSORTED;
                if (argc < 2)
                        usage_with_options(usage_str, options);
                memset(&s_r_opt, 0, sizeof(s_r_opt));
index 90c8a5047c26cd7bdb939d150b842823f595333c..2aea3b565318e11bdcc63f175631388f4f20ba44 100644 (file)
@@ -9,17 +9,67 @@
 #include "cache-tree.h"
 #include "tree-walk.h"
 #include "parse-options.h"
+#include "submodule.h"
 
 static const char * const builtin_rm_usage[] = {
-       "git rm [options] [--] <file>...",
+       N_("git rm [options] [--] <file>..."),
        NULL
 };
 
 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;
@@ -130,13 +203,13 @@ static int show_only = 0, force = 0, index_only = 0, recursive = 0, quiet = 0;
 static int ignore_unmatch = 0;
 
 static struct option builtin_rm_options[] = {
-       OPT__DRY_RUN(&show_only, "dry run"),
-       OPT__QUIET(&quiet, "do not list removed files"),
-       OPT_BOOLEAN( 0 , "cached",         &index_only, "only remove from the index"),
-       OPT__FORCE(&force, "override the up-to-date check"),
-       OPT_BOOLEAN('r', NULL,             &recursive,  "allow recursive removal"),
+       OPT__DRY_RUN(&show_only, N_("dry run")),
+       OPT__QUIET(&quiet, N_("do not list removed files")),
+       OPT_BOOLEAN( 0 , "cached",         &index_only, N_("only remove from the index")),
+       OPT__FORCE(&force, N_("override the up-to-date check")),
+       OPT_BOOLEAN('r', NULL,             &recursive,  N_("allow recursive removal")),
        OPT_BOOLEAN( 0 , "ignore-unmatch", &ignore_unmatch,
-                               "exit with a zero status even if nothing matched"),
+                               N_("exit with a zero status even if nothing matched")),
        OPT_END(),
 };
 
@@ -173,8 +246,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 +289,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 +299,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 +321,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 d5d7105ba2debde9fa6f2f33171d84cc7c25339a..7d05064218184b815fe01228a24138c1f9ac7c7f 100644 (file)
@@ -8,6 +8,7 @@
 #include "send-pack.h"
 #include "quote.h"
 #include "transport.h"
+#include "version.h"
 
 static const char send_pack_usage[] =
 "git send-pack [--all | --mirror] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\n"
@@ -251,6 +252,7 @@ int send_pack(struct send_pack_args *args,
        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;
@@ -266,6 +268,8 @@ int send_pack(struct send_pack_args *args,
                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"
@@ -305,12 +309,17 @@ int send_pack(struct send_pack_args *args,
                        char *new_hex = sha1_to_hex(ref->new_sha1);
                        int quiet = quiet_supported && (args->quiet || !args->progress);
 
-                       if (!cmds_sent && (status_report || use_sideband || args->quiet)) {
-                               packet_buf_write(&req_buf, "%s %s %s%c%s%s%s",
+                       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" : "");
+                                                quiet ? " quiet" : "",
+                                                agent_supported ? " agent=" : "",
+                                                agent_supported ? git_user_agent_sanitized() : ""
+                                               );
                        }
                        else
                                packet_buf_write(&req_buf, "%s %s %s",
index 37f3193a3366725a6b11bdb55db7b6ffc6e9b3ce..b316cf37ca768f1502c5d0cfa64372a9b322a572 100644 (file)
@@ -10,9 +10,9 @@
 #include "parse-options.h"
 
 static char const * const shortlog_usage[] = {
-       "git shortlog [-n] [-s] [-e] [-w] [rev-opts] [--] [<commit-id>... ]",
+       N_("git shortlog [-n] [-s] [-e] [-w] [rev-opts] [--] [<commit-id>... ]"),
        "",
-       "[rev-opts] are documented in git-rev-list(1)",
+       N_("[rev-opts] are documented in git-rev-list(1)"),
        NULL
 };
 
@@ -250,13 +250,13 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)
 
        static const struct option options[] = {
                OPT_BOOLEAN('n', "numbered", &log.sort_by_number,
-                           "sort output according to the number of commits per author"),
+                           N_("sort output according to the number of commits per author")),
                OPT_BOOLEAN('s', "summary", &log.summary,
-                           "Suppress commit descriptions, only provides commit count"),
+                           N_("Suppress commit descriptions, only provides commit count")),
                OPT_BOOLEAN('e', "email", &log.email,
-                           "Show the email address of each author"),
-               { OPTION_CALLBACK, 'w', NULL, &log, "w[,i1[,i2]]",
-                       "Linewrap output", PARSE_OPT_OPTARG, &parse_wrap_args },
+                           N_("Show the email address of each author")),
+               { OPTION_CALLBACK, 'w', NULL, &log, N_("w[,i1[,i2]]"),
+                       N_("Linewrap output"), PARSE_OPT_OPTARG, &parse_wrap_args },
                OPT_END(),
        };
 
index a59e088cf59215d2d196dda530ad43ef0596b6be..d208fd6c6821c729a713edb485a20bbe8d5e2692 100644 (file)
@@ -6,8 +6,8 @@
 #include "parse-options.h"
 
 static const char* show_branch_usage[] = {
-    "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>)...]",
-    "git show-branch (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]",
+    N_("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>)...]"),
+    N_("git show-branch (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]"),
     NULL
 };
 
@@ -648,36 +648,36 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
        const char *reflog_base = NULL;
        struct option builtin_show_branch_options[] = {
                OPT_BOOLEAN('a', "all", &all_heads,
-                           "show remote-tracking and local branches"),
+                           N_("show remote-tracking and local branches")),
                OPT_BOOLEAN('r', "remotes", &all_remotes,
-                           "show remote-tracking branches"),
+                           N_("show remote-tracking branches")),
                OPT__COLOR(&showbranch_use_color,
-                           "color '*!+-' corresponding to the branch"),
-               { OPTION_INTEGER, 0, "more", &extra, "n",
-                           "show <n> more commits after the common ancestor",
+                           N_("color '*!+-' corresponding to the branch")),
+               { OPTION_INTEGER, 0, "more", &extra, N_("n"),
+                           N_("show <n> more commits after the common ancestor"),
                            PARSE_OPT_OPTARG, NULL, (intptr_t)1 },
-               OPT_SET_INT(0, "list", &extra, "synonym to more=-1", -1),
-               OPT_BOOLEAN(0, "no-name", &no_name, "suppress naming strings"),
+               OPT_SET_INT(0, "list", &extra, N_("synonym to more=-1"), -1),
+               OPT_BOOLEAN(0, "no-name", &no_name, N_("suppress naming strings")),
                OPT_BOOLEAN(0, "current", &with_current_branch,
-                           "include the current branch"),
+                           N_("include the current branch")),
                OPT_BOOLEAN(0, "sha1-name", &sha1_name,
-                           "name commits with their object names"),
+                           N_("name commits with their object names")),
                OPT_BOOLEAN(0, "merge-base", &merge_base,
-                           "show possible merge bases"),
+                           N_("show possible merge bases")),
                OPT_BOOLEAN(0, "independent", &independent,
-                           "show refs unreachable from any other ref"),
+                           N_("show refs unreachable from any other ref")),
                OPT_BOOLEAN(0, "topo-order", &lifo,
-                           "show commits in topological order"),
+                           N_("show commits in topological order")),
                OPT_BOOLEAN(0, "topics", &topics,
-                           "show only commits not on the first branch"),
+                           N_("show only commits not on the first branch")),
                OPT_SET_INT(0, "sparse", &dense,
-                           "show merges reachable from only one tip", 0),
+                           N_("show merges reachable from only one tip"), 0),
                OPT_SET_INT(0, "date-order", &lifo,
-                           "show commits where no parent comes before its "
-                           "children", 0),
-               { OPTION_CALLBACK, 'g', "reflog", &reflog_base, "<n>[,<base>]",
-                           "show <n> most recent ref-log entries starting at "
-                           "base",
+                           N_("show commits where no parent comes before its "
+                              "children"), 0),
+               { OPTION_CALLBACK, 'g', "reflog", &reflog_base, N_("<n>[,<base>]"),
+                           N_("show <n> most recent ref-log entries starting at "
+                              "base"),
                            PARSE_OPT_OPTARG | PARSE_OPT_LITERAL_ARGHELP,
                            parse_reflog_param },
                OPT_END()
index 3911661900f79562133b4ebd6cbb513a06232b5b..8d9b76a02fd115c0285216c27c5232f345d0582d 100644 (file)
@@ -7,8 +7,8 @@
 #include "parse-options.h"
 
 static const char * const show_ref_usage[] = {
-       "git show-ref [-q|--quiet] [--verify] [--head] [-d|--dereference] [-s|--hash[=<n>]] [--abbrev[=<n>]] [--tags] [--heads] [--] [pattern*] ",
-       "git show-ref --exclude-existing[=pattern] < ref-list",
+       N_("git show-ref [-q|--quiet] [--verify] [--head] [-d|--dereference] [-s|--hash[=<n>]] [--abbrev[=<n>]] [--tags] [--heads] [--] [pattern*] "),
+       N_("git show-ref --exclude-existing[=pattern] < ref-list"),
        NULL
 };
 
@@ -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;
 }
@@ -179,26 +162,26 @@ static int help_callback(const struct option *opt, const char *arg, int unset)
 }
 
 static const struct option show_ref_options[] = {
-       OPT_BOOLEAN(0, "tags", &tags_only, "only show tags (can be combined with heads)"),
-       OPT_BOOLEAN(0, "heads", &heads_only, "only show heads (can be combined with tags)"),
-       OPT_BOOLEAN(0, "verify", &verify, "stricter reference checking, "
-                   "requires exact ref path"),
+       OPT_BOOLEAN(0, "tags", &tags_only, N_("only show tags (can be combined with heads)")),
+       OPT_BOOLEAN(0, "heads", &heads_only, N_("only show heads (can be combined with tags)")),
+       OPT_BOOLEAN(0, "verify", &verify, N_("stricter reference checking, "
+                   "requires exact ref path")),
        { OPTION_BOOLEAN, 'h', NULL, &show_head, NULL,
-         "show the HEAD reference",
+         N_("show the HEAD reference"),
          PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
-       OPT_BOOLEAN(0, "head", &show_head, "show the HEAD reference"),
+       OPT_BOOLEAN(0, "head", &show_head, N_("show the HEAD reference")),
        OPT_BOOLEAN('d', "dereference", &deref_tags,
-                   "dereference tags into object IDs"),
-       { OPTION_CALLBACK, 's', "hash", &abbrev, "n",
-         "only show SHA1 hash using <n> digits",
+                   N_("dereference tags into object IDs")),
+       { OPTION_CALLBACK, 's', "hash", &abbrev, N_("n"),
+         N_("only show SHA1 hash using <n> digits"),
          PARSE_OPT_OPTARG, &hash_callback },
        OPT__ABBREV(&abbrev),
        OPT__QUIET(&quiet,
-                  "do not print results to stdout (useful with --verify)"),
+                  N_("do not print results to stdout (useful with --verify)")),
        { OPTION_CALLBACK, 0, "exclude-existing", &exclude_existing_arg,
-         "pattern", "show refs from stdin that aren't in local repository",
+         N_("pattern"), N_("show refs from stdin that aren't in local repository"),
          PARSE_OPT_OPTARG | PARSE_OPT_NONEG, exclude_existing_callback },
-       { OPTION_CALLBACK, 0, "help-all", NULL, NULL, "show usage",
+       { OPTION_CALLBACK, 0, "help-all", NULL, NULL, N_("show usage"),
          PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, help_callback },
        OPT_END()
 };
index 801d62ece5d2ec84d027089c29fc58e279126ebb..9e92828b3ab02fb93c568eab03f0db9d398e8fa2 100644 (file)
@@ -4,7 +4,7 @@
 #include "parse-options.h"
 
 static const char * const git_symbolic_ref_usage[] = {
-       "git symbolic-ref [options] name [ref]",
+       N_("git symbolic-ref [options] name [ref]"),
        NULL
 };
 
@@ -35,9 +35,9 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
        const char *msg = NULL;
        struct option options[] = {
                OPT__QUIET(&quiet,
-                       "suppress error message for non-symbolic (detached) refs"),
-               OPT_BOOL(0, "short", &shorten, "shorten ref output"),
-               OPT_STRING('m', NULL, &msg, "reason", "reason of the update"),
+                       N_("suppress error message for non-symbolic (detached) refs")),
+               OPT_BOOL(0, "short", &shorten, N_("shorten ref output")),
+               OPT_STRING('m', NULL, &msg, N_("reason"), N_("reason of the update")),
                OPT_END(),
        };
 
index 7b1be85e48b67f2a2eb075f6d8366246c7938646..9c3e0673d5bd4e011c877c4d3a17975498265e22 100644 (file)
 #include "column.h"
 
 static const char * const git_tag_usage[] = {
-       "git tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]",
-       "git tag -d <tagname>...",
-       "git tag -l [-n[<num>]] [--contains <commit>] [--points-at <object>] "
-               "\n\t\t[<pattern>...]",
-       "git tag -v <tagname>...",
+       N_("git tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]"),
+       N_("git tag -d <tagname>..."),
+       N_("git tag -l [-n[<num>]] [--contains <commit>] [--points-at <object>] "
+               "\n\t\t[<pattern>...]"),
+       N_("git tag -v <tagname>..."),
        NULL
 };
 
@@ -444,37 +444,37 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
        struct msg_arg msg = { 0, STRBUF_INIT };
        struct commit_list *with_commit = NULL;
        struct option options[] = {
-               OPT_BOOLEAN('l', "list", &list, "list tag names"),
-               { OPTION_INTEGER, 'n', NULL, &lines, "n",
-                               "print <n> lines of each tag message",
+               OPT_BOOLEAN('l', "list", &list, N_("list tag names")),
+               { OPTION_INTEGER, 'n', NULL, &lines, N_("n"),
+                               N_("print <n> lines of each tag message"),
                                PARSE_OPT_OPTARG, NULL, 1 },
-               OPT_BOOLEAN('d', "delete", &delete, "delete tags"),
-               OPT_BOOLEAN('v', "verify", &verify, "verify tags"),
+               OPT_BOOLEAN('d', "delete", &delete, N_("delete tags")),
+               OPT_BOOLEAN('v', "verify", &verify, N_("verify tags")),
 
-               OPT_GROUP("Tag creation options"),
+               OPT_GROUP(N_("Tag creation options")),
                OPT_BOOLEAN('a', "annotate", &annotate,
-                                       "annotated tag, needs a message"),
-               OPT_CALLBACK('m', "message", &msg, "message",
-                            "tag message", parse_msg_arg),
-               OPT_FILENAME('F', "file", &msgfile, "read message from file"),
-               OPT_BOOLEAN('s', "sign", &opt.sign, "annotated and GPG-signed tag"),
-               OPT_STRING(0, "cleanup", &cleanup_arg, "mode",
-                       "how to strip spaces and #comments from message"),
-               OPT_STRING('u', "local-user", &keyid, "key-id",
-                                       "use another key to sign the tag"),
-               OPT__FORCE(&force, "replace the tag if exists"),
-               OPT_COLUMN(0, "column", &colopts, "show tag list in columns"),
-
-               OPT_GROUP("Tag listing options"),
+                                       N_("annotated tag, needs a message")),
+               OPT_CALLBACK('m', "message", &msg, N_("message"),
+                            N_("tag message"), parse_msg_arg),
+               OPT_FILENAME('F', "file", &msgfile, N_("read message from file")),
+               OPT_BOOLEAN('s', "sign", &opt.sign, N_("annotated and GPG-signed tag")),
+               OPT_STRING(0, "cleanup", &cleanup_arg, N_("mode"),
+                       N_("how to strip spaces and #comments from message")),
+               OPT_STRING('u', "local-user", &keyid, N_("key id"),
+                                       N_("use another key to sign the tag")),
+               OPT__FORCE(&force, N_("replace the tag if exists")),
+               OPT_COLUMN(0, "column", &colopts, N_("show tag list in columns")),
+
+               OPT_GROUP(N_("Tag listing options")),
                {
-                       OPTION_CALLBACK, 0, "contains", &with_commit, "commit",
-                       "print only tags that contain the commit",
+                       OPTION_CALLBACK, 0, "contains", &with_commit, N_("commit"),
+                       N_("print only tags that contain the commit"),
                        PARSE_OPT_LASTARG_DEFAULT,
                        parse_opt_with_commit, (intptr_t)"HEAD",
                },
                {
-                       OPTION_CALLBACK, 0, "points-at", NULL, "object",
-                       "print only tags of the object", 0, parse_opt_points_at
+                       OPTION_CALLBACK, 0, "points-at", NULL, N_("object"),
+                       N_("print only tags of the object"), 0, parse_opt_points_at
                },
                OPT_END()
        };
index 5a4e9ea55a10afe2eb0f6e138cb7fce1ef74393f..74986bf163d4dadb4497a90364c29ac71a801638 100644 (file)
@@ -95,7 +95,8 @@ static int add_one_path(struct cache_entry *old, const char *path, int len, stru
        size = cache_entry_size(len);
        ce = xcalloc(1, size);
        memcpy(ce->name, path, len);
-       ce->ce_flags = len;
+       ce->ce_flags = create_ce_flags(0);
+       ce->ce_namelen = len;
        fill_stat_cache_info(ce, st);
        ce->ce_mode = ce_mode_from_stat(old, st->st_mode);
 
@@ -229,7 +230,8 @@ static int add_cacheinfo(unsigned int mode, const unsigned char *sha1,
 
        hashcpy(ce->sha1, sha1);
        memcpy(ce->name, path, len);
-       ce->ce_flags = create_ce_flags(len, stage);
+       ce->ce_flags = create_ce_flags(stage);
+       ce->ce_namelen = len;
        ce->ce_mode = create_ce_mode(mode);
        if (assume_unchanged)
                ce->ce_flags |= CE_VALID;
@@ -396,7 +398,7 @@ static void read_index_info(int line_termination)
 }
 
 static const char * const update_index_usage[] = {
-       "git update-index [options] [--] [<file>...]",
+       N_("git update-index [options] [--] [<file>...]"),
        NULL
 };
 
@@ -427,7 +429,8 @@ static struct cache_entry *read_one_ent(const char *which,
 
        hashcpy(ce->sha1, sha1);
        memcpy(ce->name, path, namelen);
-       ce->ce_flags = create_ce_flags(namelen, stage);
+       ce->ce_flags = create_ce_flags(stage);
+       ce->ce_namelen = namelen;
        ce->ce_mode = create_ce_mode(mode);
        return ce;
 }
@@ -711,83 +714,83 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
        int parseopt_state = PARSE_OPT_UNKNOWN;
        struct option options[] = {
                OPT_BIT('q', NULL, &refresh_args.flags,
-                       "continue refresh even when index needs update",
+                       N_("continue refresh even when index needs update"),
                        REFRESH_QUIET),
                OPT_BIT(0, "ignore-submodules", &refresh_args.flags,
-                       "refresh: ignore submodules",
+                       N_("refresh: ignore submodules"),
                        REFRESH_IGNORE_SUBMODULES),
                OPT_SET_INT(0, "add", &allow_add,
-                       "do not ignore new files", 1),
+                       N_("do not ignore new files"), 1),
                OPT_SET_INT(0, "replace", &allow_replace,
-                       "let files replace directories and vice-versa", 1),
+                       N_("let files replace directories and vice-versa"), 1),
                OPT_SET_INT(0, "remove", &allow_remove,
-                       "notice files missing from worktree", 1),
+                       N_("notice files missing from worktree"), 1),
                OPT_BIT(0, "unmerged", &refresh_args.flags,
-                       "refresh even if index contains unmerged entries",
+                       N_("refresh even if index contains unmerged entries"),
                        REFRESH_UNMERGED),
                {OPTION_CALLBACK, 0, "refresh", &refresh_args, NULL,
-                       "refresh stat information",
+                       N_("refresh stat information"),
                        PARSE_OPT_NOARG | PARSE_OPT_NONEG,
                        refresh_callback},
                {OPTION_CALLBACK, 0, "really-refresh", &refresh_args, NULL,
-                       "like --refresh, but ignore assume-unchanged setting",
+                       N_("like --refresh, but ignore assume-unchanged setting"),
                        PARSE_OPT_NOARG | PARSE_OPT_NONEG,
                        really_refresh_callback},
                {OPTION_LOWLEVEL_CALLBACK, 0, "cacheinfo", NULL,
-                       "<mode> <object> <path>",
-                       "add the specified entry to the index",
+                       N_("<mode> <object> <path>"),
+                       N_("add the specified entry to the index"),
                        PARSE_OPT_NOARG |       /* disallow --cacheinfo=<mode> form */
                        PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP,
                        (parse_opt_cb *) cacheinfo_callback},
-               {OPTION_CALLBACK, 0, "chmod", &set_executable_bit, "(+/-)x",
-                       "override the executable bit of the listed files",
+               {OPTION_CALLBACK, 0, "chmod", &set_executable_bit, N_("(+/-)x"),
+                       N_("override the executable bit of the listed files"),
                        PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP,
                        chmod_callback},
                {OPTION_SET_INT, 0, "assume-unchanged", &mark_valid_only, NULL,
-                       "mark files as \"not changing\"",
+                       N_("mark files as \"not changing\""),
                        PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, MARK_FLAG},
                {OPTION_SET_INT, 0, "no-assume-unchanged", &mark_valid_only, NULL,
-                       "clear assumed-unchanged bit",
+                       N_("clear assumed-unchanged bit"),
                        PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, UNMARK_FLAG},
                {OPTION_SET_INT, 0, "skip-worktree", &mark_skip_worktree_only, NULL,
-                       "mark files as \"index-only\"",
+                       N_("mark files as \"index-only\""),
                        PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, MARK_FLAG},
                {OPTION_SET_INT, 0, "no-skip-worktree", &mark_skip_worktree_only, NULL,
-                       "clear skip-worktree bit",
+                       N_("clear skip-worktree bit"),
                        PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, UNMARK_FLAG},
                OPT_SET_INT(0, "info-only", &info_only,
-                       "add to index only; do not add content to object database", 1),
+                       N_("add to index only; do not add content to object database"), 1),
                OPT_SET_INT(0, "force-remove", &force_remove,
-                       "remove named paths even if present in worktree", 1),
+                       N_("remove named paths even if present in worktree"), 1),
                OPT_SET_INT('z', NULL, &line_termination,
-                       "with --stdin: input lines are terminated by null bytes", '\0'),
+                       N_("with --stdin: input lines are terminated by null bytes"), '\0'),
                {OPTION_LOWLEVEL_CALLBACK, 0, "stdin", &read_from_stdin, NULL,
-                       "read list of paths to be updated from standard input",
+                       N_("read list of paths to be updated from standard input"),
                        PARSE_OPT_NONEG | PARSE_OPT_NOARG,
                        (parse_opt_cb *) stdin_callback},
                {OPTION_LOWLEVEL_CALLBACK, 0, "index-info", &line_termination, NULL,
-                       "add entries from standard input to the index",
+                       N_("add entries from standard input to the index"),
                        PARSE_OPT_NONEG | PARSE_OPT_NOARG,
                        (parse_opt_cb *) stdin_cacheinfo_callback},
                {OPTION_LOWLEVEL_CALLBACK, 0, "unresolve", &has_errors, NULL,
-                       "repopulate stages #2 and #3 for the listed paths",
+                       N_("repopulate stages #2 and #3 for the listed paths"),
                        PARSE_OPT_NONEG | PARSE_OPT_NOARG,
                        (parse_opt_cb *) unresolve_callback},
                {OPTION_LOWLEVEL_CALLBACK, 'g', "again", &has_errors, NULL,
-                       "only update entries that differ from HEAD",
+                       N_("only update entries that differ from HEAD"),
                        PARSE_OPT_NONEG | PARSE_OPT_NOARG,
                        (parse_opt_cb *) reupdate_callback},
                OPT_BIT(0, "ignore-missing", &refresh_args.flags,
-                       "ignore files missing from worktree",
+                       N_("ignore files missing from worktree"),
                        REFRESH_IGNORE_MISSING),
                OPT_SET_INT(0, "verbose", &verbose,
-                       "report actions to standard output", 1),
+                       N_("report actions to standard output"), 1),
                {OPTION_CALLBACK, 0, "clear-resolve-undo", NULL, NULL,
-                       "(for porcelains) forget saved unresolved conflicts",
+                       N_("(for porcelains) forget saved unresolved conflicts"),
                        PARSE_OPT_NOARG | PARSE_OPT_NONEG,
                        resolve_undo_clear_callback},
                OPT_INTEGER(0, "index-version", &preferred_index_format,
-                           "write index in this format"),
+                       N_("write index in this format")),
                OPT_END()
        };
 
index 835c62ab15c742af2f75e7bf66e35501701ed15a..51d26848598d7f18749f1f2859d7a74558d60b69 100644 (file)
@@ -4,8 +4,8 @@
 #include "parse-options.h"
 
 static const char * const git_update_ref_usage[] = {
-       "git update-ref [options] -d <refname> [<oldval>]",
-       "git update-ref [options]    <refname> <newval> [<oldval>]",
+       N_("git update-ref [options] -d <refname> [<oldval>]"),
+       N_("git update-ref [options]    <refname> <newval> [<oldval>]"),
        NULL
 };
 
@@ -15,10 +15,10 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
        unsigned char sha1[20], oldsha1[20];
        int delete = 0, no_deref = 0, flags = 0;
        struct option options[] = {
-               OPT_STRING( 'm', NULL, &msg, "reason", "reason of the update"),
-               OPT_BOOLEAN('d', NULL, &delete, "deletes the reference"),
+               OPT_STRING( 'm', NULL, &msg, N_("reason"), N_("reason of the update")),
+               OPT_BOOLEAN('d', NULL, &delete, N_("delete the reference")),
                OPT_BOOLEAN( 0 , "no-deref", &no_deref,
-                                       "update <refname> not the one it points to"),
+                                       N_("update <refname> not the one it points to")),
                OPT_END(),
        };
 
index 0d63c4498c0c10193846c020a2d76958bd12e1bd..6c8cc3edc1f5fec4e2aa173f2650a69db5e065f0 100644 (file)
@@ -3,7 +3,7 @@
 #include "parse-options.h"
 
 static const char * const update_server_info_usage[] = {
-       "git update-server-info [--force]",
+       N_("git update-server-info [--force]"),
        NULL
 };
 
@@ -11,7 +11,7 @@ int cmd_update_server_info(int argc, const char **argv, const char *prefix)
 {
        int force = 0;
        struct option options[] = {
-               OPT__FORCE(&force, "update the info files from scratch"),
+               OPT__FORCE(&force, N_("update the info files from scratch")),
                OPT_END()
        };
 
index e841b4a38d2b47c39d95683a5747cbc19da1f48b..66cd2df0f878d362a86e8dbc3fcd49b0c2f64c0c 100644 (file)
@@ -53,7 +53,7 @@ static int verify_one_pack(const char *path, unsigned int flags)
 }
 
 static const char * const verify_pack_usage[] = {
-       "git verify-pack [-v|--verbose] [-s|--stat-only] <pack>...",
+       N_("git verify-pack [-v|--verbose] [-s|--stat-only] <pack>..."),
        NULL
 };
 
@@ -63,9 +63,9 @@ int cmd_verify_pack(int argc, const char **argv, const char *prefix)
        unsigned int flags = 0;
        int i;
        const struct option verify_pack_options[] = {
-               OPT_BIT('v', "verbose", &flags, "verbose",
+               OPT_BIT('v', "verbose", &flags, N_("verbose"),
                        VERIFY_PACK_VERBOSE),
-               OPT_BIT('s', "stat-only", &flags, "show statistics only",
+               OPT_BIT('s', "stat-only", &flags, N_("show statistics only"),
                        VERIFY_PACK_STAT_ONLY),
                OPT_END()
        };
index 986789f706911d122e24b0d784ab193e2ec3b74b..a8eee886a5281965a0660308df9e94d14c1cb2b8 100644 (file)
@@ -14,7 +14,7 @@
 #include "gpg-interface.h"
 
 static const char * const verify_tag_usage[] = {
-               "git verify-tag [-v|--verbose] <tag>...",
+               N_("git verify-tag [-v|--verbose] <tag>..."),
                NULL
 };
 
@@ -70,7 +70,7 @@ int cmd_verify_tag(int argc, const char **argv, const char *prefix)
 {
        int i = 1, verbose = 0, had_error = 0;
        const struct option verify_tag_options[] = {
-               OPT__VERBOSE(&verbose, "print tag contents"),
+               OPT__VERBOSE(&verbose, N_("print tag contents")),
                OPT_END()
        };
 
index b223af416fee5fc219fbcca7afa2b9e03feaa7d0..084c0df7833f29c7554a4ffe95dac4bda1c6ce66 100644 (file)
@@ -10,7 +10,7 @@
 #include "parse-options.h"
 
 static const char * const write_tree_usage[] = {
-       "git write-tree [--missing-ok] [--prefix=<prefix>/]",
+       N_("git write-tree [--missing-ok] [--prefix=<prefix>/]"),
        NULL
 };
 
@@ -21,13 +21,13 @@ int cmd_write_tree(int argc, const char **argv, const char *unused_prefix)
        unsigned char sha1[20];
        const char *me = "git-write-tree";
        struct option write_tree_options[] = {
-               OPT_BIT(0, "missing-ok", &flags, "allow missing objects",
+               OPT_BIT(0, "missing-ok", &flags, N_("allow missing objects"),
                        WRITE_TREE_MISSING_OK),
-               { OPTION_STRING, 0, "prefix", &prefix, "<prefix>/",
-                 "write tree object for a subdirectory <prefix>" ,
+               { OPTION_STRING, 0, "prefix", &prefix, N_("<prefix>/"),
+                 N_("write tree object for a subdirectory <prefix>") ,
                  PARSE_OPT_LITERAL_ARGHELP },
                { OPTION_BIT, 0, "ignore-cache-tree", &flags, NULL,
-                 "only useful for debugging",
+                 N_("only useful for debugging"),
                  PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, NULL,
                  WRITE_TREE_IGNORE_CACHE_TREE },
                OPT_END()
diff --git a/cache.h b/cache.h
index 75b3bea92dc3139b21541e37eb736c3ca625171d..a58df84bd374feda0e0c7fdfe65129db2cb3c252 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -128,13 +128,13 @@ struct cache_entry {
        unsigned int ce_gid;
        unsigned int ce_size;
        unsigned int ce_flags;
+       unsigned int ce_namelen;
        unsigned char sha1[20];
        struct cache_entry *next;
        struct cache_entry *dir_next;
        char name[FLEX_ARRAY]; /* more */
 };
 
-#define CE_NAMEMASK  (0x0fff)
 #define CE_STAGEMASK (0x3000)
 #define CE_EXTENDED  (0x4000)
 #define CE_VALID     (0x8000)
@@ -198,21 +198,12 @@ static inline void copy_cache_entry(struct cache_entry *dst, struct cache_entry
        dst->ce_flags = (dst->ce_flags & ~CE_STATE_MASK) | state;
 }
 
-static inline unsigned create_ce_flags(size_t len, unsigned stage)
+static inline unsigned create_ce_flags(unsigned stage)
 {
-       if (len >= CE_NAMEMASK)
-               len = CE_NAMEMASK;
-       return (len | (stage << CE_STAGESHIFT));
-}
-
-static inline size_t ce_namelen(const struct cache_entry *ce)
-{
-       size_t len = ce->ce_flags & CE_NAMEMASK;
-       if (len < CE_NAMEMASK)
-               return len;
-       return strlen(ce->name + CE_NAMEMASK) + CE_NAMEMASK;
+       return (stage << CE_STAGESHIFT);
 }
 
+#define ce_namelen(ce) ((ce)->ce_namelen)
 #define ce_size(ce) cache_entry_size(ce_namelen(ce))
 #define ce_stage(ce) ((CE_STAGEMASK & (ce)->ce_flags) >> CE_STAGESHIFT)
 #define ce_uptodate(ce) ((ce)->ce_flags & CE_UPTODATE)
@@ -563,6 +554,7 @@ extern int read_replace_refs;
 extern int fsync_object_files;
 extern int core_preload_index;
 extern int core_apply_sparse_checkout;
+extern int precomposed_unicode;
 
 enum branch_track {
        BRANCH_TRACK_UNSPECIFIED = -1,
@@ -622,6 +614,8 @@ extern char *git_snpath(char *buf, size_t n, const char *fmt, ...)
        __attribute__((format (printf, 3, 4)));
 extern char *git_pathdup(const char *fmt, ...)
        __attribute__((format (printf, 1, 2)));
+extern char *mkpathdup(const char *fmt, ...)
+       __attribute__((format (printf, 1, 2)));
 
 /* Return a statically allocated filename matching the sha1 signature */
 extern char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
@@ -711,6 +705,7 @@ int set_shared_perm(const char *path, int mode);
 int safe_create_leading_directories(char *path);
 int safe_create_leading_directories_const(const char *path);
 int mkdir_in_gitdir(const char *path);
+extern void home_config_paths(char **global, char **xdg, char *file);
 extern char *expand_user_path(const char *path);
 const char *enter_repo(const char *path, int strict);
 static inline int is_absolute_path(const char *path)
@@ -786,17 +781,25 @@ struct object_context {
        unsigned mode;
 };
 
+#define GET_SHA1_QUIETLY        01
+#define GET_SHA1_COMMIT         02
+#define GET_SHA1_COMMITTISH     04
+#define GET_SHA1_TREE          010
+#define GET_SHA1_TREEISH       020
+#define GET_SHA1_BLOB         040
+#define GET_SHA1_ONLY_TO_DIE 04000
+
 extern int get_sha1(const char *str, unsigned char *sha1);
-extern int get_sha1_with_mode_1(const char *str, unsigned char *sha1, unsigned *mode, int only_to_die, const char *prefix);
-static inline int get_sha1_with_mode(const char *str, unsigned char *sha1, unsigned *mode)
-{
-       return get_sha1_with_mode_1(str, sha1, mode, 0, NULL);
-}
-extern int get_sha1_with_context_1(const char *name, unsigned char *sha1, struct object_context *orc, int only_to_die, const char *prefix);
-static inline int get_sha1_with_context(const char *str, unsigned char *sha1, struct object_context *orc)
-{
-       return get_sha1_with_context_1(str, sha1, orc, 0, NULL);
-}
+extern int get_sha1_commit(const char *str, unsigned char *sha1);
+extern int get_sha1_committish(const char *str, unsigned char *sha1);
+extern int get_sha1_tree(const char *str, unsigned char *sha1);
+extern int get_sha1_treeish(const char *str, unsigned char *sha1);
+extern int get_sha1_blob(const char *str, unsigned char *sha1);
+extern void maybe_die_on_misspelt_object_name(const char *name, const char *prefix);
+extern int get_sha1_with_context(const char *str, unsigned flags, unsigned char *sha1, struct object_context *orc);
+
+typedef int each_abbrev_fn(const unsigned char *sha1, void *);
+extern int for_each_abbrev(const char *prefix, each_abbrev_fn, void *);
 
 /*
  * Try to read a SHA1 in hexadecimal format from the 40 characters
@@ -860,6 +863,7 @@ extern int validate_headref(const char *ref);
 extern int base_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2);
 extern int df_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2);
 extern int cache_name_compare(const char *name1, int len1, const char *name2, int len2);
+extern int cache_name_stage_compare(const char *name1, int len1, int stage1, const char *name2, int len2, int stage2);
 
 extern void *read_object_with_reference(const unsigned char *sha1,
                                        const char *required_type,
@@ -897,9 +901,7 @@ extern const char *git_author_info(int);
 extern const char *git_committer_info(int);
 extern const char *fmt_ident(const char *name, const char *email, const char *date_str, int);
 extern const char *fmt_name(const char *name, const char *email);
-extern const char *ident_default_name(void);
 extern const char *ident_default_email(void);
-extern const char *ident_default_date(void);
 extern const char *git_editor(void);
 extern const char *git_pager(int stdout_is_tty);
 extern int git_ident_config(const char *, const char *, void *);
@@ -942,9 +944,7 @@ struct cache_def {
 extern int has_symlink_leading_path(const char *name, int len);
 extern int threaded_has_symlink_leading_path(struct cache_def *, const char *, int);
 extern int check_leading_path(const char *name, int len);
-extern int threaded_check_leading_path(struct cache_def *cache, const char *name, int len);
 extern int has_dirs_only_path(const char *name, int len, int prefix_len);
-extern int threaded_has_dirs_only_path(struct cache_def *cache, const char *name, int len, int prefix_len);
 extern void schedule_dir_for_removal(const char *name, int len);
 extern void remove_scheduled_dirs(void);
 
@@ -1033,7 +1033,9 @@ struct extra_have_objects {
 };
 extern struct ref **get_remote_heads(int in, struct ref **list, unsigned int flags, struct extra_have_objects *);
 extern int server_supports(const char *feature);
-extern const char *parse_feature_request(const char *features, const char *feature);
+extern int parse_feature_request(const char *features, const char *feature);
+extern const char *server_feature_value(const char *feature, int *len_ret);
+extern const char *parse_feature_value(const char *feature_list, const char *feature, int *len_ret);
 
 extern struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path);
 
@@ -1201,7 +1203,6 @@ extern void alloc_report(void);
 /* trace.c */
 __attribute__((format (printf, 1, 2)))
 extern void trace_printf(const char *format, ...);
-extern void trace_vprintf(const char *key, const char *format, va_list ap);
 __attribute__((format (printf, 2, 3)))
 extern void trace_argv_printf(const char **argv, const char *format, ...);
 extern void trace_repo_setup(const char *prefix);
index 14ea67af038fbfce388dd20b8adcda503106911d..7e8cfec29d9e00cd6dfb26bca1f1295f64ae53fd 100644 (file)
@@ -25,6 +25,9 @@ git-commit                              mainporcelain common
 git-commit-tree                         plumbingmanipulators
 git-config                              ancillarymanipulators
 git-count-objects                       ancillaryinterrogators
+git-credential                          purehelpers
+git-credential-cache                    purehelpers
+git-credential-store                    purehelpers
 git-cvsexportcommit                     foreignscminterface
 git-cvsimport                           foreignscminterface
 git-cvsserver                           foreignscminterface
@@ -113,6 +116,7 @@ git-show                                mainporcelain common
 git-show-branch                         ancillaryinterrogators
 git-show-index                          plumbinginterrogators
 git-show-ref                            plumbinginterrogators
+git-sh-i18n                             purehelpers
 git-sh-setup                            purehelpers
 git-stash                               mainporcelain
 git-status                              mainporcelain common
index 8248a994a50ab91874600567e544aa3735e4aa98..213bc98c183b820c43c66d67a15133b4a401f6a4 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -9,6 +9,8 @@
 #include "gpg-interface.h"
 #include "mergesort.h"
 
+static struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **);
+
 int save_commit_buffer = 1;
 
 const char *commit_type = "commit";
@@ -68,7 +70,7 @@ struct commit *lookup_commit_reference_by_name(const char *name)
        unsigned char sha1[20];
        struct commit *commit;
 
-       if (get_sha1(name, sha1))
+       if (get_sha1_committish(name, sha1))
                return NULL;
        commit = lookup_commit_reference(sha1);
        if (!commit || parse_commit(commit))
@@ -607,30 +609,17 @@ static struct commit *interesting(struct commit_list *list)
        return NULL;
 }
 
-static struct commit_list *merge_bases_many(struct commit *one, int n, struct commit **twos)
+/* all input commits in one and twos[] must have been parsed! */
+static struct commit_list *paint_down_to_common(struct commit *one, int n, struct commit **twos)
 {
        struct commit_list *list = NULL;
        struct commit_list *result = NULL;
        int i;
 
-       for (i = 0; i < n; i++) {
-               if (one == twos[i])
-                       /*
-                        * We do not mark this even with RESULT so we do not
-                        * have to clean it up.
-                        */
-                       return commit_list_insert(one, &result);
-       }
-
-       if (parse_commit(one))
-               return NULL;
-       for (i = 0; i < n; i++) {
-               if (parse_commit(twos[i]))
-                       return NULL;
-       }
-
        one->object.flags |= PARENT1;
        commit_list_insert_by_date(one, &list);
+       if (!n)
+               return list;
        for (i = 0; i < n; i++) {
                twos[i]->object.flags |= PARENT2;
                commit_list_insert_by_date(twos[i], &list);
@@ -669,9 +658,34 @@ static struct commit_list *merge_bases_many(struct commit *one, int n, struct co
                }
        }
 
-       /* Clean up the result to remove stale ones */
        free_commit_list(list);
-       list = result; result = NULL;
+       return result;
+}
+
+static struct commit_list *merge_bases_many(struct commit *one, int n, struct commit **twos)
+{
+       struct commit_list *list = NULL;
+       struct commit_list *result = NULL;
+       int i;
+
+       for (i = 0; i < n; i++) {
+               if (one == twos[i])
+                       /*
+                        * We do not mark this even with RESULT so we do not
+                        * have to clean it up.
+                        */
+                       return commit_list_insert(one, &result);
+       }
+
+       if (parse_commit(one))
+               return NULL;
+       for (i = 0; i < n; i++) {
+               if (parse_commit(twos[i]))
+                       return NULL;
+       }
+
+       list = paint_down_to_common(one, n, twos);
+
        while (list) {
                struct commit_list *next = list->next;
                if (!(list->item->object.flags & STALE))
@@ -709,6 +723,62 @@ struct commit_list *get_octopus_merge_bases(struct commit_list *in)
        return ret;
 }
 
+static int remove_redundant(struct commit **array, int cnt)
+{
+       /*
+        * Some commit in the array may be an ancestor of
+        * another commit.  Move such commit to the end of
+        * the array, and return the number of commits that
+        * are independent from each other.
+        */
+       struct commit **work;
+       unsigned char *redundant;
+       int *filled_index;
+       int i, j, filled;
+
+       work = xcalloc(cnt, sizeof(*work));
+       redundant = xcalloc(cnt, 1);
+       filled_index = xmalloc(sizeof(*filled_index) * (cnt - 1));
+
+       for (i = 0; i < cnt; i++)
+               parse_commit(array[i]);
+       for (i = 0; i < cnt; i++) {
+               struct commit_list *common;
+
+               if (redundant[i])
+                       continue;
+               for (j = filled = 0; j < cnt; j++) {
+                       if (i == j || redundant[j])
+                               continue;
+                       filled_index[filled] = j;
+                       work[filled++] = array[j];
+               }
+               common = paint_down_to_common(array[i], filled, work);
+               if (array[i]->object.flags & PARENT2)
+                       redundant[i] = 1;
+               for (j = 0; j < filled; j++)
+                       if (work[j]->object.flags & PARENT1)
+                               redundant[filled_index[j]] = 1;
+               clear_commit_marks(array[i], all_flags);
+               for (j = 0; j < filled; j++)
+                       clear_commit_marks(work[j], all_flags);
+               free_commit_list(common);
+       }
+
+       /* Now collect the result */
+       memcpy(work, array, sizeof(*array) * cnt);
+       for (i = filled = 0; i < cnt; i++)
+               if (!redundant[i])
+                       array[filled++] = work[i];
+       for (j = filled, i = 0; i < cnt; i++)
+               if (redundant[i])
+                       array[j++] = work[i];
+       free(work);
+       free(redundant);
+       free(filled_index);
+       return filled;
+}
+
 struct commit_list *get_merge_bases_many(struct commit *one,
                                         int n,
                                         struct commit **twos,
@@ -717,7 +787,7 @@ struct commit_list *get_merge_bases_many(struct commit *one,
        struct commit_list *list;
        struct commit **rslt;
        struct commit_list *result;
-       int cnt, i, j;
+       int cnt, i;
 
        result = merge_bases_many(one, n, twos);
        for (i = 0; i < n; i++) {
@@ -748,28 +818,11 @@ struct commit_list *get_merge_bases_many(struct commit *one,
        clear_commit_marks(one, all_flags);
        for (i = 0; i < n; i++)
                clear_commit_marks(twos[i], all_flags);
-       for (i = 0; i < cnt - 1; i++) {
-               for (j = i+1; j < cnt; j++) {
-                       if (!rslt[i] || !rslt[j])
-                               continue;
-                       result = merge_bases_many(rslt[i], 1, &rslt[j]);
-                       clear_commit_marks(rslt[i], all_flags);
-                       clear_commit_marks(rslt[j], all_flags);
-                       for (list = result; list; list = list->next) {
-                               if (rslt[i] == list->item)
-                                       rslt[i] = NULL;
-                               if (rslt[j] == list->item)
-                                       rslt[j] = NULL;
-                       }
-               }
-       }
 
-       /* Surviving ones in rslt[] are the independent results */
+       cnt = remove_redundant(rslt, cnt);
        result = NULL;
-       for (i = 0; i < cnt; i++) {
-               if (rslt[i])
-                       commit_list_insert_by_date(rslt[i], &result);
-       }
+       for (i = 0; i < cnt; i++)
+               commit_list_insert_by_date(rslt[i], &result);
        free(rslt);
        return result;
 }
@@ -780,6 +833,9 @@ struct commit_list *get_merge_bases(struct commit *one, struct commit *two,
        return get_merge_bases_many(one, 1, &two, cleanup);
 }
 
+/*
+ * Is "commit" a decendant of one of the elements on the "with_commit" list?
+ */
 int is_descendant_of(struct commit *commit, struct commit_list *with_commit)
 {
        if (!with_commit)
@@ -789,28 +845,28 @@ int is_descendant_of(struct commit *commit, struct commit_list *with_commit)
 
                other = with_commit->item;
                with_commit = with_commit->next;
-               if (in_merge_bases(other, &commit, 1))
+               if (in_merge_bases(other, commit))
                        return 1;
        }
        return 0;
 }
 
-int in_merge_bases(struct commit *commit, struct commit **reference, int num)
+/*
+ * Is "commit" an ancestor of (i.e. reachable from) the "reference"?
+ */
+int in_merge_bases(struct commit *commit, struct commit *reference)
 {
-       struct commit_list *bases, *b;
+       struct commit_list *bases;
        int ret = 0;
 
-       if (num == 1)
-               bases = get_merge_bases(commit, *reference, 1);
-       else
-               die("not yet");
-       for (b = bases; b; b = b->next) {
-               if (!hashcmp(commit->object.sha1, b->item->object.sha1)) {
-                       ret = 1;
-                       break;
-               }
-       }
+       if (parse_commit(commit) || parse_commit(reference))
+               return ret;
 
+       bases = paint_down_to_common(commit, 1, &reference);
+       if (commit->object.flags & PARENT2)
+               ret = 1;
+       clear_commit_marks(commit, all_flags);
+       clear_commit_marks(reference, all_flags);
        free_commit_list(bases);
        return ret;
 }
@@ -819,51 +875,31 @@ struct commit_list *reduce_heads(struct commit_list *heads)
 {
        struct commit_list *p;
        struct commit_list *result = NULL, **tail = &result;
-       struct commit **other;
-       size_t num_head, num_other;
+       struct commit **array;
+       int num_head, i;
 
        if (!heads)
                return NULL;
 
-       /* Avoid unnecessary reallocations */
-       for (p = heads, num_head = 0; p; p = p->next)
-               num_head++;
-       other = xcalloc(sizeof(*other), num_head);
-
-       /* For each commit, see if it can be reached by others */
-       for (p = heads; p; p = p->next) {
-               struct commit_list *q, *base;
-
-               /* Do we already have this in the result? */
-               for (q = result; q; q = q->next)
-                       if (p->item == q->item)
-                               break;
-               if (q)
+       /* Uniquify */
+       for (p = heads; p; p = p->next)
+               p->item->object.flags &= ~STALE;
+       for (p = heads, num_head = 0; p; p = p->next) {
+               if (p->item->object.flags & STALE)
                        continue;
-
-               num_other = 0;
-               for (q = heads; q; q = q->next) {
-                       if (p->item == q->item)
-                               continue;
-                       other[num_other++] = q->item;
+               p->item->object.flags |= STALE;
+               num_head++;
+       }
+       array = xcalloc(sizeof(*array), num_head);
+       for (p = heads, i = 0; p; p = p->next) {
+               if (p->item->object.flags & STALE) {
+                       array[i++] = p->item;
+                       p->item->object.flags &= ~STALE;
                }
-               if (num_other)
-                       base = get_merge_bases_many(p->item, num_other, other, 1);
-               else
-                       base = NULL;
-               /*
-                * If p->item does not have anything common with other
-                * commits, there won't be any merge base.  If it is
-                * reachable from some of the others, p->item will be
-                * the merge base.  If its history is connected with
-                * others, but p->item is not reachable by others, we
-                * will get something other than p->item back.
-                */
-               if (!base || (base->item != p->item))
-                       tail = &(commit_list_insert(p->item, tail)->next);
-               free_commit_list(base);
        }
-       free(other);
+       num_head = remove_redundant(array, num_head);
+       for (i = 0; i < num_head; i++)
+               tail = &commit_list_insert(array[i], tail)->next;
        return result;
 }
 
@@ -1044,8 +1080,9 @@ static int excluded_header_field(const char *field, size_t len, const char **exc
        return 0;
 }
 
-struct commit_extra_header *read_commit_extra_header_lines(const char *buffer, size_t size,
-                                                          const char **exclude)
+static struct commit_extra_header *read_commit_extra_header_lines(
+       const char *buffer, size_t size,
+       const char **exclude)
 {
        struct commit_extra_header *extra = NULL, **tail = &extra, *it = NULL;
        const char *line, *next, *eof, *eob;
@@ -1112,8 +1149,92 @@ int commit_tree(const struct strbuf *msg, unsigned char *tree,
        return result;
 }
 
+static int find_invalid_utf8(const char *buf, int len)
+{
+       int offset = 0;
+
+       while (len) {
+               unsigned char c = *buf++;
+               int bytes, bad_offset;
+
+               len--;
+               offset++;
+
+               /* Simple US-ASCII? No worries. */
+               if (c < 0x80)
+                       continue;
+
+               bad_offset = offset-1;
+
+               /*
+                * Count how many more high bits set: that's how
+                * many more bytes this sequence should have.
+                */
+               bytes = 0;
+               while (c & 0x40) {
+                       c <<= 1;
+                       bytes++;
+               }
+
+               /* Must be between 1 and 5 more bytes */
+               if (bytes < 1 || bytes > 5)
+                       return bad_offset;
+
+               /* Do we *have* that many bytes? */
+               if (len < bytes)
+                       return bad_offset;
+
+               offset += bytes;
+               len -= bytes;
+
+               /* And verify that they are good continuation bytes */
+               do {
+                       if ((*buf++ & 0xc0) != 0x80)
+                               return bad_offset;
+               } while (--bytes);
+
+               /* We could/should check the value and length here too */
+       }
+       return -1;
+}
+
+/*
+ * This verifies that the buffer is in proper utf8 format.
+ *
+ * If it isn't, it assumes any non-utf8 characters are Latin1,
+ * and does the conversion.
+ *
+ * Fixme: we should probably also disallow overlong forms and
+ * invalid characters. But we don't do that currently.
+ */
+static int verify_utf8(struct strbuf *buf)
+{
+       int ok = 1;
+       long pos = 0;
+
+       for (;;) {
+               int bad;
+               unsigned char c;
+               unsigned char replace[2];
+
+               bad = find_invalid_utf8(buf->buf + pos, buf->len - pos);
+               if (bad < 0)
+                       return ok;
+               pos += bad;
+               ok = 0;
+               c = buf->buf[pos];
+               strbuf_remove(buf, pos, 1);
+
+               /* We know 'c' must be in the range 128-255 */
+               replace[0] = 0xc0 + (c >> 6);
+               replace[1] = 0x80 + (c & 0x3f);
+               strbuf_insert(buf, pos, replace, 2);
+               pos += 2;
+       }
+}
+
 static const char commit_utf8_warn[] =
-"Warning: commit message does not conform to UTF-8.\n"
+"Warning: commit message did not conform to UTF-8.\n"
 "You may want to amend it after fixing the message, or set the config\n"
 "variable i18n.commitencoding to the encoding your project uses.\n";
 
@@ -1170,7 +1291,7 @@ int commit_tree_extended(const struct strbuf *msg, unsigned char *tree,
        strbuf_addbuf(&buffer, msg);
 
        /* And check the encoding */
-       if (encoding_is_utf8 && !is_utf8(buffer.buf))
+       if (encoding_is_utf8 && !verify_utf8(&buffer))
                fprintf(stderr, commit_utf8_warn);
 
        if (sign_commit && do_sign_commit(&buffer, sign_commit))
index d617fa3f28d9fecf0bbf8e87c373f8701c286227..9f2131318d4c43fdaaca40e45e45e7d1af61cdfe 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -171,7 +171,7 @@ extern struct commit_list *get_shallow_commits(struct object_array *heads,
                int depth, int shallow_flag, int not_shallow_flag);
 
 int is_descendant_of(struct commit *, struct commit_list *);
-int in_merge_bases(struct commit *, struct commit **, int);
+int in_merge_bases(struct commit *, struct commit *);
 
 extern int interactive_add(int argc, const char **argv, const char *prefix, int patch);
 extern int run_add_interactive(const char *revision, const char *patch_mode,
@@ -204,7 +204,6 @@ extern int commit_tree_extended(const struct strbuf *msg, unsigned char *tree,
                                struct commit_extra_header *);
 
 extern struct commit_extra_header *read_commit_extra_headers(struct commit *, const char **);
-extern struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **);
 
 extern void free_commit_extra_headers(struct commit_extra_header *extra);
 
index afc892d6b1837d807490f42790bf29686d074a10..4e6383898c59f03127ed698abcb86857d63a8eac 100644 (file)
@@ -335,6 +335,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.
index 61a652138ac7b7ef412bbc15e6ce479db158b181..eeb08d120bab73154afe282873514c920628eab2 100644 (file)
@@ -185,6 +185,9 @@ FILE *mingw_fopen (const char *filename, const char *otype);
 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
 
diff --git a/compat/mkdir.c b/compat/mkdir.c
new file mode 100644 (file)
index 0000000..9e253fb
--- /dev/null
@@ -0,0 +1,24 @@
+#include "../git-compat-util.h"
+#undef mkdir
+
+/* for platforms that can't deal with a trailing '/' */
+int compat_mkdir_wo_trailing_slash(const char *dir, mode_t mode)
+{
+       int retval;
+       char *tmp_dir = NULL;
+       size_t len = strlen(dir);
+
+       if (len && dir[len-1] == '/') {
+               if ((tmp_dir = strdup(dir)) == NULL)
+                       return -1;
+               tmp_dir[len-1] = '\0';
+       }
+       else
+               tmp_dir = (char *)dir;
+
+       retval = mkdir(tmp_dir, mode);
+       if (tmp_dir != dir)
+               free(tmp_dir);
+
+       return retval;
+}
similarity index 97%
rename from compat/win32/poll.c
rename to compat/poll/poll.c
index 403eaa7a3c8c750d9be5934b197999c5057ce64d..7d226ecb293ee3c5f9b17aa3e5e36b7c8701dbae 100644 (file)
@@ -24,7 +24,9 @@
 # pragma GCC diagnostic ignored "-Wtype-limits"
 #endif
 
-#include <malloc.h>
+#if defined(WIN32)
+# include <malloc.h>
+#endif
 
 #include <sys/types.h>
 
@@ -48,7 +50,9 @@
 #else
 # include <sys/time.h>
 # include <sys/socket.h>
-# include <sys/select.h>
+# ifndef NO_SYS_SELECT_H
+#  include <sys/select.h>
+# endif
 # include <unistd.h>
 #endif
 
@@ -302,6 +306,10 @@ compute_revents (int fd, int sought, fd_set *rfds, fd_set *wfds, fd_set *efds)
               || socket_errno == ECONNABORTED || socket_errno == ENETRESET)
        happened |= POLLHUP;
 
+      /* some systems can't use recv() on non-socket, including HP NonStop */
+      else if (/* (r == -1) && */ socket_errno == ENOTSOCK)
+       happened |= (POLLIN | POLLRDNORM) & sought;
+
       else
        happened |= POLLERR;
     }
@@ -349,7 +357,7 @@ poll (struct pollfd *pfd, nfds_t nfd, int timeout)
 
   /* EFAULT is not necessary to implement, but let's do it in the
      simplest case. */
-  if (!pfd)
+  if (!pfd && nfd)
     {
       errno = EFAULT;
       return -1;
similarity index 100%
rename from compat/win32/poll.h
rename to compat/poll/poll.h
diff --git a/compat/precompose_utf8.c b/compat/precompose_utf8.c
new file mode 100644 (file)
index 0000000..8cf5955
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * Converts filenames from decomposed unicode into precomposed unicode.
+ * Used on MacOS X.
+ */
+
+#define PRECOMPOSE_UNICODE_C
+
+#include "cache.h"
+#include "utf8.h"
+#include "precompose_utf8.h"
+
+typedef char *iconv_ibp;
+static const char *repo_encoding = "UTF-8";
+static const char *path_encoding = "UTF-8-MAC";
+
+static size_t has_non_ascii(const char *s, size_t maxlen, size_t *strlen_c)
+{
+       const uint8_t *ptr = (const uint8_t *)s;
+       size_t strlen_chars = 0;
+       size_t ret = 0;
+
+       if (!ptr || !*ptr)
+               return 0;
+
+       while (*ptr && maxlen) {
+               if (*ptr & 0x80)
+                       ret++;
+               strlen_chars++;
+               ptr++;
+               maxlen--;
+       }
+       if (strlen_c)
+               *strlen_c = strlen_chars;
+
+       return ret;
+}
+
+
+void probe_utf8_pathname_composition(char *path, int len)
+{
+       static const char *auml_nfc = "\xc3\xa4";
+       static const char *auml_nfd = "\x61\xcc\x88";
+       int output_fd;
+       if (precomposed_unicode != -1)
+               return; /* We found it defined in the global config, respect it */
+       strcpy(path + len, auml_nfc);
+       output_fd = open(path, O_CREAT|O_EXCL|O_RDWR, 0600);
+       if (output_fd >= 0) {
+               close(output_fd);
+               strcpy(path + len, auml_nfd);
+               /* Indicate to the user, that we can configure it to true */
+               if (!access(path, R_OK))
+                       git_config_set("core.precomposeunicode", "false");
+               /* To be backward compatible, set precomposed_unicode to 0 */
+               precomposed_unicode = 0;
+               strcpy(path + len, auml_nfc);
+               if (unlink(path))
+                       die_errno(_("failed to unlink '%s'"), path);
+       }
+}
+
+
+void precompose_argv(int argc, const char **argv)
+{
+       int i = 0;
+       const char *oldarg;
+       char *newarg;
+       iconv_t ic_precompose;
+
+       if (precomposed_unicode != 1)
+               return;
+
+       ic_precompose = iconv_open(repo_encoding, path_encoding);
+       if (ic_precompose == (iconv_t) -1)
+               return;
+
+       while (i < argc) {
+               size_t namelen;
+               oldarg = argv[i];
+               if (has_non_ascii(oldarg, (size_t)-1, &namelen)) {
+                       newarg = reencode_string_iconv(oldarg, namelen, ic_precompose);
+                       if (newarg)
+                               argv[i] = newarg;
+               }
+               i++;
+       }
+       iconv_close(ic_precompose);
+}
+
+
+PREC_DIR *precompose_utf8_opendir(const char *dirname)
+{
+       PREC_DIR *prec_dir = xmalloc(sizeof(PREC_DIR));
+       prec_dir->dirent_nfc = xmalloc(sizeof(dirent_prec_psx));
+       prec_dir->dirent_nfc->max_name_len = sizeof(prec_dir->dirent_nfc->d_name);
+
+       prec_dir->dirp = opendir(dirname);
+       if (!prec_dir->dirp) {
+               free(prec_dir->dirent_nfc);
+               free(prec_dir);
+               return NULL;
+       } else {
+               int ret_errno = errno;
+               prec_dir->ic_precompose = iconv_open(repo_encoding, path_encoding);
+               /* if iconv_open() fails, die() in readdir() if needed */
+               errno = ret_errno;
+       }
+
+       return prec_dir;
+}
+
+struct dirent_prec_psx *precompose_utf8_readdir(PREC_DIR *prec_dir)
+{
+       struct dirent *res;
+       res = readdir(prec_dir->dirp);
+       if (res) {
+               size_t namelenz = strlen(res->d_name) + 1; /* \0 */
+               size_t new_maxlen = namelenz;
+
+               int ret_errno = errno;
+
+               if (new_maxlen > prec_dir->dirent_nfc->max_name_len) {
+                       size_t new_len = sizeof(dirent_prec_psx) + new_maxlen -
+                               sizeof(prec_dir->dirent_nfc->d_name);
+
+                       prec_dir->dirent_nfc = xrealloc(prec_dir->dirent_nfc, new_len);
+                       prec_dir->dirent_nfc->max_name_len = new_maxlen;
+               }
+
+               prec_dir->dirent_nfc->d_ino  = res->d_ino;
+               prec_dir->dirent_nfc->d_type = res->d_type;
+
+               if ((precomposed_unicode == 1) && has_non_ascii(res->d_name, (size_t)-1, NULL)) {
+                       if (prec_dir->ic_precompose == (iconv_t)-1) {
+                               die("iconv_open(%s,%s) failed, but needed:\n"
+                                               "    precomposed unicode is not supported.\n"
+                                               "    If you wnat to use decomposed unicode, run\n"
+                                               "    \"git config core.precomposeunicode false\"\n",
+                                               repo_encoding, path_encoding);
+                       } else {
+                               iconv_ibp       cp = (iconv_ibp)res->d_name;
+                               size_t inleft = namelenz;
+                               char *outpos = &prec_dir->dirent_nfc->d_name[0];
+                               size_t outsz = prec_dir->dirent_nfc->max_name_len;
+                               size_t cnt;
+                               errno = 0;
+                               cnt = iconv(prec_dir->ic_precompose, &cp, &inleft, &outpos, &outsz);
+                               if (errno || inleft) {
+                                       /*
+                                        * iconv() failed and errno could be E2BIG, EILSEQ, EINVAL, EBADF
+                                        * MacOS X avoids illegal byte sequemces.
+                                        * If they occur on a mounted drive (e.g. NFS) it is not worth to
+                                        * die() for that, but rather let the user see the original name
+                                       */
+                                       namelenz = 0; /* trigger strlcpy */
+                               }
+                       }
+               } else
+                       namelenz = 0;
+
+               if (!namelenz)
+                       strlcpy(prec_dir->dirent_nfc->d_name, res->d_name,
+                                                       prec_dir->dirent_nfc->max_name_len);
+
+               errno = ret_errno;
+               return prec_dir->dirent_nfc;
+       }
+       return NULL;
+}
+
+
+int precompose_utf8_closedir(PREC_DIR *prec_dir)
+{
+       int ret_value;
+       int ret_errno;
+       ret_value = closedir(prec_dir->dirp);
+       ret_errno = errno;
+       if (prec_dir->ic_precompose != (iconv_t)-1)
+               iconv_close(prec_dir->ic_precompose);
+       free(prec_dir->dirent_nfc);
+       free(prec_dir);
+       errno = ret_errno;
+       return ret_value;
+}
diff --git a/compat/precompose_utf8.h b/compat/precompose_utf8.h
new file mode 100644 (file)
index 0000000..3b73585
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef PRECOMPOSE_UNICODE_H
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <iconv.h>
+
+
+typedef struct dirent_prec_psx {
+       ino_t d_ino;            /* Posix */
+       size_t max_name_len;    /* See below */
+       unsigned char d_type;   /* available on all systems git runs on */
+
+       /*
+        * See http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/dirent.h.html
+        * NAME_MAX + 1 should be enough, but some systems have
+        * NAME_MAX=255 and strlen(d_name) may return 508 or 510
+        * Solution: allocate more when needed, see precompose_utf8_readdir()
+        */
+       char   d_name[NAME_MAX+1];
+} dirent_prec_psx;
+
+
+typedef struct {
+       iconv_t ic_precompose;
+       DIR *dirp;
+       struct dirent_prec_psx *dirent_nfc;
+} PREC_DIR;
+
+void precompose_argv(int argc, const char **argv);
+void probe_utf8_pathname_composition(char *, int);
+
+PREC_DIR *precompose_utf8_opendir(const char *dirname);
+struct dirent_prec_psx *precompose_utf8_readdir(PREC_DIR *dirp);
+int precompose_utf8_closedir(PREC_DIR *dirp);
+
+#ifndef PRECOMPOSE_UNICODE_C
+#define dirent dirent_prec_psx
+#define opendir(n) precompose_utf8_opendir(n)
+#define readdir(d) precompose_utf8_readdir(d)
+#define closedir(d) precompose_utf8_closedir(d)
+#define DIR PREC_DIR
+#endif /* PRECOMPOSE_UNICODE_C */
+
+#define  PRECOMPOSE_UNICODE_H
+#endif /* PRECOMPOSE_UNICODE_H */
index 71ef171cab78bfdb9d6421f2a2b84acbce0bfc00..fff8a43bc0378d7d7ee6d7ab3deee228c87b1d5c 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(path, R_OK)) {
+       if (!access_or_warn(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);
@@ -758,6 +755,11 @@ static int git_default_core_config(const char *var, const char *value)
                return 0;
        }
 
+       if (!strcmp(var, "core.precomposeunicode")) {
+               precomposed_unicode = git_config_bool(var, value);
+               return 0;
+       }
+
        /* Add other config variables here and to Documentation/config.txt. */
        return 0;
 }
@@ -894,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);
@@ -929,25 +933,28 @@ int git_config_system(void)
 int git_config_early(config_fn_t fn, void *data, const char *repo_config)
 {
        int ret = 0, found = 0;
-       const char *home = NULL;
+       char *xdg_config = NULL;
+       char *user_config = NULL;
+
+       home_config_paths(&user_config, &xdg_config, "config");
 
-       if (git_config_system() && !access(git_etc_gitconfig(), R_OK)) {
+       if (git_config_system() && !access_or_warn(git_etc_gitconfig(), R_OK)) {
                ret += git_config_from_file(fn, git_etc_gitconfig(),
                                            data);
                found += 1;
        }
 
-       home = getenv("HOME");
-       if (home) {
-               char buf[PATH_MAX];
-               char *user_config = mksnpath(buf, sizeof(buf), "%s/.gitconfig", home);
-               if (!access(user_config, R_OK)) {
-                       ret += git_config_from_file(fn, user_config, data);
-                       found += 1;
-               }
+       if (xdg_config && !access_or_warn(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)) {
+               ret += git_config_from_file(fn, user_config, data);
+               found += 1;
        }
 
-       if (repo_config && !access(repo_config, R_OK)) {
+       if (repo_config && !access_or_warn(repo_config, R_OK)) {
                ret += git_config_from_file(fn, repo_config, data);
                found += 1;
        }
@@ -963,6 +970,8 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
                break;
        }
 
+       free(xdg_config);
+       free(user_config);
        return ret == 0 ? found : ret;
 }
 
index b2ba7104ebc87c0f2fe261f16461793fcc8b8cd3..69d48382fe69b8699eb350949fff04975db923f8 100644 (file)
@@ -5,12 +5,10 @@ CC = @CC@
 CFLAGS = @CFLAGS@
 CPPFLAGS = @CPPFLAGS@
 LDFLAGS = @LDFLAGS@
-CC_LD_DYNPATH = @CC_LD_DYNPATH@
 AR = @AR@
 TAR = @TAR@
 DIFF = @DIFF@
 #INSTALL = @INSTALL@           # needs install-sh or install.sh in sources
-TCLTK_PATH = @TCLTK_PATH@
 
 prefix = @prefix@
 exec_prefix = @exec_prefix@
@@ -27,51 +25,3 @@ VPATH = @srcdir@
 
 export exec_prefix mandir
 export srcdir VPATH
-
-ASCIIDOC7=@ASCIIDOC7@
-NEEDS_SSL_WITH_CRYPTO=@NEEDS_SSL_WITH_CRYPTO@
-NO_OPENSSL=@NO_OPENSSL@
-NO_CURL=@NO_CURL@
-NO_EXPAT=@NO_EXPAT@
-NO_LIBGEN_H=@NO_LIBGEN_H@
-HAVE_PATHS_H=@HAVE_PATHS_H@
-HAVE_LIBCHARSET_H=@HAVE_LIBCHARSET_H@
-NO_GETTEXT=@NO_GETTEXT@
-LIBC_CONTAINS_LIBINTL=@LIBC_CONTAINS_LIBINTL@
-NEEDS_LIBICONV=@NEEDS_LIBICONV@
-NEEDS_SOCKET=@NEEDS_SOCKET@
-NEEDS_RESOLV=@NEEDS_RESOLV@
-NEEDS_LIBGEN=@NEEDS_LIBGEN@
-NO_SYS_SELECT_H=@NO_SYS_SELECT_H@
-NO_D_INO_IN_DIRENT=@NO_D_INO_IN_DIRENT@
-NO_D_TYPE_IN_DIRENT=@NO_D_TYPE_IN_DIRENT@
-NO_SOCKADDR_STORAGE=@NO_SOCKADDR_STORAGE@
-NO_IPV6=@NO_IPV6@
-NO_HSTRERROR=@NO_HSTRERROR@
-NO_STRCASESTR=@NO_STRCASESTR@
-NO_STRTOK_R=@NO_STRTOK_R@
-NO_FNMATCH=@NO_FNMATCH@
-NO_FNMATCH_CASEFOLD=@NO_FNMATCH_CASEFOLD@
-NO_MEMMEM=@NO_MEMMEM@
-NO_STRLCPY=@NO_STRLCPY@
-NO_UINTMAX_T=@NO_UINTMAX_T@
-NO_STRTOUMAX=@NO_STRTOUMAX@
-NO_SETENV=@NO_SETENV@
-NO_UNSETENV=@NO_UNSETENV@
-NO_MKDTEMP=@NO_MKDTEMP@
-NO_MKSTEMPS=@NO_MKSTEMPS@
-NO_INET_NTOP=@NO_INET_NTOP@
-NO_INET_PTON=@NO_INET_PTON@
-NO_ICONV=@NO_ICONV@
-OLD_ICONV=@OLD_ICONV@
-NO_REGEX=@NO_REGEX@
-USE_LIBPCRE=@USE_LIBPCRE@
-NO_DEFLATE_BOUND=@NO_DEFLATE_BOUND@
-INLINE=@INLINE@
-SOCKLEN_T=@SOCKLEN_T@
-FREAD_READS_DIRECTORIES=@FREAD_READS_DIRECTORIES@
-SNPRINTF_RETURNS_BOGUS=@SNPRINTF_RETURNS_BOGUS@
-NO_PTHREADS=@NO_PTHREADS@
-PTHREAD_CFLAGS=@PTHREAD_CFLAGS@
-PTHREAD_LIBS=@PTHREAD_LIBS@
-CHARSET_LIB=@CHARSET_LIB@
index e1255506a636722031c58398cb33056c43cffed3..ad215cc4a10ed95804e7cec929f003c985d25a3d 100644 (file)
@@ -3,11 +3,25 @@
 
 ## Definitions of private macros.
 
-# GIT_CONF_APPEND_LINE(LINE)
-# --------------------------
-# Append LINE to file ${config_append}
-AC_DEFUN([GIT_CONF_APPEND_LINE],
-         [echo "$1" >> "${config_append}"])
+# GIT_CONF_SUBST(VAL, VAR)
+# ------------------------
+# Cause the line "VAR=VAL" to be eventually appended to ${config_file}.
+AC_DEFUN([GIT_CONF_SUBST],
+[AC_REQUIRE([GIT_CONF_SUBST_INIT])
+config_appended_defs="$config_appended_defs${newline}dnl
+$1=m4_if([$#],[1],[${$1}],[$2])"])
+
+# GIT_CONF_SUBST_INIT
+# -------------------
+# Prepare shell variables and autoconf machine required by later calls
+# to GIT_CONF_SUBST.
+AC_DEFUN([GIT_CONF_SUBST_INIT],
+    [config_appended_defs=; newline='
+'
+    AC_CONFIG_COMMANDS([$config_file],
+                       [echo "$config_appended_defs" >> "$config_file"],
+                       [config_file=$config_file
+                        config_appended_defs="$config_appended_defs"])])
 
 # GIT_ARG_SET_PATH(PROGRAM)
 # -------------------------
@@ -29,13 +43,12 @@ AC_DEFUN([GIT_ARG_SET_PATH],
 # --without-PROGRAM is used.
 AC_DEFUN([GIT_CONF_APPEND_PATH],
     [m4_pushdef([GIT_UC_PROGRAM], m4_toupper([$1]))dnl
-    PROGRAM=GIT_UC_PROGRAM
     if test "$withval" = "no"; then
        if test -n "$2"; then
                GIT_UC_PROGRAM[]_PATH=$withval
-               AC_MSG_NOTICE([Disabling use of ${PROGRAM}])
-               GIT_CONF_APPEND_LINE(NO_${PROGRAM}=YesPlease)
-               GIT_CONF_APPEND_LINE(${PROGRAM}_PATH=)
+               AC_MSG_NOTICE([Disabling use of GIT_UC_PROGRAM])
+               GIT_CONF_SUBST([NO_]GIT_UC_PROGRAM, [YesPlease])
+               GIT_CONF_SUBST(GIT_UC_PROGRAM[]_PATH, [])
        else
                AC_MSG_ERROR([You cannot use git without $1])
        fi
@@ -45,7 +58,7 @@ AC_DEFUN([GIT_CONF_APPEND_PATH],
        else
                GIT_UC_PROGRAM[]_PATH=$withval
                AC_MSG_NOTICE([Setting GIT_UC_PROGRAM[]_PATH to $withval])
-               GIT_CONF_APPEND_LINE(${PROGRAM}_PATH=$withval)
+               GIT_CONF_SUBST(GIT_UC_PROGRAM[]_PATH, [$withval])
        fi
     fi
     m4_popdef([GIT_UC_PROGRAM])])
@@ -58,7 +71,6 @@ AC_DEFUN([GIT_CONF_APPEND_PATH],
 # * Unset NO_PACKAGE for --with-PACKAGE without ARG
 AC_DEFUN([GIT_PARSE_WITH],
     [m4_pushdef([GIT_UC_PACKAGE], m4_toupper([$1]))dnl
-    PACKAGE=GIT_UC_PACKAGE
     if test "$withval" = "no"; then
        NO_[]GIT_UC_PACKAGE=YesPlease
     elif test "$withval" = "yes"; then
@@ -67,7 +79,7 @@ AC_DEFUN([GIT_PARSE_WITH],
        NO_[]GIT_UC_PACKAGE=
        GIT_UC_PACKAGE[]DIR=$withval
        AC_MSG_NOTICE([Setting GIT_UC_PACKAGE[]DIR to $withval])
-       GIT_CONF_APPEND_LINE(${PACKAGE}DIR=$withval)
+       GIT_CONF_SUBST(GIT_UC_PACKAGE[DIR], [$withval])
     fi
     m4_popdef([GIT_UC_PACKAGE])])
 
@@ -87,7 +99,7 @@ AC_DEFUN([GIT_PARSE_WITH_SET_MAKE_VAR],
                     [a value for $1 ($2).  Maybe you do...?])
   fi
   AC_MSG_NOTICE([Setting $2 to $withval])
-  GIT_CONF_APPEND_LINE($2=$withval)
+  GIT_CONF_SUBST([$2], [$withval])
  fi)])# GIT_PARSE_WITH_SET_MAKE_VAR
 
 #
@@ -135,10 +147,9 @@ AC_INIT([git], [@@GIT_VERSION@@], [git@vger.kernel.org])
 AC_CONFIG_SRCDIR([git.c])
 
 config_file=config.mak.autogen
-config_append=config.mak.append
 config_in=config.mak.in
 
-echo "# ${config_append}.  Generated by configure." > "${config_append}"
+GIT_CONF_SUBST([AUTOCONFIGURED], [YesPlease])
 
 # Directories holding "saner" versions of common or POSIX binaries.
 AC_ARG_WITH([sane-tool-path],
@@ -150,7 +161,7 @@ AC_ARG_WITH([sane-tool-path],
   else
     AC_MSG_NOTICE([Setting SANE_TOOL_PATH to '$withval'])
   fi
-  GIT_CONF_APPEND_LINE([SANE_TOOL_PATH=$withval])],
+  GIT_CONF_SUBST([SANE_TOOL_PATH], [$withval])],
   [# If the "--with-sane-tool-path" option was not given, don't touch
    # SANE_TOOL_PATH here, but let defaults in Makefile take care of it.
    # This should minimize spurious differences in the behaviour of the
@@ -169,7 +180,7 @@ AC_ARG_WITH([lib],
   else
        lib=$withval
        AC_MSG_NOTICE([Setting lib to '$lib'])
-       GIT_CONF_APPEND_LINE(lib=$withval)
+       GIT_CONF_SUBST([lib])
   fi])
 
 if test -z "$lib"; then
@@ -205,7 +216,7 @@ AC_ARG_ENABLE([jsmin],
 [
   JSMIN=$enableval;
   AC_MSG_NOTICE([Setting JSMIN to '$JSMIN' to enable JavaScript minifying])
-  GIT_CONF_APPEND_LINE(JSMIN=$enableval);
+  GIT_CONF_SUBST([JSMIN])
 ])
 
 # Define option to enable CSS minification
@@ -215,7 +226,7 @@ AC_ARG_ENABLE([cssmin],
 [
   CSSMIN=$enableval;
   AC_MSG_NOTICE([Setting CSSMIN to '$CSSMIN' to enable CSS minifying])
-  GIT_CONF_APPEND_LINE(CSSMIN=$enableval);
+  GIT_CONF_SUBST([CSSMIN])
 ])
 
 ## Site configuration (override autodetection)
@@ -255,8 +266,10 @@ AS_HELP_STRING([],           [ARG can be also prefix for libpcre library and hea
     else
        USE_LIBPCRE=YesPlease
        LIBPCREDIR=$withval
-       AC_MSG_NOTICE([Setting LIBPCREDIR to $withval])
-       GIT_CONF_APPEND_LINE(LIBPCREDIR=$withval)
+       AC_MSG_NOTICE([Setting LIBPCREDIR to $LIBPCREDIR])
+        dnl USE_LIBPCRE can still be modified below, so don't substitute
+        dnl it yet.
+       GIT_CONF_SUBST([LIBPCREDIR])
     fi)
 #
 # Define NO_CURL if you do not have curl installed.  git-http-pull and
@@ -376,9 +389,10 @@ AC_MSG_NOTICE([CHECKS for programs])
 AC_PROG_CC([cc gcc])
 AC_C_INLINE
 case $ac_cv_c_inline in
-  inline | yes | no)   ;;
-  *)                   AC_SUBST([INLINE], [$ac_cv_c_inline]) ;;
+  inline | yes | no) INLINE='';;
+  *)                 INLINE=$ac_cv_c_inline ;;
 esac
+GIT_CONF_SUBST([INLINE])
 
 # which switch to pass runtime path to dynamic libraries to the linker
 AC_CACHE_CHECK([if linker supports -R], git_cv_ld_dashr, [
@@ -388,7 +402,7 @@ AC_CACHE_CHECK([if linker supports -R], git_cv_ld_dashr, [
    LDFLAGS="${SAVE_LDFLAGS}"
 ])
 if test "$git_cv_ld_dashr" = "yes"; then
-   AC_SUBST(CC_LD_DYNPATH, [-R])
+   CC_LD_DYNPATH=-R
 else
    AC_CACHE_CHECK([if linker supports -Wl,-rpath,], git_cv_ld_wl_rpath, [
       SAVE_LDFLAGS="${LDFLAGS}"
@@ -397,7 +411,7 @@ else
       LDFLAGS="${SAVE_LDFLAGS}"
    ])
    if test "$git_cv_ld_wl_rpath" = "yes"; then
-      AC_SUBST(CC_LD_DYNPATH, [-Wl,-rpath,])
+      CC_LD_DYNPATH=-Wl,-rpath,
    else
       AC_CACHE_CHECK([if linker supports -rpath], git_cv_ld_rpath, [
          SAVE_LDFLAGS="${LDFLAGS}"
@@ -406,52 +420,48 @@ else
          LDFLAGS="${SAVE_LDFLAGS}"
       ])
       if test "$git_cv_ld_rpath" = "yes"; then
-         AC_SUBST(CC_LD_DYNPATH, [-rpath])
+         CC_LD_DYNPATH=-rpath
       else
+         CC_LD_DYNPATH=
          AC_MSG_WARN([linker does not support runtime path to dynamic libraries])
       fi
    fi
 fi
+GIT_CONF_SUBST([CC_LD_DYNPATH])
 #AC_PROG_INSTALL               # needs install-sh or install.sh in sources
 AC_CHECK_TOOLS(AR, [gar ar], :)
 AC_CHECK_PROGS(TAR, [gtar tar])
 AC_CHECK_PROGS(DIFF, [gnudiff gdiff diff])
 # TCLTK_PATH will be set to some value if we want Tcl/Tk
 # or will be empty otherwise.
-if test -z "$NO_TCLTK"; then
+if test -n "$NO_TCLTK"; then
+  TCLTK_PATH=
+else
   if test "$with_tcltk" = ""; then
   # No Tcl/Tk switches given. Do not check for Tcl/Tk, use bare 'wish'.
     TCLTK_PATH=wish
-    AC_SUBST(TCLTK_PATH)
   elif test "$with_tcltk" = "yes"; then
   # Tcl/Tk check requested.
     AC_CHECK_PROGS(TCLTK_PATH, [wish], )
   else
     AC_MSG_RESULT([Using Tcl/Tk interpreter $with_tcltk])
     TCLTK_PATH="$with_tcltk"
-    AC_SUBST(TCLTK_PATH)
   fi
 fi
+GIT_CONF_SUBST([TCLTK_PATH])
 AC_CHECK_PROGS(ASCIIDOC, [asciidoc])
 if test -n "$ASCIIDOC"; then
        AC_MSG_CHECKING([for asciidoc version])
        asciidoc_version=`$ASCIIDOC --version 2>/dev/null`
        case "${asciidoc_version}" in
-       asciidoc' '7*)
-               ASCIIDOC7=YesPlease
-               AC_MSG_RESULT([${asciidoc_version} > 7])
-               ;;
        asciidoc' '8*)
-               ASCIIDOC7=
                AC_MSG_RESULT([${asciidoc_version}])
                ;;
        *)
-               ASCIIDOC7=
                AC_MSG_RESULT([${asciidoc_version} (unknown)])
                ;;
        esac
 fi
-AC_SUBST(ASCIIDOC7)
 
 
 ## Checks for libraries.
@@ -465,13 +475,13 @@ GIT_STASH_FLAGS($OPENSSLDIR)
 AC_CHECK_LIB([crypto], [SHA1_Init],
 [NEEDS_SSL_WITH_CRYPTO=],
 [AC_CHECK_LIB([ssl], [SHA1_Init],
- [NEEDS_SSL_WITH_CRYPTO=YesPlease],
- [NEEDS_SSL_WITH_CRYPTO= NO_OPENSSL=YesPlease])])
+ [NEEDS_SSL_WITH_CRYPTO=YesPlease NO_OPENSSL=],
+ [NEEDS_SSL_WITH_CRYPTO=          NO_OPENSSL=YesPlease])])
 
 GIT_UNSTASH_FLAGS($OPENSSLDIR)
 
-AC_SUBST(NEEDS_SSL_WITH_CRYPTO)
-AC_SUBST(NO_OPENSSL)
+GIT_CONF_SUBST([NEEDS_SSL_WITH_CRYPTO])
+GIT_CONF_SUBST([NO_OPENSSL])
 
 #
 # Define USE_LIBPCRE if you have and want to use libpcre. git-grep will be
@@ -488,7 +498,7 @@ AC_CHECK_LIB([pcre], [pcre_version],
 
 GIT_UNSTASH_FLAGS($LIBPCREDIR)
 
-AC_SUBST(USE_LIBPCRE)
+GIT_CONF_SUBST([USE_LIBPCRE])
 
 fi
 
@@ -505,7 +515,7 @@ AC_CHECK_LIB([curl], [curl_global_init],
 
 GIT_UNSTASH_FLAGS($CURLDIR)
 
-AC_SUBST(NO_CURL)
+GIT_CONF_SUBST([NO_CURL])
 
 #
 # Define NO_EXPAT if you do not have expat installed.  git-http-push is
@@ -519,7 +529,7 @@ AC_CHECK_LIB([expat], [XML_ParserCreate],
 
 GIT_UNSTASH_FLAGS($EXPATDIR)
 
-AC_SUBST(NO_EXPAT)
+GIT_CONF_SUBST([NO_EXPAT])
 
 #
 # Define NEEDS_LIBICONV if linking with libc is not enough (Darwin and
@@ -565,8 +575,8 @@ LIBS="$old_LIBS"
 
 GIT_UNSTASH_FLAGS($ICONVDIR)
 
-AC_SUBST(NEEDS_LIBICONV)
-AC_SUBST(NO_ICONV)
+GIT_CONF_SUBST([NEEDS_LIBICONV])
+GIT_CONF_SUBST([NO_ICONV])
 
 if test -n "$NO_ICONV"; then
     NEEDS_LIBICONV=
@@ -593,7 +603,7 @@ LIBS="$old_LIBS"
 
 GIT_UNSTASH_FLAGS($ZLIB_PATH)
 
-AC_SUBST(NO_DEFLATE_BOUND)
+GIT_CONF_SUBST([NO_DEFLATE_BOUND])
 
 #
 # Define NEEDS_SOCKET if linking with libc is not enough (SunOS,
@@ -601,7 +611,7 @@ AC_SUBST(NO_DEFLATE_BOUND)
 AC_CHECK_LIB([c], [socket],
 [NEEDS_SOCKET=],
 [NEEDS_SOCKET=YesPlease])
-AC_SUBST(NEEDS_SOCKET)
+GIT_CONF_SUBST([NEEDS_SOCKET])
 test -n "$NEEDS_SOCKET" && LIBS="$LIBS -lsocket"
 
 #
@@ -609,40 +619,43 @@ test -n "$NEEDS_SOCKET" && LIBS="$LIBS -lsocket"
 # libresolv provides some of the functions we would normally get
 # from libc.
 NEEDS_RESOLV=
-AC_SUBST(NEEDS_RESOLV)
 #
 # Define NO_INET_NTOP if linking with -lresolv is not enough.
 # Solaris 2.7 in particular hos inet_ntop in -lresolv.
 NO_INET_NTOP=
-AC_SUBST(NO_INET_NTOP)
 AC_CHECK_FUNC([inet_ntop],
-       [],
+    [],
     [AC_CHECK_LIB([resolv], [inet_ntop],
-           [NEEDS_RESOLV=YesPlease],
+       [NEEDS_RESOLV=YesPlease],
        [NO_INET_NTOP=YesPlease])
 ])
+GIT_CONF_SUBST([NO_INET_NTOP])
 #
 # Define NO_INET_PTON if linking with -lresolv is not enough.
 # Solaris 2.7 in particular hos inet_pton in -lresolv.
 NO_INET_PTON=
-AC_SUBST(NO_INET_PTON)
 AC_CHECK_FUNC([inet_pton],
-       [],
+    [],
     [AC_CHECK_LIB([resolv], [inet_pton],
-           [NEEDS_RESOLV=YesPlease],
+       [NEEDS_RESOLV=YesPlease],
        [NO_INET_PTON=YesPlease])
 ])
+GIT_CONF_SUBST([NO_INET_PTON])
 #
 # Define NO_HSTRERROR if linking with -lresolv is not enough.
 # Solaris 2.6 in particular has no hstrerror, even in -lresolv.
 NO_HSTRERROR=
 AC_CHECK_FUNC([hstrerror],
-       [],
+    [],
     [AC_CHECK_LIB([resolv], [hstrerror],
-           [NEEDS_RESOLV=YesPlease],
+       [NEEDS_RESOLV=YesPlease],
        [NO_HSTRERROR=YesPlease])
 ])
-AC_SUBST(NO_HSTRERROR)
+GIT_CONF_SUBST([NO_HSTRERROR])
+
+dnl This must go after all the possible places for its initialization,
+dnl in the AC_CHECK_FUNC invocations above.
+GIT_CONF_SUBST([NEEDS_RESOLV])
 #
 # If any of the above tests determined that -lresolv is needed at
 # build-time, also set it here for remaining configure-time checks.
@@ -651,13 +664,13 @@ test -n "$NEEDS_RESOLV" && LIBS="$LIBS -lresolv"
 AC_CHECK_LIB([c], [basename],
 [NEEDS_LIBGEN=],
 [NEEDS_LIBGEN=YesPlease])
-AC_SUBST(NEEDS_LIBGEN)
+GIT_CONF_SUBST([NEEDS_LIBGEN])
 test -n "$NEEDS_LIBGEN" && LIBS="$LIBS -lgen"
 
 AC_CHECK_LIB([c], [gettext],
 [LIBC_CONTAINS_LIBINTL=YesPlease],
 [LIBC_CONTAINS_LIBINTL=])
-AC_SUBST(LIBC_CONTAINS_LIBINTL)
+GIT_CONF_SUBST([LIBC_CONTAINS_LIBINTL])
 
 #
 # Define NO_GETTEXT if you don't want Git output to be translated.
@@ -665,7 +678,7 @@ AC_SUBST(LIBC_CONTAINS_LIBINTL)
 AC_CHECK_HEADER([libintl.h],
 [NO_GETTEXT=],
 [NO_GETTEXT=YesPlease])
-AC_SUBST(NO_GETTEXT)
+GIT_CONF_SUBST([NO_GETTEXT])
 
 if test -z "$NO_GETTEXT"; then
     test -n "$LIBC_CONTAINS_LIBINTL" || LIBS="$LIBS -lintl"
@@ -678,19 +691,19 @@ AC_MSG_NOTICE([CHECKS for header files])
 AC_CHECK_HEADER([sys/select.h],
 [NO_SYS_SELECT_H=],
 [NO_SYS_SELECT_H=UnfortunatelyYes])
-AC_SUBST(NO_SYS_SELECT_H)
+GIT_CONF_SUBST([NO_SYS_SELECT_H])
 #
 # Define NO_SYS_POLL_H if you don't have sys/poll.h
 AC_CHECK_HEADER([sys/poll.h],
 [NO_SYS_POLL_H=],
 [NO_SYS_POLL_H=UnfortunatelyYes])
-AC_SUBST(NO_SYS_POLL_H)
+GIT_CONF_SUBST([NO_SYS_POLL_H])
 #
 # Define NO_INTTYPES_H if you don't have inttypes.h
 AC_CHECK_HEADER([inttypes.h],
 [NO_INTTYPES_H=],
 [NO_INTTYPES_H=UnfortunatelyYes])
-AC_SUBST(NO_INTTYPES_H)
+GIT_CONF_SUBST([NO_INTTYPES_H])
 #
 # Define OLD_ICONV if your library has an old iconv(), where the second
 # (input buffer pointer) parameter is declared with type (const char **).
@@ -713,23 +726,24 @@ AC_COMPILE_IFELSE([OLDICONVTEST_SRC],
 
 GIT_UNSTASH_FLAGS($ICONVDIR)
 
-AC_SUBST(OLD_ICONV)
+GIT_CONF_SUBST([OLD_ICONV])
 
 ## Checks for typedefs, structures, and compiler characteristics.
 AC_MSG_NOTICE([CHECKS for typedefs, structures, and compiler characteristics])
 #
 TYPE_SOCKLEN_T
 case $ac_cv_type_socklen_t in
-  yes) ;;
-  *)   AC_SUBST([SOCKLEN_T], [$git_cv_socklen_t_equiv]) ;;
+  yes) SOCKLEN_T='';;
+  *)   SOCKLEN_T=$git_cv_socklen_t_equiv;;
 esac
+GIT_CONF_SUBST([SOCKLEN_T])
 
 # Define NO_D_INO_IN_DIRENT if you don't have d_ino in your struct dirent.
 AC_CHECK_MEMBER(struct dirent.d_ino,
 [NO_D_INO_IN_DIRENT=],
 [NO_D_INO_IN_DIRENT=YesPlease],
 [#include <dirent.h>])
-AC_SUBST(NO_D_INO_IN_DIRENT)
+GIT_CONF_SUBST([NO_D_INO_IN_DIRENT])
 #
 # Define NO_D_TYPE_IN_DIRENT if your platform defines DT_UNKNOWN but lacks
 # d_type in struct dirent (latest Cygwin -- will be fixed soonish).
@@ -737,7 +751,7 @@ AC_CHECK_MEMBER(struct dirent.d_type,
 [NO_D_TYPE_IN_DIRENT=],
 [NO_D_TYPE_IN_DIRENT=YesPlease],
 [#include <dirent.h>])
-AC_SUBST(NO_D_TYPE_IN_DIRENT)
+GIT_CONF_SUBST([NO_D_TYPE_IN_DIRENT])
 #
 # Define NO_SOCKADDR_STORAGE if your platform does not have struct
 # sockaddr_storage.
@@ -747,7 +761,7 @@ AC_CHECK_TYPE(struct sockaddr_storage,
 #include <sys/types.h>
 #include <sys/socket.h>
 ])
-AC_SUBST(NO_SOCKADDR_STORAGE)
+GIT_CONF_SUBST([NO_SOCKADDR_STORAGE])
 #
 # Define NO_IPV6 if you lack IPv6 support and getaddrinfo().
 AC_CHECK_TYPE([struct addrinfo],[
@@ -759,7 +773,7 @@ AC_CHECK_TYPE([struct addrinfo],[
 #include <sys/socket.h>
 #include <netdb.h>
 ])
-AC_SUBST(NO_IPV6)
+GIT_CONF_SUBST([NO_IPV6])
 #
 # Define NO_REGEX if you have no or inferior regex support in your C library.
 AC_CACHE_CHECK([whether the platform regex can handle null bytes],
@@ -780,7 +794,7 @@ if test $ac_cv_c_excellent_regex = yes; then
 else
        NO_REGEX=YesPlease
 fi
-AC_SUBST(NO_REGEX)
+GIT_CONF_SUBST([NO_REGEX])
 #
 # Define FREAD_READS_DIRECTORIES if your are on a system which succeeds
 # when attempting to read from an fopen'ed directory.
@@ -800,7 +814,7 @@ if test $ac_cv_fread_reads_directories = yes; then
 else
        FREAD_READS_DIRECTORIES=
 fi
-AC_SUBST(FREAD_READS_DIRECTORIES)
+GIT_CONF_SUBST([FREAD_READS_DIRECTORIES])
 #
 # Define SNPRINTF_RETURNS_BOGUS if your are on a system which snprintf()
 # or vsnprintf() return -1 instead of number of characters which would
@@ -834,7 +848,7 @@ if test $ac_cv_snprintf_returns_bogus = yes; then
 else
        SNPRINTF_RETURNS_BOGUS=
 fi
-AC_SUBST(SNPRINTF_RETURNS_BOGUS)
+GIT_CONF_SUBST([SNPRINTF_RETURNS_BOGUS])
 
 
 ## Checks for library functions.
@@ -845,47 +859,45 @@ AC_MSG_NOTICE([CHECKS for library functions])
 AC_CHECK_HEADER([libgen.h],
 [NO_LIBGEN_H=],
 [NO_LIBGEN_H=YesPlease])
-AC_SUBST(NO_LIBGEN_H)
+GIT_CONF_SUBST([NO_LIBGEN_H])
 #
 # Define HAVE_PATHS_H if you have paths.h.
 AC_CHECK_HEADER([paths.h],
 [HAVE_PATHS_H=YesPlease],
 [HAVE_PATHS_H=])
-AC_SUBST(HAVE_PATHS_H)
+GIT_CONF_SUBST([HAVE_PATHS_H])
 #
 # Define HAVE_LIBCHARSET_H if have libcharset.h
 AC_CHECK_HEADER([libcharset.h],
 [HAVE_LIBCHARSET_H=YesPlease],
 [HAVE_LIBCHARSET_H=])
-AC_SUBST(HAVE_LIBCHARSET_H)
+GIT_CONF_SUBST([HAVE_LIBCHARSET_H])
 # Define CHARSET_LIB if libiconv does not export the locale_charset symbol
 # and libcharset does
 CHARSET_LIB=
 AC_CHECK_LIB([iconv], [locale_charset],
        [],
        [AC_CHECK_LIB([charset], [locale_charset],
-                     [CHARSET_LIB=-lcharset])
-       ]
-)
-AC_SUBST(CHARSET_LIB)
+                     [CHARSET_LIB=-lcharset])])
+GIT_CONF_SUBST([CHARSET_LIB])
 #
 # Define NO_STRCASESTR if you don't have strcasestr.
 GIT_CHECK_FUNC(strcasestr,
 [NO_STRCASESTR=],
 [NO_STRCASESTR=YesPlease])
-AC_SUBST(NO_STRCASESTR)
+GIT_CONF_SUBST([NO_STRCASESTR])
 #
 # Define NO_STRTOK_R if you don't have strtok_r
 GIT_CHECK_FUNC(strtok_r,
 [NO_STRTOK_R=],
 [NO_STRTOK_R=YesPlease])
-AC_SUBST(NO_STRTOK_R)
+GIT_CONF_SUBST([NO_STRTOK_R])
 #
 # Define NO_FNMATCH if you don't have fnmatch
 GIT_CHECK_FUNC(fnmatch,
 [NO_FNMATCH=],
 [NO_FNMATCH=YesPlease])
-AC_SUBST(NO_FNMATCH)
+GIT_CONF_SUBST([NO_FNMATCH])
 #
 # Define NO_FNMATCH_CASEFOLD if your fnmatch function doesn't have the
 # FNM_CASEFOLD GNU extension.
@@ -907,19 +919,19 @@ if test $ac_cv_c_excellent_fnmatch = yes; then
 else
        NO_FNMATCH_CASEFOLD=YesPlease
 fi
-AC_SUBST(NO_FNMATCH_CASEFOLD)
+GIT_CONF_SUBST([NO_FNMATCH_CASEFOLD])
 #
 # Define NO_MEMMEM if you don't have memmem.
 GIT_CHECK_FUNC(memmem,
 [NO_MEMMEM=],
 [NO_MEMMEM=YesPlease])
-AC_SUBST(NO_MEMMEM)
+GIT_CONF_SUBST([NO_MEMMEM])
 #
 # Define NO_STRLCPY if you don't have strlcpy.
 GIT_CHECK_FUNC(strlcpy,
 [NO_STRLCPY=],
 [NO_STRLCPY=YesPlease])
-AC_SUBST(NO_STRLCPY)
+GIT_CONF_SUBST([NO_STRLCPY])
 #
 # Define NO_UINTMAX_T if your platform does not have uintmax_t
 AC_CHECK_TYPE(uintmax_t,
@@ -927,43 +939,43 @@ AC_CHECK_TYPE(uintmax_t,
 [NO_UINTMAX_T=YesPlease],[
 #include <inttypes.h>
 ])
-AC_SUBST(NO_UINTMAX_T)
+GIT_CONF_SUBST([NO_UINTMAX_T])
 #
 # Define NO_STRTOUMAX if you don't have strtoumax in the C library.
 GIT_CHECK_FUNC(strtoumax,
 [NO_STRTOUMAX=],
 [NO_STRTOUMAX=YesPlease])
-AC_SUBST(NO_STRTOUMAX)
+GIT_CONF_SUBST([NO_STRTOUMAX])
 #
 # Define NO_SETENV if you don't have setenv in the C library.
 GIT_CHECK_FUNC(setenv,
 [NO_SETENV=],
 [NO_SETENV=YesPlease])
-AC_SUBST(NO_SETENV)
+GIT_CONF_SUBST([NO_SETENV])
 #
 # Define NO_UNSETENV if you don't have unsetenv in the C library.
 GIT_CHECK_FUNC(unsetenv,
 [NO_UNSETENV=],
 [NO_UNSETENV=YesPlease])
-AC_SUBST(NO_UNSETENV)
+GIT_CONF_SUBST([NO_UNSETENV])
 #
 # Define NO_MKDTEMP if you don't have mkdtemp in the C library.
 GIT_CHECK_FUNC(mkdtemp,
 [NO_MKDTEMP=],
 [NO_MKDTEMP=YesPlease])
-AC_SUBST(NO_MKDTEMP)
+GIT_CONF_SUBST([NO_MKDTEMP])
 #
 # Define NO_MKSTEMPS if you don't have mkstemps in the C library.
 GIT_CHECK_FUNC(mkstemps,
 [NO_MKSTEMPS=],
 [NO_MKSTEMPS=YesPlease])
-AC_SUBST(NO_MKSTEMPS)
+GIT_CONF_SUBST([NO_MKSTEMPS])
 #
 # Define NO_INITGROUPS if you don't have initgroups in the C library.
 GIT_CHECK_FUNC(initgroups,
 [NO_INITGROUPS=],
 [NO_INITGROUPS=YesPlease])
-AC_SUBST(NO_INITGROUPS)
+GIT_CONF_SUBST([NO_INITGROUPS])
 #
 #
 # Define NO_MMAP if you want to avoid mmap.
@@ -1012,7 +1024,7 @@ elif test -z "$PTHREAD_CFLAGS"; then
   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=
@@ -1032,7 +1044,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=
@@ -1045,14 +1057,10 @@ fi
 
 CFLAGS="$old_CFLAGS"
 
-AC_SUBST(PTHREAD_CFLAGS)
-AC_SUBST(PTHREAD_LIBS)
-AC_SUBST(NO_PTHREADS)
+GIT_CONF_SUBST([PTHREAD_CFLAGS])
+GIT_CONF_SUBST([PTHREAD_LIBS])
+GIT_CONF_SUBST([NO_PTHREADS])
 
 ## Output files
-AC_CONFIG_FILES(["${config_file}":"${config_in}":"${config_append}"])
+AC_CONFIG_FILES(["${config_file}":"${config_in}"])
 AC_OUTPUT
-
-
-## Cleanup
-rm -f "${config_append}"
index 41b7400aa92d7c07db269de9658b9f961db9becf..49e56ba35a645359b0d7c1f7bbc9e2108b3424d9 100644 (file)
--- a/connect.c
+++ b/connect.c
@@ -49,6 +49,16 @@ static void add_extra_have(struct extra_have_objects *extra, unsigned char *sha1
        extra->nr++;
 }
 
+static void die_initial_contact(int got_at_least_one_head)
+{
+       if (got_at_least_one_head)
+               die("The remote end hung up upon initial contact");
+       else
+               die("Could not read from remote repository.\n\n"
+                   "Please make sure you have the correct access rights\n"
+                   "and the repository exists.");
+}
+
 /*
  * Read all the refs from the other end
  */
@@ -56,6 +66,8 @@ struct ref **get_remote_heads(int in, struct ref **list,
                              unsigned int flags,
                              struct extra_have_objects *extra_have)
 {
+       int got_at_least_one_head = 0;
+
        *list = NULL;
        for (;;) {
                struct ref *ref;
@@ -64,7 +76,10 @@ struct ref **get_remote_heads(int in, struct ref **list,
                char *name;
                int len, name_len;
 
-               len = packet_read_line(in, buffer, sizeof(buffer));
+               len = packet_read(in, buffer, sizeof(buffer));
+               if (len < 0)
+                       die_initial_contact(got_at_least_one_head);
+
                if (!len)
                        break;
                if (buffer[len-1] == '\n')
@@ -95,16 +110,12 @@ struct ref **get_remote_heads(int in, struct ref **list,
                hashcpy(ref->old_sha1, old_sha1);
                *list = ref;
                list = &ref->next;
+               got_at_least_one_head = 1;
        }
        return list;
 }
 
-int server_supports(const char *feature)
-{
-       return !!parse_feature_request(server_capabilities, feature);
-}
-
-const char *parse_feature_request(const char *feature_list, const char *feature)
+const char *parse_feature_value(const char *feature_list, const char *feature, int *lenp)
 {
        int len;
 
@@ -116,14 +127,46 @@ const char *parse_feature_request(const char *feature_list, const char *feature)
                const char *found = strstr(feature_list, feature);
                if (!found)
                        return NULL;
-               if ((feature_list == found || isspace(found[-1])) &&
-                   (!found[len] || isspace(found[len]) || found[len] == '='))
-                       return found;
+               if (feature_list == found || isspace(found[-1])) {
+                       const char *value = found + len;
+                       /* feature with no value (e.g., "thin-pack") */
+                       if (!*value || isspace(*value)) {
+                               if (lenp)
+                                       *lenp = 0;
+                               return value;
+                       }
+                       /* feature with a value (e.g., "agent=git/1.2.3") */
+                       else if (*value == '=') {
+                               value++;
+                               if (lenp)
+                                       *lenp = strcspn(value, " \t\n");
+                               return value;
+                       }
+                       /*
+                        * otherwise we matched a substring of another feature;
+                        * keep looking
+                        */
+               }
                feature_list = found + 1;
        }
        return NULL;
 }
 
+int parse_feature_request(const char *feature_list, const char *feature)
+{
+       return !!parse_feature_value(feature_list, feature, NULL);
+}
+
+const char *server_feature_value(const char *feature, int *len)
+{
+       return parse_feature_value(server_capabilities, feature, len);
+}
+
+int server_supports(const char *feature)
+{
+       return !!server_feature_value(feature, NULL);
+}
+
 enum protocol {
        PROTO_LOCAL = 1,
        PROTO_SSH,
old mode 100755 (executable)
new mode 100644 (file)
index 2e1b5e1..be800e0
 #    1) Copy this file to somewhere (e.g. ~/.git-completion.sh).
 #    2) Add the following line to your .bashrc/.zshrc:
 #        source ~/.git-completion.sh
-#
-#    3) Consider changing your PS1 to also show the current branch:
-#         Bash: PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '
-#         ZSH:  PS1='[%n@%m %c$(__git_ps1 " (%s)")]\$ '
-#
-#       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 branch.
-#
-#       In addition, if you set GIT_PS1_SHOWDIRTYSTATE to a nonempty
-#       value, unstaged (*) and staged (+) changes will be shown next
-#       to the branch name.  You can configure this per-repository
-#       with the bash.showDirtyState variable, which defaults to true
-#       once GIT_PS1_SHOWDIRTYSTATE is enabled.
-#
-#       You can also see if currently something is stashed, by setting
-#       GIT_PS1_SHOWSTASHSTATE to a nonempty value. If something is stashed,
-#       then a '$' will be shown next to the branch name.
-#
-#       If you would like to see if there're untracked files, then you can
-#       set GIT_PS1_SHOWUNTRACKEDFILES to a nonempty value. If there're
-#       untracked files, then a '%' will be shown next to the branch name.
-#
-#       If you would like to see the difference between HEAD and its
-#       upstream, set GIT_PS1_SHOWUPSTREAM="auto".  A "<" indicates
-#       you are behind, ">" indicates you are ahead, and "<>"
-#       indicates you have diverged.  You can further control
-#       behaviour by setting GIT_PS1_SHOWUPSTREAM to a space-separated
-#       list of values:
-#           verbose       show number of commits ahead/behind (+/-) upstream
-#           legacy        don't use the '--count' option available in recent
-#                         versions of git-rev-list
-#           git           always compare HEAD to @{upstream}
-#           svn           always compare HEAD to your SVN upstream
-#       By default, __git_ps1 will compare HEAD to your SVN upstream
-#       if it can 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.
-#
+#    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
@@ -74,9 +36,14 @@ esac
 # returns location of .git repo
 __gitdir ()
 {
+       # Note: this function is duplicated in git-prompt.sh
+       # When updating it, make sure you update the other one to match.
        if [ -z "${1-}" ]; then
                if [ -n "${__git_dir-}" ]; then
                        echo "$__git_dir"
+               elif [ -n "${GIT_DIR-}" ]; then
+                       test -d "${GIT_DIR-}" || return 1
+                       echo "$GIT_DIR"
                elif [ -d .git ]; then
                        echo .git
                else
@@ -89,221 +56,6 @@ __gitdir ()
        fi
 }
 
-# stores the divergence from upstream in $p
-# used by GIT_PS1_SHOWUPSTREAM
-__git_ps1_show_upstream ()
-{
-       local key value
-       local svn_remote svn_url_pattern count n
-       local upstream=git legacy="" verbose=""
-
-       svn_remote=()
-       # get some config options from git-config
-       local output="$(git config -z --get-regexp '^(svn-remote\..*\.url|bash\.showupstream)$' 2>/dev/null | tr '\0\n' '\n ')"
-       while read -r key value; do
-               case "$key" in
-               bash.showupstream)
-                       GIT_PS1_SHOWUPSTREAM="$value"
-                       if [[ -z "${GIT_PS1_SHOWUPSTREAM}" ]]; then
-                               p=""
-                               return
-                       fi
-                       ;;
-               svn-remote.*.url)
-                       svn_remote[ $((${#svn_remote[@]} + 1)) ]="$value"
-                       svn_url_pattern+="\\|$value"
-                       upstream=svn+git # default upstream is SVN if available, else git
-                       ;;
-               esac
-       done <<< "$output"
-
-       # parse configuration values
-       for option in ${GIT_PS1_SHOWUPSTREAM}; do
-               case "$option" in
-               git|svn) upstream="$option" ;;
-               verbose) verbose=1 ;;
-               legacy)  legacy=1  ;;
-               esac
-       done
-
-       # Find our upstream
-       case "$upstream" in
-       git)    upstream="@{upstream}" ;;
-       svn*)
-               # get the upstream from the "git-svn-id: ..." in a commit message
-               # (git-svn uses essentially the same procedure internally)
-               local svn_upstream=($(git log --first-parent -1 \
-                                       --grep="^git-svn-id: \(${svn_url_pattern#??}\)" 2>/dev/null))
-               if [[ 0 -ne ${#svn_upstream[@]} ]]; then
-                       svn_upstream=${svn_upstream[ ${#svn_upstream[@]} - 2 ]}
-                       svn_upstream=${svn_upstream%@*}
-                       local n_stop="${#svn_remote[@]}"
-                       for ((n=1; n <= n_stop; n++)); do
-                               svn_upstream=${svn_upstream#${svn_remote[$n]}}
-                       done
-
-                       if [[ -z "$svn_upstream" ]]; then
-                               # default branch name for checkouts with no layout:
-                               upstream=${GIT_SVN_ID:-git-svn}
-                       else
-                               upstream=${svn_upstream#/}
-                       fi
-               elif [[ "svn+git" = "$upstream" ]]; then
-                       upstream="@{upstream}"
-               fi
-               ;;
-       esac
-
-       # Find how many commits we are ahead/behind our upstream
-       if [[ -z "$legacy" ]]; then
-               count="$(git rev-list --count --left-right \
-                               "$upstream"...HEAD 2>/dev/null)"
-       else
-               # produce equivalent output to --count for older versions of git
-               local commits
-               if commits="$(git rev-list --left-right "$upstream"...HEAD 2>/dev/null)"
-               then
-                       local commit behind=0 ahead=0
-                       for commit in $commits
-                       do
-                               case "$commit" in
-                               "<"*) ((behind++)) ;;
-                               *)    ((ahead++))  ;;
-                               esac
-                       done
-                       count="$behind  $ahead"
-               else
-                       count=""
-               fi
-       fi
-
-       # calculate the result
-       if [[ -z "$verbose" ]]; then
-               case "$count" in
-               "") # no upstream
-                       p="" ;;
-               "0      0") # equal to upstream
-                       p="=" ;;
-               "0      "*) # ahead of upstream
-                       p=">" ;;
-               *"      0") # behind upstream
-                       p="<" ;;
-               *)          # diverged from upstream
-                       p="<>" ;;
-               esac
-       else
-               case "$count" in
-               "") # no upstream
-                       p="" ;;
-               "0      0") # equal to upstream
-                       p=" u=" ;;
-               "0      "*) # ahead of upstream
-                       p=" u+${count#0 }" ;;
-               *"      0") # behind upstream
-                       p=" u-${count%  0}" ;;
-               *)          # diverged from upstream
-                       p=" u+${count#* }-${count%      *}" ;;
-               esac
-       fi
-
-}
-
-
-# __git_ps1 accepts 0 or 1 arguments (i.e., format string)
-# returns text to add to bash PS1 prompt (includes branch name)
-__git_ps1 ()
-{
-       local g="$(__gitdir)"
-       if [ -n "$g" ]; then
-               local r=""
-               local b=""
-               if [ -f "$g/rebase-merge/interactive" ]; then
-                       r="|REBASE-i"
-                       b="$(cat "$g/rebase-merge/head-name")"
-               elif [ -d "$g/rebase-merge" ]; then
-                       r="|REBASE-m"
-                       b="$(cat "$g/rebase-merge/head-name")"
-               else
-                       if [ -d "$g/rebase-apply" ]; then
-                               if [ -f "$g/rebase-apply/rebasing" ]; then
-                                       r="|REBASE"
-                               elif [ -f "$g/rebase-apply/applying" ]; then
-                                       r="|AM"
-                               else
-                                       r="|AM/REBASE"
-                               fi
-                       elif [ -f "$g/MERGE_HEAD" ]; then
-                               r="|MERGING"
-                       elif [ -f "$g/CHERRY_PICK_HEAD" ]; then
-                               r="|CHERRY-PICKING"
-                       elif [ -f "$g/BISECT_LOG" ]; then
-                               r="|BISECTING"
-                       fi
-
-                       b="$(git symbolic-ref HEAD 2>/dev/null)" || {
-
-                               b="$(
-                               case "${GIT_PS1_DESCRIBE_STYLE-}" in
-                               (contains)
-                                       git describe --contains HEAD ;;
-                               (branch)
-                                       git describe --contains --all HEAD ;;
-                               (describe)
-                                       git describe HEAD ;;
-                               (* | default)
-                                       git describe --tags --exact-match HEAD ;;
-                               esac 2>/dev/null)" ||
-
-                               b="$(cut -c1-7 "$g/HEAD" 2>/dev/null)..." ||
-                               b="unknown"
-                               b="($b)"
-                       }
-               fi
-
-               local w=""
-               local i=""
-               local s=""
-               local u=""
-               local c=""
-               local p=""
-
-               if [ "true" = "$(git rev-parse --is-inside-git-dir 2>/dev/null)" ]; then
-                       if [ "true" = "$(git rev-parse --is-bare-repository 2>/dev/null)" ]; then
-                               c="BARE:"
-                       else
-                               b="GIT_DIR!"
-                       fi
-               elif [ "true" = "$(git rev-parse --is-inside-work-tree 2>/dev/null)" ]; then
-                       if [ -n "${GIT_PS1_SHOWDIRTYSTATE-}" ]; then
-                               if [ "$(git config --bool bash.showDirtyState)" != "false" ]; then
-                                       git diff --no-ext-diff --quiet --exit-code || w="*"
-                                       if git rev-parse --quiet --verify HEAD >/dev/null; then
-                                               git diff-index --cached --quiet HEAD -- || i="+"
-                                       else
-                                               i="#"
-                                       fi
-                               fi
-                       fi
-                       if [ -n "${GIT_PS1_SHOWSTASHSTATE-}" ]; then
-                               git rev-parse --verify refs/stash >/dev/null 2>&1 && s="$"
-                       fi
-
-                       if [ -n "${GIT_PS1_SHOWUNTRACKEDFILES-}" ]; then
-                               if [ -n "$(git ls-files --others --exclude-standard)" ]; then
-                                       u="%"
-                               fi
-                       fi
-
-                       if [ -n "${GIT_PS1_SHOWUPSTREAM-}" ]; then
-                               __git_ps1_show_upstream
-                       fi
-               fi
-
-               local f="$w$i$s$u"
-               printf -- "${1:- (%s)}" "$c${b##refs/heads/}${f:+ $f}$r$p"
-       fi
-}
-
 __gitcomp_1 ()
 {
        local c IFS=$' \t\n'
@@ -1123,11 +875,15 @@ _git_branch ()
        done
 
        case "$cur" in
+       --set-upstream-to=*)
+               __gitcomp "$(__git_refs)" "" "${cur##--set-upstream-to=}"
+               ;;
        --*)
                __gitcomp "
                        --color --no-color --verbose --abbrev= --no-abbrev
                        --track --no-track --contains --merged --no-merged
-                       --set-upstream --edit-description --list
+                       --set-upstream-to= --edit-description --list
+                       --unset-upstream
                        "
                ;;
        *)
@@ -1262,7 +1018,8 @@ _git_commit ()
        --*)
                __gitcomp "
                        --all --author= --signoff --verify --no-verify
-                       --edit --amend --include --only --interactive
+                       --edit --no-edit
+                       --amend --include --only --interactive
                        --dry-run --reuse-message= --reedit-message=
                        --reset-author --file= --message= --template=
                        --cleanup= --untracked-files --untracked-files=
@@ -1319,7 +1076,7 @@ _git_diff ()
 }
 
 __git_mergetools_common="diffuse ecmerge emerge kdiff3 meld opendiff
-                       tkdiff vimdiff gvimdiff xxdiff araxis p4merge bc3
+                       tkdiff vimdiff gvimdiff xxdiff araxis p4merge bc3 codecompare
 "
 
 _git_difftool ()
@@ -2280,7 +2037,7 @@ _git_config ()
 
 _git_remote ()
 {
-       local subcommands="add rename rm set-head set-branches set-url show prune update"
+       local subcommands="add rename remove set-head set-branches set-url show prune update"
        local subcommand="$(__git_find_on_cmdline "$subcommands")"
        if [ -z "$subcommand" ]; then
                __gitcomp "$subcommands"
@@ -2288,7 +2045,7 @@ _git_remote ()
        fi
 
        case "$subcommand" in
-       rename|rm|set-url|show|prune)
+       rename|remove|set-url|show|prune)
                __gitcomp_nl "$(__git_remotes)"
                ;;
        set-head|set-branches)
diff --git a/contrib/completion/git-prompt.sh b/contrib/completion/git-prompt.sh
new file mode 100644 (file)
index 0000000..bf20491
--- /dev/null
@@ -0,0 +1,290 @@
+# bash/zsh git prompt support
+#
+# Copyright (C) 2006,2007 Shawn O. Pearce <spearce@spearce.org>
+# Distributed under the GNU General Public License, version 2.0.
+#
+# This script allows you to see the current branch in your prompt.
+#
+# To enable:
+#
+#    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)")]\$ '
+#
+# 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
+# branch.
+#
+# In addition, if you set GIT_PS1_SHOWDIRTYSTATE to a nonempty value,
+# unstaged (*) and staged (+) changes will be shown next to the branch
+# name.  You can configure this per-repository with the
+# bash.showDirtyState variable, which defaults to true once
+# GIT_PS1_SHOWDIRTYSTATE is enabled.
+#
+# You can also see if currently something is stashed, by setting
+# GIT_PS1_SHOWSTASHSTATE to a nonempty value. If something is stashed,
+# then a '$' will be shown next to the branch name.
+#
+# If you would like to see if there're untracked files, then you can set
+# GIT_PS1_SHOWUNTRACKEDFILES to a nonempty value. If there're untracked
+# files, then a '%' will be shown next to the branch name.
+#
+# If you would like to see the difference between HEAD and its upstream,
+# set GIT_PS1_SHOWUPSTREAM="auto".  A "<" indicates you are behind, ">"
+# indicates you are ahead, "<>" indicates you have diverged and "="
+# indicates that there is no difference. You can further control
+# behaviour by setting GIT_PS1_SHOWUPSTREAM to a space-separated list
+# of values:
+#
+#     verbose       show number of commits ahead/behind (+/-) upstream
+#     legacy        don't use the '--count' option available in recent
+#                   versions of git-rev-list
+#     git           always compare HEAD to @{upstream}
+#     svn           always compare HEAD to your SVN upstream
+#
+# By default, __git_ps1 will compare HEAD to your SVN upstream if it can
+# 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.
+
+# __gitdir accepts 0 or 1 arguments (i.e., location)
+# returns location of .git repo
+__gitdir ()
+{
+       # Note: this function is duplicated in git-completion.bash
+       # When updating it, make sure you update the other one to match.
+       if [ -z "${1-}" ]; then
+               if [ -n "${__git_dir-}" ]; then
+                       echo "$__git_dir"
+               elif [ -n "${GIT_DIR-}" ]; then
+                       test -d "${GIT_DIR-}" || return 1
+                       echo "$GIT_DIR"
+               elif [ -d .git ]; then
+                       echo .git
+               else
+                       git rev-parse --git-dir 2>/dev/null
+               fi
+       elif [ -d "$1/.git" ]; then
+               echo "$1/.git"
+       else
+               echo "$1"
+       fi
+}
+
+# stores the divergence from upstream in $p
+# used by GIT_PS1_SHOWUPSTREAM
+__git_ps1_show_upstream ()
+{
+       local key value
+       local svn_remote svn_url_pattern count n
+       local upstream=git legacy="" verbose=""
+
+       svn_remote=()
+       # get some config options from git-config
+       local output="$(git config -z --get-regexp '^(svn-remote\..*\.url|bash\.showupstream)$' 2>/dev/null | tr '\0\n' '\n ')"
+       while read -r key value; do
+               case "$key" in
+               bash.showupstream)
+                       GIT_PS1_SHOWUPSTREAM="$value"
+                       if [[ -z "${GIT_PS1_SHOWUPSTREAM}" ]]; then
+                               p=""
+                               return
+                       fi
+                       ;;
+               svn-remote.*.url)
+                       svn_remote[ $((${#svn_remote[@]} + 1)) ]="$value"
+                       svn_url_pattern+="\\|$value"
+                       upstream=svn+git # default upstream is SVN if available, else git
+                       ;;
+               esac
+       done <<< "$output"
+
+       # parse configuration values
+       for option in ${GIT_PS1_SHOWUPSTREAM}; do
+               case "$option" in
+               git|svn) upstream="$option" ;;
+               verbose) verbose=1 ;;
+               legacy)  legacy=1  ;;
+               esac
+       done
+
+       # Find our upstream
+       case "$upstream" in
+       git)    upstream="@{upstream}" ;;
+       svn*)
+               # get the upstream from the "git-svn-id: ..." in a commit message
+               # (git-svn uses essentially the same procedure internally)
+               local svn_upstream=($(git log --first-parent -1 \
+                                       --grep="^git-svn-id: \(${svn_url_pattern#??}\)" 2>/dev/null))
+               if [[ 0 -ne ${#svn_upstream[@]} ]]; then
+                       svn_upstream=${svn_upstream[ ${#svn_upstream[@]} - 2 ]}
+                       svn_upstream=${svn_upstream%@*}
+                       local n_stop="${#svn_remote[@]}"
+                       for ((n=1; n <= n_stop; n++)); do
+                               svn_upstream=${svn_upstream#${svn_remote[$n]}}
+                       done
+
+                       if [[ -z "$svn_upstream" ]]; then
+                               # default branch name for checkouts with no layout:
+                               upstream=${GIT_SVN_ID:-git-svn}
+                       else
+                               upstream=${svn_upstream#/}
+                       fi
+               elif [[ "svn+git" = "$upstream" ]]; then
+                       upstream="@{upstream}"
+               fi
+               ;;
+       esac
+
+       # Find how many commits we are ahead/behind our upstream
+       if [[ -z "$legacy" ]]; then
+               count="$(git rev-list --count --left-right \
+                               "$upstream"...HEAD 2>/dev/null)"
+       else
+               # produce equivalent output to --count for older versions of git
+               local commits
+               if commits="$(git rev-list --left-right "$upstream"...HEAD 2>/dev/null)"
+               then
+                       local commit behind=0 ahead=0
+                       for commit in $commits
+                       do
+                               case "$commit" in
+                               "<"*) ((behind++)) ;;
+                               *)    ((ahead++))  ;;
+                               esac
+                       done
+                       count="$behind  $ahead"
+               else
+                       count=""
+               fi
+       fi
+
+       # calculate the result
+       if [[ -z "$verbose" ]]; then
+               case "$count" in
+               "") # no upstream
+                       p="" ;;
+               "0      0") # equal to upstream
+                       p="=" ;;
+               "0      "*) # ahead of upstream
+                       p=">" ;;
+               *"      0") # behind upstream
+                       p="<" ;;
+               *)          # diverged from upstream
+                       p="<>" ;;
+               esac
+       else
+               case "$count" in
+               "") # no upstream
+                       p="" ;;
+               "0      0") # equal to upstream
+                       p=" u=" ;;
+               "0      "*) # ahead of upstream
+                       p=" u+${count#0 }" ;;
+               *"      0") # behind upstream
+                       p=" u-${count%  0}" ;;
+               *)          # diverged from upstream
+                       p=" u+${count#* }-${count%      *}" ;;
+               esac
+       fi
+
+}
+
+
+# __git_ps1 accepts 0 or 1 arguments (i.e., format string)
+# returns text to add to bash PS1 prompt (includes branch name)
+__git_ps1 ()
+{
+       local g="$(__gitdir)"
+       if [ -n "$g" ]; then
+               local r=""
+               local b=""
+               if [ -f "$g/rebase-merge/interactive" ]; then
+                       r="|REBASE-i"
+                       b="$(cat "$g/rebase-merge/head-name")"
+               elif [ -d "$g/rebase-merge" ]; then
+                       r="|REBASE-m"
+                       b="$(cat "$g/rebase-merge/head-name")"
+               else
+                       if [ -d "$g/rebase-apply" ]; then
+                               if [ -f "$g/rebase-apply/rebasing" ]; then
+                                       r="|REBASE"
+                               elif [ -f "$g/rebase-apply/applying" ]; then
+                                       r="|AM"
+                               else
+                                       r="|AM/REBASE"
+                               fi
+                       elif [ -f "$g/MERGE_HEAD" ]; then
+                               r="|MERGING"
+                       elif [ -f "$g/CHERRY_PICK_HEAD" ]; then
+                               r="|CHERRY-PICKING"
+                       elif [ -f "$g/BISECT_LOG" ]; then
+                               r="|BISECTING"
+                       fi
+
+                       b="$(git symbolic-ref HEAD 2>/dev/null)" || {
+
+                               b="$(
+                               case "${GIT_PS1_DESCRIBE_STYLE-}" in
+                               (contains)
+                                       git describe --contains HEAD ;;
+                               (branch)
+                                       git describe --contains --all HEAD ;;
+                               (describe)
+                                       git describe HEAD ;;
+                               (* | default)
+                                       git describe --tags --exact-match HEAD ;;
+                               esac 2>/dev/null)" ||
+
+                               b="$(cut -c1-7 "$g/HEAD" 2>/dev/null)..." ||
+                               b="unknown"
+                               b="($b)"
+                       }
+               fi
+
+               local w=""
+               local i=""
+               local s=""
+               local u=""
+               local c=""
+               local p=""
+
+               if [ "true" = "$(git rev-parse --is-inside-git-dir 2>/dev/null)" ]; then
+                       if [ "true" = "$(git rev-parse --is-bare-repository 2>/dev/null)" ]; then
+                               c="BARE:"
+                       else
+                               b="GIT_DIR!"
+                       fi
+               elif [ "true" = "$(git rev-parse --is-inside-work-tree 2>/dev/null)" ]; then
+                       if [ -n "${GIT_PS1_SHOWDIRTYSTATE-}" ]; then
+                               if [ "$(git config --bool bash.showDirtyState)" != "false" ]; then
+                                       git diff --no-ext-diff --quiet --exit-code || w="*"
+                                       if git rev-parse --quiet --verify HEAD >/dev/null; then
+                                               git diff-index --cached --quiet HEAD -- || i="+"
+                                       else
+                                               i="#"
+                                       fi
+                               fi
+                       fi
+                       if [ -n "${GIT_PS1_SHOWSTASHSTATE-}" ]; then
+                               git rev-parse --verify refs/stash >/dev/null 2>&1 && s="$"
+                       fi
+
+                       if [ -n "${GIT_PS1_SHOWUNTRACKEDFILES-}" ]; then
+                               if [ -n "$(git ls-files --others --exclude-standard)" ]; then
+                                       u="%"
+                               fi
+                       fi
+
+                       if [ -n "${GIT_PS1_SHOWUPSTREAM-}" ]; then
+                               __git_ps1_show_upstream
+                       fi
+               fi
+
+               local f="$w$i$s$u"
+               printf -- "${1:- (%s)}" "$c${b##refs/heads/}${f:+ $f}$r$p"
+       fi
+}
diff --git a/contrib/credential/gnome-keyring/.gitignore b/contrib/credential/gnome-keyring/.gitignore
new file mode 100644 (file)
index 0000000..88d8fcd
--- /dev/null
@@ -0,0 +1 @@
+git-credential-gnome-keyring
diff --git a/contrib/credential/gnome-keyring/Makefile b/contrib/credential/gnome-keyring/Makefile
new file mode 100644 (file)
index 0000000..e6561d8
--- /dev/null
@@ -0,0 +1,24 @@
+MAIN:=git-credential-gnome-keyring
+all:: $(MAIN)
+
+CC = gcc
+RM = rm -f
+CFLAGS = -g -O2 -Wall
+
+-include ../../../config.mak.autogen
+-include ../../../config.mak
+
+INCS:=$(shell pkg-config --cflags gnome-keyring-1)
+LIBS:=$(shell pkg-config --libs gnome-keyring-1)
+
+SRCS:=$(MAIN).c
+OBJS:=$(SRCS:.c=.o)
+
+%.o: %.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) $(INCS) -o $@ -c $<
+
+$(MAIN): $(OBJS)
+       $(CC) -o $@ $(LDFLAGS) $^ $(LIBS)
+
+clean:
+       @$(RM) $(MAIN) $(OBJS)
diff --git a/contrib/credential/gnome-keyring/git-credential-gnome-keyring.c b/contrib/credential/gnome-keyring/git-credential-gnome-keyring.c
new file mode 100644 (file)
index 0000000..41f61c5
--- /dev/null
@@ -0,0 +1,445 @@
+/*
+ * Copyright (C) 2011 John Szakmeister <john@szakmeister.net>
+ *               2012 Philipp A. Hartmann <pah@qo.cx>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ * Credits:
+ * - GNOME Keyring API handling originally written by John Szakmeister
+ * - ported to credential helper API by Philipp A. Hartmann
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <gnome-keyring.h>
+
+/*
+ * This credential struct and API is simplified from git's credential.{h,c}
+ */
+struct credential
+{
+       char          *protocol;
+       char          *host;
+       unsigned short port;
+       char          *path;
+       char          *username;
+       char          *password;
+};
+
+#define CREDENTIAL_INIT \
+  { NULL,NULL,0,NULL,NULL,NULL }
+
+void credential_init(struct credential *c);
+void credential_clear(struct credential *c);
+int  credential_read(struct credential *c);
+void credential_write(const struct credential *c);
+
+typedef int (*credential_op_cb)(struct credential*);
+
+struct credential_operation
+{
+       char             *name;
+       credential_op_cb op;
+};
+
+#define CREDENTIAL_OP_END \
+  { NULL,NULL }
+
+/*
+ * Table with operation callbacks is defined in concrete
+ * credential helper implementation and contains entries
+ * like { "get", function_to_get_credential } terminated
+ * by CREDENTIAL_OP_END.
+ */
+struct credential_operation const credential_helper_ops[];
+
+/* ---------------- common helper functions ----------------- */
+
+static inline void free_password(char *password)
+{
+       char *c = password;
+       if (!password)
+               return;
+
+       while (*c) *c++ = '\0';
+       free(password);
+}
+
+static inline void warning(const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       fprintf(stderr, "warning: ");
+       vfprintf(stderr, fmt, ap);
+       fprintf(stderr, "\n" );
+       va_end(ap);
+}
+
+static inline void error(const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       fprintf(stderr, "error: ");
+       vfprintf(stderr, fmt, ap);
+       fprintf(stderr, "\n" );
+       va_end(ap);
+}
+
+static inline void die(const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap,fmt);
+       error(fmt, ap);
+       va_end(ap);
+       exit(EXIT_FAILURE);
+}
+
+static inline void die_errno(int err)
+{
+       error("%s", strerror(err));
+       exit(EXIT_FAILURE);
+}
+
+static inline char *xstrdup(const char *str)
+{
+       char *ret = strdup(str);
+       if (!ret)
+               die_errno(errno);
+
+       return ret;
+}
+
+/* ----------------- GNOME Keyring functions ----------------- */
+
+/* create a special keyring option string, if path is given */
+static char* keyring_object(struct credential *c)
+{
+       char* object = NULL;
+
+       if (!c->path)
+               return object;
+
+       object = (char*) malloc(strlen(c->host)+strlen(c->path)+8);
+       if(!object)
+               die_errno(errno);
+
+       if(c->port)
+               sprintf(object,"%s:%hd/%s",c->host,c->port,c->path);
+       else
+               sprintf(object,"%s/%s",c->host,c->path);
+
+       return object;
+}
+
+int keyring_get(struct credential *c)
+{
+       char* object = NULL;
+       GList *entries;
+       GnomeKeyringNetworkPasswordData *password_data;
+       GnomeKeyringResult result;
+
+       if (!c->protocol || !(c->host || c->path))
+               return EXIT_FAILURE;
+
+       object = keyring_object(c);
+
+       result = gnome_keyring_find_network_password_sync(
+                               c->username,
+                               NULL /* domain */,
+                               c->host,
+                               object,
+                               c->protocol,
+                               NULL /* authtype */,
+                               c->port,
+                               &entries);
+
+       free(object);
+
+       if (result == GNOME_KEYRING_RESULT_NO_MATCH)
+               return EXIT_SUCCESS;
+
+       if (result == GNOME_KEYRING_RESULT_CANCELLED)
+               return EXIT_SUCCESS;
+
+       if (result != GNOME_KEYRING_RESULT_OK) {
+               error("%s",gnome_keyring_result_to_message(result));
+               return EXIT_FAILURE;
+       }
+
+       /* pick the first one from the list */
+       password_data = (GnomeKeyringNetworkPasswordData *) entries->data;
+
+       free_password(c->password);
+       c->password = xstrdup(password_data->password);
+
+       if (!c->username)
+               c->username = xstrdup(password_data->user);
+
+       gnome_keyring_network_password_list_free(entries);
+
+       return EXIT_SUCCESS;
+}
+
+
+int keyring_store(struct credential *c)
+{
+       guint32 item_id;
+       char  *object = NULL;
+
+       /*
+        * Sanity check that what we are storing is actually sensible.
+        * In particular, we can't make a URL without a protocol field.
+        * Without either a host or pathname (depending on the scheme),
+        * we have no primary key. And without a username and password,
+        * we are not actually storing a credential.
+        */
+       if (!c->protocol || !(c->host || c->path) ||
+           !c->username || !c->password)
+               return EXIT_FAILURE;
+
+       object = keyring_object(c);
+
+       gnome_keyring_set_network_password_sync(
+                               GNOME_KEYRING_DEFAULT,
+                               c->username,
+                               NULL /* domain */,
+                               c->host,
+                               object,
+                               c->protocol,
+                               NULL /* authtype */,
+                               c->port,
+                               c->password,
+                               &item_id);
+
+       free(object);
+       return EXIT_SUCCESS;
+}
+
+int keyring_erase(struct credential *c)
+{
+       char  *object = NULL;
+       GList *entries;
+       GnomeKeyringNetworkPasswordData *password_data;
+       GnomeKeyringResult result;
+
+       /*
+        * Sanity check that we actually have something to match
+        * against. The input we get is a restrictive pattern,
+        * so technically a blank credential means "erase everything".
+        * But it is too easy to accidentally send this, since it is equivalent
+        * to empty input. So explicitly disallow it, and require that the
+        * pattern have some actual content to match.
+        */
+       if (!c->protocol && !c->host && !c->path && !c->username)
+               return EXIT_FAILURE;
+
+       object = keyring_object(c);
+
+       result = gnome_keyring_find_network_password_sync(
+                               c->username,
+                               NULL /* domain */,
+                               c->host,
+                               object,
+                               c->protocol,
+                               NULL /* authtype */,
+                               c->port,
+                               &entries);
+
+       free(object);
+
+       if (result == GNOME_KEYRING_RESULT_NO_MATCH)
+               return EXIT_SUCCESS;
+
+       if (result == GNOME_KEYRING_RESULT_CANCELLED)
+               return EXIT_SUCCESS;
+
+       if (result != GNOME_KEYRING_RESULT_OK)
+       {
+               error("%s",gnome_keyring_result_to_message(result));
+               return EXIT_FAILURE;
+       }
+
+       /* pick the first one from the list (delete all matches?) */
+       password_data = (GnomeKeyringNetworkPasswordData *) entries->data;
+
+       result = gnome_keyring_item_delete_sync(
+               password_data->keyring, password_data->item_id);
+
+       gnome_keyring_network_password_list_free(entries);
+
+       if (result != GNOME_KEYRING_RESULT_OK)
+       {
+               error("%s",gnome_keyring_result_to_message(result));
+               return EXIT_FAILURE;
+       }
+
+       return EXIT_SUCCESS;
+}
+
+/*
+ * Table with helper operation callbacks, used by generic
+ * credential helper main function.
+ */
+struct credential_operation const credential_helper_ops[] =
+{
+       { "get",   keyring_get   },
+       { "store", keyring_store },
+       { "erase", keyring_erase },
+       CREDENTIAL_OP_END
+};
+
+/* ------------------ credential functions ------------------ */
+
+void credential_init(struct credential *c)
+{
+       memset(c, 0, sizeof(*c));
+}
+
+void credential_clear(struct credential *c)
+{
+       free(c->protocol);
+       free(c->host);
+       free(c->path);
+       free(c->username);
+       free_password(c->password);
+
+       credential_init(c);
+}
+
+int credential_read(struct credential *c)
+{
+       char    buf[1024];
+       ssize_t line_len = 0;
+       char   *key      = buf;
+       char   *value;
+
+       while (fgets(buf, sizeof(buf), stdin))
+       {
+               line_len = strlen(buf);
+
+               if(buf[line_len-1]=='\n')
+                       buf[--line_len]='\0';
+
+               if(!line_len)
+                       break;
+
+               value = strchr(buf,'=');
+               if(!value) {
+                       warning("invalid credential line: %s", key);
+                       return -1;
+               }
+               *value++ = '\0';
+
+               if (!strcmp(key, "protocol")) {
+                       free(c->protocol);
+                       c->protocol = xstrdup(value);
+               } else if (!strcmp(key, "host")) {
+                       free(c->host);
+                       c->host = xstrdup(value);
+                       value = strrchr(c->host,':');
+                       if (value) {
+                               *value++ = '\0';
+                               c->port = atoi(value);
+                       }
+               } else if (!strcmp(key, "path")) {
+                       free(c->path);
+                       c->path = xstrdup(value);
+               } else if (!strcmp(key, "username")) {
+                       free(c->username);
+                       c->username = xstrdup(value);
+               } else if (!strcmp(key, "password")) {
+                       free_password(c->password);
+                       c->password = xstrdup(value);
+                       while (*value) *value++ = '\0';
+               }
+               /*
+                * Ignore other lines; we don't know what they mean, but
+                * this future-proofs us when later versions of git do
+                * learn new lines, and the helpers are updated to match.
+                */
+       }
+       return 0;
+}
+
+void credential_write_item(FILE *fp, const char *key, const char *value)
+{
+       if (!value)
+               return;
+       fprintf(fp, "%s=%s\n", key, value);
+}
+
+void credential_write(const struct credential *c)
+{
+       /* only write username/password, if set */
+       credential_write_item(stdout, "username", c->username);
+       credential_write_item(stdout, "password", c->password);
+}
+
+static void usage(const char *name)
+{
+       struct credential_operation const *try_op = credential_helper_ops;
+       const char *basename = strrchr(name,'/');
+
+       basename = (basename) ? basename + 1 : name;
+       fprintf(stderr, "Usage: %s <", basename);
+       while(try_op->name) {
+               fprintf(stderr,"%s",(try_op++)->name);
+               if(try_op->name)
+                       fprintf(stderr,"%s","|");
+       }
+       fprintf(stderr,"%s",">\n");
+}
+
+int main(int argc, char *argv[])
+{
+       int ret = EXIT_SUCCESS;
+
+       struct credential_operation const *try_op = credential_helper_ops;
+       struct credential                  cred   = CREDENTIAL_INIT;
+
+       if (!argv[1]) {
+               usage(argv[0]);
+               goto out;
+       }
+
+       /* lookup operation callback */
+       while(try_op->name && strcmp(argv[1], try_op->name))
+               try_op++;
+
+       /* unsupported operation given -- ignore silently */
+       if(!try_op->name || !try_op->op)
+               goto out;
+
+       ret = credential_read(&cred);
+       if(ret)
+               goto out;
+
+       /* perform credential operation */
+       ret = (*try_op->op)(&cred);
+
+       credential_write(&cred);
+
+out:
+       credential_clear(&cred);
+       return ret;
+}
diff --git a/contrib/credential/wincred/Makefile b/contrib/credential/wincred/Makefile
new file mode 100644 (file)
index 0000000..bad45ca
--- /dev/null
@@ -0,0 +1,14 @@
+all: git-credential-wincred.exe
+
+CC = gcc
+RM = rm -f
+CFLAGS = -O2 -Wall
+
+-include ../../../config.mak.autogen
+-include ../../../config.mak
+
+git-credential-wincred.exe : git-credential-wincred.c
+       $(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@
+
+clean:
+       $(RM) git-credential-wincred.exe
diff --git a/contrib/credential/wincred/git-credential-wincred.c b/contrib/credential/wincred/git-credential-wincred.c
new file mode 100644 (file)
index 0000000..cbaec5f
--- /dev/null
@@ -0,0 +1,357 @@
+/*
+ * A git credential helper that interface with Windows' Credential Manager
+ *
+ */
+#include <windows.h>
+#include <stdio.h>
+#include <io.h>
+#include <fcntl.h>
+
+/* common helpers */
+
+static void die(const char *err, ...)
+{
+       char msg[4096];
+       va_list params;
+       va_start(params, err);
+       vsnprintf(msg, sizeof(msg), err, params);
+       fprintf(stderr, "%s\n", msg);
+       va_end(params);
+       exit(1);
+}
+
+static void *xmalloc(size_t size)
+{
+       void *ret = malloc(size);
+       if (!ret && !size)
+               ret = malloc(1);
+       if (!ret)
+                die("Out of memory");
+       return ret;
+}
+
+static char *xstrdup(const char *str)
+{
+       char *ret = strdup(str);
+       if (!ret)
+               die("Out of memory");
+       return ret;
+}
+
+/* MinGW doesn't have wincred.h, so we need to define stuff */
+
+typedef struct _CREDENTIAL_ATTRIBUTEW {
+       LPWSTR Keyword;
+       DWORD  Flags;
+       DWORD  ValueSize;
+       LPBYTE Value;
+} CREDENTIAL_ATTRIBUTEW, *PCREDENTIAL_ATTRIBUTEW;
+
+typedef struct _CREDENTIALW {
+       DWORD                  Flags;
+       DWORD                  Type;
+       LPWSTR                 TargetName;
+       LPWSTR                 Comment;
+       FILETIME               LastWritten;
+       DWORD                  CredentialBlobSize;
+       LPBYTE                 CredentialBlob;
+       DWORD                  Persist;
+       DWORD                  AttributeCount;
+       PCREDENTIAL_ATTRIBUTEW Attributes;
+       LPWSTR                 TargetAlias;
+       LPWSTR                 UserName;
+} CREDENTIALW, *PCREDENTIALW;
+
+#define CRED_TYPE_GENERIC 1
+#define CRED_PERSIST_LOCAL_MACHINE 2
+#define CRED_MAX_ATTRIBUTES 64
+
+typedef BOOL (WINAPI *CredWriteWT)(PCREDENTIALW, DWORD);
+typedef BOOL (WINAPI *CredUnPackAuthenticationBufferWT)(DWORD, PVOID, DWORD,
+    LPWSTR, DWORD *, LPWSTR, DWORD *, LPWSTR, DWORD *);
+typedef BOOL (WINAPI *CredEnumerateWT)(LPCWSTR, DWORD, DWORD *,
+    PCREDENTIALW **);
+typedef BOOL (WINAPI *CredPackAuthenticationBufferWT)(DWORD, LPWSTR, LPWSTR,
+    PBYTE, DWORD *);
+typedef VOID (WINAPI *CredFreeT)(PVOID);
+typedef BOOL (WINAPI *CredDeleteWT)(LPCWSTR, DWORD, DWORD);
+
+static HMODULE advapi, credui;
+static CredWriteWT CredWriteW;
+static CredUnPackAuthenticationBufferWT CredUnPackAuthenticationBufferW;
+static CredEnumerateWT CredEnumerateW;
+static CredPackAuthenticationBufferWT CredPackAuthenticationBufferW;
+static CredFreeT CredFree;
+static CredDeleteWT CredDeleteW;
+
+static void load_cred_funcs(void)
+{
+       /* load DLLs */
+       advapi = LoadLibrary("advapi32.dll");
+       credui = LoadLibrary("credui.dll");
+       if (!advapi || !credui)
+               die("failed to load DLLs");
+
+       /* get function pointers */
+       CredWriteW = (CredWriteWT)GetProcAddress(advapi, "CredWriteW");
+       CredUnPackAuthenticationBufferW = (CredUnPackAuthenticationBufferWT)
+           GetProcAddress(credui, "CredUnPackAuthenticationBufferW");
+       CredEnumerateW = (CredEnumerateWT)GetProcAddress(advapi,
+           "CredEnumerateW");
+       CredPackAuthenticationBufferW = (CredPackAuthenticationBufferWT)
+           GetProcAddress(credui, "CredPackAuthenticationBufferW");
+       CredFree = (CredFreeT)GetProcAddress(advapi, "CredFree");
+       CredDeleteW = (CredDeleteWT)GetProcAddress(advapi, "CredDeleteW");
+       if (!CredWriteW || !CredUnPackAuthenticationBufferW ||
+           !CredEnumerateW || !CredPackAuthenticationBufferW || !CredFree ||
+           !CredDeleteW)
+               die("failed to load functions");
+}
+
+static char target_buf[1024];
+static char *protocol, *host, *path, *username;
+static WCHAR *wusername, *password, *target;
+
+static void write_item(const char *what, WCHAR *wbuf)
+{
+       char *buf;
+       int len = WideCharToMultiByte(CP_UTF8, 0, wbuf, -1, NULL, 0, NULL,
+           FALSE);
+       buf = xmalloc(len);
+
+       if (!WideCharToMultiByte(CP_UTF8, 0, wbuf, -1, buf, len, NULL, FALSE))
+               die("WideCharToMultiByte failed!");
+
+       printf("%s=", what);
+       fwrite(buf, 1, len - 1, stdout);
+       putchar('\n');
+       free(buf);
+}
+
+static int match_attr(const CREDENTIALW *cred, const WCHAR *keyword,
+    const char *want)
+{
+       int i;
+       if (!want)
+               return 1;
+
+       for (i = 0; i < cred->AttributeCount; ++i)
+               if (!wcscmp(cred->Attributes[i].Keyword, keyword))
+                       return !strcmp((const char *)cred->Attributes[i].Value,
+                           want);
+
+       return 0; /* not found */
+}
+
+static int match_cred(const CREDENTIALW *cred)
+{
+       return (!wusername || !wcscmp(wusername, cred->UserName)) &&
+           match_attr(cred, L"git_protocol", protocol) &&
+           match_attr(cred, L"git_host", host) &&
+           match_attr(cred, L"git_path", path);
+}
+
+static void get_credential(void)
+{
+       WCHAR *user_buf, *pass_buf;
+       DWORD user_buf_size = 0, pass_buf_size = 0;
+       CREDENTIALW **creds, *cred = NULL;
+       DWORD num_creds;
+       int i;
+
+       if (!CredEnumerateW(L"git:*", 0, &num_creds, &creds))
+               return;
+
+       /* search for the first credential that matches username */
+       for (i = 0; i < num_creds; ++i)
+               if (match_cred(creds[i])) {
+                       cred = creds[i];
+                       break;
+               }
+       if (!cred)
+               return;
+
+       CredUnPackAuthenticationBufferW(0, cred->CredentialBlob,
+           cred->CredentialBlobSize, NULL, &user_buf_size, NULL, NULL,
+           NULL, &pass_buf_size);
+
+       user_buf = xmalloc(user_buf_size * sizeof(WCHAR));
+       pass_buf = xmalloc(pass_buf_size * sizeof(WCHAR));
+
+       if (!CredUnPackAuthenticationBufferW(0, cred->CredentialBlob,
+           cred->CredentialBlobSize, user_buf, &user_buf_size, NULL, NULL,
+           pass_buf, &pass_buf_size))
+               die("CredUnPackAuthenticationBuffer failed");
+
+       CredFree(creds);
+
+       /* zero-terminate (sizes include zero-termination) */
+       user_buf[user_buf_size - 1] = L'\0';
+       pass_buf[pass_buf_size - 1] = L'\0';
+
+       write_item("username", user_buf);
+       write_item("password", pass_buf);
+
+       free(user_buf);
+       free(pass_buf);
+}
+
+static void write_attr(CREDENTIAL_ATTRIBUTEW *attr, const WCHAR *keyword,
+    const char *value)
+{
+       attr->Keyword = (LPWSTR)keyword;
+       attr->Flags = 0;
+       attr->ValueSize = strlen(value) + 1; /* store zero-termination */
+       attr->Value = (LPBYTE)value;
+}
+
+static void store_credential(void)
+{
+       CREDENTIALW cred;
+       BYTE *auth_buf;
+       DWORD auth_buf_size = 0;
+       CREDENTIAL_ATTRIBUTEW attrs[CRED_MAX_ATTRIBUTES];
+
+       if (!wusername || !password)
+               return;
+
+       /* query buffer size */
+       CredPackAuthenticationBufferW(0, wusername, password,
+           NULL, &auth_buf_size);
+
+       auth_buf = xmalloc(auth_buf_size);
+
+       if (!CredPackAuthenticationBufferW(0, wusername, password,
+           auth_buf, &auth_buf_size))
+               die("CredPackAuthenticationBuffer failed");
+
+       cred.Flags = 0;
+       cred.Type = CRED_TYPE_GENERIC;
+       cred.TargetName = target;
+       cred.Comment = L"saved by git-credential-wincred";
+       cred.CredentialBlobSize = auth_buf_size;
+       cred.CredentialBlob = auth_buf;
+       cred.Persist = CRED_PERSIST_LOCAL_MACHINE;
+       cred.AttributeCount = 1;
+       cred.Attributes = attrs;
+       cred.TargetAlias = NULL;
+       cred.UserName = wusername;
+
+       write_attr(attrs, L"git_protocol", protocol);
+
+       if (host) {
+               write_attr(attrs + cred.AttributeCount, L"git_host", host);
+               cred.AttributeCount++;
+       }
+
+       if (path) {
+               write_attr(attrs + cred.AttributeCount, L"git_path", path);
+               cred.AttributeCount++;
+       }
+
+       if (!CredWriteW(&cred, 0))
+               die("CredWrite failed");
+}
+
+static void erase_credential(void)
+{
+       CREDENTIALW **creds;
+       DWORD num_creds;
+       int i;
+
+       if (!CredEnumerateW(L"git:*", 0, &num_creds, &creds))
+               return;
+
+       for (i = 0; i < num_creds; ++i) {
+               if (match_cred(creds[i]))
+                       CredDeleteW(creds[i]->TargetName, creds[i]->Type, 0);
+       }
+
+       CredFree(creds);
+}
+
+static WCHAR *utf8_to_utf16_dup(const char *str)
+{
+       int wlen = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
+       WCHAR *wstr = xmalloc(sizeof(WCHAR) * wlen);
+       MultiByteToWideChar(CP_UTF8, 0, str, -1, wstr, wlen);
+       return wstr;
+}
+
+static void read_credential(void)
+{
+       char buf[1024];
+
+       while (fgets(buf, sizeof(buf), stdin)) {
+               char *v;
+
+               if (!strcmp(buf, "\n"))
+                       break;
+               buf[strlen(buf)-1] = '\0';
+
+               v = strchr(buf, '=');
+               if (!v)
+                       die("bad input: %s", buf);
+               *v++ = '\0';
+
+               if (!strcmp(buf, "protocol"))
+                       protocol = xstrdup(v);
+               else if (!strcmp(buf, "host"))
+                       host = xstrdup(v);
+               else if (!strcmp(buf, "path"))
+                       path = xstrdup(v);
+               else if (!strcmp(buf, "username")) {
+                       username = xstrdup(v);
+                       wusername = utf8_to_utf16_dup(v);
+               } else if (!strcmp(buf, "password"))
+                       password = utf8_to_utf16_dup(v);
+               else
+                       die("unrecognized input");
+       }
+}
+
+int main(int argc, char *argv[])
+{
+       const char *usage =
+           "Usage: git credential-wincred <get|store|erase>\n";
+
+       if (!argv[1])
+               die(usage);
+
+       /* git use binary pipes to avoid CRLF-issues */
+       _setmode(_fileno(stdin), _O_BINARY);
+       _setmode(_fileno(stdout), _O_BINARY);
+
+       read_credential();
+
+       load_cred_funcs();
+
+       if (!protocol || !(host || path))
+               return 0;
+
+       /* prepare 'target', the unique key for the credential */
+       strncat(target_buf, "git:", sizeof(target_buf));
+       strncat(target_buf, protocol, sizeof(target_buf));
+       strncat(target_buf, "://", sizeof(target_buf));
+       if (username) {
+               strncat(target_buf, username, sizeof(target_buf));
+               strncat(target_buf, "@", sizeof(target_buf));
+       }
+       if (host)
+               strncat(target_buf, host, sizeof(target_buf));
+       if (path) {
+               strncat(target_buf, "/", sizeof(target_buf));
+               strncat(target_buf, path, sizeof(target_buf));
+       }
+
+       target = utf8_to_utf16_dup(target_buf);
+
+       if (!strcmp(argv[1], "get"))
+               get_credential();
+       else if (!strcmp(argv[1], "store"))
+               store_credential();
+       else if (!strcmp(argv[1], "erase"))
+               erase_credential();
+       /* otherwise, ignore unknown action */
+       return 0;
+}
index 0d54aa7061e780dd0000b8c2a48e266ad5b8ce53..8bc8c7533a8678e2a43d3ddd49bc9aa8d670897d 100644 (file)
@@ -96,7 +96,7 @@ static int update_local_ref(const char *name,
        strcpy(oldh, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV));
        strcpy(newh, find_unique_abbrev(sha1_new, DEFAULT_ABBREV));
 
-       if (in_merge_bases(current, &updated, 1)) {
+       if (in_merge_bases(current, updated)) {
                fprintf(stderr, "* %s: fast-forward to %s\n",
                        name, note);
                fprintf(stderr, "  old..new: %s..%s\n", oldh, newh);
index a33674e47a669e45f257a92aaffad8002d190c5d..dc90cd6379de4e9bf1eadc69560867601227b55d 100755 (executable)
@@ -21,9 +21,9 @@ open_editor() {
 }
 
 mode_diff() {
-       git diff --relative "$@" |
+       git diff --no-prefix --relative "$@" |
        perl -ne '
-       if (m{^\+\+\+ b/(.*)}) { $file = $1; next }
+       if (m{^\+\+\+ (.*)}) { $file = $1; next }
        defined($file) or next;
        if (m/^@@ .*\+(\d+)/) { $line = $1; next }
        defined($line) or next;
index 01af9df15e180288723caadf42b500fe78a8c694..b2171a092eafef4cf1e5e1abfa37695a0c111927 100755 (executable)
@@ -403,7 +403,7 @@ generate_update_branch_email()
                        echo "            \\"
                        echo "             O -- O -- O ($oldrev)"
                        echo ""
-                       echo "The removed revisions are not necessarilly gone - if another reference"
+                       echo "The removed revisions are not necessarily gone - if another reference"
                        echo "still refers to them they will stay in the repository."
                        rewind_only=1
                else
diff --git a/contrib/mw-to-git/Makefile b/contrib/mw-to-git/Makefile
new file mode 100644 (file)
index 0000000..3ed728b
--- /dev/null
@@ -0,0 +1,47 @@
+#
+# Copyright (C) 2012
+#     Charles Roussel <charles.roussel@ensimag.imag.fr>
+#     Simon Cathebras <simon.cathebras@ensimag.imag.fr>
+#     Julien Khayat <julien.khayat@ensimag.imag.fr>
+#     Guillaume Sasdy <guillaume.sasdy@ensimag.imag.fr>
+#     Simon Perrat <simon.perrat@ensimag.imag.fr>
+#
+## Build git-remote-mediawiki
+
+-include ../../config.mak.autogen
+-include ../../config.mak
+
+ifndef PERL_PATH
+       PERL_PATH = /usr/bin/perl
+endif
+ifndef gitexecdir
+       gitexecdir = $(shell git --exec-path)
+endif
+
+PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH))
+gitexecdir_SQ = $(subst ','\'',$(gitexecdir))
+SCRIPT = git-remote-mediawiki
+
+.PHONY: install help doc test clean
+
+help:
+       @echo 'This is the help target of the Makefile. Current configuration:'
+       @echo '  gitexecdir = $(gitexecdir_SQ)'
+       @echo '  PERL_PATH = $(PERL_PATH_SQ)'
+       @echo 'Run "$(MAKE) install" to install $(SCRIPT) in gitexecdir'
+       @echo 'Run "$(MAKE) test" to run the testsuite'
+
+install:
+       sed -e '1s|#!.*/perl|#!$(PERL_PATH_SQ)|' $(SCRIPT) \
+               > '$(gitexecdir_SQ)/$(SCRIPT)'
+       chmod +x '$(gitexecdir)/$(SCRIPT)'
+
+doc:
+       @echo 'Sorry, "make doc" is not implemented yet for $(SCRIPT)'
+
+test:
+       $(MAKE) -C t/ test
+
+clean:
+       $(RM) '$(gitexecdir)/$(SCRIPT)'
+       $(MAKE) -C t/ clean
index c18bfa1f1515a8edb27c2d468a2982860a561939..68555d426540d710b5220168c9fa8eee9f946219 100755 (executable)
@@ -9,40 +9,19 @@
 # License: GPL v2 or later
 
 # Gateway between Git and MediaWiki.
-#   https://github.com/Bibzball/Git-Mediawiki/wiki
-#
-# Known limitations:
-#
-# - Only wiki pages are managed, no support for [[File:...]]
-#   attachments.
-#
-# - Poor performance in the best case: it takes forever to check
-#   whether we're up-to-date (on fetch or push) or to fetch a few
-#   revisions from a large wiki, because we use exclusively a
-#   page-based synchronization. We could switch to a wiki-wide
-#   synchronization when the synchronization involves few revisions
-#   but the wiki is large.
-#
-# - Git renames could be turned into MediaWiki renames (see TODO
-#   below)
-#
-# - login/password support requires the user to write the password
-#   cleartext in a file (see TODO below).
-#
-# - No way to import "one page, and all pages included in it"
-#
-# - Multiple remote MediaWikis have not been very well tested.
+# Documentation & bugtracker: https://github.com/moy/Git-Mediawiki/
 
 use strict;
 use MediaWiki::API;
 use DateTime::Format::ISO8601;
-use encoding 'utf8';
 
-# use encoding 'utf8' doesn't change STDERROR
-# but we're going to output UTF-8 filenames to STDERR
+# By default, use UTF-8 to communicate with Git and the user
 binmode STDERR, ":utf8";
+binmode STDOUT, ":utf8";
 
 use URI::Escape;
+use IPC::Open2;
+
 use warnings;
 
 # Mediawiki filenames can contain forward slashes. This variable decides by which pattern they should be replaced
@@ -59,6 +38,9 @@ use constant EMPTY_CONTENT => "<!-- empty page -->\n";
 # used to reflect file creation or deletion in diff.
 use constant NULL_SHA1 => "0000000000000000000000000000000000000000";
 
+# Used on Git's side to reflect empty edit messages on the wiki
+use constant EMPTY_MESSAGE => '*Empty MediaWiki Message*';
+
 my $remotename = $ARGV[0];
 my $url = $ARGV[1];
 
@@ -71,10 +53,18 @@ chomp(@tracked_pages);
 my @tracked_categories = split(/[ \n]/, run_git("config --get-all remote.". $remotename .".categories"));
 chomp(@tracked_categories);
 
+# Import media files on pull
+my $import_media = run_git("config --get --bool remote.". $remotename .".mediaimport");
+chomp($import_media);
+$import_media = ($import_media eq "true");
+
+# Export media files on push
+my $export_media = run_git("config --get --bool remote.". $remotename .".mediaexport");
+chomp($export_media);
+$export_media = !($export_media eq "false");
+
 my $wiki_login = run_git("config --get remote.". $remotename .".mwLogin");
-# TODO: ideally, this should be able to read from keyboard, but we're
-# inside a remote helper, so our stdin is connect to git, not to a
-# terminal.
+# Note: mwPassword is discourraged. Use the credential system instead.
 my $wiki_passwd = run_git("config --get remote.". $remotename .".mwPassword");
 my $wiki_domain = run_git("config --get remote.". $remotename .".mwDomain");
 chomp($wiki_login);
@@ -86,6 +76,21 @@ my $shallow_import = run_git("config --get --bool remote.". $remotename .".shall
 chomp($shallow_import);
 $shallow_import = ($shallow_import eq "true");
 
+# Fetch (clone and pull) by revisions instead of by pages. This behavior
+# is more efficient when we have a wiki with lots of pages and we fetch
+# the revisions quite often so that they concern only few pages.
+# Possible values:
+# - by_rev: perform one query per new revision on the remote wiki
+# - by_page: query each tracked page for new revision
+my $fetch_strategy = run_git("config --get remote.$remotename.fetchStrategy");
+unless ($fetch_strategy) {
+       $fetch_strategy = run_git("config --get mediawiki.fetchStrategy");
+}
+chomp($fetch_strategy);
+unless ($fetch_strategy) {
+       $fetch_strategy = "by_page";
+}
+
 # Dumb push: don't update notes and mediawiki ref to reflect the last push.
 #
 # Configurable with mediawiki.dumbPush, or per-remote with
@@ -151,32 +156,152 @@ while (<STDIN>) {
 
 ########################## Functions ##############################
 
+## credential API management (generic functions)
+
+sub credential_read {
+       my %credential;
+       my $reader = shift;
+       my $op = shift;
+       while (<$reader>) {
+               my ($key, $value) = /([^=]*)=(.*)/;
+               if (not defined $key) {
+                       die "ERROR receiving response from git credential $op:\n$_\n";
+               }
+               $credential{$key} = $value;
+       }
+       return %credential;
+}
+
+sub credential_write {
+       my $credential = shift;
+       my $writer = shift;
+       # url overwrites other fields, so it must come first
+       print $writer "url=$credential->{url}\n" if exists $credential->{url};
+       while (my ($key, $value) = each(%$credential) ) {
+               if (length $value && $key ne 'url') {
+                       print $writer "$key=$value\n";
+               }
+       }
+}
+
+sub credential_run {
+       my $op = shift;
+       my $credential = shift;
+       my $pid = open2(my $reader, my $writer, "git credential $op");
+       credential_write($credential, $writer);
+       print $writer "\n";
+       close($writer);
+
+       if ($op eq "fill") {
+               %$credential = credential_read($reader, $op);
+       } else {
+               if (<$reader>) {
+                       die "ERROR while running git credential $op:\n$_";
+               }
+       }
+       close($reader);
+       waitpid($pid, 0);
+       my $child_exit_status = $? >> 8;
+       if ($child_exit_status != 0) {
+               die "'git credential $op' failed with code $child_exit_status.";
+       }
+}
+
 # MediaWiki API instance, created lazily.
 my $mediawiki;
 
 sub mw_connect_maybe {
        if ($mediawiki) {
-           return;
+               return;
        }
        $mediawiki = MediaWiki::API->new;
        $mediawiki->{config}->{api_url} = "$url/api.php";
        if ($wiki_login) {
-               if (!$mediawiki->login({
-                       lgname => $wiki_login,
-                       lgpassword => $wiki_passwd,
-                       lgdomain => $wiki_domain,
-               })) {
-                       print STDERR "Failed to log in mediawiki user \"$wiki_login\" on $url\n";
-                       print STDERR "(error " .
-                           $mediawiki->{error}->{code} . ': ' .
-                           $mediawiki->{error}->{details} . ")\n";
-                       exit 1;
+               my %credential = (url => $url);
+               $credential{username} = $wiki_login;
+               $credential{password} = $wiki_passwd;
+               credential_run("fill", \%credential);
+               my $request = {lgname => $credential{username},
+                              lgpassword => $credential{password},
+                              lgdomain => $wiki_domain};
+               if ($mediawiki->login($request)) {
+                       credential_run("approve", \%credential);
+                       print STDERR "Logged in mediawiki user \"$credential{username}\".\n";
                } else {
-                       print STDERR "Logged in with user \"$wiki_login\".\n";
+                       print STDERR "Failed to log in mediawiki user \"$credential{username}\" on $url\n";
+                       print STDERR "  (error " .
+                               $mediawiki->{error}->{code} . ': ' .
+                               $mediawiki->{error}->{details} . ")\n";
+                       credential_run("reject", \%credential);
+                       exit 1;
+               }
+       }
+}
+
+## Functions for listing pages on the remote wiki
+sub get_mw_tracked_pages {
+       my $pages = shift;
+       get_mw_page_list(\@tracked_pages, $pages);
+}
+
+sub get_mw_page_list {
+       my $page_list = shift;
+       my $pages = shift;
+       my @some_pages = @$page_list;
+       while (@some_pages) {
+               my $last = 50;
+               if ($#some_pages < $last) {
+                       $last = $#some_pages;
+               }
+               my @slice = @some_pages[0..$last];
+               get_mw_first_pages(\@slice, $pages);
+               @some_pages = @some_pages[51..$#some_pages];
+       }
+}
+
+sub get_mw_tracked_categories {
+       my $pages = shift;
+       foreach my $category (@tracked_categories) {
+               if (index($category, ':') < 0) {
+                       # Mediawiki requires the Category
+                       # prefix, but let's not force the user
+                       # to specify it.
+                       $category = "Category:" . $category;
+               }
+               my $mw_pages = $mediawiki->list( {
+                       action => 'query',
+                       list => 'categorymembers',
+                       cmtitle => $category,
+                       cmlimit => 'max' } )
+                       || die $mediawiki->{error}->{code} . ': '
+                               . $mediawiki->{error}->{details};
+               foreach my $page (@{$mw_pages}) {
+                       $pages->{$page->{title}} = $page;
                }
        }
 }
 
+sub get_mw_all_pages {
+       my $pages = shift;
+       # No user-provided list, get the list of pages from the API.
+       my $mw_pages = $mediawiki->list({
+               action => 'query',
+               list => 'allpages',
+               aplimit => 'max'
+       });
+       if (!defined($mw_pages)) {
+               print STDERR "fatal: could not get the list of wiki pages.\n";
+               print STDERR "fatal: '$url' does not appear to be a mediawiki\n";
+               print STDERR "fatal: make sure '$url/api.php' is a valid page.\n";
+               exit 1;
+       }
+       foreach my $page (@{$mw_pages}) {
+               $pages->{$page->{title}} = $page;
+       }
+}
+
+# queries the wiki for a set of pages. Meant to be used within a loop
+# querying the wiki for slices of page list.
 sub get_mw_first_pages {
        my $some_pages = shift;
        my @some_pages = @{$some_pages};
@@ -205,70 +330,45 @@ sub get_mw_first_pages {
        }
 }
 
+# Get the list of pages to be fetched according to configuration.
 sub get_mw_pages {
        mw_connect_maybe();
 
+       print STDERR "Listing pages on remote wiki...\n";
+
        my %pages; # hash on page titles to avoid duplicates
        my $user_defined;
        if (@tracked_pages) {
                $user_defined = 1;
                # The user provided a list of pages titles, but we
                # still need to query the API to get the page IDs.
-
-               my @some_pages = @tracked_pages;
-               while (@some_pages) {
-                       my $last = 50;
-                       if ($#some_pages < $last) {
-                               $last = $#some_pages;
-                       }
-                       my @slice = @some_pages[0..$last];
-                       get_mw_first_pages(\@slice, \%pages);
-                       @some_pages = @some_pages[51..$#some_pages];
-               }
+               get_mw_tracked_pages(\%pages);
        }
        if (@tracked_categories) {
                $user_defined = 1;
-               foreach my $category (@tracked_categories) {
-                       if (index($category, ':') < 0) {
-                               # Mediawiki requires the Category
-                               # prefix, but let's not force the user
-                               # to specify it.
-                               $category = "Category:" . $category;
-                       }
-                       my $mw_pages = $mediawiki->list( {
-                               action => 'query',
-                               list => 'categorymembers',
-                               cmtitle => $category,
-                               cmlimit => 'max' } )
-                           || die $mediawiki->{error}->{code} . ': ' . $mediawiki->{error}->{details};
-                       foreach my $page (@{$mw_pages}) {
-                               $pages{$page->{title}} = $page;
-                       }
-               }
+               get_mw_tracked_categories(\%pages);
        }
        if (!$user_defined) {
-               # No user-provided list, get the list of pages from
-               # the API.
-               my $mw_pages = $mediawiki->list({
-                       action => 'query',
-                       list => 'allpages',
-                       aplimit => 500,
-               });
-               if (!defined($mw_pages)) {
-                       print STDERR "fatal: could not get the list of wiki pages.\n";
-                       print STDERR "fatal: '$url' does not appear to be a mediawiki\n";
-                       print STDERR "fatal: make sure '$url/api.php' is a valid page.\n";
-                       exit 1;
-               }
-               foreach my $page (@{$mw_pages}) {
-                       $pages{$page->{title}} = $page;
+               get_mw_all_pages(\%pages);
+       }
+       if ($import_media) {
+               print STDERR "Getting media files for selected pages...\n";
+               if ($user_defined) {
+                       get_linked_mediafiles(\%pages);
+               } else {
+                       get_all_mediafiles(\%pages);
                }
        }
-       return values(%pages);
+       print STDERR (scalar keys %pages) . " pages found.\n";
+       return %pages;
 }
 
+# usage: $out = run_git("command args");
+#        $out = run_git("command args", "raw"); # don't interpret output as UTF-8.
 sub run_git {
-       open(my $git, "-|:encoding(UTF-8)", "git " . $_[0]);
+       my $args = shift;
+       my $encoding = (shift || "encoding(UTF-8)");
+       open(my $git, "-|:$encoding", "git " . $args);
        my $res = do { local $/; <$git> };
        close($git);
 
@@ -276,6 +376,123 @@ sub run_git {
 }
 
 
+sub get_all_mediafiles {
+       my $pages = shift;
+       # Attach list of all pages for media files from the API,
+       # they are in a different namespace, only one namespace
+       # can be queried at the same moment
+       my $mw_pages = $mediawiki->list({
+               action => 'query',
+               list => 'allpages',
+               apnamespace => get_mw_namespace_id("File"),
+               aplimit => 'max'
+       });
+       if (!defined($mw_pages)) {
+               print STDERR "fatal: could not get the list of pages for media files.\n";
+               print STDERR "fatal: '$url' does not appear to be a mediawiki\n";
+               print STDERR "fatal: make sure '$url/api.php' is a valid page.\n";
+               exit 1;
+       }
+       foreach my $page (@{$mw_pages}) {
+               $pages->{$page->{title}} = $page;
+       }
+}
+
+sub get_linked_mediafiles {
+       my $pages = shift;
+       my @titles = map $_->{title}, values(%{$pages});
+
+       # The query is split in small batches because of the MW API limit of
+       # the number of links to be returned (500 links max).
+       my $batch = 10;
+       while (@titles) {
+               if ($#titles < $batch) {
+                       $batch = $#titles;
+               }
+               my @slice = @titles[0..$batch];
+
+               # pattern 'page1|page2|...' required by the API
+               my $mw_titles = join('|', @slice);
+
+               # Media files could be included or linked from
+               # a page, get all related
+               my $query = {
+                       action => 'query',
+                       prop => 'links|images',
+                       titles => $mw_titles,
+                       plnamespace => get_mw_namespace_id("File"),
+                       pllimit => 'max'
+               };
+               my $result = $mediawiki->api($query);
+
+               while (my ($id, $page) = each(%{$result->{query}->{pages}})) {
+                       my @media_titles;
+                       if (defined($page->{links})) {
+                               my @link_titles = map $_->{title}, @{$page->{links}};
+                               push(@media_titles, @link_titles);
+                       }
+                       if (defined($page->{images})) {
+                               my @image_titles = map $_->{title}, @{$page->{images}};
+                               push(@media_titles, @image_titles);
+                       }
+                       if (@media_titles) {
+                               get_mw_page_list(\@media_titles, $pages);
+                       }
+               }
+
+               @titles = @titles[($batch+1)..$#titles];
+       }
+}
+
+sub get_mw_mediafile_for_page_revision {
+       # Name of the file on Wiki, with the prefix.
+       my $filename = shift;
+       my $timestamp = shift;
+       my %mediafile;
+
+       # Search if on a media file with given timestamp exists on
+       # MediaWiki. In that case download the file.
+       my $query = {
+               action => 'query',
+               prop => 'imageinfo',
+               titles => "File:" . $filename,
+               iistart => $timestamp,
+               iiend => $timestamp,
+               iiprop => 'timestamp|archivename|url',
+               iilimit => 1
+       };
+       my $result = $mediawiki->api($query);
+
+       my ($fileid, $file) = each( %{$result->{query}->{pages}} );
+       # If not defined it means there is no revision of the file for
+       # given timestamp.
+       if (defined($file->{imageinfo})) {
+               $mediafile{title} = $filename;
+
+               my $fileinfo = pop(@{$file->{imageinfo}});
+               $mediafile{timestamp} = $fileinfo->{timestamp};
+               # Mediawiki::API's download function doesn't support https URLs
+               # and can't download old versions of files.
+               print STDERR "\tDownloading file $mediafile{title}, version $mediafile{timestamp}\n";
+               $mediafile{content} = download_mw_mediafile($fileinfo->{url});
+       }
+       return %mediafile;
+}
+
+sub download_mw_mediafile {
+       my $url = shift;
+
+       my $response = $mediawiki->{ua}->get($url);
+       if ($response->code == 200) {
+               return $response->decoded_content;
+       } else {
+               print STDERR "Error downloading mediafile from :\n";
+               print STDERR "URL: $url\n";
+               print STDERR "Server response: " . $response->code . " " . $response->message . "\n";
+               exit 1;
+       }
+}
+
 sub get_last_local_revision {
        # Get note regarding last mediawiki revision
        my $note = run_git("notes --ref=$remotename/mediawiki show refs/mediawiki/$remotename/master 2>/dev/null");
@@ -297,13 +514,36 @@ sub get_last_local_revision {
 # Remember the timestamp corresponding to a revision id.
 my %basetimestamps;
 
+# Get the last remote revision without taking in account which pages are
+# tracked or not. This function makes a single request to the wiki thus
+# avoid a loop onto all tracked pages. This is useful for the fetch-by-rev
+# option.
+sub get_last_global_remote_rev {
+       mw_connect_maybe();
+
+       my $query = {
+               action => 'query',
+               list => 'recentchanges',
+               prop => 'revisions',
+               rclimit => '1',
+               rcdir => 'older',
+       };
+       my $result = $mediawiki->api($query);
+       return $result->{query}->{recentchanges}[0]->{revid};
+}
+
+# Get the last remote revision concerning the tracked pages and the tracked
+# categories.
 sub get_last_remote_revision {
        mw_connect_maybe();
 
-       my @pages = get_mw_pages();
+       my %pages_hash = get_mw_pages();
+       my @pages = values(%pages_hash);
 
        my $max_rev_num = 0;
 
+       print STDERR "Getting last revision id on tracked pages...\n";
+
        foreach my $page (@pages) {
                my $id = $page->{pageid};
 
@@ -379,6 +619,16 @@ sub literal_data {
        print STDOUT "data ", bytes::length($content), "\n", $content;
 }
 
+sub literal_data_raw {
+       # Output possibly binary content.
+       my ($content) = @_;
+       # Avoid confusion between size in bytes and in characters
+       utf8::downgrade($content);
+       binmode STDOUT, ":raw";
+       print STDOUT "data ", bytes::length($content), "\n", $content;
+       binmode STDOUT, ":utf8";
+}
+
 sub mw_capabilities {
        # Revisions are imported to the private namespace
        # refs/mediawiki/$remotename/ by the helper and fetched into
@@ -466,6 +716,11 @@ sub import_file_revision {
        my %commit = %{$commit};
        my $full_import = shift;
        my $n = shift;
+       my $mediafile = shift;
+       my %mediafile;
+       if ($mediafile) {
+               %mediafile = %{$mediafile};
+       }
 
        my $title = $commit{title};
        my $comment = $commit{comment};
@@ -485,6 +740,10 @@ sub import_file_revision {
        if ($content ne DELETED_CONTENT) {
                print STDOUT "M 644 inline $title.mw\n";
                literal_data($content);
+               if (%mediafile) {
+                       print STDOUT "M 644 inline $mediafile{title}\n";
+                       literal_data_raw($mediafile{content});
+               }
                print STDOUT "\n\n";
        } else {
                print STDOUT "D $title.mw\n";
@@ -547,8 +806,6 @@ sub mw_import_ref {
 
        mw_connect_maybe();
 
-       my @pages = get_mw_pages();
-
        print STDERR "Searching revisions...\n";
        my $last_local = get_last_local_revision();
        my $fetch_from = $last_local + 1;
@@ -557,36 +814,111 @@ sub mw_import_ref {
        } else {
                print STDERR ", fetching from here.\n";
        }
+
+       my $n = 0;
+       if ($fetch_strategy eq "by_rev") {
+               print STDERR "Fetching & writing export data by revs...\n";
+               $n = mw_import_ref_by_revs($fetch_from);
+       } elsif ($fetch_strategy eq "by_page") {
+               print STDERR "Fetching & writing export data by pages...\n";
+               $n = mw_import_ref_by_pages($fetch_from);
+       } else {
+               print STDERR "fatal: invalid fetch strategy \"$fetch_strategy\".\n";
+               print STDERR "Check your configuration variables remote.$remotename.fetchStrategy and mediawiki.fetchStrategy\n";
+               exit 1;
+       }
+
+       if ($fetch_from == 1 && $n == 0) {
+               print STDERR "You appear to have cloned an empty MediaWiki.\n";
+               # Something has to be done remote-helper side. If nothing is done, an error is
+               # thrown saying that HEAD is refering to unknown object 0000000000000000000
+               # and the clone fails.
+       }
+}
+
+sub mw_import_ref_by_pages {
+
+       my $fetch_from = shift;
+       my %pages_hash = get_mw_pages();
+       my @pages = values(%pages_hash);
+
        my ($n, @revisions) = fetch_mw_revisions(\@pages, $fetch_from);
 
-       # Creation of the fast-import stream
-       print STDERR "Fetching & writing export data...\n";
+       @revisions = sort {$a->{revid} <=> $b->{revid}} @revisions;
+       my @revision_ids = map $_->{revid}, @revisions;
 
-       $n = 0;
+       return mw_import_revids($fetch_from, \@revision_ids, \%pages_hash);
+}
+
+sub mw_import_ref_by_revs {
+
+       my $fetch_from = shift;
+       my %pages_hash = get_mw_pages();
+
+       my $last_remote = get_last_global_remote_rev();
+       my @revision_ids = $fetch_from..$last_remote;
+       return mw_import_revids($fetch_from, \@revision_ids, \%pages_hash);
+}
+
+# Import revisions given in second argument (array of integers).
+# Only pages appearing in the third argument (hash indexed by page titles)
+# will be imported.
+sub mw_import_revids {
+       my $fetch_from = shift;
+       my $revision_ids = shift;
+       my $pages = shift;
+
+       my $n = 0;
+       my $n_actual = 0;
        my $last_timestamp = 0; # Placeholer in case $rev->timestamp is undefined
 
-       foreach my $pagerevid (sort {$a->{revid} <=> $b->{revid}} @revisions) {
+       foreach my $pagerevid (@$revision_ids) {
+               # Count page even if we skip it, since we display
+               # $n/$total and $total includes skipped pages.
+               $n++;
+
                # fetch the content of the pages
                my $query = {
                        action => 'query',
                        prop => 'revisions',
                        rvprop => 'content|timestamp|comment|user|ids',
-                       revids => $pagerevid->{revid},
+                       revids => $pagerevid,
                };
 
                my $result = $mediawiki->api($query);
 
-               my $rev = pop(@{$result->{query}->{pages}->{$pagerevid->{pageid}}->{revisions}});
+               if (!$result) {
+                       die "Failed to retrieve modified page for revision $pagerevid";
+               }
 
-               $n++;
+               if (defined($result->{query}->{badrevids}->{$pagerevid})) {
+                       # The revision id does not exist on the remote wiki.
+                       next;
+               }
+
+               if (!defined($result->{query}->{pages})) {
+                       die "Invalid revision $pagerevid.";
+               }
+
+               my @result_pages = values(%{$result->{query}->{pages}});
+               my $result_page = $result_pages[0];
+               my $rev = $result_pages[0]->{revisions}->[0];
+
+               my $page_title = $result_page->{title};
+
+               if (!exists($pages->{$page_title})) {
+                       print STDERR "$n/", scalar(@$revision_ids),
+                               ": Skipping revision #$rev->{revid} of $page_title\n";
+                       next;
+               }
+
+               $n_actual++;
 
                my %commit;
                $commit{author} = $rev->{user} || 'Anonymous';
-               $commit{comment} = $rev->{comment} || '*Empty MediaWiki Message*';
-               $commit{title} = mediawiki_smudge_filename(
-                       $result->{query}->{pages}->{$pagerevid->{pageid}}->{title}
-                   );
-               $commit{mw_revision} = $pagerevid->{revid};
+               $commit{comment} = $rev->{comment} || EMPTY_MESSAGE;
+               $commit{title} = mediawiki_smudge_filename($page_title);
+               $commit{mw_revision} = $rev->{revid};
                $commit{content} = mediawiki_smudge($rev->{'*'});
 
                if (!defined($rev->{timestamp})) {
@@ -596,17 +928,23 @@ sub mw_import_ref {
                }
                $commit{date} = DateTime::Format::ISO8601->parse_datetime($last_timestamp);
 
-               print STDERR "$n/", scalar(@revisions), ": Revision #$pagerevid->{revid} of $commit{title}\n";
-
-               import_file_revision(\%commit, ($fetch_from == 1), $n);
+               # Differentiates classic pages and media files.
+               my ($namespace, $filename) = $page_title =~ /^([^:]*):(.*)$/;
+               my %mediafile;
+               if ($namespace) {
+                       my $id = get_mw_namespace_id($namespace);
+                       if ($id && $id == get_mw_namespace_id("File")) {
+                               %mediafile = get_mw_mediafile_for_page_revision($filename, $rev->{timestamp});
+                       }
+               }
+               # If this is a revision of the media page for new version
+               # of a file do one common commit for both file and media page.
+               # Else do commit only for that page.
+               print STDERR "$n/", scalar(@$revision_ids), ": Revision #$rev->{revid} of $commit{title}\n";
+               import_file_revision(\%commit, ($fetch_from == 1), $n_actual, \%mediafile);
        }
 
-       if ($fetch_from == 1 && $n == 0) {
-               print STDERR "You appear to have cloned an empty MediaWiki.\n";
-               # Something has to be done remote-helper side. If nothing is done, an error is
-               # thrown saying that HEAD is refering to unknown object 0000000000000000000
-               # and the clone fails.
-       }
+       return $n_actual;
 }
 
 sub error_non_fast_forward {
@@ -624,6 +962,63 @@ sub error_non_fast_forward {
        return 0;
 }
 
+sub mw_upload_file {
+       my $complete_file_name = shift;
+       my $new_sha1 = shift;
+       my $extension = shift;
+       my $file_deleted = shift;
+       my $summary = shift;
+       my $newrevid;
+       my $path = "File:" . $complete_file_name;
+       my %hashFiles = get_allowed_file_extensions();
+       if (!exists($hashFiles{$extension})) {
+               print STDERR "$complete_file_name is not a permitted file on this wiki.\n";
+               print STDERR "Check the configuration of file uploads in your mediawiki.\n";
+               return $newrevid;
+       }
+       # Deleting and uploading a file requires a priviledged user
+       if ($file_deleted) {
+               mw_connect_maybe();
+               my $query = {
+                       action => 'delete',
+                       title => $path,
+                       reason => $summary
+               };
+               if (!$mediawiki->edit($query)) {
+                       print STDERR "Failed to delete file on remote wiki\n";
+                       print STDERR "Check your permissions on the remote site. Error code:\n";
+                       print STDERR $mediawiki->{error}->{code} . ':' . $mediawiki->{error}->{details};
+                       exit 1;
+               }
+       } else {
+               # Don't let perl try to interpret file content as UTF-8 => use "raw"
+               my $content = run_git("cat-file blob $new_sha1", "raw");
+               if ($content ne "") {
+                       mw_connect_maybe();
+                       $mediawiki->{config}->{upload_url} =
+                               "$url/index.php/Special:Upload";
+                       $mediawiki->edit({
+                               action => 'upload',
+                               filename => $complete_file_name,
+                               comment => $summary,
+                               file => [undef,
+                                        $complete_file_name,
+                                        Content => $content],
+                               ignorewarnings => 1,
+                       }, {
+                               skip_encoding => 1
+                       } ) || die $mediawiki->{error}->{code} . ':'
+                                . $mediawiki->{error}->{details};
+                       my $last_file_page = $mediawiki->get_page({title => $path});
+                       $newrevid = $last_file_page->{revid};
+                       print STDERR "Pushed file: $new_sha1 - $complete_file_name.\n";
+               } else {
+                       print STDERR "Empty file $complete_file_name not pushed.\n";
+               }
+       }
+       return $newrevid;
+}
+
 sub mw_push_file {
        my $diff_info = shift;
        # $diff_info contains a string in this format:
@@ -636,7 +1031,12 @@ sub mw_push_file {
        my $summary = shift;
        # MediaWiki revision number. Keep the previous one by default,
        # in case there's no edit to perform.
-       my $newrevid = shift;
+       my $oldrevid = shift;
+       my $newrevid;
+
+       if ($summary eq EMPTY_MESSAGE) {
+               $summary = '';
+       }
 
        my $new_sha1 = $diff_info_split[3];
        my $old_sha1 = $diff_info_split[2];
@@ -644,9 +1044,16 @@ sub mw_push_file {
        my $page_deleted = ($new_sha1 eq NULL_SHA1);
        $complete_file_name = mediawiki_clean_filename($complete_file_name);
 
-       if (substr($complete_file_name,-3) eq ".mw") {
-               my $title = substr($complete_file_name,0,-3);
-
+       my ($title, $extension) = $complete_file_name =~ /^(.*)\.([^\.]*)$/;
+       if (!defined($extension)) {
+               $extension = "";
+       }
+       if ($extension eq "mw") {
+               my $ns = get_mw_namespace_id_for_page($complete_file_name);
+               if ($ns && $ns == get_mw_namespace_id("File") && (!$export_media)) {
+                       print STDERR "Ignoring media file related page: $complete_file_name\n";
+                       return ($oldrevid, "ok");
+               }
                my $file_content;
                if ($page_deleted) {
                        # Deleting a page usually requires
@@ -664,7 +1071,7 @@ sub mw_push_file {
                        action => 'edit',
                        summary => $summary,
                        title => $title,
-                       basetimestamp => $basetimestamps{$newrevid},
+                       basetimestamp => $basetimestamps{$oldrevid},
                        text => mediawiki_clean($file_content, $page_created),
                                  }, {
                                          skip_encoding => 1 # Helps with names with accentuated characters
@@ -676,7 +1083,7 @@ sub mw_push_file {
                                    $mediawiki->{error}->{code} .
                                    ' from mediwiki: ' . $mediawiki->{error}->{details} .
                                    ".\n";
-                               return ($newrevid, "non-fast-forward");
+                               return ($oldrevid, "non-fast-forward");
                        } else {
                                # Other errors. Shouldn't happen => just die()
                                die 'Fatal: Error ' .
@@ -686,9 +1093,14 @@ sub mw_push_file {
                }
                $newrevid = $result->{edit}->{newrevid};
                print STDERR "Pushed file: $new_sha1 - $title\n";
+       } elsif ($export_media) {
+               $newrevid = mw_upload_file($complete_file_name, $new_sha1,
+                                          $extension, $page_deleted,
+                                          $summary);
        } else {
-               print STDERR "$complete_file_name not a mediawiki file (Not pushable on this version of git-remote-mediawiki).\n"
+               print STDERR "Ignoring media file $title\n";
        }
+       $newrevid = ($newrevid or $oldrevid);
        return ($newrevid, "ok");
 }
 
@@ -760,16 +1172,26 @@ sub mw_push_revision {
        if ($last_local_revid > 0) {
                my $parsed_sha1 = $remoteorigin_sha1;
                # Find a path from last MediaWiki commit to pushed commit
+               print STDERR "Computing path from local to remote ...\n";
+               my @local_ancestry = split(/\n/, run_git("rev-list --boundary --parents $local ^$parsed_sha1"));
+               my %local_ancestry;
+               foreach my $line (@local_ancestry) {
+                       if (my ($child, $parents) = $line =~ m/^-?([a-f0-9]+) ([a-f0-9 ]+)/) {
+                               foreach my $parent (split(' ', $parents)) {
+                                       $local_ancestry{$parent} = $child;
+                               }
+                       } elsif (!$line =~ m/^([a-f0-9]+)/) {
+                               die "Unexpected output from git rev-list: $line";
+                       }
+               }
                while ($parsed_sha1 ne $HEAD_sha1) {
-                       my @commit_info =  grep(/^$parsed_sha1/, split(/\n/, run_git("rev-list --children $local")));
-                       if (!@commit_info) {
+                       my $child = $local_ancestry{$parsed_sha1};
+                       if (!$child) {
+                               printf STDERR "Cannot find a path in history from remote commit to last commit\n";
                                return error_non_fast_forward($remote);
                        }
-                       my @commit_info_split = split(/ |\n/, $commit_info[0]);
-                       # $commit_info_split[1] is the sha1 of the commit to export
-                       # $commit_info_split[0] is the sha1 of its direct child
-                       push(@commit_pairs, \@commit_info_split);
-                       $parsed_sha1 = $commit_info_split[1];
+                       push(@commit_pairs, [$parsed_sha1, $child]);
+                       $parsed_sha1 = $child;
                }
        } else {
                # No remote mediawiki revision. Export the whole
@@ -791,8 +1213,8 @@ sub mw_push_revision {
                # TODO: we could detect rename, and encode them with a #redirect on the wiki.
                # TODO: for now, it's just a delete+add
                my @diff_info_list = split(/\0/, $diff_infos);
-               # Keep the first line of the commit message as mediawiki comment for the revision
-               my $commit_msg = (split(/\n/, run_git("show --pretty=format:\"%s\" $sha1_commit")))[0];
+               # Keep the subject line of the commit message as mediawiki comment for the revision
+               my $commit_msg = run_git("log --no-walk --format=\"%s\" $sha1_commit");
                chomp($commit_msg);
                # Push every blob
                while (@diff_info_list) {
@@ -817,7 +1239,7 @@ sub mw_push_revision {
                        }
                }
                unless ($dumb_push) {
-                       run_git("notes --ref=$remotename/mediawiki add -m \"mediawiki_revision: $mw_revision\" $sha1_commit");
+                       run_git("notes --ref=$remotename/mediawiki add -f -m \"mediawiki_revision: $mw_revision\" $sha1_commit");
                        run_git("update-ref -m \"Git-MediaWiki push\" refs/mediawiki/$remotename/master $sha1_commit $sha1_child");
                }
        }
@@ -825,3 +1247,104 @@ sub mw_push_revision {
        print STDOUT "ok $remote\n";
        return 1;
 }
+
+sub get_allowed_file_extensions {
+       mw_connect_maybe();
+
+       my $query = {
+               action => 'query',
+               meta => 'siteinfo',
+               siprop => 'fileextensions'
+               };
+       my $result = $mediawiki->api($query);
+       my @file_extensions= map $_->{ext},@{$result->{query}->{fileextensions}};
+       my %hashFile = map {$_ => 1}@file_extensions;
+
+       return %hashFile;
+}
+
+# In memory cache for MediaWiki namespace ids.
+my %namespace_id;
+
+# Namespaces whose id is cached in the configuration file
+# (to avoid duplicates)
+my %cached_mw_namespace_id;
+
+# Return MediaWiki id for a canonical namespace name.
+# Ex.: "File", "Project".
+sub get_mw_namespace_id {
+       mw_connect_maybe();
+       my $name = shift;
+
+       if (!exists $namespace_id{$name}) {
+               # Look at configuration file, if the record for that namespace is
+               # already cached. Namespaces are stored in form:
+               # "Name_of_namespace:Id_namespace", ex.: "File:6".
+               my @temp = split(/[\n]/, run_git("config --get-all remote."
+                                               . $remotename .".namespaceCache"));
+               chomp(@temp);
+               foreach my $ns (@temp) {
+                       my ($n, $id) = split(/:/, $ns);
+                       if ($id eq 'notANameSpace') {
+                               $namespace_id{$n} = {is_namespace => 0};
+                       } else {
+                               $namespace_id{$n} = {is_namespace => 1, id => $id};
+                       }
+                       $cached_mw_namespace_id{$n} = 1;
+               }
+       }
+
+       if (!exists $namespace_id{$name}) {
+               print STDERR "Namespace $name not found in cache, querying the wiki ...\n";
+               # NS not found => get namespace id from MW and store it in
+               # configuration file.
+               my $query = {
+                       action => 'query',
+                       meta => 'siteinfo',
+                       siprop => 'namespaces'
+               };
+               my $result = $mediawiki->api($query);
+
+               while (my ($id, $ns) = each(%{$result->{query}->{namespaces}})) {
+                       if (defined($ns->{id}) && defined($ns->{canonical})) {
+                               $namespace_id{$ns->{canonical}} = {is_namespace => 1, id => $ns->{id}};
+                               if ($ns->{'*'}) {
+                                       # alias (e.g. french Fichier: as alias for canonical File:)
+                                       $namespace_id{$ns->{'*'}} = {is_namespace => 1, id => $ns->{id}};
+                               }
+                       }
+               }
+       }
+
+       my $ns = $namespace_id{$name};
+       my $id;
+
+       unless (defined $ns) {
+               print STDERR "No such namespace $name on MediaWiki.\n";
+               $ns = {is_namespace => 0};
+               $namespace_id{$name} = $ns;
+       }
+
+       if ($ns->{is_namespace}) {
+               $id = $ns->{id};
+       }
+
+       # Store "notANameSpace" as special value for inexisting namespaces
+       my $store_id = ($id || 'notANameSpace');
+
+       # Store explicitely requested namespaces on disk
+       if (!exists $cached_mw_namespace_id{$name}) {
+               run_git("config --add remote.". $remotename
+                       .".namespaceCache \"". $name .":". $store_id ."\"");
+               $cached_mw_namespace_id{$name} = 1;
+       }
+       return $id;
+}
+
+sub get_mw_namespace_id_for_page {
+       if (my ($namespace) = $_[0] =~ /^([^:]*):/) {
+               return get_mw_namespace_id($namespace);
+       } else {
+               return;
+       }
+}
diff --git a/contrib/mw-to-git/t/.gitignore b/contrib/mw-to-git/t/.gitignore
new file mode 100644 (file)
index 0000000..a7a40b4
--- /dev/null
@@ -0,0 +1,4 @@
+WEB/
+wiki/
+trash directory.t*/
+test-results/
diff --git a/contrib/mw-to-git/t/Makefile b/contrib/mw-to-git/t/Makefile
new file mode 100644 (file)
index 0000000..f422203
--- /dev/null
@@ -0,0 +1,31 @@
+#
+# Copyright (C) 2012
+#     Charles Roussel <charles.roussel@ensimag.imag.fr>
+#     Simon Cathebras <simon.cathebras@ensimag.imag.fr>
+#     Julien Khayat <julien.khayat@ensimag.imag.fr>
+#     Guillaume Sasdy <guillaume.sasdy@ensimag.imag.fr>
+#     Simon Perrat <simon.perrat@ensimag.imag.fr>
+#
+## Test git-remote-mediawiki
+
+all: test
+
+-include ../../../config.mak.autogen
+-include ../../../config.mak
+
+T = $(wildcard t[0-9][0-9][0-9][0-9]-*.sh)
+
+.PHONY: help test clean all
+
+help:
+       @echo 'Run "$(MAKE) test" to launch test scripts'
+       @echo 'Run "$(MAKE) clean" to remove trash folders'
+
+test:
+       @for t in $(T); do \
+               echo "$$t"; \
+               "./$$t" || exit 1; \
+       done
+
+clean:
+       $(RM) -r 'trash directory'.*
diff --git a/contrib/mw-to-git/t/README b/contrib/mw-to-git/t/README
new file mode 100644 (file)
index 0000000..96e9739
--- /dev/null
@@ -0,0 +1,124 @@
+Tests for Mediawiki-to-Git
+==========================
+
+Introduction
+------------
+This manual describes how to install the git-remote-mediawiki test
+environment on a machine with git installed on it.
+
+Prerequisite
+------------
+
+In order to run this test environment correctly, you will need to
+install the following packages (Debian/Ubuntu names, may need to be
+adapted for another distribution):
+
+* lighttpd
+* php5
+* php5-cgi
+* php5-cli
+* php5-curl
+* php5-sqlite
+
+Principles and Technical Choices
+--------------------------------
+
+The test environment makes it easy to install and manipulate one or
+several MediaWiki instances. To allow developers to run the testsuite
+easily, the environment does not require root priviledge (except to
+install the required packages if needed). It starts a webserver
+instance on the user's account (using lighttpd greatly helps for
+that), and does not need a separate database daemon (thanks to the use
+of sqlite).
+
+Run the test environment
+------------------------
+
+Install a new wiki
+~~~~~~~~~~~~~~~~~~
+
+Once you have all the prerequisite, you need to install a MediaWiki
+instance on your machine. If you already have one, it is still
+strongly recommended to install one with the script provided. Here's
+how to work it:
+
+a. change directory to contrib/mw-to-git/t/
+b. if needed, edit test.config to choose your installation parameters
+c. run `./install-wiki.sh install`
+d. check on your favourite web browser if your wiki is correctly
+   installed.
+
+Remove an existing wiki
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Edit the file test.config to fit the wiki you want to delete, and then
+execute the command `./install-wiki.sh delete` from the
+contrib/mw-to-git/t directory.
+
+Run the existing tests
+~~~~~~~~~~~~~~~~~~~~~~
+
+The provided tests are currently in the `contrib/mw-to-git/t` directory.
+The files are all the t936[0-9]-*.sh shell scripts.
+
+a. Run all tests:
+To do so, run "make test" from the contrib/mw-to-git/ directory.
+
+b. Run a specific test:
+To run a given test <test_name>, run ./<test_name> from the
+contrib/mw-to-git/t directory.
+
+How to create new tests
+-----------------------
+
+Available functions
+~~~~~~~~~~~~~~~~~~~
+
+The test environment of git-remote-mediawiki provides some functions
+useful to test its behaviour. for more details about the functions'
+parameters, please refer to the `test-gitmw-lib.sh` and
+`test-gitmw.pl` files.
+
+** `test_check_wiki_precond`:
+Check if the tests must be skipped or not. Please use this function
+at the beggining of each new test file.
+
+** `wiki_getpage`:
+Fetch a given page from the wiki and puts its content in the
+directory in parameter.
+
+** `wiki_delete_page`:
+Delete a given page from the wiki.
+
+** `wiki_edit_page`:
+Create or modify a given page in the wiki. You can specify several
+parameters like a summary for the page edition, or add the page to a
+given category.
+See test-gitmw.pl for more details.
+
+** `wiki_getallpage`:
+Fetch all pages from the wiki into a given directory. The directory
+is created if it does not exists.
+
+** `test_diff_directories`:
+Compare the content of two directories. The content must be the same.
+Use this function to compare the content of a git directory and a wiki
+one created by wiki_getallpage.
+
+** `test_contains_N_files`:
+Check if the given directory contains a given number of file.
+
+** `wiki_page_exists`:
+Tests if a given page exists on the wiki.
+
+** `wiki_reset`:
+Reset the wiki, i.e. flush the database. Use this function at the
+begining of each new test, except if the test re-uses the same wiki
+(and history) as the previous test.
+
+How to write a new test
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Please, follow the standards given by git. See git/t/README.
+New file should be named as t936[0-9]-*.sh.
+Be sure to reset your wiki regulary with the function `wiki_reset`.
diff --git a/contrib/mw-to-git/t/install-wiki.sh b/contrib/mw-to-git/t/install-wiki.sh
new file mode 100755 (executable)
index 0000000..c6d6fa3
--- /dev/null
@@ -0,0 +1,45 @@
+#!/bin/sh
+
+# This script installs or deletes a MediaWiki on your computer.
+# It requires a web server with PHP and SQLite running. In addition, if you
+# do not have MediaWiki sources on your computer, the option 'install'
+# downloads them for you.
+# Please set the CONFIGURATION VARIABLES in ./test-gitmw-lib.sh
+
+WIKI_TEST_DIR=$(cd "$(dirname "$0")" && pwd)
+
+if test -z "$WIKI_TEST_DIR"
+then
+       WIKI_TEST_DIR=.
+fi
+
+. "$WIKI_TEST_DIR"/test-gitmw-lib.sh
+usage () {
+       echo "Usage: "
+       echo "  ./install-wiki.sh <install | delete | --help>"
+       echo "          install | -i :  Install a wiki on your computer."
+       echo "          delete | -d : Delete the wiki and all its pages and "
+       echo "                  content."
+}
+
+
+# Argument: install, delete, --help | -h
+case "$1" in
+       "install" | "-i")
+               wiki_install
+               exit 0
+               ;;
+       "delete" | "-d")
+               wiki_delete
+               exit 0
+               ;;
+       "--help" | "-h")
+               usage
+               exit 0
+               ;;
+       *)
+               echo "Invalid argument: $1"
+               usage
+               exit 1
+               ;;
+esac
diff --git a/contrib/mw-to-git/t/install-wiki/.gitignore b/contrib/mw-to-git/t/install-wiki/.gitignore
new file mode 100644 (file)
index 0000000..b5a2a44
--- /dev/null
@@ -0,0 +1 @@
+wikidb.sqlite
diff --git a/contrib/mw-to-git/t/install-wiki/LocalSettings.php b/contrib/mw-to-git/t/install-wiki/LocalSettings.php
new file mode 100644 (file)
index 0000000..29f1251
--- /dev/null
@@ -0,0 +1,129 @@
+<?php
+# This file was automatically generated by the MediaWiki 1.19.0
+# installer. If you make manual changes, please keep track in case you
+# need to recreate them later.
+#
+# See includes/DefaultSettings.php for all configurable settings
+# and their default values, but don't forget to make changes in _this_
+# file, not there.
+#
+# Further documentation for configuration settings may be found at:
+# http://www.mediawiki.org/wiki/Manual:Configuration_settings
+
+# Protect against web entry
+if ( !defined( 'MEDIAWIKI' ) ) {
+       exit;
+}
+
+## Uncomment this to disable output compression
+# $wgDisableOutputCompression = true;
+
+$wgSitename      = "Git-MediaWiki-Test";
+$wgMetaNamespace = "Git-MediaWiki-Test";
+
+## The URL base path to the directory containing the wiki;
+## defaults for all runtime URL paths are based off of this.
+## For more information on customizing the URLs please see:
+## http://www.mediawiki.org/wiki/Manual:Short_URL
+$wgScriptPath       = "@WG_SCRIPT_PATH@";
+$wgScriptExtension  = ".php";
+
+## The protocol and server name to use in fully-qualified URLs
+$wgServer           = "@WG_SERVER@";
+
+## The relative URL path to the skins directory
+$wgStylePath        = "$wgScriptPath/skins";
+
+## The relative URL path to the logo.  Make sure you change this from the default,
+## or else you'll overwrite your logo when you upgrade!
+$wgLogo             = "$wgStylePath/common/images/wiki.png";
+
+## UPO means: this is also a user preference option
+
+$wgEnableEmail      = true;
+$wgEnableUserEmail  = true; # UPO
+
+$wgEmergencyContact = "apache@localhost";
+$wgPasswordSender   = "apache@localhost";
+
+$wgEnotifUserTalk      = false; # UPO
+$wgEnotifWatchlist     = false; # UPO
+$wgEmailAuthentication = true;
+
+## Database settings
+$wgDBtype           = "sqlite";
+$wgDBserver         = "";
+$wgDBname           = "@WG_SQLITE_DATAFILE@";
+$wgDBuser           = "";
+$wgDBpassword       = "";
+
+# SQLite-specific settings
+$wgSQLiteDataDir    = "@WG_SQLITE_DATADIR@";
+
+
+## Shared memory settings
+$wgMainCacheType    = CACHE_NONE;
+$wgMemCachedServers = array();
+
+## To enable image uploads, make sure the 'images' directory
+## is writable, then set this to true:
+$wgEnableUploads  = true;
+$wgUseImageMagick = true;
+$wgImageMagickConvertCommand ="@CONVERT@";
+$wgFileExtensions[] = 'txt';
+
+# InstantCommons allows wiki to use images from http://commons.wikimedia.org
+$wgUseInstantCommons  = false;
+
+## If you use ImageMagick (or any other shell command) on a
+## Linux server, this will need to be set to the name of an
+## available UTF-8 locale
+$wgShellLocale = "en_US.utf8";
+
+## If you want to use image uploads under safe mode,
+## create the directories images/archive, images/thumb and
+## images/temp, and make them all writable. Then uncomment
+## this, if it's not already uncommented:
+#$wgHashedUploadDirectory = false;
+
+## Set $wgCacheDirectory to a writable directory on the web server
+## to make your wiki go slightly faster. The directory should not
+## be publically accessible from the web.
+#$wgCacheDirectory = "$IP/cache";
+
+# Site language code, should be one of the list in ./languages/Names.php
+$wgLanguageCode = "en";
+
+$wgSecretKey = "1c912bfe3519fb70f5dc523ecc698111cd43d81a11c585b3eefb28f29c2699b7";
+#$wgSecretKey = "@SECRETKEY@";
+
+
+# Site upgrade key. Must be set to a string (default provided) to turn on the
+# web installer while LocalSettings.php is in place
+$wgUpgradeKey = "ddae7dc87cd0a645";
+
+## Default skin: you can change the default skin. Use the internal symbolic
+## names, ie 'standard', 'nostalgia', 'cologneblue', 'monobook', 'vector':
+$wgDefaultSkin = "vector";
+
+## For attaching licensing metadata to pages, and displaying an
+## appropriate copyright notice / icon. GNU Free Documentation
+## License and Creative Commons licenses are supported so far.
+$wgRightsPage = ""; # Set to the title of a wiki page that describes your license/copyright
+$wgRightsUrl  = "";
+$wgRightsText = "";
+$wgRightsIcon = "";
+
+# Path to the GNU diff3 utility. Used for conflict resolution.
+$wgDiff3 = "/usr/bin/diff3";
+
+# Query string length limit for ResourceLoader. You should only set this if
+# your web server has a query string length limit (then set it to that limit),
+# or if you have suhosin.get.max_value_length set in php.ini (then set it to
+# that value)
+$wgResourceLoaderMaxQueryLength = -1;
+
+
+
+# End of automatically generated settings.
+# Add more configuration options below.
diff --git a/contrib/mw-to-git/t/install-wiki/db_install.php b/contrib/mw-to-git/t/install-wiki/db_install.php
new file mode 100644 (file)
index 0000000..0f3f4e0
--- /dev/null
@@ -0,0 +1,120 @@
+<?php
+/**
+ * This script generates a SQLite database for a MediaWiki version 1.19.0
+ * You must specify the login of the admin (argument 1) and its
+ * password (argument 2) and the folder where the database file
+ * is located (absolute path in argument 3).
+ * It is used by the script install-wiki.sh in order to make easy the
+ * installation of a MediaWiki.
+ *
+ * In order to generate a SQLite database file, MediaWiki ask the user
+ * to submit some forms in its web browser. This script simulates this
+ * behavior though the functions <get> and <submit>
+ *
+ */
+$argc = $_SERVER['argc'];
+$argv = $_SERVER['argv'];
+
+$login = $argv[2];
+$pass = $argv[3];
+$tmp = $argv[4];
+$port = $argv[5];
+
+$url = 'http://localhost:'.$port.'/wiki/mw-config/index.php';
+$db_dir = urlencode($tmp);
+$tmp_cookie = tempnam($tmp, "COOKIE_");
+/*
+ * Fetchs a page with cURL.
+ */
+function get($page_name = "") {
+       $curl = curl_init();
+       $page_name_add = "";
+       if ($page_name != "") {
+               $page_name_add = '?page='.$page_name;
+       }
+       $url = $GLOBALS['url'].$page_name_add;
+       $tmp_cookie = $GLOBALS['tmp_cookie'];
+       curl_setopt($curl, CURLOPT_COOKIEJAR, $tmp_cookie);
+       curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
+       curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
+       curl_setopt($curl, CURLOPT_COOKIEFILE, $tmp_cookie);
+       curl_setopt($curl, CURLOPT_HEADER, true);
+       curl_setopt($curl, CURLOPT_URL, $url);
+
+       $page = curl_exec($curl);
+       if (!$page) {
+               die("Could not get page: $url\n");
+       }
+       curl_close($curl);
+       return $page;
+}
+
+/*
+ * Submits a form with cURL.
+ */
+function submit($page_name, $option = "") {
+       $curl = curl_init();
+       $datapost = 'submit-continue=Continue+%E2%86%92';
+       if ($option != "") {
+               $datapost = $option.'&'.$datapost;
+       }
+       $url = $GLOBALS['url'].'?page='.$page_name;
+       $tmp_cookie = $GLOBALS['tmp_cookie'];
+       curl_setopt($curl, CURLOPT_URL, $url);
+       curl_setopt($curl, CURLOPT_POST, true);
+       curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
+       curl_setopt($curl, CURLOPT_POSTFIELDS, $datapost);
+       curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
+       curl_setopt($curl, CURLOPT_COOKIEJAR, $tmp_cookie);
+       curl_setopt($curl, CURLOPT_COOKIEFILE, $tmp_cookie);
+
+       $page = curl_exec($curl);
+       if (!$page) {
+               die("Could not get page: $url\n");
+       }
+       curl_close($curl);
+       return "$page";
+}
+
+/*
+ * Here starts this script: simulates the behavior of the user
+ * submitting forms to generates the database file.
+ * Note this simulation was made for the MediaWiki version 1.19.0,
+ * we can't assume it works with other versions.
+ *
+ */
+
+$page = get();
+if (!preg_match('/input type="hidden" value="([0-9]+)" name="LanguageRequestTime"/',
+               $page, $matches)) {
+       echo "Unexpected content for page downloaded:\n";
+       echo "$page";
+       die;
+};
+$timestamp = $matches[1];
+$language = "LanguageRequestTime=$timestamp&uselang=en&ContLang=en";
+$page = submit('Language', $language);
+
+submit('Welcome');
+
+$db_config = 'DBType=sqlite';
+$db_config = $db_config.'&sqlite_wgSQLiteDataDir='.$db_dir;
+$db_config = $db_config.'&sqlite_wgDBname='.$argv[1];
+submit('DBConnect', $db_config);
+
+$wiki_config = 'config_wgSitename=TEST';
+$wiki_config = $wiki_config.'&config__NamespaceType=site-name';
+$wiki_config = $wiki_config.'&config_wgMetaNamespace=MyWiki';
+$wiki_config = $wiki_config.'&config__AdminName='.$login;
+
+$wiki_config = $wiki_config.'&config__AdminPassword='.$pass;
+$wiki_config = $wiki_config.'&config__AdminPassword2='.$pass;
+
+$wiki_config = $wiki_config.'&wiki__configEmail=email%40email.org';
+$wiki_config = $wiki_config.'&config__SkipOptional=skip';
+submit('Name', $wiki_config);
+submit('Install');
+submit('Install');
+
+unlink($tmp_cookie);
+?>
diff --git a/contrib/mw-to-git/t/push-pull-tests.sh b/contrib/mw-to-git/t/push-pull-tests.sh
new file mode 100644 (file)
index 0000000..9da2dc5
--- /dev/null
@@ -0,0 +1,144 @@
+test_push_pull () {
+
+       test_expect_success 'Git pull works after adding a new wiki page' '
+               wiki_reset &&
+
+               git clone mediawiki::'"$WIKI_URL"' mw_dir_1 &&
+               wiki_editpage Foo "page created after the git clone" false &&
+
+               (
+                       cd mw_dir_1 &&
+                       git pull
+               ) &&
+
+               wiki_getallpage ref_page_1 &&
+               test_diff_directories mw_dir_1 ref_page_1
+       '
+
+       test_expect_success 'Git pull works after editing a wiki page' '
+               wiki_reset &&
+
+               wiki_editpage Foo "page created before the git clone" false &&
+               git clone mediawiki::'"$WIKI_URL"' mw_dir_2 &&
+               wiki_editpage Foo "new line added on the wiki" true &&
+
+               (
+                       cd mw_dir_2 &&
+                       git pull
+               ) &&
+
+               wiki_getallpage ref_page_2 &&
+               test_diff_directories mw_dir_2 ref_page_2
+       '
+
+       test_expect_success 'git pull works on conflict handled by auto-merge' '
+               wiki_reset &&
+
+               wiki_editpage Foo "1 init
+3
+5
+       " false &&
+               git clone mediawiki::'"$WIKI_URL"' mw_dir_3 &&
+
+               wiki_editpage Foo "1 init
+2 content added on wiki after clone
+3
+5
+       " false &&
+
+               (
+                       cd mw_dir_3 &&
+               echo "1 init
+3
+4 content added on git after clone
+5
+" >Foo.mw &&
+                       git commit -am "conflicting change on foo" &&
+                       git pull &&
+                       git push
+               )
+       '
+
+       test_expect_success 'Git push works after adding a file .mw' '
+               wiki_reset &&
+               git clone mediawiki::'"$WIKI_URL"' mw_dir_4 &&
+               wiki_getallpage ref_page_4 &&
+               (
+                       cd mw_dir_4 &&
+                       test_path_is_missing Foo.mw &&
+                       touch Foo.mw &&
+                       echo "hello world" >>Foo.mw &&
+                       git add Foo.mw &&
+                       git commit -m "Foo" &&
+                       git push
+               ) &&
+               wiki_getallpage ref_page_4 &&
+               test_diff_directories mw_dir_4 ref_page_4
+       '
+
+       test_expect_success 'Git push works after editing a file .mw' '
+               wiki_reset &&
+               wiki_editpage "Foo" "page created before the git clone" false &&
+               git clone mediawiki::'"$WIKI_URL"' mw_dir_5 &&
+
+               (
+                       cd mw_dir_5 &&
+                       echo "new line added in the file Foo.mw" >>Foo.mw &&
+                       git commit -am "edit file Foo.mw" &&
+                       git push
+               ) &&
+
+               wiki_getallpage ref_page_5 &&
+               test_diff_directories mw_dir_5 ref_page_5
+       '
+
+       test_expect_failure 'Git push works after deleting a file' '
+               wiki_reset &&
+               wiki_editpage Foo "wiki page added before git clone" false &&
+               git clone mediawiki::'"$WIKI_URL"' mw_dir_6 &&
+
+               (
+                       cd mw_dir_6 &&
+                       git rm Foo.mw &&
+                       git commit -am "page Foo.mw deleted" &&
+                       git push
+               ) &&
+
+               test_must_fail wiki_page_exist Foo
+       '
+
+       test_expect_success 'Merge conflict expected and solving it' '
+               wiki_reset &&
+
+               git clone mediawiki::'"$WIKI_URL"' mw_dir_7 &&
+               wiki_editpage Foo "1 conflict
+3 wiki
+4" false &&
+
+               (
+                       cd mw_dir_7 &&
+               echo "1 conflict
+2 git
+4" >Foo.mw &&
+                       git add Foo.mw &&
+                       git commit -m "conflict created" &&
+                       test_must_fail git pull &&
+                       "$PERL_PATH" -pi -e "s/[<=>].*//g" Foo.mw &&
+                       git commit -am "merge conflict solved" &&
+                       git push
+               )
+       '
+
+       test_expect_failure 'git pull works after deleting a wiki page' '
+               wiki_reset &&
+               wiki_editpage Foo "wiki page added before the git clone" false &&
+               git clone mediawiki::'"$WIKI_URL"' mw_dir_8 &&
+
+               wiki_delete_page Foo &&
+               (
+                       cd mw_dir_8 &&
+                       git pull &&
+                       test_path_is_missing Foo.mw
+               )
+       '
+}
diff --git a/contrib/mw-to-git/t/t9360-mw-to-git-clone.sh b/contrib/mw-to-git/t/t9360-mw-to-git-clone.sh
new file mode 100755 (executable)
index 0000000..811a90c
--- /dev/null
@@ -0,0 +1,257 @@
+#!/bin/sh
+#
+# Copyright (C) 2012
+#     Charles Roussel <charles.roussel@ensimag.imag.fr>
+#     Simon Cathebras <simon.cathebras@ensimag.imag.fr>
+#     Julien Khayat <julien.khayat@ensimag.imag.fr>
+#     Guillaume Sasdy <guillaume.sasdy@ensimag.imag.fr>
+#     Simon Perrat <simon.perrat@ensimag.imag.fr>
+#
+# License: GPL v2 or later
+
+
+test_description='Test the Git Mediawiki remote helper: git clone'
+
+. ./test-gitmw-lib.sh
+. $TEST_DIRECTORY/test-lib.sh
+
+
+test_check_precond
+
+
+test_expect_success 'Git clone creates the expected git log with one file' '
+       wiki_reset &&
+       wiki_editpage foo "this is not important" false -c cat -s "this must be the same" &&
+       git clone mediawiki::'"$WIKI_URL"' mw_dir_1 &&
+       (
+               cd mw_dir_1 &&
+               git log --format=%s HEAD^..HEAD >log.tmp
+       ) &&
+       echo "this must be the same" >msg.tmp &&
+       diff -b mw_dir_1/log.tmp msg.tmp
+'
+
+
+test_expect_success 'Git clone creates the expected git log with multiple files' '
+       wiki_reset &&
+       wiki_editpage daddy "this is not important" false -s="this must be the same" &&
+       wiki_editpage daddy "neither is this" true -s="this must also be the same" &&
+       wiki_editpage daddy "neither is this" true -s="same same same" &&
+       wiki_editpage dj "dont care" false -s="identical" &&
+       wiki_editpage dj "dont care either" true -s="identical too" &&
+       git clone mediawiki::'"$WIKI_URL"' mw_dir_2 &&
+       (
+               cd mw_dir_2 &&
+               git log --format=%s Daddy.mw  >logDaddy.tmp &&
+               git log --format=%s Dj.mw >logDj.tmp
+       ) &&
+       echo "same same same" >msgDaddy.tmp &&
+       echo "this must also be the same" >>msgDaddy.tmp &&
+       echo "this must be the same" >>msgDaddy.tmp &&
+       echo "identical too" >msgDj.tmp &&
+       echo "identical" >>msgDj.tmp &&
+       diff -b mw_dir_2/logDaddy.tmp msgDaddy.tmp &&
+       diff -b mw_dir_2/logDj.tmp msgDj.tmp
+'
+
+
+test_expect_success 'Git clone creates only Main_Page.mw with an empty wiki' '
+       wiki_reset &&
+       git clone mediawiki::'"$WIKI_URL"' mw_dir_3 &&
+       test_contains_N_files mw_dir_3 1 &&
+       test_path_is_file mw_dir_3/Main_Page.mw
+'
+
+test_expect_success 'Git clone does not fetch a deleted page' '
+       wiki_reset &&
+       wiki_editpage foo "this page must be deleted before the clone" false &&
+       wiki_delete_page foo &&
+       git clone mediawiki::'"$WIKI_URL"' mw_dir_4 &&
+       test_contains_N_files mw_dir_4 1 &&
+       test_path_is_file mw_dir_4/Main_Page.mw &&
+       test_path_is_missing mw_dir_4/Foo.mw
+'
+
+test_expect_success 'Git clone works with page added' '
+       wiki_reset &&
+       wiki_editpage foo " I will be cloned" false &&
+       wiki_editpage bar "I will be cloned" false &&
+       git clone mediawiki::'"$WIKI_URL"' mw_dir_5 &&
+       wiki_getallpage ref_page_5 &&
+       test_diff_directories mw_dir_5 ref_page_5 &&
+       wiki_delete_page foo &&
+       wiki_delete_page bar
+'
+
+test_expect_success 'Git clone works with an edited page ' '
+       wiki_reset &&
+       wiki_editpage foo "this page will be edited" \
+               false -s "first edition of page foo"&&
+       wiki_editpage foo "this page has been edited and must be on the clone " true &&
+       git clone mediawiki::'"$WIKI_URL"' mw_dir_6 &&
+       test_path_is_file mw_dir_6/Foo.mw &&
+       test_path_is_file mw_dir_6/Main_Page.mw &&
+       wiki_getallpage mw_dir_6/page_ref_6 &&
+       test_diff_directories mw_dir_6 mw_dir_6/page_ref_6 &&
+       (
+               cd mw_dir_6 &&
+               git log --format=%s HEAD^ Foo.mw > ../Foo.log
+       ) &&
+       echo "first edition of page foo" > FooExpect.log &&
+       diff FooExpect.log Foo.log
+'
+
+
+test_expect_success 'Git clone works with several pages and some deleted ' '
+       wiki_reset &&
+       wiki_editpage foo "this page will not be deleted" false &&
+       wiki_editpage bar "I must not be erased" false &&
+       wiki_editpage namnam "I will not be there at the end" false &&
+       wiki_editpage nyancat "nyan nyan nyan delete me" false &&
+       wiki_delete_page namnam &&
+       wiki_delete_page nyancat &&
+       git clone mediawiki::'"$WIKI_URL"' mw_dir_7 &&
+       test_path_is_file mw_dir_7/Foo.mw &&
+       test_path_is_file mw_dir_7/Bar.mw &&
+       test_path_is_missing mw_dir_7/Namnam.mw &&
+       test_path_is_missing mw_dir_7/Nyancat.mw &&
+       wiki_getallpage mw_dir_7/page_ref_7 &&
+       test_diff_directories mw_dir_7 mw_dir_7/page_ref_7
+'
+
+
+test_expect_success 'Git clone works with one specific page cloned ' '
+       wiki_reset &&
+       wiki_editpage foo "I will not be cloned" false &&
+       wiki_editpage bar "Do not clone me" false &&
+       wiki_editpage namnam "I will be cloned :)" false  -s="this log must stay" &&
+       wiki_editpage nyancat "nyan nyan nyan you cant clone me" false &&
+       git clone -c remote.origin.pages=namnam \
+               mediawiki::'"$WIKI_URL"' mw_dir_8 &&
+       test_contains_N_files mw_dir_8 1 &&
+       test_path_is_file mw_dir_8/Namnam.mw &&
+       test_path_is_missing mw_dir_8/Main_Page.mw &&
+       (
+               cd mw_dir_8 &&
+               echo "this log must stay" >msg.tmp &&
+               git log --format=%s >log.tmp &&
+               diff -b msg.tmp log.tmp
+       ) &&
+       wiki_check_content mw_dir_8/Namnam.mw Namnam
+'
+
+test_expect_success 'Git clone works with multiple specific page cloned ' '
+       wiki_reset &&
+       wiki_editpage foo "I will be there" false &&
+       wiki_editpage bar "I will not disapear" false &&
+       wiki_editpage namnam "I be erased" false &&
+       wiki_editpage nyancat "nyan nyan nyan you will not erase me" false &&
+       wiki_delete_page namnam &&
+       git clone -c remote.origin.pages="foo bar nyancat namnam" \
+               mediawiki::'"$WIKI_URL"' mw_dir_9 &&
+       test_contains_N_files mw_dir_9 3 &&
+       test_path_is_missing mw_dir_9/Namnam.mw &&
+       test_path_is_file mw_dir_9/Foo.mw &&
+       test_path_is_file mw_dir_9/Nyancat.mw &&
+       test_path_is_file mw_dir_9/Bar.mw &&
+       wiki_check_content mw_dir_9/Foo.mw Foo &&
+       wiki_check_content mw_dir_9/Bar.mw Bar &&
+       wiki_check_content mw_dir_9/Nyancat.mw Nyancat
+'
+
+test_expect_success 'Mediawiki-clone of several specific pages on wiki' '
+       wiki_reset &&
+       wiki_editpage foo "foo 1" false &&
+       wiki_editpage bar "bar 1" false &&
+       wiki_editpage dummy "dummy 1" false &&
+       wiki_editpage cloned_1 "cloned_1 1" false &&
+       wiki_editpage cloned_2 "cloned_2 2" false &&
+       wiki_editpage cloned_3 "cloned_3 3" false &&
+       mkdir -p ref_page_10 &&
+       wiki_getpage cloned_1 ref_page_10 &&
+       wiki_getpage cloned_2 ref_page_10 &&
+       wiki_getpage cloned_3 ref_page_10 &&
+       git clone -c remote.origin.pages="cloned_1 cloned_2 cloned_3" \
+               mediawiki::'"$WIKI_URL"' mw_dir_10 &&
+       test_diff_directories mw_dir_10 ref_page_10
+'
+
+test_expect_success 'Git clone works with the shallow option' '
+       wiki_reset &&
+       wiki_editpage foo "1st revision, should be cloned" false &&
+       wiki_editpage bar "1st revision, should be cloned" false &&
+       wiki_editpage nyan "1st revision, should not be cloned" false &&
+       wiki_editpage nyan "2nd revision, should be cloned" false &&
+       git -c remote.origin.shallow=true clone \
+               mediawiki::'"$WIKI_URL"' mw_dir_11 &&
+       test_contains_N_files mw_dir_11 4 &&
+       test_path_is_file mw_dir_11/Nyan.mw &&
+       test_path_is_file mw_dir_11/Foo.mw &&
+       test_path_is_file mw_dir_11/Bar.mw &&
+       test_path_is_file mw_dir_11/Main_Page.mw &&
+       (
+               cd mw_dir_11 &&
+               test `git log --oneline Nyan.mw | wc -l` -eq 1 &&
+               test `git log --oneline Foo.mw | wc -l` -eq 1 &&
+               test `git log --oneline Bar.mw | wc -l` -eq 1 &&
+               test `git log --oneline Main_Page.mw | wc -l ` -eq 1
+       ) &&
+       wiki_check_content mw_dir_11/Nyan.mw Nyan &&
+       wiki_check_content mw_dir_11/Foo.mw Foo &&
+       wiki_check_content mw_dir_11/Bar.mw Bar &&
+       wiki_check_content mw_dir_11/Main_Page.mw Main_Page
+'
+
+test_expect_success 'Git clone works with the shallow option with a delete page' '
+       wiki_reset &&
+       wiki_editpage foo "1st revision, will be deleted" false &&
+       wiki_editpage bar "1st revision, should be cloned" false &&
+       wiki_editpage nyan "1st revision, should not be cloned" false &&
+       wiki_editpage nyan "2nd revision, should be cloned" false &&
+       wiki_delete_page foo &&
+       git -c remote.origin.shallow=true clone \
+               mediawiki::'"$WIKI_URL"' mw_dir_12 &&
+       test_contains_N_files mw_dir_12 3 &&
+       test_path_is_file mw_dir_12/Nyan.mw &&
+       test_path_is_missing mw_dir_12/Foo.mw &&
+       test_path_is_file mw_dir_12/Bar.mw &&
+       test_path_is_file mw_dir_12/Main_Page.mw &&
+       (
+               cd mw_dir_12 &&
+               test `git log --oneline Nyan.mw | wc -l` -eq 1 &&
+               test `git log --oneline Bar.mw | wc -l` -eq 1 &&
+               test `git log --oneline Main_Page.mw | wc -l ` -eq 1
+       ) &&
+       wiki_check_content mw_dir_12/Nyan.mw Nyan &&
+       wiki_check_content mw_dir_12/Bar.mw Bar &&
+       wiki_check_content mw_dir_12/Main_Page.mw Main_Page
+'
+
+test_expect_success 'Test of fetching a category' '
+       wiki_reset &&
+       wiki_editpage Foo "I will be cloned" false -c=Category &&
+       wiki_editpage Bar "Meet me on the repository" false -c=Category &&
+       wiki_editpage Dummy "I will not come" false &&
+       wiki_editpage BarWrong "I will stay online only" false -c=NotCategory &&
+       git clone -c remote.origin.categories="Category" \
+               mediawiki::'"$WIKI_URL"' mw_dir_13 &&
+       wiki_getallpage ref_page_13 Category &&
+       test_diff_directories mw_dir_13 ref_page_13
+'
+
+test_expect_success 'Test of resistance to modification of category on wiki for clone' '
+       wiki_reset &&
+       wiki_editpage Tobedeleted "this page will be deleted" false -c=Catone &&
+       wiki_editpage Tobeedited "this page will be modified" false -c=Catone &&
+       wiki_editpage Normalone "this page wont be modified and will be on git" false -c=Catone &&
+       wiki_editpage Notconsidered "this page will not appear on local" false &&
+       wiki_editpage Othercategory "this page will not appear on local" false -c=Cattwo &&
+       wiki_editpage Tobeedited "this page have been modified" true -c=Catone &&
+       wiki_delete_page Tobedeleted
+       git clone -c remote.origin.categories="Catone" \
+               mediawiki::'"$WIKI_URL"' mw_dir_14 &&
+       wiki_getallpage ref_page_14 Catone &&
+       test_diff_directories mw_dir_14 ref_page_14
+'
+
+test_done
diff --git a/contrib/mw-to-git/t/t9361-mw-to-git-push-pull.sh b/contrib/mw-to-git/t/t9361-mw-to-git-push-pull.sh
new file mode 100755 (executable)
index 0000000..9ea2014
--- /dev/null
@@ -0,0 +1,24 @@
+#!/bin/sh
+#
+# Copyright (C) 2012
+#     Charles Roussel <charles.roussel@ensimag.imag.fr>
+#     Simon Cathebras <simon.cathebras@ensimag.imag.fr>
+#     Julien Khayat <julien.khayat@ensimag.imag.fr>
+#     Guillaume Sasdy <guillaume.sasdy@ensimag.imag.fr>
+#     Simon Perrat <simon.perrat@ensimag.imag.fr>
+#
+# License: GPL v2 or later
+
+# tests for git-remote-mediawiki
+
+test_description='Test the Git Mediawiki remote helper: git push and git pull simple test cases'
+
+. ./test-gitmw-lib.sh
+. ./push-pull-tests.sh
+. $TEST_DIRECTORY/test-lib.sh
+
+test_check_precond
+
+test_push_pull
+
+test_done
diff --git a/contrib/mw-to-git/t/t9362-mw-to-git-utf8.sh b/contrib/mw-to-git/t/t9362-mw-to-git-utf8.sh
new file mode 100755 (executable)
index 0000000..246d47d
--- /dev/null
@@ -0,0 +1,321 @@
+#!/bin/sh
+#
+# Copyright (C) 2012
+#     Charles Roussel <charles.roussel@ensimag.imag.fr>
+#     Simon Cathebras <simon.cathebras@ensimag.imag.fr>
+#     Julien Khayat <julien.khayat@ensimag.imag.fr>
+#     Guillaume Sasdy <guillaume.sasdy@ensimag.imag.fr>
+#     Simon Perrat <simon.perrat@ensimag.imag.fr>
+#
+# License: GPL v2 or later
+
+# tests for git-remote-mediawiki
+
+test_description='Test git-mediawiki with special characters in filenames'
+
+. ./test-gitmw-lib.sh
+. $TEST_DIRECTORY/test-lib.sh
+
+
+test_check_precond
+
+
+test_expect_success 'Git clone works for a wiki with accents in the page names' '
+       wiki_reset &&
+       wiki_editpage féé "This page must be délétéd before clone" false &&
+       wiki_editpage kèè "This page must be deleted before clone" false &&
+       wiki_editpage hàà "This page must be deleted before clone" false &&
+       wiki_editpage kîî "This page must be deleted before clone" false &&
+       wiki_editpage foo "This page must be deleted before clone" false &&
+       git clone mediawiki::'"$WIKI_URL"' mw_dir_1 &&
+       wiki_getallpage ref_page_1 &&
+       test_diff_directories mw_dir_1 ref_page_1
+'
+
+
+test_expect_success 'Git pull works with a wiki with accents in the pages names' '
+       wiki_reset &&
+       wiki_editpage kîî "this page must be cloned" false &&
+       wiki_editpage foo "this page must be cloned" false &&
+       git clone mediawiki::'"$WIKI_URL"' mw_dir_2 &&
+       wiki_editpage éàîôû "This page must be pulled" false &&
+       (
+               cd mw_dir_2 &&
+               git pull
+       ) &&
+       wiki_getallpage ref_page_2 &&
+       test_diff_directories mw_dir_2 ref_page_2
+'
+
+
+test_expect_success 'Cloning a chosen page works with accents' '
+       wiki_reset &&
+       wiki_editpage kîî "this page must be cloned" false &&
+       git clone -c remote.origin.pages=kîî \
+               mediawiki::'"$WIKI_URL"' mw_dir_3 &&
+       wiki_check_content mw_dir_3/Kîî.mw Kîî &&
+       test_path_is_file mw_dir_3/Kîî.mw &&
+       rm -rf mw_dir_3
+'
+
+
+test_expect_success 'The shallow option works with accents' '
+       wiki_reset &&
+       wiki_editpage néoà "1st revision, should not be cloned" false &&
+       wiki_editpage néoà "2nd revision, should be cloned" false &&
+       git -c remote.origin.shallow=true clone \
+               mediawiki::'"$WIKI_URL"' mw_dir_4 &&
+       test_contains_N_files mw_dir_4 2 &&
+       test_path_is_file mw_dir_4/Néoà.mw &&
+       test_path_is_file mw_dir_4/Main_Page.mw &&
+       (
+               cd mw_dir_4 &&
+               test `git log --oneline Néoà.mw | wc -l` -eq 1 &&
+               test `git log --oneline Main_Page.mw | wc -l ` -eq 1
+       ) &&
+       wiki_check_content mw_dir_4/Néoà.mw Néoà &&
+       wiki_check_content mw_dir_4/Main_Page.mw Main_Page
+'
+
+
+test_expect_success 'Cloning works when page name first letter has an accent' '
+       wiki_reset &&
+       wiki_editpage îî "this page must be cloned" false &&
+       git clone -c remote.origin.pages=îî \
+               mediawiki::'"$WIKI_URL"' mw_dir_5 &&
+       test_path_is_file mw_dir_5/Îî.mw &&
+       wiki_check_content mw_dir_5/Îî.mw Îî
+'
+
+
+test_expect_success 'Git push works with a wiki with accents' '
+       wiki_reset &&
+       wiki_editpage féé "lots of accents : éèàÖ" false &&
+       wiki_editpage foo "this page must be cloned" false &&
+       git clone mediawiki::'"$WIKI_URL"' mw_dir_6 &&
+       (
+               cd mw_dir_6 &&
+               echo "A wild Pîkächû appears on the wiki" >Pîkächû.mw &&
+               git add Pîkächû.mw &&
+               git commit -m "A new page appears" &&
+               git push
+       ) &&
+       wiki_getallpage ref_page_6 &&
+       test_diff_directories mw_dir_6 ref_page_6
+'
+
+test_expect_success 'Git clone works with accentsand spaces' '
+       wiki_reset &&
+       wiki_editpage "é à î" "this page must be délété before the clone" false &&
+       git clone mediawiki::'"$WIKI_URL"' mw_dir_7 &&
+       wiki_getallpage ref_page_7 &&
+       test_diff_directories mw_dir_7 ref_page_7
+'
+
+test_expect_success 'character $ 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_8 &&
+       test_path_is_file mw_dir_8/File_\$_foo.mw &&
+       wiki_getallpage ref_page_8 &&
+       test_diff_directories mw_dir_8 ref_page_8
+'
+
+
+
+test_expect_success 'character $ in file name (git -> mw) ' '
+       wiki_reset &&
+       git clone mediawiki::'"$WIKI_URL"' mw_dir_9 &&
+       (
+               cd mw_dir_9 &&
+               echo "this file is called File_\$_foo.mw" >File_\$_foo.mw &&
+               git add . &&
+               git commit -am "file File_\$_foo.mw" &&
+               git pull &&
+               git push
+       ) &&
+       wiki_getallpage ref_page_9 &&
+       test_diff_directories mw_dir_9 ref_page_9
+'
+
+
+test_expect_failure 'capital at the begining of file names' '
+       wiki_reset &&
+       git clone mediawiki::'"$WIKI_URL"' mw_dir_10 &&
+       (
+               cd mw_dir_10 &&
+               echo "my new file foo" >foo.mw &&
+               echo "my new file Foo... Finger crossed" >Foo.mw &&
+               git add . &&
+               git commit -am "file foo.mw" &&
+               git pull &&
+               git push
+       ) &&
+       wiki_getallpage ref_page_10 &&
+       test_diff_directories mw_dir_10 ref_page_10
+'
+
+
+test_expect_failure 'special character at the begining of file name from mw to git' '
+       wiki_reset &&
+       git clone mediawiki::'"$WIKI_URL"' mw_dir_11 &&
+       wiki_editpage {char_1 "expect to be renamed {char_1" false &&
+       wiki_editpage [char_2 "expect to be renamed [char_2" false &&
+       (
+               cd mw_dir_11 &&
+               git pull
+       ) &&
+       test_path_is_file mw_dir_11/{char_1 &&
+       test_path_is_file mw_dir_11/[char_2
+'
+
+test_expect_success 'Pull page with title containing ":" other than namespace separator' '
+       wiki_editpage Foo:Bar content false &&
+       (
+               cd mw_dir_11 &&
+               git pull
+       ) &&
+       test_path_is_file mw_dir_11/Foo:Bar.mw
+'
+
+test_expect_success 'Push page with title containing ":" other than namespace separator' '
+       (
+               cd mw_dir_11 &&
+               echo content >NotANameSpace:Page.mw &&
+               git add NotANameSpace:Page.mw &&
+               git commit -m "add page with colon" &&
+               git push
+       ) &&
+       wiki_page_exist NotANameSpace:Page
+'
+
+test_expect_success 'test of correct formating for file name from mw to git' '
+       wiki_reset &&
+       git clone mediawiki::'"$WIKI_URL"' mw_dir_12 &&
+       wiki_editpage char_%_7b_1 "expect to be renamed char{_1" false &&
+       wiki_editpage char_%_5b_2 "expect to be renamed char{_2" false &&
+       (
+               cd mw_dir_12 &&
+               git pull
+       ) &&
+       test_path_is_file mw_dir_12/Char\{_1.mw &&
+       test_path_is_file mw_dir_12/Char\[_2.mw &&
+       wiki_getallpage ref_page_12 &&
+       mv ref_page_12/Char_%_7b_1.mw ref_page_12/Char\{_1.mw &&
+       mv ref_page_12/Char_%_5b_2.mw ref_page_12/Char\[_2.mw &&
+       test_diff_directories mw_dir_12 ref_page_12
+'
+
+
+test_expect_failure 'test of correct formating for file name begining with special character' '
+       wiki_reset &&
+       git clone mediawiki::'"$WIKI_URL"' mw_dir_13 &&
+       (
+               cd mw_dir_13 &&
+               echo "my new file {char_1" >\{char_1.mw &&
+               echo "my new file [char_2" >\[char_2.mw &&
+               git add . &&
+               git commit -am "commiting some exotic file name..." &&
+               git push &&
+               git pull
+       ) &&
+       wiki_getallpage ref_page_13 &&
+       test_path_is_file ref_page_13/{char_1.mw &&
+       test_path_is_file ref_page_13/[char_2.mw &&
+       test_diff_directories mw_dir_13 ref_page_13
+'
+
+
+test_expect_success 'test of correct formating for file name from git to mw' '
+       wiki_reset &&
+       git clone mediawiki::'"$WIKI_URL"' mw_dir_14 &&
+       (
+               cd mw_dir_14 &&
+               echo "my new file char{_1" >Char\{_1.mw &&
+               echo "my new file char[_2" >Char\[_2.mw &&
+               git add . &&
+               git commit -m "commiting some exotic file name..." &&
+               git push
+       ) &&
+       wiki_getallpage ref_page_14 &&
+       mv mw_dir_14/Char\{_1.mw mw_dir_14/Char_%_7b_1.mw &&
+       mv mw_dir_14/Char\[_2.mw mw_dir_14/Char_%_5b_2.mw &&
+       test_diff_directories mw_dir_14 ref_page_14
+'
+
+
+test_expect_success 'git clone with /' '
+       wiki_reset &&
+       wiki_editpage \/fo\/o "this is not important" false -c=Deleted &&
+       git clone mediawiki::'"$WIKI_URL"' mw_dir_15 &&
+       test_path_is_file mw_dir_15/%2Ffo%2Fo.mw &&
+       wiki_check_content mw_dir_15/%2Ffo%2Fo.mw \/fo\/o
+'
+
+
+test_expect_success 'git push with /' '
+       wiki_reset &&
+       git clone mediawiki::'"$WIKI_URL"' mw_dir_16 &&
+       echo "I will be on the wiki" >mw_dir_16/%2Ffo%2Fo.mw &&
+       (
+               cd mw_dir_16 &&
+               git add %2Ffo%2Fo.mw &&
+               git commit -m " %2Ffo%2Fo added" &&
+               git push
+       ) &&
+       wiki_page_exist \/fo\/o &&
+       wiki_check_content mw_dir_16/%2Ffo%2Fo.mw \/fo\/o
+
+'
+
+
+test_expect_success 'git clone with \' '
+       wiki_reset &&
+       wiki_editpage \\ko\\o "this is not important" false -c=Deleted &&
+       git clone mediawiki::'"$WIKI_URL"' mw_dir_17 &&
+       test_path_is_file mw_dir_17/\\ko\\o.mw &&
+       wiki_check_content mw_dir_17/\\ko\\o.mw \\ko\\o
+'
+
+
+test_expect_success 'git push with \' '
+       wiki_reset &&
+       git clone mediawiki::'"$WIKI_URL"' mw_dir_18 &&
+       echo "I will be on the wiki" >mw_dir_18/\\ko\\o.mw &&
+       (
+               cd mw_dir_18 &&
+               git add \\ko\\o.mw &&
+               git commit -m " \\ko\\o added" &&
+               git push
+       )&&
+       wiki_page_exist \\ko\\o &&
+       wiki_check_content mw_dir_18/\\ko\\o.mw \\ko\\o
+
+'
+
+test_expect_success 'git clone with \ in format control' '
+       wiki_reset &&
+       wiki_editpage \\no\\o "this is not important" false &&
+       git clone mediawiki::'"$WIKI_URL"' mw_dir_19 &&
+       test_path_is_file mw_dir_19/\\no\\o.mw &&
+       wiki_check_content mw_dir_19/\\no\\o.mw \\no\\o
+'
+
+
+test_expect_success 'git push with \ in format control' '
+       wiki_reset &&
+       git clone mediawiki::'"$WIKI_URL"' mw_dir_20 &&
+       echo "I will be on the wiki" >mw_dir_20/\\fo\\o.mw &&
+       (
+               cd mw_dir_20 &&
+               git add \\fo\\o.mw &&
+               git commit -m " \\fo\\o added" &&
+               git push
+       )&&
+       wiki_page_exist \\fo\\o &&
+       wiki_check_content mw_dir_20/\\fo\\o.mw \\fo\\o
+
+'
+
+
+test_done
diff --git a/contrib/mw-to-git/t/t9363-mw-to-git-export-import.sh b/contrib/mw-to-git/t/t9363-mw-to-git-export-import.sh
new file mode 100755 (executable)
index 0000000..5a03739
--- /dev/null
@@ -0,0 +1,198 @@
+#!/bin/sh
+#
+# Copyright (C) 2012
+#     Charles Roussel <charles.roussel@ensimag.imag.fr>
+#     Simon Cathebras <simon.cathebras@ensimag.imag.fr>
+#     Julien Khayat <julien.khayat@ensimag.imag.fr>
+#     Guillaume Sasdy <guillaume.sasdy@ensimag.imag.fr>
+#     Simon Perrat <simon.perrat@ensimag.imag.fr>
+#
+# License: GPL v2 or later
+
+# tests for git-remote-mediawiki
+
+test_description='Test the Git Mediawiki remote helper: git push and git pull simple test cases'
+
+. ./test-gitmw-lib.sh
+. $TEST_DIRECTORY/test-lib.sh
+
+
+test_check_precond
+
+
+test_git_reimport () {
+       git -c remote.origin.dumbPush=true push &&
+       git -c remote.origin.mediaImport=true pull --rebase
+}
+
+# Don't bother with permissions, be administrator by default
+test_expect_success 'setup config' '
+       git config --global remote.origin.mwLogin WikiAdmin &&
+       git config --global remote.origin.mwPassword AdminPass &&
+       test_might_fail git config --global --unset remote.origin.mediaImport
+'
+
+test_expect_success 'git push can upload media (File:) files' '
+       wiki_reset &&
+       git clone mediawiki::'"$WIKI_URL"' mw_dir &&
+       (
+               cd mw_dir &&
+               echo "hello world" >Foo.txt &&
+               git add Foo.txt &&
+               git commit -m "add a text file" &&
+               git push &&
+               "$PERL_PATH" -e "print STDOUT \"binary content: \".chr(255);" >Foo.txt &&
+               git add Foo.txt &&
+               git commit -m "add a text file with binary content" &&
+               git push
+       )
+'
+
+test_expect_success 'git clone works on previously created wiki with media files' '
+       test_when_finished "rm -rf mw_dir mw_dir_clone" &&
+       git clone -c remote.origin.mediaimport=true \
+               mediawiki::'"$WIKI_URL"' mw_dir_clone &&
+       test_cmp mw_dir_clone/Foo.txt mw_dir/Foo.txt &&
+       (cd mw_dir_clone && git checkout HEAD^) &&
+       (cd mw_dir && git checkout HEAD^) &&
+       test_cmp mw_dir_clone/Foo.txt mw_dir/Foo.txt
+'
+
+test_expect_success 'git push & pull work with locally renamed media files' '
+       wiki_reset &&
+       git clone mediawiki::'"$WIKI_URL"' mw_dir &&
+       test_when_finished "rm -fr mw_dir" &&
+       (
+               cd mw_dir &&
+               echo "A File" >Foo.txt &&
+               git add Foo.txt &&
+               git commit -m "add a file" &&
+               git mv Foo.txt Bar.txt &&
+               git commit -m "Rename a file" &&
+               test_git_reimport &&
+               echo "A File" >expect &&
+               test_cmp expect Bar.txt &&
+               test_path_is_missing Foo.txt
+       )
+'
+
+test_expect_success 'git push can propagate local page deletion' '
+       wiki_reset &&
+       git clone mediawiki::'"$WIKI_URL"' mw_dir &&
+       test_when_finished "rm -fr mw_dir" &&
+       (
+               cd mw_dir &&
+               test_path_is_missing Foo.mw &&
+               echo "hello world" >Foo.mw &&
+               git add Foo.mw &&
+               git commit -m "Add the page Foo" &&
+               git push &&
+               rm -f Foo.mw &&
+               git commit -am "Delete the page Foo" &&
+               test_git_reimport &&
+               test_path_is_missing Foo.mw
+       )
+'
+
+test_expect_success 'git push can propagate local media file deletion' '
+       wiki_reset &&
+       git clone mediawiki::'"$WIKI_URL"' mw_dir &&
+       test_when_finished "rm -fr mw_dir" &&
+       (
+               cd mw_dir &&
+               echo "hello world" >Foo.txt &&
+               git add Foo.txt &&
+               git commit -m "Add the text file Foo" &&
+               git rm Foo.txt &&
+               git commit -m "Delete the file Foo" &&
+               test_git_reimport &&
+               test_path_is_missing Foo.txt
+       )
+'
+
+# test failure: the file is correctly uploaded, and then deleted but
+# as no page link to it, the import (which looks at page revisions)
+# doesn't notice the file deletion on the wiki. We fetch the list of
+# files from the wiki, but as the file is deleted, it doesn't appear.
+test_expect_failure 'git pull correctly imports media file deletion when no page link to it' '
+       wiki_reset &&
+       git clone mediawiki::'"$WIKI_URL"' mw_dir &&
+       test_when_finished "rm -fr mw_dir" &&
+       (
+               cd mw_dir &&
+               echo "hello world" >Foo.txt &&
+               git add Foo.txt &&
+               git commit -m "Add the text file Foo" &&
+               git push &&
+               git rm Foo.txt &&
+               git commit -m "Delete the file Foo" &&
+               test_git_reimport &&
+               test_path_is_missing Foo.txt
+       )
+'
+
+test_expect_success 'git push properly warns about insufficient permissions' '
+       wiki_reset &&
+       git clone mediawiki::'"$WIKI_URL"' mw_dir &&
+       test_when_finished "rm -fr mw_dir" &&
+       (
+               cd mw_dir &&
+               echo "A File" >foo.forbidden &&
+               git add foo.forbidden &&
+               git commit -m "add a file" &&
+               git push 2>actual &&
+               test_i18ngrep "foo.forbidden is not a permitted file" actual
+       )
+'
+
+test_expect_success 'setup a repository with media files' '
+       wiki_reset &&
+       wiki_editpage testpage "I am linking a file [[File:File.txt]]" false &&
+       echo "File content" >File.txt &&
+       wiki_upload_file File.txt &&
+       echo "Another file content" >AnotherFile.txt &&
+       wiki_upload_file AnotherFile.txt
+'
+
+test_expect_success 'git clone works with one specific page cloned and mediaimport=true' '
+       git clone -c remote.origin.pages=testpage \
+                 -c remote.origin.mediaimport=true \
+                       mediawiki::'"$WIKI_URL"' mw_dir_15 &&
+       test_when_finished "rm -rf mw_dir_15" &&
+       test_contains_N_files mw_dir_15 3 &&
+       test_path_is_file mw_dir_15/Testpage.mw &&
+       test_path_is_file mw_dir_15/File:File.txt.mw &&
+       test_path_is_file mw_dir_15/File.txt &&
+       test_path_is_missing mw_dir_15/Main_Page.mw &&
+       test_path_is_missing mw_dir_15/File:AnotherFile.txt.mw &&
+       test_path_is_missing mw_dir_15/AnothetFile.txt &&
+       wiki_check_content mw_dir_15/Testpage.mw Testpage &&
+       test_cmp mw_dir_15/File.txt File.txt
+'
+
+test_expect_success 'git clone works with one specific page cloned and mediaimport=false' '
+       test_when_finished "rm -rf mw_dir_16" &&
+       git clone -c remote.origin.pages=testpage \
+                       mediawiki::'"$WIKI_URL"' mw_dir_16 &&
+       test_contains_N_files mw_dir_16 1 &&
+       test_path_is_file mw_dir_16/Testpage.mw &&
+       test_path_is_missing mw_dir_16/File:File.txt.mw &&
+       test_path_is_missing mw_dir_16/File.txt &&
+       test_path_is_missing mw_dir_16/Main_Page.mw &&
+       wiki_check_content mw_dir_16/Testpage.mw Testpage
+'
+
+# should behave like mediaimport=false
+test_expect_success 'git clone works with one specific page cloned and mediaimport unset' '
+       test_when_finished "rm -fr mw_dir_17" &&
+       git clone -c remote.origin.pages=testpage \
+               mediawiki::'"$WIKI_URL"' mw_dir_17 &&
+       test_contains_N_files mw_dir_17 1 &&
+       test_path_is_file mw_dir_17/Testpage.mw &&
+       test_path_is_missing mw_dir_17/File:File.txt.mw &&
+       test_path_is_missing mw_dir_17/File.txt &&
+       test_path_is_missing mw_dir_17/Main_Page.mw &&
+       wiki_check_content mw_dir_17/Testpage.mw Testpage
+'
+
+test_done
diff --git a/contrib/mw-to-git/t/t9364-pull-by-rev.sh b/contrib/mw-to-git/t/t9364-pull-by-rev.sh
new file mode 100755 (executable)
index 0000000..5c22457
--- /dev/null
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+test_description='Test the Git Mediawiki remote helper: git pull by revision'
+
+. ./test-gitmw-lib.sh
+. ./push-pull-tests.sh
+. $TEST_DIRECTORY/test-lib.sh
+
+test_check_precond
+
+test_expect_success 'configuration' '
+       git config --global mediawiki.fetchStrategy by_rev
+'
+
+test_push_pull
+
+test_done
diff --git a/contrib/mw-to-git/t/test-gitmw-lib.sh b/contrib/mw-to-git/t/test-gitmw-lib.sh
new file mode 100755 (executable)
index 0000000..3b2cfac
--- /dev/null
@@ -0,0 +1,435 @@
+# Copyright (C) 2012
+#     Charles Roussel <charles.roussel@ensimag.imag.fr>
+#     Simon Cathebras <simon.cathebras@ensimag.imag.fr>
+#     Julien Khayat <julien.khayat@ensimag.imag.fr>
+#     Guillaume Sasdy <guillaume.sasdy@ensimag.imag.fr>
+#     Simon Perrat <simon.perrat@ensimag.imag.fr>
+# License: GPL v2 or later
+
+#
+# CONFIGURATION VARIABLES
+# You might want to change these ones
+#
+
+. ./test.config
+
+WIKI_URL=http://"$SERVER_ADDR:$PORT/$WIKI_DIR_NAME"
+CURR_DIR=$(pwd)
+TEST_OUTPUT_DIRECTORY=$(pwd)
+TEST_DIRECTORY="$CURR_DIR"/../../../t
+
+export TEST_OUTPUT_DIRECTORY TEST_DIRECTORY CURR_DIR
+
+if test "$LIGHTTPD" = "false" ; then
+       PORT=80
+else
+       WIKI_DIR_INST="$CURR_DIR/$WEB_WWW"
+fi
+
+wiki_upload_file () {
+       "$CURR_DIR"/test-gitmw.pl upload_file "$@"
+}
+
+wiki_getpage () {
+       "$CURR_DIR"/test-gitmw.pl get_page "$@"
+}
+
+wiki_delete_page () {
+       "$CURR_DIR"/test-gitmw.pl delete_page "$@"
+}
+
+wiki_editpage () {
+       "$CURR_DIR"/test-gitmw.pl edit_page "$@"
+}
+
+die () {
+       die_with_status 1 "$@"
+}
+
+die_with_status () {
+       status=$1
+       shift
+       echo >&2 "$*"
+       exit "$status"
+}
+
+
+# Check the preconditions to run git-remote-mediawiki's tests
+test_check_precond () {
+       if ! test_have_prereq PERL
+       then
+               skip_all='skipping gateway git-mw tests, perl not available'
+               test_done
+       fi
+
+       if [ ! -f "$GIT_BUILD_DIR"/git-remote-mediawiki ];
+       then
+               echo "No remote mediawiki for git found. Copying it in git"
+               echo "cp $GIT_BUILD_DIR/contrib/mw-to-git/git-remote-mediawiki $GIT_BUILD_DIR/"
+               ln -s "$GIT_BUILD_DIR"/contrib/mw-to-git/git-remote-mediawiki "$GIT_BUILD_DIR"
+       fi
+
+       if [ ! -d "$WIKI_DIR_INST/$WIKI_DIR_NAME" ];
+       then
+               skip_all='skipping gateway git-mw tests, no mediawiki found'
+               test_done
+       fi
+}
+
+# test_diff_directories <dir_git> <dir_wiki>
+#
+# Compare the contents of directories <dir_git> and <dir_wiki> with diff
+# and errors if they do not match. The program will
+# not look into .git in the process.
+# Warning: the first argument MUST be the directory containing the git data
+test_diff_directories () {
+       rm -rf "$1_tmp"
+       mkdir -p "$1_tmp"
+       cp "$1"/*.mw "$1_tmp"
+       diff -r -b "$1_tmp" "$2"
+}
+
+# $1=<dir>
+# $2=<N>
+#
+# Check that <dir> contains exactly <N> files
+test_contains_N_files () {
+       if test `ls -- "$1" | wc -l` -ne "$2"; then
+               echo "directory $1 sould contain $2 files"
+               echo "it contains these files:"
+               ls "$1"
+               false
+       fi
+}
+
+
+# wiki_check_content <file_name> <page_name>
+#
+# Compares the contents of the file <file_name> and the wiki page
+# <page_name> and exits with error 1 if they do not match.
+wiki_check_content () {
+       mkdir -p wiki_tmp
+       wiki_getpage "$2" wiki_tmp
+       # replacement of forbidden character in file name
+       page_name=$(printf "%s\n" "$2" | sed -e "s/\//%2F/g")
+
+       diff -b "$1" wiki_tmp/"$page_name".mw
+       if test $? -ne 0
+       then
+               rm -rf wiki_tmp
+               error "ERROR: file $2 not found on wiki"
+       fi
+       rm -rf wiki_tmp
+}
+
+# wiki_page_exist <page_name>
+#
+# Check the existence of the page <page_name> on the wiki and exits
+# with error if it is absent from it.
+wiki_page_exist () {
+       mkdir -p wiki_tmp
+       wiki_getpage "$1" wiki_tmp
+       page_name=$(printf "%s\n" "$1" | sed "s/\//%2F/g")
+       if test -f wiki_tmp/"$page_name".mw ; then
+               rm -rf wiki_tmp
+       else
+               rm -rf wiki_tmp
+               error "test failed: file $1 not found on wiki"
+       fi
+}
+
+# wiki_getallpagename
+#
+# Fetch the name of each page on the wiki.
+wiki_getallpagename () {
+       "$CURR_DIR"/test-gitmw.pl getallpagename
+}
+
+# wiki_getallpagecategory <category>
+#
+# Fetch the name of each page belonging to <category> on the wiki.
+wiki_getallpagecategory () {
+       "$CURR_DIR"/test-gitmw.pl getallpagename "$@"
+}
+
+# wiki_getallpage <dest_dir> [<category>]
+#
+# Fetch all the pages from the wiki and place them in the directory
+# <dest_dir>.
+# If <category> is define, then wiki_getallpage fetch the pages included
+# in <category>.
+wiki_getallpage () {
+       if test -z "$2";
+       then
+               wiki_getallpagename
+       else
+               wiki_getallpagecategory "$2"
+       fi
+       mkdir -p "$1"
+       while read -r line; do
+               wiki_getpage "$line" $1;
+       done < all.txt
+}
+
+# ================= Install part =================
+
+error () {
+       echo "$@" >&2
+       exit 1
+}
+
+# config_lighttpd
+#
+# Create the configuration files and the folders necessary to start lighttpd.
+# Overwrite any existing file.
+config_lighttpd () {
+       mkdir -p $WEB
+       mkdir -p $WEB_TMP
+       mkdir -p $WEB_WWW
+       cat > $WEB/lighttpd.conf <<EOF
+       server.document-root = "$CURR_DIR/$WEB_WWW"
+       server.port = $PORT
+       server.pid-file = "$CURR_DIR/$WEB_TMP/pid"
+
+       server.modules = (
+       "mod_rewrite",
+       "mod_redirect",
+       "mod_access",
+       "mod_accesslog",
+       "mod_fastcgi"
+       )
+
+       index-file.names = ("index.php" , "index.html")
+
+       mimetype.assign             = (
+       ".pdf"          =>      "application/pdf",
+       ".sig"          =>      "application/pgp-signature",
+       ".spl"          =>      "application/futuresplash",
+       ".class"        =>      "application/octet-stream",
+       ".ps"           =>      "application/postscript",
+       ".torrent"      =>      "application/x-bittorrent",
+       ".dvi"          =>      "application/x-dvi",
+       ".gz"           =>      "application/x-gzip",
+       ".pac"          =>      "application/x-ns-proxy-autoconfig",
+       ".swf"          =>      "application/x-shockwave-flash",
+       ".tar.gz"       =>      "application/x-tgz",
+       ".tgz"          =>      "application/x-tgz",
+       ".tar"          =>      "application/x-tar",
+       ".zip"          =>      "application/zip",
+       ".mp3"          =>      "audio/mpeg",
+       ".m3u"          =>      "audio/x-mpegurl",
+       ".wma"          =>      "audio/x-ms-wma",
+       ".wax"          =>      "audio/x-ms-wax",
+       ".ogg"          =>      "application/ogg",
+       ".wav"          =>      "audio/x-wav",
+       ".gif"          =>      "image/gif",
+       ".jpg"          =>      "image/jpeg",
+       ".jpeg"         =>      "image/jpeg",
+       ".png"          =>      "image/png",
+       ".xbm"          =>      "image/x-xbitmap",
+       ".xpm"          =>      "image/x-xpixmap",
+       ".xwd"          =>      "image/x-xwindowdump",
+       ".css"          =>      "text/css",
+       ".html"         =>      "text/html",
+       ".htm"          =>      "text/html",
+       ".js"           =>      "text/javascript",
+       ".asc"          =>      "text/plain",
+       ".c"            =>      "text/plain",
+       ".cpp"          =>      "text/plain",
+       ".log"          =>      "text/plain",
+       ".conf"         =>      "text/plain",
+       ".text"         =>      "text/plain",
+       ".txt"          =>      "text/plain",
+       ".dtd"          =>      "text/xml",
+       ".xml"          =>      "text/xml",
+       ".mpeg"         =>      "video/mpeg",
+       ".mpg"          =>      "video/mpeg",
+       ".mov"          =>      "video/quicktime",
+       ".qt"           =>      "video/quicktime",
+       ".avi"          =>      "video/x-msvideo",
+       ".asf"          =>      "video/x-ms-asf",
+       ".asx"          =>      "video/x-ms-asf",
+       ".wmv"          =>      "video/x-ms-wmv",
+       ".bz2"          =>      "application/x-bzip",
+       ".tbz"          =>      "application/x-bzip-compressed-tar",
+       ".tar.bz2"      =>      "application/x-bzip-compressed-tar",
+       ""              =>      "text/plain"
+       )
+
+       fastcgi.server = ( ".php" =>
+       ("localhost" =>
+       ( "socket" => "$CURR_DIR/$WEB_TMP/php.socket",
+       "bin-path" => "$PHP_DIR/php-cgi -c $CURR_DIR/$WEB/php.ini"
+
+       )
+       )
+       )
+EOF
+
+       cat > $WEB/php.ini <<EOF
+       session.save_path ='$CURR_DIR/$WEB_TMP'
+EOF
+}
+
+# start_lighttpd
+#
+# Start or restart daemon lighttpd. If restart, rewrite configuration files.
+start_lighttpd () {
+       if test -f "$WEB_TMP/pid"; then
+               echo "Instance already running. Restarting..."
+               stop_lighttpd
+       fi
+       config_lighttpd
+       "$LIGHTTPD_DIR"/lighttpd -f "$WEB"/lighttpd.conf
+
+       if test $? -ne 0 ; then
+               echo "Could not execute http deamon lighttpd"
+               exit 1
+       fi
+}
+
+# stop_lighttpd
+#
+# Kill daemon lighttpd and removes files and folders associated.
+stop_lighttpd () {
+       test -f "$WEB_TMP/pid" && kill $(cat "$WEB_TMP/pid")
+       rm -rf "$WEB"
+}
+
+# Create the SQLite database of the MediaWiki. If the database file already
+# exists, it will be deleted.
+# This script should be runned from the directory where $FILES_FOLDER is
+# located.
+create_db () {
+       rm -f "$TMP/$DB_FILE"
+
+       echo "Generating the SQLite database file. It can take some time ..."
+       # Run the php script to generate the SQLite database file
+       # with cURL calls.
+       php "$FILES_FOLDER/$DB_INSTALL_SCRIPT" $(basename "$DB_FILE" .sqlite) \
+               "$WIKI_ADMIN" "$WIKI_PASSW" "$TMP" "$PORT"
+
+       if [ ! -f "$TMP/$DB_FILE" ] ; then
+               error "Can't create database file $TMP/$DB_FILE. Try to run ./install-wiki.sh delete first."
+       fi
+
+       # Copy the generated database file into the directory the
+       # user indicated.
+       cp "$TMP/$DB_FILE" "$FILES_FOLDER" ||
+               error "Unable to copy $TMP/$DB_FILE to $FILES_FOLDER"
+}
+
+# Install a wiki in your web server directory.
+wiki_install () {
+       if test $LIGHTTPD = "true" ; then
+               start_lighttpd
+       fi
+
+       SERVER_ADDR=$SERVER_ADDR:$PORT
+       # In this part, we change directory to $TMP in order to download,
+       # unpack and copy the files of MediaWiki
+       (
+       mkdir -p "$WIKI_DIR_INST/$WIKI_DIR_NAME"
+       if [ ! -d "$WIKI_DIR_INST/$WIKI_DIR_NAME" ] ; then
+               error "Folder $WIKI_DIR_INST/$WIKI_DIR_NAME doesn't exist.
+               Please create it and launch the script again."
+       fi
+
+       # Fetch MediaWiki's archive if not already present in the TMP directory
+       cd "$TMP"
+       if [ ! -f "$MW_VERSION.tar.gz" ] ; then
+               echo "Downloading $MW_VERSION sources ..."
+               wget "http://download.wikimedia.org/mediawiki/1.19/mediawiki-1.19.0.tar.gz" ||
+                       error "Unable to download "\
+                       "http://download.wikimedia.org/mediawiki/1.19/"\
+                       "mediawiki-1.19.0.tar.gz. "\
+                       "Please fix your connection and launch the script again."
+               echo "$MW_VERSION.tar.gz downloaded in `pwd`. "\
+                       "You can delete it later if you want."
+       else
+               echo "Reusing existing $MW_VERSION.tar.gz downloaded in `pwd`."
+       fi
+       archive_abs_path=$(pwd)/"$MW_VERSION.tar.gz"
+       cd "$WIKI_DIR_INST/$WIKI_DIR_NAME/" ||
+               error "can't cd to $WIKI_DIR_INST/$WIKI_DIR_NAME/"
+       tar xzf "$archive_abs_path" --strip-components=1 ||
+               error "Unable to extract WikiMedia's files from $archive_abs_path to "\
+                       "$WIKI_DIR_INST/$WIKI_DIR_NAME"
+       ) || exit 1
+
+       create_db
+
+       # Copy the generic LocalSettings.php in the web server's directory
+       # And modify parameters according to the ones set at the top
+       # of this script.
+       # Note that LocalSettings.php is never modified.
+       if [ ! -f "$FILES_FOLDER/LocalSettings.php" ] ; then
+               error "Can't find $FILES_FOLDER/LocalSettings.php " \
+                       "in the current folder. "\
+               "Please run the script inside its folder."
+       fi
+       cp "$FILES_FOLDER/LocalSettings.php" \
+               "$FILES_FOLDER/LocalSettings-tmp.php" ||
+               error "Unable to copy $FILES_FOLDER/LocalSettings.php " \
+               "to $FILES_FOLDER/LocalSettings-tmp.php"
+
+       # Parse and set the LocalSettings file of the user according to the
+       # CONFIGURATION VARIABLES section at the beginning of this script
+       file_swap="$FILES_FOLDER/LocalSettings-swap.php"
+       sed "s,@WG_SCRIPT_PATH@,/$WIKI_DIR_NAME," \
+               "$FILES_FOLDER/LocalSettings-tmp.php" > "$file_swap"
+       mv "$file_swap" "$FILES_FOLDER/LocalSettings-tmp.php"
+       sed "s,@WG_SERVER@,http://$SERVER_ADDR," \
+               "$FILES_FOLDER/LocalSettings-tmp.php" > "$file_swap"
+       mv "$file_swap" "$FILES_FOLDER/LocalSettings-tmp.php"
+       sed "s,@WG_SQLITE_DATADIR@,$TMP," \
+               "$FILES_FOLDER/LocalSettings-tmp.php" > "$file_swap"
+       mv "$file_swap" "$FILES_FOLDER/LocalSettings-tmp.php"
+       sed "s,@WG_SQLITE_DATAFILE@,$( basename $DB_FILE .sqlite)," \
+               "$FILES_FOLDER/LocalSettings-tmp.php" > "$file_swap"
+       mv "$file_swap" "$FILES_FOLDER/LocalSettings-tmp.php"
+
+       mv "$FILES_FOLDER/LocalSettings-tmp.php" \
+               "$WIKI_DIR_INST/$WIKI_DIR_NAME/LocalSettings.php" ||
+               error "Unable to move $FILES_FOLDER/LocalSettings-tmp.php" \
+               "in $WIKI_DIR_INST/$WIKI_DIR_NAME"
+       echo "File $FILES_FOLDER/LocalSettings.php is set in" \
+               " $WIKI_DIR_INST/$WIKI_DIR_NAME"
+
+       echo "Your wiki has been installed. You can check it at
+               http://$SERVER_ADDR/$WIKI_DIR_NAME"
+}
+
+# Reset the database of the wiki and the password of the admin
+#
+# Warning: This function must be called only in a subdirectory of t/ directory
+wiki_reset () {
+       # Copy initial database of the wiki
+       if [ ! -f "../$FILES_FOLDER/$DB_FILE" ] ; then
+               error "Can't find ../$FILES_FOLDER/$DB_FILE in the current folder."
+       fi
+       cp "../$FILES_FOLDER/$DB_FILE" "$TMP" ||
+               error "Can't copy ../$FILES_FOLDER/$DB_FILE in $TMP"
+       echo "File $FILES_FOLDER/$DB_FILE is set in $TMP"
+}
+
+# Delete the wiki created in the web server's directory and all its content
+# saved in the database.
+wiki_delete () {
+       if test $LIGHTTPD = "true"; then
+               stop_lighttpd
+       else
+               # Delete the wiki's directory.
+               rm -rf "$WIKI_DIR_INST/$WIKI_DIR_NAME" ||
+                       error "Wiki's directory $WIKI_DIR_INST/" \
+                       "$WIKI_DIR_NAME could not be deleted"
+               # Delete the wiki's SQLite database.
+               rm -f "$TMP/$DB_FILE" ||
+                       error "Database $TMP/$DB_FILE could not be deleted."
+       fi
+
+       # Delete the wiki's SQLite database
+       rm -f "$TMP/$DB_FILE" || error "Database $TMP/$DB_FILE could not be deleted."
+       rm -f "$FILES_FOLDER/$DB_FILE"
+       rm -rf "$TMP/$MW_VERSION"
+}
diff --git a/contrib/mw-to-git/t/test-gitmw.pl b/contrib/mw-to-git/t/test-gitmw.pl
new file mode 100755 (executable)
index 0000000..0ff7625
--- /dev/null
@@ -0,0 +1,225 @@
+#!/usr/bin/perl -w -s
+# Copyright (C) 2012
+#     Charles Roussel <charles.roussel@ensimag.imag.fr>
+#     Simon Cathebras <simon.cathebras@ensimag.imag.fr>
+#     Julien Khayat <julien.khayat@ensimag.imag.fr>
+#     Guillaume Sasdy <guillaume.sasdy@ensimag.imag.fr>
+#     Simon Perrat <simon.perrat@ensimag.imag.fr>
+# License: GPL v2 or later
+
+# Usage:
+#       ./test-gitmw.pl <command> [argument]*
+# Execute in terminal using the name of the function to call as first
+# parameter, and the function's arguments as following parameters
+#
+# Example:
+#     ./test-gitmw.pl "get_page" foo .
+# will call <wiki_getpage> with arguments <foo> and <.>
+#
+# Available functions are:
+#     "get_page"
+#     "delete_page"
+#     "edit_page"
+#     "getallpagename"
+
+use MediaWiki::API;
+use Getopt::Long;
+use encoding 'utf8';
+use DateTime::Format::ISO8601;
+use open ':encoding(utf8)';
+use constant SLASH_REPLACEMENT => "%2F";
+
+#Parsing of the config file
+
+my $configfile = "$ENV{'CURR_DIR'}/test.config";
+my %config;
+open my $CONFIG, "<",  $configfile or die "can't open $configfile: $!";
+while (<$CONFIG>)
+{
+       chomp;
+       s/#.*//;
+       s/^\s+//;
+       s/\s+$//;
+       next unless length;
+       my ($key, $value) = split (/\s*=\s*/,$_, 2);
+       $config{$key} = $value;
+       last if ($key eq 'LIGHTTPD' and $value eq 'false');
+       last if ($key eq 'PORT');
+}
+close $CONFIG or die "can't close $configfile: $!";
+
+my $wiki_address = "http://$config{'SERVER_ADDR'}".":"."$config{'PORT'}";
+my $wiki_url = "$wiki_address/$config{'WIKI_DIR_NAME'}/api.php";
+my $wiki_admin = "$config{'WIKI_ADMIN'}";
+my $wiki_admin_pass = "$config{'WIKI_PASSW'}";
+my $mw = MediaWiki::API->new;
+$mw->{config}->{api_url} = $wiki_url;
+
+
+# wiki_login <name> <password>
+#
+# Logs the user with <name> and <password> in the global variable
+# of the mediawiki $mw
+sub wiki_login {
+       $mw->login( { lgname => "$_[0]",lgpassword => "$_[1]" } )
+       || die "getpage: login failed";
+}
+
+# wiki_getpage <wiki_page> <dest_path>
+#
+# fetch a page <wiki_page> from the wiki referenced in the global variable
+# $mw and copies its content in directory dest_path
+sub wiki_getpage {
+       my $pagename = $_[0];
+       my $destdir = $_[1];
+
+       my $page = $mw->get_page( { title => $pagename } );
+       if (!defined($page)) {
+               die "getpage: wiki does not exist";
+       }
+
+       my $content = $page->{'*'};
+       if (!defined($content)) {
+               die "getpage: page does not exist";
+       }
+
+       $pagename=$page->{'title'};
+       # Replace spaces by underscore in the page name
+       $pagename =~ s/ /_/g;
+       $pagename =~ s/\//%2F/g;
+       open(my $file, ">$destdir/$pagename.mw");
+       print $file "$content";
+       close ($file);
+
+}
+
+# wiki_delete_page <page_name>
+#
+# delete the page with name <page_name> from the wiki referenced
+# in the global variable $mw
+sub wiki_delete_page {
+       my $pagename = $_[0];
+
+       my $exist=$mw->get_page({title => $pagename});
+
+       if (defined($exist->{'*'})){
+               $mw->edit({ action => 'delete',
+                               title => $pagename})
+               || die $mw->{error}->{code} . ": " . $mw->{error}->{details};
+       } else {
+               die "no page with such name found: $pagename\n";
+       }
+}
+
+# wiki_editpage <wiki_page> <wiki_content> <wiki_append> [-c=<category>] [-s=<summary>]
+#
+# Edit a page named <wiki_page> with content <wiki_content> on the wiki
+# referenced with the global variable $mw
+# If <wiki_append> == true : append <wiki_content> at the end of the actual
+# content of the page <wiki_page>
+# If <wik_page> doesn't exist, that page is created with the <wiki_content>
+sub wiki_editpage {
+       my $wiki_page = $_[0];
+       my $wiki_content = $_[1];
+       my $wiki_append = $_[2];
+       my $summary = "";
+       my ($summ, $cat) = ();
+       GetOptions('s=s' => \$summ, 'c=s' => \$cat);
+
+       my $append = 0;
+       if (defined($wiki_append) && $wiki_append eq 'true') {
+               $append=1;
+       }
+
+       my $previous_text ="";
+
+       if ($append) {
+               my $ref = $mw->get_page( { title => $wiki_page } );
+               $previous_text = $ref->{'*'};
+       }
+
+       my $text = $wiki_content;
+       if (defined($previous_text)) {
+               $text="$previous_text$text";
+       }
+
+       # Eventually, add this page to a category.
+       if (defined($cat)) {
+               my $category_name="[[Category:$cat]]";
+               $text="$text\n $category_name";
+       }
+       if(defined($summ)){
+               $summary=$summ;
+       }
+
+       $mw->edit( { action => 'edit', title => $wiki_page, summary => $summary, text => "$text"} );
+}
+
+# wiki_getallpagename [<category>]
+#
+# Fetch all pages of the wiki referenced by the global variable $mw
+# and print the names of each one in the file all.txt with a new line
+# ("\n") between these.
+# If the argument <category> is defined, then this function get only the pages
+# belonging to <category>.
+sub wiki_getallpagename {
+       # fetch the pages of the wiki
+       if (defined($_[0])) {
+               my $mw_pages = $mw->list ( { action => 'query',
+                               list => 'categorymembers',
+                               cmtitle => "Category:$_[0]",
+                               cmnamespace => 0,
+                               cmlimit => 500 },
+               )
+               || die $mw->{error}->{code}.": ".$mw->{error}->{details};
+               open(my $file, ">all.txt");
+               foreach my $page (@{$mw_pages}) {
+                       print $file "$page->{title}\n";
+               }
+               close ($file);
+
+       } else {
+               my $mw_pages = $mw->list({
+                               action => 'query',
+                               list => 'allpages',
+                               aplimit => 500,
+                       })
+               || die $mw->{error}->{code}.": ".$mw->{error}->{details};
+               open(my $file, ">all.txt");
+               foreach my $page (@{$mw_pages}) {
+                       print $file "$page->{title}\n";
+               }
+               close ($file);
+       }
+}
+
+sub wiki_upload_file {
+       my $file_name = $_[0];
+       my $resultat = $mw->edit ( {
+               action => 'upload',
+               filename => $file_name,
+               comment => 'upload a file',
+               file => [ $file_name ],
+               ignorewarnings=>1,
+       }, {
+               skip_encoding => 1
+       } ) || die $mw->{error}->{code} . ' : ' . $mw->{error}->{details};
+}
+
+
+
+# Main part of this script: parse the command line arguments
+# and select which function to execute
+my $fct_to_call = shift;
+
+wiki_login($wiki_admin, $wiki_admin_pass);
+
+my %functions_to_call = qw(
+       upload_file    wiki_upload_file
+       get_page       wiki_getpage
+       delete_page    wiki_delete_page
+       edit_page      wiki_editpage
+       getallpagename wiki_getallpagename
+);
+die "$0 ERROR: wrong argument" unless exists $functions_to_call{$fct_to_call};
+&{$functions_to_call{$fct_to_call}}(@ARGV);
diff --git a/contrib/mw-to-git/t/test.config b/contrib/mw-to-git/t/test.config
new file mode 100644 (file)
index 0000000..958b37b
--- /dev/null
@@ -0,0 +1,35 @@
+# Name of the web server's directory dedicated to the wiki is WIKI_DIR_NAME
+WIKI_DIR_NAME=wiki
+
+# Login and password of the wiki's admin
+WIKI_ADMIN=WikiAdmin
+WIKI_PASSW=AdminPass
+
+# Address of the web server
+SERVER_ADDR=localhost
+
+# SQLite database of the wiki, named DB_FILE, is located in TMP
+TMP=/tmp
+DB_FILE=wikidb.sqlite
+
+# If LIGHTTPD is not set to true, the script will use the defaut
+# web server running in WIKI_DIR_INST.
+WIKI_DIR_INST=/var/www
+
+# If LIGHTTPD is set to true, the script will use Lighttpd to run
+# the wiki.
+LIGHTTPD=true
+
+# The variables below are useful only if LIGHTTPD is set to true.
+PORT=1234
+PHP_DIR=/usr/bin
+LIGHTTPD_DIR=/usr/sbin
+WEB=WEB
+WEB_TMP=$WEB/tmp
+WEB_WWW=$WEB/www
+
+# The variables below are used by the script to install a wiki.
+# You should not modify these unless you are modifying the script itself.
+MW_VERSION=mediawiki-1.19.0
+FILES_FOLDER=install-wiki
+DB_INSTALL_SCRIPT=db_install.php
index 35db24f5eae600a973391915ceb61c4635941aec..f363505abb278f89a94413874099e0e80ee8192c 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 62d1c56819e5351e5697dab7ff13d33ac806c398..e54753c75d1c2abf7916f1aa7075d4ada3cfc61f 100644 (file)
@@ -172,6 +172,8 @@ int credential_read(struct credential *c, FILE *fp)
                } else if (!strcmp(key, "path")) {
                        free(c->path);
                        c->path = xstrdup(value);
+               } else if (!strcmp(key, "url")) {
+                       credential_from_url(c, value);
                }
                /*
                 * Ignore other lines; we don't know what they mean, but
@@ -191,7 +193,7 @@ static void credential_write_item(FILE *fp, const char *key, const char *value)
        fprintf(fp, "%s=%s\n", key, value);
 }
 
-static void credential_write(const struct credential *c, FILE *fp)
+void credential_write(const struct credential *c, FILE *fp)
 {
        credential_write_item(fp, "protocol", c->protocol);
        credential_write_item(fp, "host", c->host);
index 96ea41bd1c99c05d63cb965a5fc57fcd838f3fdb..0c3e85e8e4232ad9298372efebf7696a77dc94b1 100644 (file)
@@ -26,6 +26,7 @@ void credential_approve(struct credential *);
 void credential_reject(struct credential *);
 
 int credential_read(struct credential *, FILE *);
+void credential_write(const struct credential *, FILE *);
 void credential_from_url(struct credential *, const char *url);
 int credential_match(const struct credential *have,
                     const struct credential *want);
index ab21e66b2fb69015c3085761b344b11053c67f4a..4602b46a5c39e1d501143ab4e95b55aff5c8f23b 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -30,6 +30,7 @@ static const char daemon_usage[] =
 "           [--interpolated-path=<path>]\n"
 "           [--reuseaddr] [--pid-file=<file>]\n"
 "           [--(enable|disable|allow-override|forbid-override)=<service>]\n"
+"           [--access-hook=<path>]\n"
 "           [--inetd | [--listen=<host_or_ipaddr>] [--port=<n>]\n"
 "                      [--detach] [--user=<user> [--group=<group>]]\n"
 "           [<directory>...]";
@@ -256,6 +257,71 @@ static int daemon_error(const char *dir, const char *msg)
        return -1;
 }
 
+static char *access_hook;
+
+static int run_access_hook(struct daemon_service *service, const char *dir, const char *path)
+{
+       struct child_process child;
+       struct strbuf buf = STRBUF_INIT;
+       const char *argv[8];
+       const char **arg = argv;
+       char *eol;
+       int seen_errors = 0;
+
+#define STRARG(x) ((x) ? (x) : "")
+       *arg++ = access_hook;
+       *arg++ = service->name;
+       *arg++ = path;
+       *arg++ = STRARG(hostname);
+       *arg++ = STRARG(canon_hostname);
+       *arg++ = STRARG(ip_address);
+       *arg++ = STRARG(tcp_port);
+       *arg = NULL;
+#undef STRARG
+
+       memset(&child, 0, sizeof(child));
+       child.use_shell = 1;
+       child.argv = argv;
+       child.no_stdin = 1;
+       child.no_stderr = 1;
+       child.out = -1;
+       if (start_command(&child)) {
+               logerror("daemon access hook '%s' failed to start",
+                        access_hook);
+               goto error_return;
+       }
+       if (strbuf_read(&buf, child.out, 0) < 0) {
+               logerror("failed to read from pipe to daemon access hook '%s'",
+                        access_hook);
+               strbuf_reset(&buf);
+               seen_errors = 1;
+       }
+       if (close(child.out) < 0) {
+               logerror("failed to close pipe to daemon access hook '%s'",
+                        access_hook);
+               seen_errors = 1;
+       }
+       if (finish_command(&child))
+               seen_errors = 1;
+
+       if (!seen_errors) {
+               strbuf_release(&buf);
+               return 0;
+       }
+
+error_return:
+       strbuf_ltrim(&buf);
+       if (!buf.len)
+               strbuf_addstr(&buf, "service rejected");
+       eol = strchr(buf.buf, '\n');
+       if (eol)
+               *eol = '\0';
+       errno = EACCES;
+       daemon_error(dir, buf.buf);
+       strbuf_release(&buf);
+       return -1;
+}
+
 static int run_service(char *dir, struct daemon_service *service)
 {
        const char *path;
@@ -303,6 +369,13 @@ static int run_service(char *dir, struct daemon_service *service)
                return daemon_error(dir, "service not enabled");
        }
 
+       /*
+        * Optionally, a hook can choose to deny access to the
+        * repository depending on the phase of the moon.
+        */
+       if (access_hook && run_access_hook(service, dir, path))
+               return -1;
+
        /*
         * We'll ignore SIGTERM from now on, we have a
         * good client.
@@ -1142,6 +1215,10 @@ int main(int argc, char **argv)
                        export_all_trees = 1;
                        continue;
                }
+               if (!prefixcmp(arg, "--access-hook=")) {
+                       access_hook = arg + 14;
+                       continue;
+               }
                if (!prefixcmp(arg, "--timeout=")) {
                        timeout = atoi(arg+10);
                        continue;
diff --git a/diff.c b/diff.c
index f1b044780ffb0e590f8dd1d609ae2b2c3b54b473..7fef69d85c33faaaaf23cbff536ca0639ab2f1c6 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
@@ -25,7 +26,8 @@
 static int diff_detect_rename_default;
 static int diff_rename_limit_default = 400;
 static int diff_suppress_blank_empty;
-int diff_use_color_default = -1;
+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,24 +105,21 @@ 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;
 }
 
@@ -141,6 +144,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;
@@ -1398,11 +1407,11 @@ int print_stat_summary(FILE *fp, int files, int insertions, int deletions)
 
        if (!files) {
                assert(insertions == 0 && deletions == 0);
-               return fputs(_(" 0 files changed\n"), fp);
+               return fprintf(fp, "%s\n", " 0 files changed");
        }
 
        strbuf_addf(&sb,
-                   Q_(" %d file changed", " %d files changed", files),
+                   (files == 1) ? " %d file changed" : " %d files changed",
                    files);
 
        /*
@@ -1419,8 +1428,7 @@ int print_stat_summary(FILE *fp, int files, int insertions, int deletions)
                 * do not translate it.
                 */
                strbuf_addf(&sb,
-                           Q_(", %d insertion(+)", ", %d insertions(+)",
-                              insertions),
+                           (insertions == 1) ? ", %d insertion(+)" : ", %d insertions(+)",
                            insertions);
        }
 
@@ -1430,8 +1438,7 @@ int print_stat_summary(FILE *fp, int files, int insertions, int deletions)
                 * do not translate it.
                 */
                strbuf_addf(&sb,
-                           Q_(", %d deletion(-)", ", %d deletions(-)",
-                              deletions),
+                           (deletions == 1) ? ", %d deletion(-)" : ", %d deletions(-)",
                            deletions);
        }
        strbuf_addch(&sb, '\n');
@@ -3172,7 +3179,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;
diff --git a/diff.h b/diff.h
index e25addb806a190f138a14ca64190fa5d2f311aaa..a658f85f2bc87864f673f737f70c8ad366ab7153 100644 (file)
--- a/diff.h
+++ b/diff.h
@@ -243,7 +243,6 @@ extern int parse_long_opt(const char *opt, const char **argv,
 
 extern int git_diff_basic_config(const char *var, const char *value, void *cb);
 extern int git_diff_ui_config(const char *var, const char *value, void *cb);
-extern int diff_use_color_default;
 extern void diff_setup(struct diff_options *);
 extern int diff_opt_parse(struct diff_options *, const char **, int);
 extern void diff_setup_done(struct diff_options *);
diff --git a/dir.c b/dir.c
index 2c02b312b77f3363c234bdc66faaeafd5899586d..5a83aa7897f270279c403778f43aea6db1efc5af 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -288,48 +288,89 @@ int match_pathspec_depth(const struct pathspec *ps,
        return retval;
 }
 
+/*
+ * Return the length of the "simple" part of a path match limiter.
+ */
+static int simple_length(const char *match)
+{
+       int len = -1;
+
+       for (;;) {
+               unsigned char c = *match++;
+               len++;
+               if (c == '\0' || is_glob_special(c))
+                       return len;
+       }
+}
+
 static int no_wildcard(const char *string)
 {
-       return string[strcspn(string, "*?[{\\")] == '\0';
+       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;
-       if (no_wildcard(string))
-               x->flags |= EXC_FLAG_NOWILDCARD;
-       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;
 }
@@ -383,6 +424,8 @@ int add_excludes_from_file_to_list(const char *fname,
 
        fd = open(fname, O_RDONLY);
        if (fd < 0 || fstat(fd, &st) < 0) {
+               if (errno != ENOENT)
+                       warn_on_inaccessible(fname);
                if (0 <= fd)
                        close(fd);
                if (!check_index ||
@@ -489,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.
  */
@@ -498,57 +607,36 @@ int excluded_from_list(const char *pathname,
 {
        int i;
 
-       if (el->nr) {
-               for (i = el->nr - 1; 0 <= i; i--) {
-                       struct exclude *x = el->excludes[i];
-                       const char *exclude = x->pattern;
-                       int to_exclude = x->to_exclude;
-
-                       if (x->flags & EXC_FLAG_MUSTBEDIR) {
-                               if (*dtype == DT_UNKNOWN)
-                                       *dtype = get_dtype(NULL, pathname, pathlen);
-                               if (*dtype != DT_DIR)
-                                       continue;
-                       }
+       if (!el->nr)
+               return -1;      /* undefined */
 
-                       if (x->flags & EXC_FLAG_NODIR) {
-                               /* match basename */
-                               if (x->flags & EXC_FLAG_NOWILDCARD) {
-                                       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;
-                               }
-                       }
-                       else {
-                               /* match with FNM_PATHNAME:
-                                * exclude has base (baselen long) implicitly
-                                * in front of it.
-                                */
-                               int baselen = x->baselen;
-                               if (*exclude == '/')
-                                       exclude++;
-
-                               if (pathlen < baselen ||
-                                   (baselen && pathname[baselen-1] != '/') ||
-                                   strncmp_icase(pathname, x->base, baselen))
-                                   continue;
-
-                               if (x->flags & EXC_FLAG_NOWILDCARD) {
-                                       if (!strcmp_icase(exclude, pathname + baselen))
-                                               return to_exclude;
-                               } else {
-                                       if (fnmatch_icase(exclude, pathname+baselen,
-                                                   FNM_PATHNAME) == 0)
-                                           return to_exclude;
-                               }
-                       }
+       for (i = el->nr - 1; 0 <= i; i--) {
+               struct exclude *x = el->excludes[i];
+               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)
+                               *dtype = get_dtype(NULL, pathname, pathlen);
+                       if (*dtype != DT_DIR)
+                               continue;
                }
+
+               if (x->flags & EXC_FLAG_NODIR) {
+                       if (match_basename(basename,
+                                          pathlen - (basename - pathname),
+                                          exclude, prefix, x->patternlen,
+                                          x->flags))
+                               return to_exclude;
+                       continue;
+               }
+
+               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 */
 }
@@ -1055,21 +1143,6 @@ static int cmp_name(const void *p1, const void *p2)
                                  e2->name, e2->len);
 }
 
-/*
- * Return the length of the "simple" part of a path match limiter.
- */
-static int simple_length(const char *match)
-{
-       int len = -1;
-
-       for (;;) {
-               unsigned char c = *match++;
-               len++;
-               if (c == '\0' || is_glob_special(c))
-                       return len;
-       }
-}
-
 static struct path_simplify *create_simplify(const char **pathspec)
 {
        int nr, alloc = 0;
@@ -1292,12 +1365,17 @@ int remove_dir_recursively(struct strbuf *path, int flag)
 void setup_standard_excludes(struct dir_struct *dir)
 {
        const char *path;
+       char *xdg_path;
 
        dir->exclude_per_dir = ".gitignore";
        path = git_path("info/exclude");
-       if (!access(path, R_OK))
+       if (!excludes_file) {
+               home_config_paths(NULL, &xdg_path, "ignore");
+               excludes_file = xdg_path;
+       }
+       if (!access_or_warn(path, R_OK))
                add_excludes_from_file(dir, path);
-       if (excludes_file && !access(excludes_file, R_OK))
+       if (excludes_file && !access_or_warn(excludes_file, R_OK))
                add_excludes_from_file(dir, excludes_file);
 }
 
diff --git a/dir.h b/dir.h
index 6c73e4151de8374d35427358cde50b506a2d7de9..f5c89e3b80143f2508ac5b69d432aa82a4254751 100644 (file)
--- a/dir.h
+++ b/dir.h
@@ -9,9 +9,9 @@ struct dir_entry {
 };
 
 #define EXC_FLAG_NODIR 1
-#define EXC_FLAG_NOWILDCARD 2
 #define EXC_FLAG_ENDSWITH 4
 #define EXC_FLAG_MUSTBEDIR 8
+#define EXC_FLAG_NEGATIVE 16
 
 struct exclude_list {
        int nr;
@@ -19,9 +19,9 @@ struct exclude_list {
        struct exclude {
                const char *pattern;
                int patternlen;
+               int nowildcardlen;
                const char *base;
                int baselen;
-               int to_exclude;
                int flags;
        } **excludes;
 };
@@ -80,6 +80,16 @@ extern int excluded_from_list(const char *pathname, int pathlen, const char *bas
                              int *dtype, struct exclude_list *el);
 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
@@ -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 669e498f5a245909725494feda2531f0088f8160..85edd7f95adecd8316b49638d7bda2841839206d 100644 (file)
@@ -58,6 +58,7 @@ char *notes_ref_name;
 int grafts_replace_parents = 1;
 int core_apply_sparse_checkout;
 int merge_log_config = -1;
+int precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */
 struct startup_info *startup_info;
 unsigned long pack_size_limit_cfg;
 
index eed97c8fa9f3e1624f69443e28f76d995e589b34..c2a814ec660862937e495c0a7efb6375dc7718ac 100644 (file)
@@ -1691,7 +1691,7 @@ static int update_branch(struct branch *b)
                        return error("Branch %s is missing commits.", b->name);
                }
 
-               if (!in_merge_bases(old_cmit, &new_cmit, 1)) {
+               if (!in_merge_bases(old_cmit, new_cmit)) {
                        unlock_ref(lock);
                        warning("Not updating %s"
                                " (new tip %s does not contain %s)",
index 7c2069c97234453cb6a0a774c1859b7055b791d8..cb148719bfd3bace27a0ca9611f1c38066fb6ed4 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef FETCH_PACK_H
 #define FETCH_PACK_H
 
+#include "string-list.h"
+
 struct fetch_pack_args {
        const char *uploadpack;
        int unpacklimit;
@@ -17,12 +19,18 @@ struct fetch_pack_args {
                stateless_rpc:1;
 };
 
+/*
+ * sought contains the full names of remote references that should be
+ * updated from.  On return, the names that were found on the remote
+ * will have been removed from the list.  The util members of the
+ * string_list_items are used internally; they must be NULL on entry
+ * (and will be NULL on exit).
+ */
 struct ref *fetch_pack(struct fetch_pack_args *args,
-               int fd[], struct child_process *conn,
-               const struct ref *ref,
-               const char *dest,
-               int nr_heads,
-               char **heads,
-               char **pack_lockfile);
+                      int fd[], struct child_process *conn,
+                      const struct ref *ref,
+                      const char *dest,
+                      struct string_list *sought,
+                      char **pack_lockfile);
 
 #endif
index f75bca7f56b7b27c135d92acba816c40211fdece..71e954563d7068500bd41269dd57f01b097f7c3d 100644 (file)
--- a/gettext.c
+++ b/gettext.c
@@ -4,6 +4,8 @@
 
 #include "git-compat-util.h"
 #include "gettext.h"
+#include "strbuf.h"
+#include "utf8.h"
 
 #ifndef NO_GETTEXT
 #      include <locale.h>
@@ -27,10 +29,9 @@ int use_gettext_poison(void)
 #endif
 
 #ifndef NO_GETTEXT
+static const char *charset;
 static void init_gettext_charset(const char *domain)
 {
-       const char *charset;
-
        /*
           This trick arranges for messages to be emitted in the user's
           requested encoding, but avoids setting LC_CTYPE from the
@@ -128,4 +129,14 @@ void git_setup_gettext(void)
        init_gettext_charset("git");
        textdomain("git");
 }
+
+/* return the number of columns of string 's' in current locale */
+int gettext_width(const char *s)
+{
+       static int is_utf8 = -1;
+       if (is_utf8 == -1)
+               is_utf8 = !strcmp(charset, "UTF-8");
+
+       return is_utf8 ? utf8_strwidth(s) : strlen(s);
+}
 #endif
index 57ba8bb02e39d59752a5b2fbf016bc6fe49d27c1..7671d09d04bb87541b11209b5cdbddbb9e4e59b8 100644 (file)
--- a/gettext.h
+++ b/gettext.h
 
 #ifndef NO_GETTEXT
 extern void git_setup_gettext(void);
+extern int gettext_width(const char *s);
 #else
 static inline void git_setup_gettext(void)
 {
 }
+static inline int gettext_width(const char *s)
+{
+       return strlen(s);
+}
 #endif
 
 #ifdef GETTEXT_POISON
@@ -44,6 +49,8 @@ extern int use_gettext_poison(void);
 
 static inline FORMAT_PRESERVING(1) const char *_(const char *msgid)
 {
+       if (!*msgid)
+               return "";
        return use_gettext_poison() ? "# GETTEXT POISON #" : gettext(msgid);
 }
 
index 9abad36abdea89c88d7d0378fd2d556057bc065b..c682d34094d618734ac52d6d7e15a6c10ccfdeb6 100755 (executable)
--- a/git-am.sh
+++ b/git-am.sh
@@ -92,7 +92,7 @@ safe_to_abort () {
        then
                return 0
        fi
-               gettextln "You seem to have moved HEAD since the last 'am' failure.
+       gettextln "You seem to have moved HEAD since the last 'am' failure.
 Not rewinding to ORIG_HEAD" >&2
        return 1
 }
@@ -102,9 +102,9 @@ stop_here_user_resolve () {
            printf '%s\n' "$resolvemsg"
            stop_here $1
     fi
-    eval_gettextln "When you have resolved this problem run \"\$cmdline --resolved\".
-If you would prefer to skip this patch, instead run \"\$cmdline --skip\".
-To restore the original branch and stop patching run \"\$cmdline --abort\"."
+    eval_gettextln "When you have resolved this problem, run \"\$cmdline --resolved\".
+If you prefer to skip this patch, run \"\$cmdline --skip\" instead.
+To restore the original branch and stop patching, run \"\$cmdline --abort\"."
 
     stop_here $1
 }
@@ -136,7 +136,7 @@ fall_back_3way () {
     git write-tree >"$dotest/patch-merge-base+" ||
     cannot_fallback "$(gettext "Repository lacks necessary blobs to fall back on 3-way merge.")"
 
-    say Using index info to reconstruct a base tree...
+    say "$(gettext "Using index info to reconstruct a base tree...")"
 
     cmd='GIT_INDEX_FILE="$dotest/patch-merge-tmp-index"'
 
@@ -176,8 +176,7 @@ It does not apply to blobs recorded in its index.")"
     fi
     git-merge-recursive $orig_tree -- HEAD $his_tree || {
            git rerere $allow_rerere_autoupdate
-           echo Failed to merge in the changes.
-           exit 1
+           die "$(gettext "Failed to merge in the changes.")"
     }
     unset GITHEAD_$his_tree
 }
@@ -260,7 +259,7 @@ check_patch_format () {
 split_patches () {
        case "$patch_format" in
        mbox)
-               if test -n "$rebasing" || test t = "$keepcr"
+               if test t = "$keepcr"
                then
                    keep_cr=--keep-cr
                else
@@ -387,8 +386,8 @@ do
        -i|--interactive)
                interactive=t ;;
        -b|--binary)
-               echo >&2 "The $1 option has been a no-op for long time, and"
-               echo >&2 "it will be removed. Please do not use it anymore."
+               gettextln >&2 "The -b/--binary option has been a no-op for long time, and
+it will be removed. Please do not use it anymore."
                ;;
        -3|--3way)
                threeway=t ;;
@@ -413,10 +412,7 @@ do
        --abort)
                abort=t ;;
        --rebasing)
-               rebasing=t threeway=t keep=t scissors=f no_inbody_headers=t ;;
-       -d|--dotest)
-               die "$(gettext "-d option is no longer supported.  Do not use.")"
-               ;;
+               rebasing=t threeway=t ;;
        --resolvemsg)
                shift; resolvemsg=$1 ;;
        --whitespace|--directory|--exclude|--include)
@@ -658,32 +654,34 @@ do
        # by the user, or the user can tell us to do so by --resolved flag.
        case "$resume" in
        '')
-               git mailinfo $keep $no_inbody_headers $scissors $utf8 "$dotest/msg" "$dotest/patch" \
-                       <"$dotest/$msgnum" >"$dotest/info" ||
-                       stop_here $this
-
-               # skip pine's internal folder data
-               sane_grep '^Author: Mail System Internal Data$' \
-                       <"$dotest"/info >/dev/null &&
-                       go_next && continue
-
-               test -s "$dotest/patch" || {
-                       eval_gettextln "Patch is empty.  Was it split wrong?
-If you would prefer to skip this patch, instead run \"\$cmdline --skip\".
-To restore the original branch and stop patching run \"\$cmdline --abort\"."
-                       stop_here $this
-               }
-               rm -f "$dotest/original-commit" "$dotest/author-script"
-               if test -f "$dotest/rebasing" &&
+               if test -f "$dotest/rebasing"
+               then
                        commit=$(sed -e 's/^From \([0-9a-f]*\) .*/\1/' \
                                -e q "$dotest/$msgnum") &&
-                       test "$(git cat-file -t "$commit")" = commit
-               then
+                       test "$(git cat-file -t "$commit")" = commit ||
+                               stop_here $this
                        git cat-file commit "$commit" |
                        sed -e '1,/^$/d' >"$dotest/msg-clean"
-                       echo "$commit" > "$dotest/original-commit"
-                       get_author_ident_from_commit "$commit" > "$dotest/author-script"
+                       echo "$commit" >"$dotest/original-commit"
+                       get_author_ident_from_commit "$commit" >"$dotest/author-script"
+                       git diff-tree --root --binary "$commit" >"$dotest/patch"
                else
+                       git mailinfo $keep $no_inbody_headers $scissors $utf8 "$dotest/msg" "$dotest/patch" \
+                               <"$dotest/$msgnum" >"$dotest/info" ||
+                               stop_here $this
+
+                       # skip pine's internal folder data
+                       sane_grep '^Author: Mail System Internal Data$' \
+                               <"$dotest"/info >/dev/null &&
+                               go_next && continue
+
+                       test -s "$dotest/patch" || {
+                               eval_gettextln "Patch is empty.  Was it split wrong?
+If you would prefer to skip this patch, instead run \"\$cmdline --skip\".
+To restore the original branch and stop patching run \"\$cmdline --abort\"."
+                               stop_here $this
+                       }
+                       rm -f "$dotest/original-commit" "$dotest/author-script"
                        {
                                sed -n '/^Subject/ s/Subject: //p' "$dotest/info"
                                echo
@@ -857,8 +855,8 @@ did you forget to use 'git add'?"
                eval_gettextln 'Patch failed at $msgnum $FIRSTLINE'
                if test "$(git config --bool advice.amworkdir)" != false
                then
-                       eval_gettextln "The copy of the patch that failed is found in:
-   $dotest/patch"
+                       eval_gettextln 'The copy of the patch that failed is found in:
+   $dotest/patch'
                fi
                stop_here_user_resolve $this
        fi
index f011a8d7bb9fc61b0bd840ea954257f505bd62d5..2e79b8a2f379d7c72a0934b36c7538db2143c722 100644 (file)
@@ -74,7 +74,8 @@
 # define _XOPEN_SOURCE 500
 # endif
 #elif !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__USLC__) && \
-      !defined(_M_UNIX) && !defined(__sgi) && !defined(__DragonFly__)
+      !defined(_M_UNIX) && !defined(__sgi) && !defined(__DragonFly__) && \
+      !defined(__TANDEM)
 #define _XOPEN_SOURCE 600 /* glibc2 and AIX 5.3L need 500, OpenBSD needs 600 for S_ISLNK() */
 #define _XOPEN_SOURCE_EXTENDED 1 /* AIX 5.3L needs this */
 #endif
@@ -98,6 +99,9 @@
 #include <stdlib.h>
 #include <stdarg.h>
 #include <string.h>
+#ifdef __TANDEM /* or HAVE_STRINGS_H or !NO_STRINGS_H? */
+#include <strings.h> /* for strcasecmp() */
+#endif
 #include <errno.h>
 #include <limits.h>
 #include <sys/param.h>
 #else
 #include <stdint.h>
 #endif
+#ifdef NO_INTPTR_T
+/*
+ * On I16LP32, ILP32 and LP64 "long" is the save bet, however
+ * on LLP86, IL33LLP64 and P64 it needs to be "long long",
+ * while on IP16 and IP16L32 it is "int" (resp. "short")
+ * Size needs to match (or exceed) 'sizeof(void *)'.
+ * We can't take "long long" here as not everybody has it.
+ */
+typedef long intptr_t;
+typedef unsigned long uintptr_t;
+#endif
 #if defined(__CYGWIN__)
 #undef _XOPEN_SOURCE
 #include <grp.h>
 #endif
 #endif
 
+/* used on Mac OS X */
+#ifdef PRECOMPOSE_UNICODE
+#include "compat/precompose_utf8.h"
+#else
+#define precompose_str(in,i_nfd2nfc)
+#define precompose_argv(c,v)
+#define probe_utf8_pathname_composition(a,b)
+#endif
+
+#ifdef MKDIR_WO_TRAILING_SLASH
+#define mkdir(a,b) compat_mkdir_wo_trailing_slash((a),(b))
+extern int compat_mkdir_wo_trailing_slash(const char*, mode_t);
+#endif
+
+#ifdef NO_STRUCT_ITIMERVAL
+struct itimerval {
+       struct timeval it_interval;
+       struct timeval it_value;
+}
+#endif
+
+#ifdef NO_SETITIMER
+#define setitimer(which,value,ovalue)
+#endif
+
 #ifndef NO_LIBGEN_H
 #include <libgen.h>
 #else
@@ -597,6 +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. */
+int access_or_warn(const char *path, int mode);
+
+/* Warn on an inaccessible file that ought to be accessible */
+void warn_on_inaccessible(const char *path);
+
 /* Get the passwd entry for the UID of the current process. */
 struct passwd *xgetpwuid_self(void);
 
index 8d41610bcf260545bcc5b6a8c30b43d427c70491..8032f23202ff9a1e8e0fd2a6745021fb8f1fcf71 100755 (executable)
@@ -889,10 +889,37 @@ sub commit {
                $xtag =~ s/\s+\*\*.*$//; # Remove stuff like ** INVALID ** and ** FUNKY **
                $xtag =~ tr/_/\./ if ( $opt_u );
                $xtag =~ s/[\/]/$opt_s/g;
-               $xtag =~ s/\[//g;
 
-               system('git' , 'tag', '-f', $xtag, $cid) == 0
-                       or die "Cannot create tag $xtag: $!\n";
+               # See refs.c for these rules.
+               # Tag cannot contain bad chars. (See bad_ref_char in refs.c.)
+               $xtag =~ s/[ ~\^:\\\*\?\[]//g;
+               # Other bad strings for tags:
+               # (See check_refname_component in refs.c.)
+               1 while $xtag =~ s/
+                       (?: \.\.        # Tag cannot contain '..'.
+                       |   \@{         # Tag cannot contain '@{'.
+                       | ^ -           # Tag cannot begin with '-'.
+                       |   \.lock $    # Tag cannot end with '.lock'.
+                       | ^ \.          # Tag cannot begin...
+                       |   \. $        # ...or end with '.'
+                       )//xg;
+               # Tag cannot be empty.
+               if ($xtag eq '') {
+                       warn("warning: ignoring tag '$tag'",
+                       " with invalid tagname\n");
+                       return;
+               }
+
+               if (system('git' , 'tag', '-f', $xtag, $cid) != 0) {
+                       # We did our best to sanitize the tag, but still failed
+                       # for whatever reason. Bail out, and give the user
+                       # enough information to understand if/how we should
+                       # improve the translation in the future.
+                       if ($tag ne $xtag) {
+                               print "Translated '$tag' tag to '$xtag'\n";
+                       }
+                       die "Cannot create tag $xtag: $!\n";
+               }
 
                print "Created tag '$xtag' on '$branch'\n" if $opt_v;
        }
index ae1e0525d89181f8adbe288b62e107b8dadb8ca1..edd0493a08b501d60c04044e79a9e0b096d77953 100755 (executable)
@@ -15,19 +15,14 @@ use strict;
 use warnings;
 use File::Basename qw(dirname);
 use File::Copy;
+use File::Compare;
 use File::Find;
 use File::stat;
-use File::Path qw(mkpath);
+use File::Path qw(mkpath rmtree);
 use File::Temp qw(tempdir);
 use Getopt::Long qw(:config pass_through);
 use Git;
 
-my @tools;
-my @working_tree;
-my $rc;
-my $repo = Git->repository();
-my $repo_path = $repo->repo_path();
-
 sub usage
 {
        my $exitcode = shift;
@@ -44,6 +39,8 @@ USAGE
 
 sub find_worktree
 {
+       my ($repo) = @_;
+
        # Git->repository->wc_path() does not honor changes to the working
        # tree location made by $ENV{GIT_WORK_TREE} or the 'core.worktree'
        # config variable.
@@ -62,10 +59,9 @@ sub find_worktree
        return $worktree;
 }
 
-my $workdir = find_worktree();
-
 sub filter_tool_scripts
 {
+       my ($tools) = @_;
        if (-d $_) {
                if ($_ ne ".") {
                        # Ignore files in subdirectories
@@ -73,17 +69,17 @@ sub filter_tool_scripts
                }
        } else {
                if ((-f $_) && ($_ ne "defaults")) {
-                       push(@tools, $_);
+                       push(@$tools, $_);
                }
        }
 }
 
 sub print_tool_help
 {
-       my ($cmd, @found, @notfound);
+       my ($cmd, @found, @notfound, @tools);
        my $gitpath = Git::exec_path();
 
-       find(\&filter_tool_scripts, "$gitpath/mergetools");
+       find(sub { filter_tool_scripts(\@tools) }, "$gitpath/mergetools");
 
        foreach my $tool (@tools) {
                $cmd  = "TOOL_MODE=diff";
@@ -97,34 +93,52 @@ sub print_tool_help
                }
        }
 
-       print "'git difftool --tool=<tool>' may be set to one of the following:\n";
+       print << 'EOF';
+'git difftool --tool=<tool>' may be set to one of the following:
+EOF
        print "\t$_\n" for (sort(@found));
 
-       print "\nThe following tools are valid, but not currently available:\n";
+       print << 'EOF';
+
+The following tools are valid, but not currently available:
+EOF
        print "\t$_\n" for (sort(@notfound));
 
-       print "\nNOTE: Some of the tools listed above only work in a windowed\n";
-       print "environment. If run in a terminal-only session, they will fail.\n";
+       print << 'EOF';
 
+NOTE: Some of the tools listed above only work in a windowed
+environment. If run in a terminal-only session, they will fail.
+EOF
        exit(0);
 }
 
+sub exit_cleanup
+{
+       my ($tmpdir, $status) = @_;
+       my $errno = $!;
+       rmtree($tmpdir);
+       if ($status and $errno) {
+               my ($package, $file, $line) = caller();
+               warn "$file line $line: $errno\n";
+       }
+       exit($status | ($status >> 8));
+}
+
 sub setup_dir_diff
 {
+       my ($repo, $workdir, $symlinks) = @_;
+
        # Run the diff; exit immediately if no diff found
        # 'Repository' and 'WorkingCopy' must be explicitly set to insure that
        # if $GIT_DIR and $GIT_WORK_TREE are set in ENV, they are actually used
        # by Git->repository->command*.
-       my $diffrepo = Git->repository(Repository => $repo_path, WorkingCopy => $workdir);
-       my $diffrtn = $diffrepo->command_oneline('diff', '--raw', '--no-abbrev', '-z', @ARGV);
-       exit(0) if (length($diffrtn) == 0);
+       my $repo_path = $repo->repo_path();
+       my %repo_args = (Repository => $repo_path, WorkingCopy => $workdir);
+       my $diffrepo = Git->repository(%repo_args);
 
-       # Setup temp directories
-       my $tmpdir = tempdir('git-diffall.XXXXX', CLEANUP => 1, TMPDIR => 1);
-       my $ldir = "$tmpdir/left";
-       my $rdir = "$tmpdir/right";
-       mkpath($ldir) or die $!;
-       mkpath($rdir) or die $!;
+       my @gitargs = ('diff', '--raw', '--no-abbrev', '-z', @ARGV);
+       my $diffrtn = $diffrepo->command_oneline(@gitargs);
+       exit(0) unless defined($diffrtn);
 
        # Build index info for left and right sides of the diff
        my $submodule_mode = '160000';
@@ -135,16 +149,21 @@ sub setup_dir_diff
        my $rindex = '';
        my %submodule;
        my %symlink;
+       my @working_tree = ();
        my @rawdiff = split('\0', $diffrtn);
 
        my $i = 0;
        while ($i < $#rawdiff) {
                if ($rawdiff[$i] =~ /^::/) {
-                       print "Combined diff formats ('-c' and '--cc') are not supported in directory diff mode.\n";
+                       warn << 'EOF';
+Combined diff formats ('-c' and '--cc') are not supported in
+directory diff mode ('-d' and '--dir-diff').
+EOF
                        exit(1);
                }
 
-               my ($lmode, $rmode, $lsha1, $rsha1, $status) = split(' ', substr($rawdiff[$i], 1));
+               my ($lmode, $rmode, $lsha1, $rsha1, $status) =
+                       split(' ', substr($rawdiff[$i], 1));
                my $src_path = $rawdiff[$i + 1];
                my $dst_path;
 
@@ -156,7 +175,7 @@ sub setup_dir_diff
                        $i += 2;
                }
 
-               if (($lmode eq $submodule_mode) or ($rmode eq $submodule_mode)) {
+               if ($lmode eq $submodule_mode or $rmode eq $submodule_mode) {
                        $submodule{$src_path}{left} = $lsha1;
                        if ($lsha1 ne $rsha1) {
                                $submodule{$dst_path}{right} = $rsha1;
@@ -167,14 +186,16 @@ sub setup_dir_diff
                }
 
                if ($lmode eq $symlink_mode) {
-                       $symlink{$src_path}{left} = $diffrepo->command_oneline('show', "$lsha1");
+                       $symlink{$src_path}{left} =
+                               $diffrepo->command_oneline('show', "$lsha1");
                }
 
                if ($rmode eq $symlink_mode) {
-                       $symlink{$dst_path}{right} = $diffrepo->command_oneline('show', "$rsha1");
+                       $symlink{$dst_path}{right} =
+                               $diffrepo->command_oneline('show', "$rsha1");
                }
 
-               if (($lmode ne $null_mode) and ($status !~ /^C/)) {
+               if ($lmode ne $null_mode and $status !~ /^C/) {
                        $lindex .= "$lmode $lsha1\t$src_path\0";
                }
 
@@ -187,6 +208,13 @@ sub setup_dir_diff
                }
        }
 
+       # Setup temp directories
+       my $tmpdir = tempdir('git-difftool.XXXXX', CLEANUP => 0, TMPDIR => 1);
+       my $ldir = "$tmpdir/left";
+       my $rdir = "$tmpdir/right";
+       mkpath($ldir) or exit_cleanup($tmpdir, 1);
+       mkpath($rdir) or exit_cleanup($tmpdir, 1);
+
        # If $GIT_DIR is not set prior to calling 'git update-index' and
        # 'git checkout-index', then those commands will fail if difftool
        # is called from a directory other than the repo root.
@@ -199,18 +227,22 @@ sub setup_dir_diff
        # Populate the left and right directories based on each index file
        my ($inpipe, $ctx);
        $ENV{GIT_INDEX_FILE} = "$tmpdir/lindex";
-       ($inpipe, $ctx) = $repo->command_input_pipe(qw/update-index -z --index-info/);
+       ($inpipe, $ctx) =
+               $repo->command_input_pipe(qw(update-index -z --index-info));
        print($inpipe $lindex);
        $repo->command_close_pipe($inpipe, $ctx);
-       $rc = system('git', 'checkout-index', '--all', "--prefix=$ldir/");
-       exit($rc | ($rc >> 8)) if ($rc != 0);
+
+       my $rc = system('git', 'checkout-index', '--all', "--prefix=$ldir/");
+       exit_cleanup($tmpdir, $rc) if $rc != 0;
 
        $ENV{GIT_INDEX_FILE} = "$tmpdir/rindex";
-       ($inpipe, $ctx) = $repo->command_input_pipe(qw/update-index -z --index-info/);
+       ($inpipe, $ctx) =
+               $repo->command_input_pipe(qw(update-index -z --index-info));
        print($inpipe $rindex);
        $repo->command_close_pipe($inpipe, $ctx);
+
        $rc = system('git', 'checkout-index', '--all', "--prefix=$rdir/");
-       exit($rc | ($rc >> 8)) if ($rc != 0);
+       exit_cleanup($tmpdir, $rc) if $rc != 0;
 
        # If $GIT_DIR was explicitly set just for the update/checkout
        # commands, then it should be unset before continuing.
@@ -222,37 +254,55 @@ sub setup_dir_diff
        for my $file (@working_tree) {
                my $dir = dirname($file);
                unless (-d "$rdir/$dir") {
-                       mkpath("$rdir/$dir") or die $!;
+                       mkpath("$rdir/$dir") or
+                       exit_cleanup($tmpdir, 1);
+               }
+               if ($symlinks) {
+                       symlink("$workdir/$file", "$rdir/$file") or
+                       exit_cleanup($tmpdir, 1);
+               } else {
+                       copy("$workdir/$file", "$rdir/$file") or
+                       exit_cleanup($tmpdir, 1);
+
+                       my $mode = stat("$workdir/$file")->mode;
+                       chmod($mode, "$rdir/$file") or
+                       exit_cleanup($tmpdir, 1);
                }
-               copy("$workdir/$file", "$rdir/$file") or die $!;
-               chmod(stat("$workdir/$file")->mode, "$rdir/$file") or die $!;
        }
 
        # Changes to submodules require special treatment. This loop writes a
        # temporary file to both the left and right directories to show the
        # change in the recorded SHA1 for the submodule.
        for my $path (keys %submodule) {
+               my $ok;
                if (defined($submodule{$path}{left})) {
-                       write_to_file("$ldir/$path", "Subproject commit $submodule{$path}{left}");
+                       $ok = write_to_file("$ldir/$path",
+                               "Subproject commit $submodule{$path}{left}");
                }
                if (defined($submodule{$path}{right})) {
-                       write_to_file("$rdir/$path", "Subproject commit $submodule{$path}{right}");
+                       $ok = write_to_file("$rdir/$path",
+                               "Subproject commit $submodule{$path}{right}");
                }
+               exit_cleanup($tmpdir, 1) if not $ok;
        }
 
        # Symbolic links require special treatment. The standard "git diff"
        # shows only the link itself, not the contents of the link target.
        # This loop replicates that behavior.
        for my $path (keys %symlink) {
+               my $ok;
                if (defined($symlink{$path}{left})) {
-                       write_to_file("$ldir/$path", $symlink{$path}{left});
+                       $ok = write_to_file("$ldir/$path",
+                                       $symlink{$path}{left});
                }
                if (defined($symlink{$path}{right})) {
-                       write_to_file("$rdir/$path", $symlink{$path}{right});
+                       $ok = write_to_file("$rdir/$path",
+                                       $symlink{$path}{right});
                }
+               exit_cleanup($tmpdir, 1) if not $ok;
        }
 
-       return ($ldir, $rdir);
+       return ($ldir, $rdir, $tmpdir, @working_tree);
 }
 
 sub write_to_file
@@ -263,83 +313,141 @@ sub write_to_file
        # Make sure the path to the file exists
        my $dir = dirname($path);
        unless (-d "$dir") {
-               mkpath("$dir") or die $!;
+               mkpath("$dir") or return 0;
        }
 
        # If the file already exists in that location, delete it.  This
        # is required in the case of symbolic links.
-       unlink("$path");
+       unlink($path);
 
-       open(my $fh, '>', "$path") or die $!;
+       open(my $fh, '>', $path) or return 0;
        print($fh $value);
        close($fh);
-}
 
-# parse command-line options. all unrecognized options and arguments
-# are passed through to the 'git diff' command.
-my ($difftool_cmd, $dirdiff, $extcmd, $gui, $help, $prompt, $tool_help);
-GetOptions('g|gui!' => \$gui,
-       'd|dir-diff' => \$dirdiff,
-       'h' => \$help,
-       'prompt!' => \$prompt,
-       'y' => sub { $prompt = 0; },
-       't|tool:s' => \$difftool_cmd,
-       'tool-help' => \$tool_help,
-       'x|extcmd:s' => \$extcmd);
-
-if (defined($help)) {
-       usage(0);
-}
-if (defined($tool_help)) {
-       print_tool_help();
+       return 1;
 }
-if (defined($difftool_cmd)) {
-       if (length($difftool_cmd) > 0) {
-               $ENV{GIT_DIFF_TOOL} = $difftool_cmd;
-       } else {
-               print "No <tool> given for --tool=<tool>\n";
-               usage(1);
+
+sub main
+{
+       # parse command-line options. all unrecognized options and arguments
+       # are passed through to the 'git diff' command.
+       my %opts = (
+               difftool_cmd => undef,
+               dirdiff => undef,
+               extcmd => undef,
+               gui => undef,
+               help => undef,
+               prompt => undef,
+               symlinks => $^O ne 'cygwin' &&
+                               $^O ne 'MSWin32' && $^O ne 'msys',
+               tool_help => undef,
+       );
+       GetOptions('g|gui!' => \$opts{gui},
+               'd|dir-diff' => \$opts{dirdiff},
+               'h' => \$opts{help},
+               'prompt!' => \$opts{prompt},
+               'y' => sub { $opts{prompt} = 0; },
+               'symlinks' => \$opts{symlinks},
+               'no-symlinks' => sub { $opts{symlinks} = 0; },
+               't|tool:s' => \$opts{difftool_cmd},
+               'tool-help' => \$opts{tool_help},
+               'x|extcmd:s' => \$opts{extcmd});
+
+       if (defined($opts{help})) {
+               usage(0);
        }
-}
-if (defined($extcmd)) {
-       if (length($extcmd) > 0) {
-               $ENV{GIT_DIFFTOOL_EXTCMD} = $extcmd;
-       } else {
-               print "No <cmd> given for --extcmd=<cmd>\n";
-               usage(1);
+       if (defined($opts{tool_help})) {
+               print_tool_help();
        }
-}
-if ($gui) {
-       my $guitool = '';
-       $guitool = Git::config('diff.guitool');
-       if (length($guitool) > 0) {
-               $ENV{GIT_DIFF_TOOL} = $guitool;
+       if (defined($opts{difftool_cmd})) {
+               if (length($opts{difftool_cmd}) > 0) {
+                       $ENV{GIT_DIFF_TOOL} = $opts{difftool_cmd};
+               } else {
+                       print "No <tool> given for --tool=<tool>\n";
+                       usage(1);
+               }
+       }
+       if (defined($opts{extcmd})) {
+               if (length($opts{extcmd}) > 0) {
+                       $ENV{GIT_DIFFTOOL_EXTCMD} = $opts{extcmd};
+               } else {
+                       print "No <cmd> given for --extcmd=<cmd>\n";
+                       usage(1);
+               }
+       }
+       if ($opts{gui}) {
+               my $guitool = Git::config('diff.guitool');
+               if (length($guitool) > 0) {
+                       $ENV{GIT_DIFF_TOOL} = $guitool;
+               }
+       }
+
+       # In directory diff mode, 'git-difftool--helper' is called once
+       # to compare the a/b directories.  In file diff mode, 'git diff'
+       # will invoke a separate instance of 'git-difftool--helper' for
+       # each file that changed.
+       if (defined($opts{dirdiff})) {
+               dir_diff($opts{extcmd}, $opts{symlinks});
+       } else {
+               file_diff($opts{prompt});
        }
 }
 
-# In directory diff mode, 'git-difftool--helper' is called once
-# to compare the a/b directories.  In file diff mode, 'git diff'
-# will invoke a separate instance of 'git-difftool--helper' for
-# each file that changed.
-if (defined($dirdiff)) {
-       my ($a, $b) = setup_dir_diff();
+sub dir_diff
+{
+       my ($extcmd, $symlinks) = @_;
+       my $rc;
+       my $error = 0;
+       my $repo = Git->repository();
+       my $workdir = find_worktree($repo);
+       my ($a, $b, $tmpdir, @worktree) =
+               setup_dir_diff($repo, $workdir, $symlinks);
+
        if (defined($extcmd)) {
                $rc = system($extcmd, $a, $b);
        } else {
                $ENV{GIT_DIFFTOOL_DIRDIFF} = 'true';
                $rc = system('git', 'difftool--helper', $a, $b);
        }
-
-       exit($rc | ($rc >> 8)) if ($rc != 0);
-
        # If the diff including working copy files and those
        # files were modified during the diff, then the changes
-       # should be copied back to the working tree
-       for my $file (@working_tree) {
-               copy("$b/$file", "$workdir/$file") or die $!;
-               chmod(stat("$b/$file")->mode, "$workdir/$file") or die $!;
+       # should be copied back to the working tree.
+       # Do not copy back files when symlinks are used and the
+       # external tool did not replace the original link with a file.
+       for my $file (@worktree) {
+               next if $symlinks && -l "$b/$file";
+               next if ! -f "$b/$file";
+
+               my $diff = compare("$b/$file", "$workdir/$file");
+               if ($diff == 0) {
+                       next;
+               } elsif ($diff == -1) {
+                       my $errmsg = "warning: Could not compare ";
+                       $errmsg += "'$b/$file' with '$workdir/$file'\n";
+                       warn $errmsg;
+                       $error = 1;
+               } elsif ($diff == 1) {
+                       my $mode = stat("$b/$file")->mode;
+                       copy("$b/$file", "$workdir/$file") or
+                       exit_cleanup($tmpdir, 1);
+
+                       chmod($mode, "$workdir/$file") or
+                       exit_cleanup($tmpdir, 1);
+               }
        }
-} else {
+       if ($error) {
+               warn "warning: Temporary files exist in '$tmpdir'.\n";
+               warn "warning: You may want to cleanup or recover these.\n";
+               exit(1);
+       } else {
+               exit_cleanup($tmpdir, $rc);
+       }
+}
+
+sub file_diff
+{
+       my ($prompt) = @_;
+
        if (defined($prompt)) {
                if ($prompt) {
                        $ENV{GIT_DIFFTOOL_PROMPT} = 'true';
@@ -359,3 +467,5 @@ if (defined($dirdiff)) {
        my $rc = system('git', 'diff', @ARGV);
        exit($rc | ($rc >> 8));
 }
+
+main();
index 178e45305d2b66bbe5a0c0902d989ea66888869b..53142492afcfb92f0453359af9a00a045c51e7e9 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 65709437ff06a2b371fe70fd846922c73ebc23b0..49b62ea6ebc61c4af16d7d740e5b423e5787b915 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=0.16.GITGUI
+DEF_VER=0.17.GITGUI
 
 LF='
 '
index ba4e5c1330c84f54a6809991eec22aa2e8e25ddd..89f636f4963cf7933639f6a23b3be2e8fd4c0964 100755 (executable)
@@ -154,6 +154,7 @@ set _trace [lsearch -exact $argv --trace]
 if {$_trace >= 0} {
        set argv [lreplace $argv $_trace $_trace]
        set _trace 1
+       if {[tk windowingsystem] eq "win32"} { console show }
 } else {
        set _trace 0
 }
@@ -1463,7 +1464,7 @@ proc rescan {after {honor_trustmtime 1}} {
                (![$ui_comm edit modified]
                || [string trim [$ui_comm get 0.0 end]] eq {})} {
                if {[string match amend* $commit_type]} {
-               } elseif {[load_message GITGUI_MSG]} {
+               } elseif {[load_message GITGUI_MSG utf-8]} {
                } elseif {[run_prepare_commit_msg_hook]} {
                } elseif {[load_message MERGE_MSG]} {
                } elseif {[load_message SQUASH_MSG]} {
@@ -1549,7 +1550,7 @@ proc rescan_stage2 {fd after} {
        fileevent $fd_lo readable [list read_ls_others $fd_lo $after]
 }
 
-proc load_message {file} {
+proc load_message {file {encoding {}}} {
        global ui_comm
 
        set f [gitdir $file]
@@ -1558,6 +1559,9 @@ proc load_message {file} {
                        return 0
                }
                fconfigure $fd -eofchar {}
+               if {$encoding ne {}} {
+                       fconfigure $fd -encoding $encoding
+               }
                set content [string trim [read $fd]]
                close $fd
                regsub -all -line {[ \r\t]+$} $content {} content
@@ -2266,6 +2270,7 @@ proc do_quit {{rc {1}}} {
                                && $msg ne {}} {
                                catch {
                                        set fd [open $save w]
+                                       fconfigure $fd -encoding utf-8
                                        puts -nonewline $fd $msg
                                        close $fd
                                }
@@ -2998,10 +3003,19 @@ blame {
        set jump_spec {}
        set is_path 0
        foreach a $argv {
-               if {$is_path || [file exists $_prefix$a]} {
+               if {[file exists $a]} {
+                       if {$path ne {}} usage
+                       set path [normalize_relpath $a]
+                       break
+               } elseif {[file exists $_prefix$a]} {
                        if {$path ne {}} usage
                        set path [normalize_relpath $_prefix$a]
                        break
+               }
+
+               if {$is_path} {
+                       if {$path ne {}} usage
+                       break
                } elseif {$a eq {--}} {
                        if {$path ne {}} {
                                if {$head ne {}} usage
@@ -3023,8 +3037,13 @@ blame {
        unset is_path
 
        if {$head ne {} && $path eq {}} {
-               set path [normalize_relpath $_prefix$head]
-               set head {}
+               if {[string index $head 0] eq {/}} {
+                       set path [normalize_relpath $head]
+                       set head {}
+               } else {
+                       set path [normalize_relpath $_prefix$head]
+                       set head {}
+               }
        }
 
        if {$head eq {}} {
@@ -3710,6 +3729,8 @@ bind $ui_diff <$M1B-Key-v> {break}
 bind $ui_diff <$M1B-Key-V> {break}
 bind $ui_diff <$M1B-Key-a> {%W tag add sel 0.0 end;break}
 bind $ui_diff <$M1B-Key-A> {%W tag add sel 0.0 end;break}
+bind $ui_diff <$M1B-Key-j> {do_revert_selection;break}
+bind $ui_diff <$M1B-Key-J> {do_revert_selection;break}
 bind $ui_diff <Key-Up>     {catch {%W yview scroll -1 units};break}
 bind $ui_diff <Key-Down>   {catch {%W yview scroll  1 units};break}
 bind $ui_diff <Key-Left>   {catch {%W xview scroll -1 units};break}
@@ -3742,6 +3763,8 @@ bind .   <$M1B-Key-s> do_signoff
 bind .   <$M1B-Key-S> do_signoff
 bind .   <$M1B-Key-t> do_add_selection
 bind .   <$M1B-Key-T> do_add_selection
+bind .   <$M1B-Key-u> do_unstage_selection
+bind .   <$M1B-Key-U> do_unstage_selection
 bind .   <$M1B-Key-j> do_revert_selection
 bind .   <$M1B-Key-J> do_revert_selection
 bind .   <$M1B-Key-i> do_add_all
@@ -3835,7 +3858,7 @@ if {[is_enabled transport]} {
 }
 
 if {[winfo exists $ui_comm]} {
-       set GITGUI_BCK_exists [load_message GITGUI_BCK]
+       set GITGUI_BCK_exists [load_message GITGUI_BCK utf-8]
 
        # -- If both our backup and message files exist use the
        #    newer of the two files to initialize the buffer.
@@ -3872,6 +3895,7 @@ if {[winfo exists $ui_comm]} {
                        } elseif {$m} {
                                catch {
                                        set fd [open [gitdir GITGUI_BCK] w]
+                                       fconfigure $fd -encoding utf-8
                                        puts -nonewline $fd $msg
                                        close $fd
                                        set GITGUI_BCK_exists 1
index 0d81432af53ba873d89421fa4767243818ab1f0a..864b687057c9759f2b06a9a83e3ca18c51113d92 100644 (file)
@@ -268,7 +268,7 @@ proc commit_commitmsg {curHEAD msg_p} {
            &&  [is_config_true gui.warndetachedcommit]} {
                set msg [mc "You are about to commit on a detached head.\
 This is a potentially dangerous thing to do because if you switch\
-to another branch you will loose your changes and it can be difficult\
+to another branch you will lose your changes and it can be difficult\
 to retrieve them later from the reflog. You should probably cancel this\
 commit and create a new branch to continue.\n\
 \n\
@@ -409,6 +409,7 @@ A rescan will be automatically started now.
        catch {file delete [gitdir MERGE_MSG]}
        catch {file delete [gitdir SQUASH_MSG]}
        catch {file delete [gitdir GITGUI_MSG]}
+       catch {file delete [gitdir CHERRY_PICK_HEAD]}
 
        # -- Let rerere do its thing.
        #
index 95cb44991fc5b018805d6091c4f98ce7ae0ccf52..02111a1742f92eff7efc6b8e54323919029867bc 100644 (file)
@@ -77,6 +77,7 @@ method start {msg uds} {
 
 method update {have total} {
        set pdone 0
+       set cdone 0
        if {$total > 0} {
                set pdone [expr {100 * $have / $total}]
                set cdone [expr {[winfo width $w_c] * $have / $total}]
index ddbe6334a258dae46b6c333d53590f3b920a9cab..738bdd03ed8a3940ae9bec362ddcfd16a3c48e9c 100644 (file)
@@ -12,7 +12,9 @@ if {[file tail [lindex $argv 0]] eq {gitk}} {
 } else {
        set argv0 [file join $gitexecdir [file tail [lindex $argv 0]]]
        set AppMain_source [file join $gitguilib git-gui.tcl]
-       if {[pwd] eq {/}} {
+       if {[info exists env(PWD)]} {
+               cd $env(PWD)
+       } elseif {[pwd] eq {/}} {
                cd $env(HOME)
        }
 }
index 44c5ddc8b67cbdb5dbec19e779394745d8f2e6ad..baebff2ffff7f84d5765c809cd44bc8bf93e766e 100644 (file)
@@ -72,7 +72,7 @@ msgstr ""
 
 #: git-gui.sh:1154
 msgid "Cannot use bare repository:"
-msgstr "Leeres Projektarchiv kann nicht benutzt werden:"
+msgstr "Bloßes Projektarchiv kann nicht benutzt werden:"
 
 #: git-gui.sh:1162
 msgid "No working directory"
@@ -88,7 +88,7 @@ msgstr "Nach geänderten Dateien suchen..."
 
 #: git-gui.sh:1454
 msgid "Calling prepare-commit-msg hook..."
-msgstr "Aufrufen der Eintragen-Vorbereiten-Kontrolle..."
+msgstr "Aufrufen der Eintragen-Vorbereiten-Kontrolle (»prepare-commit hook«)..."
 
 #: git-gui.sh:1471
 msgid "Commit declined by prepare-commit-msg hook."
@@ -188,7 +188,7 @@ msgstr "Zusammenführen"
 
 #: git-gui.sh:2465 lib/choose_rev.tcl:557
 msgid "Remote"
-msgstr "Andere Archive"
+msgstr "Externe Archive"
 
 #: git-gui.sh:2468
 msgid "Tools"
@@ -478,7 +478,7 @@ msgstr "Zusammenführungswerkzeug"
 
 #: git-gui.sh:3328
 msgid "Use Remote Version"
-msgstr "Entfernte Version benutzen"
+msgstr "Externe Version benutzen"
 
 #: git-gui.sh:3332
 msgid "Use Local Version"
@@ -771,7 +771,7 @@ msgstr "Bitte wählen Sie einen Übernahmezweig."
 #: lib/branch_create.tcl:140
 #, tcl-format
 msgid "Tracking branch %s is not a branch in the remote repository."
-msgstr "Übernahmezweig »%s« ist kein Zweig im anderen Projektarchiv."
+msgstr "Übernahmezweig »%s« ist kein Zweig im externen Projektarchiv."
 
 #: lib/branch_create.tcl:153 lib/branch_rename.tcl:86
 msgid "Please supply a branch name."
@@ -1446,7 +1446,7 @@ msgstr ""
 
 #: lib/commit.tcl:234
 msgid "Calling pre-commit hook..."
-msgstr "Aufrufen der Vor-Eintragen-Kontrolle..."
+msgstr "Aufrufen der Vor-Eintragen-Kontrolle (»pre-commit hook«)..."
 
 #: lib/commit.tcl:249
 msgid "Commit declined by pre-commit hook."
@@ -1454,7 +1454,7 @@ msgstr "Eintragen abgelehnt durch Vor-Eintragen-Kontrolle (»pre-commit hook«).
 
 #: lib/commit.tcl:272
 msgid "Calling commit-msg hook..."
-msgstr "Aufrufen der Versionsbeschreibungs-Kontrolle..."
+msgstr "Aufrufen der Versionsbeschreibungs-Kontrolle (»commit-message hook«)..."
 
 #: lib/commit.tcl:287
 msgid "Commit declined by commit-msg hook."
@@ -2134,11 +2134,11 @@ msgstr "Optionen konnten nicht gespeichert werden:"
 
 #: lib/remote_add.tcl:19
 msgid "Add Remote"
-msgstr "Anderes Archiv hinzufügen"
+msgstr "Externes Archiv hinzufügen"
 
 #: lib/remote_add.tcl:24
 msgid "Add New Remote"
-msgstr "Neues anderes Archiv hinzufügen"
+msgstr "Neues externes Archiv hinzufügen"
 
 #: lib/remote_add.tcl:28 lib/tools_dlg.tcl:36
 msgid "Add"
@@ -2146,7 +2146,7 @@ msgstr "Hinzufügen"
 
 #: lib/remote_add.tcl:37
 msgid "Remote Details"
-msgstr "Einzelheiten des anderen Archivs"
+msgstr "Einzelheiten des externen Archivs"
 
 #: lib/remote_add.tcl:50
 msgid "Location:"
@@ -2162,7 +2162,7 @@ msgstr "Gleich anfordern"
 
 #: lib/remote_add.tcl:71
 msgid "Initialize Remote Repository and Push"
-msgstr "Anderes Archiv initialisieren und dahin versenden"
+msgstr "Externes Archiv initialisieren und dahin versenden"
 
 #: lib/remote_add.tcl:77
 msgid "Do Nothing Else Now"
@@ -2170,17 +2170,17 @@ msgstr "Nichts tun"
 
 #: lib/remote_add.tcl:101
 msgid "Please supply a remote name."
-msgstr "Bitte geben Sie einen Namen des anderen Archivs an."
+msgstr "Bitte geben Sie einen Namen des externen Archivs an."
 
 #: lib/remote_add.tcl:114
 #, tcl-format
 msgid "'%s' is not an acceptable remote name."
-msgstr "»%s« ist kein zulässiger Name eines anderen Archivs."
+msgstr "»%s« ist kein zulässiger Name eines externen Archivs."
 
 #: lib/remote_add.tcl:125
 #, tcl-format
 msgid "Failed to add remote '%s' of location '%s'."
-msgstr "Fehler beim Hinzufügen des anderen Archivs »%s« aus Herkunftsort »%s«."
+msgstr "Fehler beim Hinzufügen des externen Archivs »%s« aus Herkunftsort »%s«."
 
 #: lib/remote_add.tcl:133 lib/transport.tcl:6
 #, tcl-format
@@ -2195,7 +2195,7 @@ msgstr "»%s« anfordern"
 #: lib/remote_add.tcl:157
 #, tcl-format
 msgid "Do not know how to initialize repository at location '%s'."
-msgstr "Initialisieren eines anderen Archivs an Adresse »%s« ist nicht möglich."
+msgstr "Initialisieren eines externen Archivs an Adresse »%s« ist nicht möglich."
 
 #: lib/remote_add.tcl:163 lib/transport.tcl:25 lib/transport.tcl:63
 #: lib/transport.tcl:81
@@ -2210,7 +2210,7 @@ msgstr "Einrichten von »%s« an »%s«"
 
 #: lib/remote_branch_delete.tcl:29 lib/remote_branch_delete.tcl:34
 msgid "Delete Branch Remotely"
-msgstr "Zweig in anderem Archiv löschen"
+msgstr "Zweig in externem Archiv löschen"
 
 #: lib/remote_branch_delete.tcl:47
 msgid "From Repository"
@@ -2218,7 +2218,7 @@ msgstr "In Projektarchiv"
 
 #: lib/remote_branch_delete.tcl:50 lib/transport.tcl:134
 msgid "Remote:"
-msgstr "Anderes Archiv:"
+msgstr "Externes Archiv:"
 
 #: lib/remote_branch_delete.tcl:66 lib/transport.tcl:149
 msgid "Arbitrary Location:"
@@ -2281,7 +2281,7 @@ msgstr "»%s« laden..."
 
 #: lib/remote.tcl:163
 msgid "Remove Remote"
-msgstr "Anderes Archiv entfernen"
+msgstr "Externes Archiv entfernen"
 
 #: lib/remote.tcl:168
 msgid "Prune from"
@@ -2397,7 +2397,7 @@ msgid "Generation failed."
 msgstr "Schlüsselerzeugung fehlgeschlagen."
 
 #: lib/sshkey.tcl:118
-msgid "Generation succeded, but no keys found."
+msgid "Generation succeeded, but no keys found."
 msgstr "Schlüsselerzeugung erfolgreich, aber keine Schlüssel gefunden."
 
 #: lib/sshkey.tcl:121
index 81706965f377787f8048bc5705ab8da10af55586..40441dbb0da4fe5a62776054aa2d5d2d30d9af8f 100644 (file)
@@ -2399,7 +2399,7 @@ msgid "Generation failed."
 msgstr "La génération a échoué."
 
 #: lib/sshkey.tcl:118
-msgid "Generation succeded, but no keys found."
+msgid "Generation succeeded, but no keys found."
 msgstr "La génération a réussi, mais aucune clé n'a été trouvée."
 
 #: lib/sshkey.tcl:121
index 1ae2aaa0b3bb46302a9a4876dbbb1be00d2c2ddf..0c94f9c2c6df3a5d7088d5669138aaebdad0974c 100644 (file)
@@ -2203,7 +2203,7 @@ msgid "Generation failed."
 msgstr ""
 
 #: lib/sshkey.tcl:118
-msgid "Generation succeded, but no keys found."
+msgid "Generation succeeded, but no keys found."
 msgstr ""
 
 #: lib/sshkey.tcl:121
index 0f87bc1cbeedca8d9040777a5484500d1071c2e6..d106dadac89b01ba27170e95aa2d1ef02fa8b940 100644 (file)
@@ -2354,7 +2354,7 @@ msgid "Generation failed."
 msgstr "A generálás nem sikerült."
 
 #: lib/sshkey.tcl:118
-msgid "Generation succeded, but no keys found."
+msgid "Generation succeeded, but no keys found."
 msgstr "A generálás sikeres, de egy kulcs se található."
 
 #: lib/sshkey.tcl:121
index aa15a204d85c5fdffbb74a5882c759c36f547184..1bd8b8e04f716d46627ded00997a0f9ca85f7b60 100644 (file)
@@ -2397,7 +2397,7 @@ msgid "Generation failed."
 msgstr "Errore durante la creazione della chiave."
 
 #: lib/sshkey.tcl:118
-msgid "Generation succeded, but no keys found."
+msgid "Generation succeeded, but no keys found."
 msgstr "La chiave è stata creata con successo, ma non è stata trovata."
 
 #: lib/sshkey.tcl:121
index 15017985e5f3a731cd9b16f1d71442b22e67f771..9aff249d5f533638170e7e14e03930a560978f46 100644 (file)
@@ -2362,7 +2362,7 @@ msgid "Generation failed."
 msgstr "生成に失敗しました。"
 
 #: lib/sshkey.tcl:118
-msgid "Generation succeded, but no keys found."
+msgid "Generation succeeded, but no keys found."
 msgstr "生成には成功しましたが、鍵が見つかりません。"
 
 #: lib/sshkey.tcl:121
index 6de93c28c2e2b7cb0413521c987161c4a4fcb59d..d66aa5026391fbba38ff8b02c50c363965927131 100644 (file)
@@ -2286,7 +2286,7 @@ msgid "Generation failed."
 msgstr "Generering feilet."
 
 #: lib/sshkey.tcl:118
-msgid "Generation succeded, but no keys found."
+msgid "Generation succeeded, but no keys found."
 msgstr "Generering vellykket, men ingen nøkler er funnet."
 
 #: lib/sshkey.tcl:121
index b175b9791ecb83c761d360e38ff2526717ad3deb..bad116c78038936b59e88b714de8a37ce02739c9 100644 (file)
@@ -2375,7 +2375,7 @@ msgid "Generation failed."
 msgstr "A geração da chave falhou."
 
 #: lib/sshkey.tcl:118
-msgid "Generation succeded, but no keys found."
+msgid "Generation succeeded, but no keys found."
 msgstr "A geração da chave foi bem-sucedida, mas nenhuma chave foi encontrada."
 
 #: lib/sshkey.tcl:121
index 30f4b77dac08d9c69ea3d0009ec97d30b9349be8..ca4343b40cd9a166fc9c3526d68b6182057e71a3 100644 (file)
@@ -2370,7 +2370,7 @@ msgid "Generation failed."
 msgstr "Ключ не создан."
 
 #: lib/sshkey.tcl:118
-msgid "Generation succeded, but no keys found."
+msgid "Generation succeeded, but no keys found."
 msgstr "Создание ключа завершилось, но результат не был найден"
 
 #: lib/sshkey.tcl:121
index 24cc4e3675e05e9bd3bf7ea17335a67a3aa5166b..fcb063ffa6436271968f7991cccad1a2303fd8c0 100644 (file)
@@ -2382,7 +2382,7 @@ msgid "Generation failed."
 msgstr "Misslyckades med att skapa."
 
 #: lib/sshkey.tcl:120
-msgid "Generation succeded, but no keys found."
+msgid "Generation succeeded, but no keys found."
 msgstr "Lyckades skapa nyckeln, men hittar inte någon nyckel."
 
 #: lib/sshkey.tcl:123
index f730253c0eac181ec8507d2c837d4ec85a0ae991..f013a0350665e8c11b52853b5794631dcf7694d0 100644 (file)
@@ -104,13 +104,49 @@ run_merge_tool () {
 
        if merge_mode
        then
-               merge_cmd "$1"
+               run_merge_cmd "$1"
        else
-               diff_cmd "$1"
+               run_diff_cmd "$1"
        fi
        return $status
 }
 
+# Run a either a configured or built-in diff tool
+run_diff_cmd () {
+       merge_tool_cmd="$(get_merge_tool_cmd "$1")"
+       if test -n "$merge_tool_cmd"
+       then
+               ( eval $merge_tool_cmd )
+               status=$?
+               return $status
+       else
+               diff_cmd "$1"
+       fi
+}
+
+# Run a either a configured or built-in merge tool
+run_merge_cmd () {
+       merge_tool_cmd="$(get_merge_tool_cmd "$1")"
+       if test -n "$merge_tool_cmd"
+       then
+               trust_exit_code="$(git config --bool \
+                       mergetool."$1".trustExitCode || echo false)"
+               if test "$trust_exit_code" = "false"
+               then
+                       touch "$BACKUP"
+                       ( eval $merge_tool_cmd )
+                       status=$?
+                       check_unchanged
+               else
+                       ( eval $merge_tool_cmd )
+                       status=$?
+               fi
+               return $status
+       else
+               merge_cmd "$1"
+       fi
+}
+
 list_merge_tool_candidates () {
        if merge_mode
        then
@@ -126,7 +162,7 @@ list_merge_tool_candidates () {
                else
                        tools="opendiff kdiff3 tkdiff xxdiff meld $tools"
                fi
-               tools="$tools gvimdiff diffuse ecmerge p4merge araxis bc3"
+               tools="$tools gvimdiff diffuse ecmerge p4merge araxis bc3 codecompare"
        fi
        case "${VISUAL:-$EDITOR}" in
        *vim*)
index f895a2412bd5723d72f3bcfdcddbce495070d5e6..882b1bbab53c6e184c7eadb5250c128b59c93482 100755 (executable)
--- a/git-p4.py
+++ b/git-p4.py
@@ -120,6 +120,15 @@ def p4_read_pipe_lines(c):
     real_cmd = p4_build_cmd(c)
     return read_pipe_lines(real_cmd)
 
+def p4_has_command(cmd):
+    """Ask p4 for help on this command.  If it returns an error, the
+       command does not exist in this version of p4."""
+    real_cmd = p4_build_cmd(["help", cmd])
+    p = subprocess.Popen(real_cmd, stdout=subprocess.PIPE,
+                                   stderr=subprocess.PIPE)
+    p.communicate()
+    return p.returncode == 0
+
 def system(cmd):
     expand = isinstance(cmd,basestring)
     if verbose:
@@ -157,6 +166,9 @@ def p4_revert(f):
 def p4_reopen(type, f):
     p4_system(["reopen", "-t", type, wildcard_encode(f)])
 
+def p4_move(src, dest):
+    p4_system(["move", "-k", wildcard_encode(src), wildcard_encode(dest)])
+
 #
 # Canonicalize the p4 type and return a tuple of the
 # base type, plus any modifiers.  See "p4 help filetypes"
@@ -832,6 +844,9 @@ class P4RollBack(Command):
         return True
 
 class P4Submit(Command, P4UserMap):
+
+    conflict_behavior_choices = ("ask", "skip", "quit")
+
     def __init__(self):
         Command.__init__(self)
         P4UserMap.__init__(self)
@@ -841,23 +856,55 @@ class P4Submit(Command, P4UserMap):
                 # preserve the user, requires relevant p4 permissions
                 optparse.make_option("--preserve-user", dest="preserveUser", action="store_true"),
                 optparse.make_option("--export-labels", dest="exportLabels", action="store_true"),
+                optparse.make_option("--dry-run", "-n", dest="dry_run", action="store_true"),
+                optparse.make_option("--prepare-p4-only", dest="prepare_p4_only", action="store_true"),
+                optparse.make_option("--conflict", dest="conflict_behavior",
+                                     choices=self.conflict_behavior_choices)
         ]
         self.description = "Submit changes from git to the perforce depot."
         self.usage += " [name of git branch to submit into perforce depot]"
-        self.interactive = True
         self.origin = ""
         self.detectRenames = False
         self.preserveUser = gitConfig("git-p4.preserveUser").lower() == "true"
+        self.dry_run = False
+        self.prepare_p4_only = False
+        self.conflict_behavior = None
         self.isWindows = (platform.system() == "Windows")
         self.exportLabels = False
+        self.p4HasMoveCommand = p4_has_command("move")
 
     def check(self):
         if len(p4CmdList("opened ...")) > 0:
             die("You have files opened with perforce! Close them before starting the sync.")
 
-    # replaces everything between 'Description:' and the next P4 submit template field with the
-    # commit message
-    def prepareLogMessage(self, template, message):
+    def separate_jobs_from_description(self, message):
+        """Extract and return a possible Jobs field in the commit
+           message.  It goes into a separate section in the p4 change
+           specification.
+
+           A jobs line starts with "Jobs:" and looks like a new field
+           in a form.  Values are white-space separated on the same
+           line or on following lines that start with a tab.
+
+           This does not parse and extract the full git commit message
+           like a p4 form.  It just sees the Jobs: line as a marker
+           to pass everything from then on directly into the p4 form,
+           but outside the description section.
+
+           Return a tuple (stripped log message, jobs string)."""
+
+        m = re.search(r'^Jobs:', message, re.MULTILINE)
+        if m is None:
+            return (message, None)
+
+        jobtext = message[m.start():]
+        stripped_message = message[:m.start()].rstrip()
+        return (stripped_message, jobtext)
+
+    def prepareLogMessage(self, template, message, jobs):
+        """Edits the template returned from "p4 change -o" to insert
+           the message in the Description field, and the jobs text in
+           the Jobs field."""
         result = ""
 
         inDescriptionSection = False
@@ -870,6 +917,9 @@ class P4Submit(Command, P4UserMap):
             if inDescriptionSection:
                 if line.startswith("Files:") or line.startswith("Jobs:"):
                     inDescriptionSection = False
+                    # insert Jobs section
+                    if jobs:
+                        result += jobs + "\n"
                 else:
                     continue
             else:
@@ -981,7 +1031,13 @@ class P4Submit(Command, P4UserMap):
         return 0
 
     def prepareSubmitTemplate(self):
-        # remove lines in the Files section that show changes to files outside the depot path we're committing into
+        """Run "p4 change -o" to grab a change specification template.
+           This does not use "p4 -G", as it is nice to keep the submission
+           template in original order, since a human might edit it.
+
+           Remove lines in the Files section that show changes to files
+           outside the depot path we're committing into."""
+
         template = ""
         inFilesSection = False
         for line in p4_read_pipe_lines(['change', '-o']):
@@ -1042,31 +1098,14 @@ class P4Submit(Command, P4UserMap):
                 return False
 
     def applyCommit(self, id):
-        print "Applying %s" % (read_pipe("git log --max-count=1 --pretty=oneline %s" % id))
+        """Apply one commit, return True if it succeeded."""
 
-        (p4User, gitEmail) = self.p4UserForCommit(id)
-
-        if not self.detectRenames:
-            # If not explicitly set check the config variable
-            self.detectRenames = gitConfig("git-p4.detectRenames")
-
-        if self.detectRenames.lower() == "false" or self.detectRenames == "":
-            diffOpts = ""
-        elif self.detectRenames.lower() == "true":
-            diffOpts = "-M"
-        else:
-            diffOpts = "-M%s" % self.detectRenames
-
-        detectCopies = gitConfig("git-p4.detectCopies")
-        if detectCopies.lower() == "true":
-            diffOpts += " -C"
-        elif detectCopies != "" and detectCopies.lower() != "false":
-            diffOpts += " -C%s" % detectCopies
+        print "Applying", read_pipe(["git", "show", "-s",
+                                     "--format=format:%h %s", id])
 
-        if gitConfig("git-p4.detectCopiesHarder", "--bool") == "true":
-            diffOpts += " --find-copies-harder"
+        (p4User, gitEmail) = self.p4UserForCommit(id)
 
-        diff = read_pipe_lines("git diff-tree -r %s \"%s^\" \"%s\"" % (diffOpts, id, id))
+        diff = read_pipe_lines("git diff-tree -r %s \"%s^\" \"%s\"" % (self.diffOpts, id, id))
         filesToAdd = set()
         filesToDelete = set()
         editedFiles = set()
@@ -1106,17 +1145,23 @@ class P4Submit(Command, P4UserMap):
                 editedFiles.add(dest)
             elif modifier == "R":
                 src, dest = diff['src'], diff['dst']
-                p4_integrate(src, dest)
-                if diff['src_sha1'] != diff['dst_sha1']:
-                    p4_edit(dest)
+                if self.p4HasMoveCommand:
+                    p4_edit(src)        # src must be open before move
+                    p4_move(src, dest)  # opens for (move/delete, move/add)
                 else:
-                    pureRenameCopy.add(dest)
+                    p4_integrate(src, dest)
+                    if diff['src_sha1'] != diff['dst_sha1']:
+                        p4_edit(dest)
+                    else:
+                        pureRenameCopy.add(dest)
                 if isModeExecChanged(diff['src_mode'], diff['dst_mode']):
-                    p4_edit(dest)
+                    if not self.p4HasMoveCommand:
+                        p4_edit(dest)   # with move: already open, writable
                     filesToChangeExecBit[dest] = diff['dst_mode']
-                os.unlink(dest)
+                if not self.p4HasMoveCommand:
+                    os.unlink(dest)
+                    filesToDelete.add(src)
                 editedFiles.add(dest)
-                filesToDelete.add(src)
             else:
                 die("unknown modifier %s for %s" % (modifier, path))
 
@@ -1163,34 +1208,13 @@ class P4Submit(Command, P4UserMap):
                     patch_succeeded = True
 
         if not patch_succeeded:
-            print "What do you want to do?"
-            response = "x"
-            while response != "s" and response != "a" and response != "w":
-                response = raw_input("[s]kip this patch / [a]pply the patch forcibly "
-                                     "and with .rej files / [w]rite the patch to a file (patch.txt) ")
-            if response == "s":
-                print "Skipping! Good luck with the next patches..."
-                for f in editedFiles:
-                    p4_revert(f)
-                for f in filesToAdd:
-                    os.remove(f)
-                return
-            elif response == "a":
-                os.system(applyPatchCmd)
-                if len(filesToAdd) > 0:
-                    print "You may also want to call p4 add on the following files:"
-                    print " ".join(filesToAdd)
-                if len(filesToDelete):
-                    print "The following files should be scheduled for deletion with p4 delete:"
-                    print " ".join(filesToDelete)
-                die("Please resolve and submit the conflict manually and "
-                    + "continue afterwards with git p4 submit --continue")
-            elif response == "w":
-                system(diffcmd + " > patch.txt")
-                print "Patch saved to patch.txt in %s !" % self.clientPath
-                die("Please resolve and submit the conflict manually and "
-                    "continue afterwards with git p4 submit --continue")
+            for f in editedFiles:
+                p4_revert(f)
+            return False
 
+        #
+        # Apply the patch for real, and do add/delete/+x handling.
+        #
         system(applyPatchCmd)
 
         for f in filesToAdd:
@@ -1204,91 +1228,132 @@ class P4Submit(Command, P4UserMap):
             mode = filesToChangeExecBit[f]
             setP4ExecBit(f, mode)
 
+        #
+        # Build p4 change description, starting with the contents
+        # of the git commit message.
+        #
         logMessage = extractLogMessageFromGitCommit(id)
         logMessage = logMessage.strip()
+        (logMessage, jobs) = self.separate_jobs_from_description(logMessage)
 
         template = self.prepareSubmitTemplate()
+        submitTemplate = self.prepareLogMessage(template, logMessage, jobs)
 
-        if self.interactive:
-            submitTemplate = self.prepareLogMessage(template, logMessage)
-
-            if self.preserveUser:
-               submitTemplate = submitTemplate + ("\n######## Actual user %s, modified after commit\n" % p4User)
-
-            if os.environ.has_key("P4DIFF"):
-                del(os.environ["P4DIFF"])
-            diff = ""
-            for editedFile in editedFiles:
-                diff += p4_read_pipe(['diff', '-du',
-                                      wildcard_encode(editedFile)])
-
-            newdiff = ""
-            for newFile in filesToAdd:
-                newdiff += "==== new file ====\n"
-                newdiff += "--- /dev/null\n"
-                newdiff += "+++ %s\n" % newFile
-                f = open(newFile, "r")
-                for line in f.readlines():
-                    newdiff += "+" + line
-                f.close()
-
-            if self.checkAuthorship and not self.p4UserIsMe(p4User):
-                submitTemplate += "######## git author %s does not match your p4 account.\n" % gitEmail
-                submitTemplate += "######## Use option --preserve-user to modify authorship.\n"
-                submitTemplate += "######## Variable git-p4.skipUserNameCheck hides this message.\n"
-
-            separatorLine = "######## everything below this line is just the diff #######\n"
-
-            (handle, fileName) = tempfile.mkstemp()
-            tmpFile = os.fdopen(handle, "w+")
-            if self.isWindows:
-                submitTemplate = submitTemplate.replace("\n", "\r\n")
-                separatorLine = separatorLine.replace("\n", "\r\n")
-                newdiff = newdiff.replace("\n", "\r\n")
-            tmpFile.write(submitTemplate + separatorLine + diff + newdiff)
-            tmpFile.close()
-
-            if self.edit_template(fileName):
-                # read the edited message and submit
-                tmpFile = open(fileName, "rb")
-                message = tmpFile.read()
-                tmpFile.close()
-                submitTemplate = message[:message.index(separatorLine)]
-                if self.isWindows:
-                    submitTemplate = submitTemplate.replace("\r\n", "\n")
-                p4_write_pipe(['submit', '-i'], submitTemplate)
-
-                if self.preserveUser:
-                    if p4User:
-                        # Get last changelist number. Cannot easily get it from
-                        # the submit command output as the output is
-                        # unmarshalled.
-                        changelist = self.lastP4Changelist()
-                        self.modifyChangelistUser(changelist, p4User)
-
-                # The rename/copy happened by applying a patch that created a
-                # new file.  This leaves it writable, which confuses p4.
+        if self.preserveUser:
+           submitTemplate += "\n######## Actual user %s, modified after commit\n" % p4User
+
+        if self.checkAuthorship and not self.p4UserIsMe(p4User):
+            submitTemplate += "######## git author %s does not match your p4 account.\n" % gitEmail
+            submitTemplate += "######## Use option --preserve-user to modify authorship.\n"
+            submitTemplate += "######## Variable git-p4.skipUserNameCheck hides this message.\n"
+
+        separatorLine = "######## everything below this line is just the diff #######\n"
+
+        # diff
+        if os.environ.has_key("P4DIFF"):
+            del(os.environ["P4DIFF"])
+        diff = ""
+        for editedFile in editedFiles:
+            diff += p4_read_pipe(['diff', '-du',
+                                  wildcard_encode(editedFile)])
+
+        # new file diff
+        newdiff = ""
+        for newFile in filesToAdd:
+            newdiff += "==== new file ====\n"
+            newdiff += "--- /dev/null\n"
+            newdiff += "+++ %s\n" % newFile
+            f = open(newFile, "r")
+            for line in f.readlines():
+                newdiff += "+" + line
+            f.close()
+
+        # change description file: submitTemplate, separatorLine, diff, newdiff
+        (handle, fileName) = tempfile.mkstemp()
+        tmpFile = os.fdopen(handle, "w+")
+        if self.isWindows:
+            submitTemplate = submitTemplate.replace("\n", "\r\n")
+            separatorLine = separatorLine.replace("\n", "\r\n")
+            newdiff = newdiff.replace("\n", "\r\n")
+        tmpFile.write(submitTemplate + separatorLine + diff + newdiff)
+        tmpFile.close()
+
+        if self.prepare_p4_only:
+            #
+            # Leave the p4 tree prepared, and the submit template around
+            # and let the user decide what to do next
+            #
+            print
+            print "P4 workspace prepared for submission."
+            print "To submit or revert, go to client workspace"
+            print "  " + self.clientPath
+            print
+            print "To submit, use \"p4 submit\" to write a new description,"
+            print "or \"p4 submit -i %s\" to use the one prepared by" \
+                  " \"git p4\"." % fileName
+            print "You can delete the file \"%s\" when finished." % fileName
+
+            if self.preserveUser and p4User and not self.p4UserIsMe(p4User):
+                print "To preserve change ownership by user %s, you must\n" \
+                      "do \"p4 change -f <change>\" after submitting and\n" \
+                      "edit the User field."
+            if pureRenameCopy:
+                print "After submitting, renamed files must be re-synced."
+                print "Invoke \"p4 sync -f\" on each of these files:"
                 for f in pureRenameCopy:
-                    p4_sync(f, "-f")
+                    print "  " + f
 
-            else:
-                # skip this patch
-                print "Submission cancelled, undoing p4 changes."
-                for f in editedFiles:
-                    p4_revert(f)
+            print
+            print "To revert the changes, use \"p4 revert ...\", and delete"
+            print "the submit template file \"%s\"" % fileName
+            if filesToAdd:
+                print "Since the commit adds new files, they must be deleted:"
                 for f in filesToAdd:
-                    p4_revert(f)
-                    os.remove(f)
+                    print "  " + f
+            print
+            return True
+
+        #
+        # Let the user edit the change description, then submit it.
+        #
+        if self.edit_template(fileName):
+            # read the edited message and submit
+            ret = True
+            tmpFile = open(fileName, "rb")
+            message = tmpFile.read()
+            tmpFile.close()
+            submitTemplate = message[:message.index(separatorLine)]
+            if self.isWindows:
+                submitTemplate = submitTemplate.replace("\r\n", "\n")
+            p4_write_pipe(['submit', '-i'], submitTemplate)
+
+            if self.preserveUser:
+                if p4User:
+                    # Get last changelist number. Cannot easily get it from
+                    # the submit command output as the output is
+                    # unmarshalled.
+                    changelist = self.lastP4Changelist()
+                    self.modifyChangelistUser(changelist, p4User)
+
+            # The rename/copy happened by applying a patch that created a
+            # new file.  This leaves it writable, which confuses p4.
+            for f in pureRenameCopy:
+                p4_sync(f, "-f")
 
-            os.remove(fileName)
         else:
-            fileName = "submit.txt"
-            file = open(fileName, "w+")
-            file.write(self.prepareLogMessage(template, logMessage))
-            file.close()
-            print ("Perforce submit template written as %s. "
-                   + "Please review/edit and then use p4 submit -i < %s to submit directly!"
-                   % (fileName, fileName))
+            # skip this patch
+            ret = False
+            print "Submission cancelled, undoing p4 changes."
+            for f in editedFiles:
+                p4_revert(f)
+            for f in filesToAdd:
+                p4_revert(f)
+                os.remove(f)
+            for f in filesToDelete:
+                p4_revert(f)
+
+        os.remove(fileName)
+        return ret
 
     # Export git tags as p4 labels. Create a p4 label and then tag
     # with that.
@@ -1346,14 +1411,20 @@ class P4Submit(Command, P4UserMap):
             for mapping in clientSpec.mappings:
                 labelTemplate += "\t%s\n" % mapping.depot_side.path
 
-            p4_write_pipe(["label", "-i"], labelTemplate)
+            if self.dry_run:
+                print "Would create p4 label %s for tag" % name
+            elif self.prepare_p4_only:
+                print "Not creating p4 label %s for tag due to option" \
+                      " --prepare-p4-only" % name
+            else:
+                p4_write_pipe(["label", "-i"], labelTemplate)
 
-            # Use the label
-            p4_system(["tag", "-l", name] +
-                      ["%s@%s" % (mapping.depot_side.path, changelist) for mapping in clientSpec.mappings])
+                # Use the label
+                p4_system(["tag", "-l", name] +
+                          ["%s@%s" % (mapping.depot_side.path, changelist) for mapping in clientSpec.mappings])
 
-            if verbose:
-                print "created p4 label for tag %s" % name
+                if verbose:
+                    print "created p4 label for tag %s" % name
 
     def run(self, args):
         if len(args) == 0:
@@ -1380,6 +1451,16 @@ class P4Submit(Command, P4UserMap):
             if not self.canChangeChangelists():
                 die("Cannot preserve user names without p4 super-user or admin permissions")
 
+        # if not set from the command line, try the config file
+        if self.conflict_behavior is None:
+            val = gitConfig("git-p4.conflict")
+            if val:
+                if val not in self.conflict_behavior_choices:
+                    die("Invalid value '%s' for config git-p4.conflict" % val)
+            else:
+                val = "ask"
+            self.conflict_behavior = val
+
         if self.verbose:
             print "Origin branch is " + self.origin
 
@@ -1412,12 +1493,15 @@ class P4Submit(Command, P4UserMap):
             os.makedirs(self.clientPath)
 
         chdir(self.clientPath)
-        print "Synchronizing p4 checkout..."
-        if new_client_dir:
-            # old one was destroyed, and maybe nobody told p4
-            p4_sync("...", "-f")
+        if self.dry_run:
+            print "Would synchronize p4 checkout in %s" % self.clientPath
         else:
-            p4_sync("...")
+            print "Synchronizing p4 checkout..."
+            if new_client_dir:
+                # old one was destroyed, and maybe nobody told p4
+                p4_sync("...", "-f")
+            else:
+                p4_sync("...")
         self.check()
 
         commits = []
@@ -1433,16 +1517,95 @@ class P4Submit(Command, P4UserMap):
         if self.preserveUser:
             self.checkValidP4Users(commits)
 
-        while len(commits) > 0:
-            commit = commits[0]
-            commits = commits[1:]
-            self.applyCommit(commit)
-            if not self.interactive:
-                break
+        #
+        # Build up a set of options to be passed to diff when
+        # submitting each commit to p4.
+        #
+        if self.detectRenames:
+            # command-line -M arg
+            self.diffOpts = "-M"
+        else:
+            # If not explicitly set check the config variable
+            detectRenames = gitConfig("git-p4.detectRenames")
+
+            if detectRenames.lower() == "false" or detectRenames == "":
+                self.diffOpts = ""
+            elif detectRenames.lower() == "true":
+                self.diffOpts = "-M"
+            else:
+                self.diffOpts = "-M%s" % detectRenames
+
+        # no command-line arg for -C or --find-copies-harder, just
+        # config variables
+        detectCopies = gitConfig("git-p4.detectCopies")
+        if detectCopies.lower() == "false" or detectCopies == "":
+            pass
+        elif detectCopies.lower() == "true":
+            self.diffOpts += " -C"
+        else:
+            self.diffOpts += " -C%s" % detectCopies
+
+        if gitConfig("git-p4.detectCopiesHarder", "--bool") == "true":
+            self.diffOpts += " --find-copies-harder"
+
+        #
+        # Apply the commits, one at a time.  On failure, ask if should
+        # continue to try the rest of the patches, or quit.
+        #
+        if self.dry_run:
+            print "Would apply"
+        applied = []
+        last = len(commits) - 1
+        for i, commit in enumerate(commits):
+            if self.dry_run:
+                print " ", read_pipe(["git", "show", "-s",
+                                      "--format=format:%h %s", commit])
+                ok = True
+            else:
+                ok = self.applyCommit(commit)
+            if ok:
+                applied.append(commit)
+            else:
+                if self.prepare_p4_only and i < last:
+                    print "Processing only the first commit due to option" \
+                          " --prepare-p4-only"
+                    break
+                if i < last:
+                    quit = False
+                    while True:
+                        # prompt for what to do, or use the option/variable
+                        if self.conflict_behavior == "ask":
+                            print "What do you want to do?"
+                            response = raw_input("[s]kip this commit but apply"
+                                                 " the rest, or [q]uit? ")
+                            if not response:
+                                continue
+                        elif self.conflict_behavior == "skip":
+                            response = "s"
+                        elif self.conflict_behavior == "quit":
+                            response = "q"
+                        else:
+                            die("Unknown conflict_behavior '%s'" %
+                                self.conflict_behavior)
+
+                        if response[0] == "s":
+                            print "Skipping this commit, but applying the rest"
+                            break
+                        if response[0] == "q":
+                            print "Quitting"
+                            quit = True
+                            break
+                    if quit:
+                        break
+
+        chdir(self.oldWorkingDirectory)
 
-        if len(commits) == 0:
-            print "All changes applied!"
-            chdir(self.oldWorkingDirectory)
+        if self.dry_run:
+            pass
+        elif self.prepare_p4_only:
+            pass
+        elif len(commits) == len(applied):
+            print "All commits applied!"
 
             sync = P4Sync()
             sync.run([])
@@ -1450,6 +1613,20 @@ class P4Submit(Command, P4UserMap):
             rebase = P4Rebase()
             rebase.rebase()
 
+        else:
+            if len(applied) == 0:
+                print "No commits applied."
+            else:
+                print "Applied only the commits marked with '*':"
+                for c in commits:
+                    if c in applied:
+                        star = "*"
+                    else:
+                        star = " "
+                    print star, read_pipe(["git", "show", "-s",
+                                           "--format=format:%h %s",  c])
+                print "You will have to do 'git p4 sync' and rebase."
+
         if gitConfig("git-p4.exportLabels", "--bool") == "true":
             self.exportLabels = True
 
@@ -1460,6 +1637,10 @@ class P4Submit(Command, P4UserMap):
             missingGitTags = gitTags - p4Labels
             self.exportGitTags(missingGitTags)
 
+        # exit with error unless everything applied perfecly
+        if len(commits) != len(applied):
+                sys.exit(1)
+
         return True
 
 class View(object):
@@ -1766,19 +1947,41 @@ class P4Sync(Command, P4UserMap):
         return files
 
     def stripRepoPath(self, path, prefixes):
-        if self.useClientSpec:
-            return self.clientSpecDirs.map_in_client(path)
+        """When streaming files, this is called to map a p4 depot path
+           to where it should go in git.  The prefixes are either
+           self.depotPaths, or self.branchPrefixes in the case of
+           branch detection."""
 
-        if self.keepRepoPath:
-            prefixes = [re.sub("^(//[^/]+/).*", r'\1', prefixes[0])]
+        if self.useClientSpec:
+            # branch detection moves files up a level (the branch name)
+            # from what client spec interpretation gives
+            path = self.clientSpecDirs.map_in_client(path)
+            if self.detectBranches:
+                for b in self.knownBranches:
+                    if path.startswith(b + "/"):
+                        path = path[len(b)+1:]
+
+        elif self.keepRepoPath:
+            # Preserve everything in relative path name except leading
+            # //depot/; just look at first prefix as they all should
+            # be in the same depot.
+            depot = re.sub("^(//[^/]+/).*", r'\1', prefixes[0])
+            if p4PathStartsWith(path, depot):
+                path = path[len(depot):]
 
-        for p in prefixes:
-            if p4PathStartsWith(path, p):
-                path = path[len(p):]
+        else:
+            for p in prefixes:
+                if p4PathStartsWith(path, p):
+                    path = path[len(p):]
+                    break
 
+        path = wildcard_decode(path)
         return path
 
     def splitFilesIntoBranches(self, commit):
+        """Look at each depotFile in the commit to figure out to what
+           branch it belongs."""
+
         branches = {}
         fnum = 0
         while commit.has_key("depotFile%s" % fnum):
@@ -1796,12 +1999,16 @@ class P4Sync(Command, P4UserMap):
             file["type"] = commit["type%s" % fnum]
             fnum = fnum + 1
 
-            relPath = self.stripRepoPath(path, self.depotPaths)
-            relPath = wildcard_decode(relPath)
+            # start with the full relative path where this file would
+            # go in a p4 client
+            if self.useClientSpec:
+                relPath = self.clientSpecDirs.map_in_client(path)
+            else:
+                relPath = self.stripRepoPath(path, self.depotPaths)
 
             for branch in self.knownBranches.keys():
-
-                # add a trailing slash so that a commit into qt/4.2foo doesn't end up in qt/4.2
+                # add a trailing slash so that a commit into qt/4.2foo
+                # doesn't end up in qt/4.2, e.g.
                 if relPath.startswith(branch + "/"):
                     if branch not in branches:
                         branches[branch] = []
@@ -1815,7 +2022,6 @@ class P4Sync(Command, P4UserMap):
 
     def streamOneP4File(self, file, contents):
         relPath = self.stripRepoPath(file['depotFile'], self.branchPrefixes)
-        relPath = wildcard_decode(relPath)
         if verbose:
             sys.stderr.write("%s\n" % relPath)
 
@@ -1884,7 +2090,6 @@ class P4Sync(Command, P4UserMap):
 
     def streamOneP4Deletion(self, file):
         relPath = self.stripRepoPath(file['path'], self.branchPrefixes)
-        relPath = wildcard_decode(relPath)
         if verbose:
             sys.stderr.write("delete %s\n" % relPath)
         self.gitStream.write("D %s\n" % relPath)
@@ -1989,10 +2194,9 @@ class P4Sync(Command, P4UserMap):
         gitStream.write(description)
         gitStream.write("\n")
 
-    def commit(self, details, files, branch, branchPrefixes, parent = ""):
+    def commit(self, details, files, branch, parent = ""):
         epoch = details["time"]
         author = details["user"]
-        self.branchPrefixes = branchPrefixes
 
         if self.verbose:
             print "commit into %s" % branch
@@ -2001,7 +2205,7 @@ class P4Sync(Command, P4UserMap):
         # create a commit.
         new_files = []
         for f in files:
-            if [p for p in branchPrefixes if p4PathStartsWith(f['path'], p)]:
+            if [p for p in self.branchPrefixes if p4PathStartsWith(f['path'], p)]:
                 new_files.append (f)
             else:
                 sys.stderr.write("Ignoring file outside of prefix: %s\n" % f['path'])
@@ -2018,8 +2222,8 @@ class P4Sync(Command, P4UserMap):
 
         self.gitStream.write("data <<EOT\n")
         self.gitStream.write(details["desc"])
-        self.gitStream.write("\n[git-p4: depot-paths = \"%s\": change = %s"
-                             % (','.join (branchPrefixes), details["change"]))
+        self.gitStream.write("\n[git-p4: depot-paths = \"%s\": change = %s" %
+                             (','.join(self.branchPrefixes), details["change"]))
         if len(details['options']) > 0:
             self.gitStream.write(": options = %s" % details['options'])
         self.gitStream.write("]\nEOT\n\n")
@@ -2042,7 +2246,7 @@ class P4Sync(Command, P4UserMap):
                 print "Change %s is labelled %s" % (change, labelDetails)
 
             files = p4CmdList(["files"] + ["%s...@%s" % (p, change)
-                                                    for p in branchPrefixes])
+                                                for p in self.branchPrefixes])
 
             if len(files) == len(labelRevisions):
 
@@ -2353,6 +2557,7 @@ class P4Sync(Command, P4UserMap):
                     for branch in branches.keys():
                         ## HACK  --hwn
                         branchPrefix = self.depotPaths[0] + branch + "/"
+                        self.branchPrefixes = [ branchPrefix ]
 
                         parent = ""
 
@@ -2397,19 +2602,19 @@ class P4Sync(Command, P4UserMap):
                             tempBranch = os.path.join(self.tempBranchLocation, "%d" % (change))
                             if self.verbose:
                                 print "Creating temporary branch: " + tempBranch
-                            self.commit(description, filesForCommit, tempBranch, [branchPrefix])
+                            self.commit(description, filesForCommit, tempBranch)
                             self.tempBranches.append(tempBranch)
                             self.checkpoint()
                             blob = self.searchParent(parent, branch, tempBranch)
                         if blob:
-                            self.commit(description, filesForCommit, branch, [branchPrefix], blob)
+                            self.commit(description, filesForCommit, branch, blob)
                         else:
                             if self.verbose:
                                 print "Parent of %s not found. Committing into head of %s" % (branch, parent)
-                            self.commit(description, filesForCommit, branch, [branchPrefix], parent)
+                            self.commit(description, filesForCommit, branch, parent)
                 else:
                     files = self.extractFilesFromCommit(description)
-                    self.commit(description, files, self.branch, self.depotPaths,
+                    self.commit(description, files, self.branch,
                                 self.initialParent)
                     self.initialParent = ""
             except IOError:
@@ -2473,7 +2678,7 @@ class P4Sync(Command, P4UserMap):
 
         self.updateOptionDict(details)
         try:
-            self.commit(details, self.extractFilesFromCommit(details), self.branch, self.depotPaths)
+            self.commit(details, self.extractFilesFromCommit(details), self.branch)
         except IOError:
             print "IO error with git fast-import. Is your git version recent enough?"
             print self.gitError.read()
@@ -2631,6 +2836,9 @@ class P4Sync(Command, P4UserMap):
 
         self.depotPaths = newPaths
 
+        # --detect-branches may change this for each branch
+        self.branchPrefixes = self.depotPaths
+
         self.loadUserMapFromCache()
         self.labels = {}
         if self.detectLabels:
@@ -2936,7 +3144,7 @@ def main():
 
     args = sys.argv[2:]
 
-    options.append(optparse.make_option("--verbose", dest="verbose", action="store_true"))
+    options.append(optparse.make_option("--verbose", "-v", dest="verbose", action="store_true"))
     if cmd.needsGit:
         options.append(optparse.make_option("--git-dir", dest="gitdir"))
 
index 2a10047eb710011213024bd0acc57eec87a6f965..266e682f6c518ab72dc710d52ed4f1dbe22881b5 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 04d89415fe8ca1634fa362c66ea9569794dcadd5..392ebc9790c88f9857fc4e943d1fe6351e953c7d 100644 (file)
@@ -3,8 +3,6 @@
 # Copyright (c) 2010 Junio C Hamano.
 #
 
-. git-sh-setup
-
 case "$action" in
 continue)
        git am --resolved --resolvemsg="$resolvemsg" &&
index 84926783d1c4956727226bbabe796467819d36e5..44901d53c43d972e03a71bfbe0b769f2e8f22d7b 100644 (file)
@@ -9,9 +9,7 @@
 #
 # The original idea comes from Eric W. Biederman, in
 # http://article.gmane.org/gmane.comp.version-control.git/22407
-
-. git-sh-setup
-
+#
 # The file containing rebase commands, comments, and empty lines.
 # This file is created by "git rebase -i" then edited by the user.  As
 # the lines are processed, they are removed from the front of this
@@ -117,6 +115,23 @@ mark_action_done () {
        fi
 }
 
+append_todo_help () {
+       cat >> "$todo" << EOF
+#
+# Commands:
+#  p, pick = use commit
+#  r, reword = use commit, but edit the commit message
+#  e, edit = use commit, but stop for amending
+#  s, squash = use commit, but meld into previous commit
+#  f, fixup = like "squash", but discard this commit's log message
+#  x, exec = run command (the rest of the line) using shell
+#
+# These lines can be re-ordered; they are executed from top to bottom.
+#
+# If you remove a line here THAT COMMIT WILL BE LOST.
+EOF
+}
+
 make_patch () {
        sha1_and_parents="$(git rev-list --parents -1 "$1")"
        case "$sha1_and_parents" in
@@ -417,6 +432,29 @@ record_in_rewritten() {
        esac
 }
 
+do_pick () {
+       if test "$(git rev-parse HEAD)" = "$squash_onto"
+       then
+               # Set the correct commit message and author info on the
+               # sentinel root before cherry-picking the original changes
+               # without committing (-n).  Finally, update the sentinel again
+               # to include these changes.  If the cherry-pick results in a
+               # conflict, this means our behaviour is similar to a standard
+               # failed cherry-pick during rebase, with a dirty index to
+               # resolve before manually running git commit --amend then git
+               # rebase --continue.
+               git commit --allow-empty --allow-empty-message --amend \
+                          --no-post-rewrite -n -q -C $1 &&
+                       pick_one -n $1 &&
+                       git commit --allow-empty --allow-empty-message \
+                                  --amend --no-post-rewrite -n -q -C $1 ||
+                       die_with_patch $1 "Could not apply $1... $2"
+       else
+               pick_one $1 ||
+                       die_with_patch $1 "Could not apply $1... $2"
+       fi
+}
+
 do_next () {
        rm -f "$msg" "$author_script" "$amend" || exit
        read -r command sha1 rest < "$todo"
@@ -428,16 +466,14 @@ do_next () {
                comment_for_reflog pick
 
                mark_action_done
-               pick_one $sha1 ||
-                       die_with_patch $sha1 "Could not apply $sha1... $rest"
+               do_pick $sha1 "$rest"
                record_in_rewritten $sha1
                ;;
        reword|r)
                comment_for_reflog reword
 
                mark_action_done
-               pick_one $sha1 ||
-                       die_with_patch $sha1 "Could not apply $sha1... $rest"
+               do_pick $sha1 "$rest"
                git commit --amend --no-post-rewrite || {
                        warn "Could not amend commit after successfully picking $sha1... $rest"
                        warn "This is most likely due to an empty commit message, or the pre-commit hook"
@@ -451,8 +487,7 @@ do_next () {
                comment_for_reflog edit
 
                mark_action_done
-               pick_one $sha1 ||
-                       die_with_patch $sha1 "Could not apply $sha1... $rest"
+               do_pick $sha1 "$rest"
                warn "Stopped at $sha1... $rest"
                exit_with_patch $sha1 0
                ;;
@@ -475,25 +510,28 @@ do_next () {
                author_script_content=$(get_author_ident_from_commit HEAD)
                echo "$author_script_content" > "$author_script"
                eval "$author_script_content"
-               output git reset --soft HEAD^
-               pick_one -n $sha1 || die_failed_squash $sha1 "$rest"
+               if ! pick_one -n $sha1
+               then
+                       git rev-parse --verify HEAD >"$amend"
+                       die_failed_squash $sha1 "$rest"
+               fi
                case "$(peek_next_command)" in
                squash|s|fixup|f)
                        # This is an intermediate commit; its message will only be
                        # used in case of trouble.  So use the long version:
-                       do_with_author output git commit --no-verify -F "$squash_msg" ||
+                       do_with_author output git commit --amend --no-verify -F "$squash_msg" ||
                                die_failed_squash $sha1 "$rest"
                        ;;
                *)
                        # This is the final command of this squash/fixup group
                        if test -f "$fixup_msg"
                        then
-                               do_with_author git commit --no-verify -F "$fixup_msg" ||
+                               do_with_author git commit --amend --no-verify -F "$fixup_msg" ||
                                        die_failed_squash $sha1 "$rest"
                        else
                                cp "$squash_msg" "$GIT_DIR"/SQUASH_MSG || exit
                                rm -f "$GIT_DIR"/MERGE_MSG
-                               do_with_author git commit --no-verify -e ||
+                               do_with_author git commit --amend --no-verify -F "$GIT_DIR"/SQUASH_MSG -e ||
                                        die_failed_squash $sha1 "$rest"
                        fi
                        rm -f "$squash_msg" "$fixup_msg"
@@ -523,6 +561,10 @@ do_next () {
                        warn
                        warn "  git rebase --continue"
                        warn
+                       if test $status -eq 127         # command not found
+                       then
+                               status=1
+                       fi
                        exit "$status"
                elif test "$dirty" = t
                then
@@ -537,11 +579,12 @@ do_next () {
                ;;
        *)
                warn "Unknown command: $command $sha1 $rest"
+               fixtodo="Please fix this using 'git rebase --edit-todo'."
                if git rev-parse --verify -q "$sha1" >/dev/null
                then
-                       die_with_patch $sha1 "Please fix this in the file $todo."
+                       die_with_patch $sha1 "$fixtodo"
                else
-                       die "Please fix this in the file $todo."
+                       die "$fixtodo"
                fi
                ;;
        esac
@@ -683,6 +726,27 @@ rearrange_squash () {
        rm -f "$1.sq" "$1.rearranged"
 }
 
+# Add commands after a pick or after a squash/fixup serie
+# in the todo list.
+add_exec_commands () {
+       {
+               first=t
+               while read -r insn rest
+               do
+                       case $insn in
+                       pick)
+                               test -n "$first" ||
+                               printf "%s" "$cmd"
+                               ;;
+                       esac
+                       printf "%s %s\n" "$insn" "$rest"
+                       first=
+               done
+               printf "%s" "$cmd"
+       } <"$1" >"$1.new" &&
+       mv "$1.new" "$1"
+}
+
 case "$action" in
 continue)
        # do we have anything to commit?
@@ -708,7 +772,6 @@ In both case, once you're done, continue with:
                fi
                . "$author_script" ||
                        die "Error trying to find the author identity to amend commit"
-               current_head=
                if test -f "$amend"
                then
                        current_head=$(git rev-parse --verify HEAD)
@@ -716,13 +779,12 @@ In both case, once you're done, continue with:
                        die "\
 You have uncommitted changes in your working tree. Please, commit them
 first and then run 'git rebase --continue' again."
-                       git reset --soft HEAD^ ||
-                       die "Cannot rewind the HEAD"
+                       do_with_author git commit --amend --no-verify -F "$msg" -e ||
+                               die "Could not commit staged changes."
+               else
+                       do_with_author git commit --no-verify -F "$msg" -e ||
+                               die "Could not commit staged changes."
                fi
-               do_with_author git commit --no-verify -F "$msg" -e || {
-                       test -n "$current_head" && git reset --soft $current_head
-                       die "Could not commit staged changes."
-               }
        fi
 
        record_in_rewritten "$(cat "$state_dir"/stopped-sha)"
@@ -735,6 +797,23 @@ skip)
 
        do_rest
        ;;
+edit-todo)
+       sed -e '/^#/d' < "$todo" > "$todo".new
+       mv -f "$todo".new "$todo"
+       append_todo_help
+       cat >> "$todo" << EOF
+#
+# You are editing the todo file of an ongoing interactive rebase.
+# To continue rebase after editing, run:
+#     git rebase --continue
+#
+EOF
+
+       git_sequence_editor "$todo" ||
+               die "Could not execute editor"
+
+       exit
+       ;;
 esac
 
 git var GIT_COMMITTER_IDENT >/dev/null ||
@@ -856,21 +935,15 @@ fi
 
 test -s "$todo" || echo noop >> "$todo"
 test -n "$autosquash" && rearrange_squash "$todo"
+test -n "$cmd" && add_exec_commands "$todo"
+
 cat >> "$todo" << EOF
 
 # Rebase $shortrevisions onto $shortonto
+EOF
+append_todo_help
+cat >> "$todo" << EOF
 #
-# Commands:
-#  p, pick = use commit
-#  r, reword = use commit, but edit the commit message
-#  e, edit = use commit, but stop for amending
-#  s, squash = use commit, but meld into previous commit
-#  f, fixup = like "squash", but discard this commit's log message
-#  x, exec = run command (the rest of the line) using shell
-#
-# These lines can be re-ordered; they are executed from top to bottom.
-#
-# If you remove a line here THAT COMMIT WILL BE LOST.
 # However, if you remove everything, the rebase will be aborted.
 #
 EOF
index dc599077f0e55472ae814ed4e15f5b3a1b729caf..b10f2cf21b904bbbc3fafc27d183d8ad7917b479 100644 (file)
@@ -3,8 +3,6 @@
 # Copyright (c) 2010 Junio C Hamano.
 #
 
-. git-sh-setup
-
 prec=4
 
 read_state () {
index e6167374445dfbb5e0b6bedc9a5f33a01cb5a7df..b2f1c76dc3ede707870564a8ba73af6d1753e95c 100755 (executable)
@@ -3,36 +3,12 @@
 # Copyright (c) 2005 Junio C Hamano.
 #
 
-USAGE='[--interactive | -i] [-v] [--force-rebase | -f] [--no-ff] [--onto <newbase>] [<upstream>|--root] [<branch>] [--quiet | -q]'
-LONG_USAGE='git-rebase replaces <branch> with a new branch of the
-same name.  When the --onto option is provided the new branch starts
-out with a HEAD equal to <newbase>, otherwise it is equal to <upstream>
-It then attempts to create a new commit for each commit from the original
-<branch> that does not exist in the <upstream> branch.
-
-It is possible that a merge failure will prevent this process from being
-completely automatic.  You will have to resolve any such merge failure
-and run git rebase --continue.  Another option is to bypass the commit
-that caused the merge failure with git rebase --skip.  To check out the
-original <branch> and remove the .git/rebase-apply working files, use the
-command git rebase --abort instead.
-
-Note that if <branch> is not specified on the command line, the
-currently checked out branch is used.
-
-Example:       git-rebase master~1 topic
-
-       A---B---C topic                   A'\''--B'\''--C'\'' topic
-       /                   -->           /
-  D---E---F---G master          D---E---F---G master
-'
-
 SUBDIRECTORY_OK=Yes
 OPTIONS_KEEPDASHDASH=
 OPTIONS_SPEC="\
-git rebase [-i] [options] [--onto <newbase>] [<upstream>] [<branch>]
-git rebase [-i] [options] --onto <newbase> --root [<branch>]
-git-rebase [-i] --continue | --abort | --skip
+git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] [<upstream>] [<branch>]
+git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] --root [<branch>]
+git-rebase --continue | --abort | --skip | --edit-todo
 --
  Available options are
 v,verbose!         display a diffstat of what changed upstream
@@ -43,6 +19,7 @@ s,strategy=!       use the given merge strategy
 no-ff!             cherry-pick all commits, even if unchanged
 m,merge!           use merging strategies to rebase
 i,interactive!     let the user edit the list of commits to rebase
+x,exec=!           add exec lines after each commit of the editable list
 k,keep-empty      preserve empty commits during rebase
 f,force-rebase!    force rebase even if branch is up to date
 X,strategy-option=! pass the argument through to the merge strategy
@@ -61,8 +38,10 @@ C=!                passed to 'git apply'
 continue!          continue
 abort!             abort and check out the original branch
 skip!              skip current patch and continue
+edit-todo!         edit the todo list during an interactive rebase
 "
 . git-sh-setup
+. git-sh-i18n
 set_reflog_action rebase
 require_work_tree_exists
 cd_to_toplevel
@@ -71,11 +50,12 @@ LF='
 '
 ok_to_skip_pre_rebase=
 resolvemsg="
-When you have resolved this problem run \"git rebase --continue\".
-If you would prefer to skip this patch, instead run \"git rebase --skip\".
-To check out the original branch and stop rebasing run \"git rebase --abort\".
+$(gettext 'When you have resolved this problem, run "git rebase --continue".
+If you prefer to skip this patch, run "git rebase --skip" instead.
+To check out the original branch and stop rebasing, run "git rebase --abort".')
 "
 unset onto
+cmd=
 strategy=
 strategy_opts=
 do_merge=
@@ -158,7 +138,7 @@ move_to_original_branch () {
                git symbolic-ref \
                        -m "rebase finished: returning to $head_name" \
                        HEAD $head_name ||
-               die "Could not move back to $head_name"
+               die "$(gettext "Could not move back to $head_name")"
                ;;
        esac
 }
@@ -177,12 +157,12 @@ run_pre_rebase_hook () {
           test -x "$GIT_DIR/hooks/pre-rebase"
        then
                "$GIT_DIR/hooks/pre-rebase" ${1+"$@"} ||
-               die "The pre-rebase hook refused to rebase."
+               die "$(gettext "The pre-rebase hook refused to rebase.")"
        fi
 }
 
 test -f "$apply_dir"/applying &&
-       die 'It looks like git-am is in progress. Cannot rebase.'
+       die "$(gettext "It looks like git-am is in progress. Cannot rebase.")"
 
 if test -d "$apply_dir"
 then
@@ -211,7 +191,7 @@ do
        --verify)
                ok_to_skip_pre_rebase=
                ;;
-       --continue|--skip|--abort)
+       --continue|--skip|--abort|--edit-todo)
                test $total_argc -eq 2 || usage
                action=${1##--}
                ;;
@@ -220,6 +200,11 @@ do
                onto="$2"
                shift
                ;;
+       -x)
+               test 2 -le "$#" || usage
+               cmd="${cmd}exec $2${LF}"
+               shift
+               ;;
        -i)
                interactive_rebase=explicit
                ;;
@@ -305,9 +290,15 @@ do
 done
 test $# -gt 2 && usage
 
+if test -n "$cmd" &&
+   test "$interactive_rebase" != explicit
+then
+       die "$(gettext "The --exec option must be used with the --interactive option")"
+fi
+
 if test -n "$action"
 then
-       test -z "$in_progress" && die "No rebase in progress?"
+       test -z "$in_progress" && die "$(gettext "No rebase in progress?")"
        # Only interactive rebase uses detailed reflog messages
        if test "$type" = interactive && test "$GIT_REFLOG_ACTION" = rebase
        then
@@ -316,15 +307,20 @@ then
        fi
 fi
 
+if test "$action" = "edit-todo" && test "$type" != "interactive"
+then
+       die "$(gettext "The --edit-todo action can only be used during interactive rebase.")"
+fi
+
 case "$action" in
 continue)
        # Sanity check
        git rev-parse --verify HEAD >/dev/null ||
-               die "Cannot read HEAD"
+               die "$(gettext "Cannot read HEAD")"
        git update-index --ignore-submodules --refresh &&
        git diff-files --quiet --ignore-submodules || {
-               echo "You must edit all merge conflicts and then"
-               echo "mark them as resolved using git add"
+               echo "$(gettext "You must edit all merge conflicts and then
+mark them as resolved using git add")"
                exit 1
        }
        read_basic_state
@@ -341,27 +337,38 @@ abort)
        case "$head_name" in
        refs/*)
                git symbolic-ref -m "rebase: aborting" HEAD $head_name ||
-               die "Could not move back to $head_name"
+               die "$(eval_gettext "Could not move back to \$head_name")"
                ;;
        esac
        output git reset --hard $orig_head
        rm -r "$state_dir"
        exit
        ;;
+edit-todo)
+       run_specific_rebase
+       ;;
 esac
 
 # Make sure no rebase is in progress
 if test -n "$in_progress"
 then
-       die '
-It seems that there is already a '"${state_dir##*/}"' directory, and
+       state_dir_base=${state_dir##*/}
+       cmd_live_rebase="git rebase (--continue | --abort | --skip)"
+       cmd_clear_stale_rebase="rm -fr \"$state_dir\""
+       die "
+$(eval_gettext 'It seems that there is already a $state_dir_base directory, and
 I wonder if you are in the middle of another rebase.  If that is the
 case, please try
-       git rebase (--continue | --abort | --skip)
+       $cmd_live_rebase
 If that is not the case, please
-       rm -fr '"$state_dir"'
+       $cmd_clear_stale_rebase
 and run me again.  I am stopping in case you still have something
-valuable there.'
+valuable there.')"
+fi
+
+if test -n "$rebase_root" && test -z "$onto"
+then
+       test -z "$interactive_rebase" && interactive_rebase=implied
 fi
 
 if test -n "$interactive_rebase"
@@ -394,12 +401,18 @@ then
                ;;
        esac
        upstream=`git rev-parse --verify "${upstream_name}^0"` ||
-       die "invalid upstream $upstream_name"
+       die "$(eval_gettext "invalid upstream \$upstream_name")"
        upstream_arg="$upstream_name"
 else
-       test -z "$onto" && die "You must specify --onto when using --root"
+       if test -z "$onto"
+       then
+               empty_tree=`git hash-object -t tree /dev/null`
+               onto=`git commit-tree $empty_tree </dev/null`
+               squash_onto="$onto"
+       fi
        unset upstream_name
        unset upstream
+       test $# -gt 1 && usage
        upstream_arg=--root
 fi
 
@@ -412,19 +425,19 @@ case "$onto_name" in
        then
                case "$onto" in
                ?*"$LF"?*)
-                       die "$onto_name: there are more than one merge bases"
+                       die "$(eval_gettext "\$onto_name: there are more than one merge bases")"
                        ;;
                '')
-                       die "$onto_name: there is no merge base"
+                       die "$(eval_gettext "\$onto_name: there is no merge base")"
                        ;;
                esac
        else
-               die "$onto_name: there is no merge base"
+               die "$(eval_gettext "\$onto_name: there is no merge base")"
        fi
        ;;
 *)
        onto=$(git rev-parse --verify "${onto_name}^0") ||
-       die "Does not point to a valid commit: $onto_name"
+       die "$(eval_gettext "Does not point to a valid commit: \$onto_name")"
        ;;
 esac
 
@@ -447,10 +460,10 @@ case "$#" in
        then
                head_name="detached HEAD"
        else
-               die "fatal: no such branch: $1"
+               die "$(eval_gettext "fatal: no such branch: \$branch_name")"
        fi
        ;;
-*)
+0)
        # Do not need to switch branches, we are already on it.
        if branch_name=`git symbolic-ref -q HEAD`
        then
@@ -462,9 +475,12 @@ case "$#" in
        fi
        orig_head=$(git rev-parse --verify "${branch_name}^0") || exit
        ;;
+*)
+       die "BUG: unexpected number of arguments left to parse"
+       ;;
 esac
 
-require_clean_work_tree "rebase" "Please commit or stash them."
+require_clean_work_tree "rebase" "$(gettext "Please commit or stash them.")"
 
 # Now we are rebasing commits $upstream..$orig_head (or with --root,
 # everything leading up to $orig_head) on top of $onto
@@ -482,10 +498,10 @@ then
        then
                # Lazily switch to the target branch if needed...
                test -z "$switch_to" || git checkout "$switch_to" --
-               say "Current branch $branch_name is up to date."
+               say "$(eval_gettext "Current branch \$branch_name is up to date.")"
                exit 0
        else
-               say "Current branch $branch_name is up to date, rebase forced."
+               say "$(eval_gettext "Current branch \$branch_name is up to date, rebase forced.")"
        fi
 fi
 
@@ -496,7 +512,7 @@ if test -n "$diffstat"
 then
        if test -n "$verbose"
        then
-               echo "Changes from $mb to $onto:"
+               echo "$(eval_gettext "Changes from \$mb to \$onto:")"
        fi
        # We want color (if set), but no pager
        GIT_PAGER='' git diff --stat --summary "$mb" "$onto"
@@ -505,7 +521,7 @@ fi
 test "$type" = interactive && run_specific_rebase
 
 # Detach HEAD and reset the tree
-say "First, rewinding head to replay your work on top of it..."
+say "$(gettext "First, rewinding head to replay your work on top of it...")"
 git checkout -q "$onto^0" || die "could not detach HEAD"
 git update-ref ORIG_HEAD $orig_head
 
@@ -513,7 +529,7 @@ git update-ref ORIG_HEAD $orig_head
 # we just fast-forwarded.
 if test "$mb" = "$orig_head"
 then
-       say "Fast-forwarded $branch_name to $onto_name."
+       say "$(eval_gettext "Fast-forwarded \$branch_name to \$onto_name.")"
        move_to_original_branch
        exit 0
 fi
index 664713709c0b6e6e4974faa8f0800df2f0beb8e5..aea66a0d47a9ad64fe805351c631fe5fddbf6182 100755 (executable)
@@ -681,6 +681,7 @@ sub ask {
        my ($prompt, %arg) = @_;
        my $valid_re = $arg{valid_re};
        my $default = $arg{default};
+       my $confirm_only = $arg{confirm_only};
        my $resp;
        my $i = 0;
        return defined $default ? $default : undef
@@ -698,6 +699,12 @@ sub ask {
                if (!defined $valid_re or $resp =~ /$valid_re/) {
                        return $resp;
                }
+               if ($confirm_only) {
+                       my $yesno = $term->readline("Are you sure you want to use <$resp> [y/N]? ");
+                       if (defined $yesno && $yesno =~ /y/i) {
+                               return $resp;
+                       }
+               }
        }
        return undef;
 }
@@ -745,13 +752,16 @@ my $prompting = 0;
 if (!defined $sender) {
        $sender = $repoauthor || $repocommitter || '';
        $sender = ask("Who should the emails appear to be from? [$sender] ",
-                     default => $sender);
+                     default => $sender,
+                     valid_re => qr/\@.*\./, confirm_only => 1);
        print "Emails will be sent from: ", $sender, "\n";
        $prompting++;
 }
 
 if (!@initial_to && !defined $to_cmd) {
-       my $to = ask("Who should the emails be sent to? ");
+       my $to = ask("Who should the emails be sent to (if any)? ",
+                    default => "",
+                    valid_re => qr/\@.*\./, confirm_only => 1);
        push @initial_to, parse_address_line($to) if defined $to; # sanitized/validated later
        $prompting++;
 }
@@ -777,7 +787,9 @@ sub expand_one_alias {
 
 if ($thread && !defined $initial_reply_to && $prompting) {
        $initial_reply_to = ask(
-               "Message-ID to be used as In-Reply-To for the first email? ");
+               "Message-ID to be used as In-Reply-To for the first email (if any)? ",
+               default => "",
+               valid_re => qr/\@.*\./, confirm_only => 1);
 }
 if (defined $initial_reply_to) {
        $initial_reply_to =~ s/^\s*<?//;
index ee0e0bc045bb7d92045a3afb0a042748834e6163..22f0aed6db366c3d4a291b3ae646c45002ff86c1 100644 (file)
@@ -191,28 +191,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 e89b516039347ce8d3f28efaf8894d75e6bf1d8e..3d1617fa9eb490463f9a4a4218082de168e1491a 100755 (executable)
@@ -5,7 +5,7 @@
 # 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>...]
@@ -29,8 +29,24 @@ files=
 nofetch=
 update=
 prefix=
+custom_name=
 
-# Resolve relative url by appending to parent's url
+# The function takes at most 2 arguments. The first argument is the
+# URL that navigates to the submodule origin repo. When relative, this URL
+# is relative to the superproject origin URL repo. The second up_path
+# argument, if specified, is the relative path that navigates
+# from the submodule working tree to the superproject working tree.
+#
+# The output of the function is the origin URL of the submodule.
+#
+# The output will either be an absolute URL or filesystem path (if the
+# superproject origin URL is an absolute URL or filesystem path,
+# respectively) or a relative file system path (if the superproject
+# origin URL is a relative file system path).
+#
+# When the output is a relative file system path, the path is either
+# relative to the submodule working tree, if up_path is specified, or to
+# the superproject working tree otherwise.
 resolve_relative_url ()
 {
        remote=$(get_default_remote)
@@ -39,6 +55,21 @@ resolve_relative_url ()
        url="$1"
        remoteurl=${remoteurl%/}
        sep=/
+       up_path="$2"
+
+       case "$remoteurl" in
+       *:*|/*)
+               is_relative=
+               ;;
+       ./*|../*)
+               is_relative=t
+               ;;
+       *)
+               is_relative=t
+               remoteurl="./$remoteurl"
+               ;;
+       esac
+
        while test -n "$url"
        do
                case "$url" in
@@ -53,7 +84,12 @@ resolve_relative_url ()
                                sep=:
                                ;;
                        *)
-                               die "$(eval_gettext "cannot strip one component off url '\$remoteurl'")"
+                               if test -z "$is_relative" || test "." = "$remoteurl"
+                               then
+                                       die "$(eval_gettext "cannot strip one component off url '\$remoteurl'")"
+                               else
+                                       remoteurl=.
+                               fi
                                ;;
                        esac
                        ;;
@@ -64,7 +100,8 @@ resolve_relative_url ()
                        break;;
                esac
        done
-       echo "$remoteurl$sep${url%/}"
+       remoteurl="$remoteurl$sep${url%/}"
+       echo "${is_relative:+${up_path}}${remoteurl#./}"
 }
 
 #
@@ -143,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
@@ -153,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)
@@ -167,8 +203,11 @@ module_clone()
                rm -f "$gitdir/index"
        else
                mkdir -p "$gitdir_base"
-               git clone $quiet -n ${reference:+"$reference"} \
-                       --separate-git-dir "$gitdir" "$url" "$sm_path" ||
+               (
+                       clear_local_git_env
+                       git clone $quiet -n ${reference:+"$reference"} \
+                               --separate-git-dir "$gitdir" "$url" "$sm_path"
+               ) ||
                die "$(eval_gettext "Clone of '\$url' into submodule path '\$sm_path' failed")"
        fi
 
@@ -231,6 +270,10 @@ cmd_add()
                        ;;
                --reference=*)
                        reference="$1"
+                       ;;
+               --name)
+                       case "$2" in '') usage ;; esac
+                       custom_name=$2
                        shift
                        ;;
                --)
@@ -297,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
@@ -308,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" &&
@@ -320,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'")"
 }
@@ -555,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
@@ -737,7 +800,7 @@ cmd_summary() {
        if [ -n "$files" ]
        then
                test -n "$cached" &&
-               die "$(gettext -- "--cached cannot be used with --files")"
+               die "$(gettext "The --cached option cannot be used with the --files option")"
                diff_cmd=diff-files
                head=
        fi
@@ -994,14 +1057,26 @@ cmd_sync()
                # Possibly a url relative to parent
                case "$url" in
                ./*|../*)
-                       url=$(resolve_relative_url "$url") || exit
+                       # rewrite foo/bar as ../.. to find path from
+                       # submodule work tree to superproject work tree
+                       up_path="$(echo "$sm_path" | sed "s/[^/][^/]*/../g")" &&
+                       # guarantee a trailing /
+                       up_path=${up_path%/}/ &&
+                       # path from submodule work tree to submodule origin repo
+                       sub_origin_url=$(resolve_relative_url "$url" "$up_path") &&
+                       # path from superproject work tree to submodule origin repo
+                       super_config_url=$(resolve_relative_url "$url") || exit
+                       ;;
+               *)
+                       sub_origin_url="$url"
+                       super_config_url="$url"
                        ;;
                esac
 
                if git config "submodule.$name.url" >/dev/null 2>/dev/null
                then
                        say "$(eval_gettext "Synchronizing submodule url for '\$name'")"
-                       git config submodule."$name".url "$url"
+                       git config submodule."$name".url "$super_config_url"
 
                        if test -e "$sm_path"/.git
                        then
@@ -1009,7 +1084,7 @@ cmd_sync()
                                clear_local_git_env
                                cd "$sm_path"
                                remote=$(get_default_remote)
-                               git config remote."$remote".url "$url"
+                               git config remote."$remote".url "$sub_origin_url"
                        )
                        fi
                fi
@@ -1056,7 +1131,15 @@ do
 done
 
 # No command word defaults to "status"
-test -n "$command" || command=status
+if test -z "$command"
+then
+    if test $# = 0
+    then
+       command=status
+    else
+       usage
+    fi
+fi
 
 # "-b branch" is accepted only by "add"
 if test -n "$branch" && test "$command" != add
index 0b074c4c63ebb6e1334cf05371cd22087fb79f63..bd5266c86b299bbc75878b7529820798d194fc72 100755 (executable)
@@ -10,6 +10,52 @@ use vars qw/ $AUTHOR $VERSION
 $AUTHOR = 'Eric Wong <normalperson@yhbt.net>';
 $VERSION = '@@GIT_VERSION@@';
 
+use Carp qw/croak/;
+use Digest::MD5;
+use IO::File qw//;
+use File::Basename qw/dirname basename/;
+use File::Path qw/mkpath/;
+use File::Spec;
+use File::Find;
+use Getopt::Long qw/:config gnu_getopt no_ignore_case auto_abbrev/;
+use IPC::Open3;
+use Memoize;
+
+use Git::SVN;
+use Git::SVN::Editor;
+use Git::SVN::Fetcher;
+use Git::SVN::Ra;
+use Git::SVN::Prompt;
+use Git::SVN::Log;
+use Git::SVN::Migration;
+
+use Git::SVN::Utils qw(
+       fatal
+       can_compress
+       canonicalize_path
+       canonicalize_url
+       join_paths
+       add_path_to_url
+       join_paths
+);
+
+use Git qw(
+       git_cmd_try
+       command
+       command_oneline
+       command_noisy
+       command_output_pipe
+       command_close_pipe
+       command_bidi_pipe
+       command_close_bidi_pipe
+);
+
+BEGIN {
+       Memoize::memoize 'Git::config';
+       Memoize::memoize 'Git::config_bool';
+}
+
+
 # From which subdir have we been invoked?
 my $cmd_dir_prefix = eval {
        command_oneline([qw/rev-parse --show-prefix/], STDERR => 0)
@@ -17,10 +63,7 @@ my $cmd_dir_prefix = eval {
 
 my $git_dir_user_set = 1 if defined $ENV{GIT_DIR};
 $ENV{GIT_DIR} ||= '.git';
-$Git::SVN::default_repo_id = 'svn';
-$Git::SVN::default_ref_id = $ENV{GIT_SVN_ID} || 'git-svn';
 $Git::SVN::Ra::_log_window_size = 100;
-$Git::SVN::_minimize_url = 'unset';
 
 if (! exists $ENV{SVN_SSH} && exists $ENV{GIT_SSH}) {
        $ENV{SVN_SSH} = $ENV{GIT_SSH};
@@ -35,8 +78,6 @@ $Git::SVN::Log::TZ = $ENV{TZ};
 $ENV{TZ} = 'UTC';
 $| = 1; # unbuffer STDOUT
 
-sub fatal (@) { print STDERR "@_\n"; exit 1 }
-
 # All SVN commands do it.  Otherwise we may die on SIGPIPE when the remote
 # repository decides to close the connection which we expect to be kept alive.
 $SIG{PIPE} = 'IGNORE';
@@ -66,39 +107,6 @@ sub _req_svn {
                fatal "Need SVN::Core 1.1.0 or better (got $SVN::Core::VERSION)";
        }
 }
-my $can_compress = eval { require Compress::Zlib; 1};
-use Carp qw/croak/;
-use Digest::MD5;
-use IO::File qw//;
-use File::Basename qw/dirname basename/;
-use File::Path qw/mkpath/;
-use File::Spec;
-use File::Find;
-use Getopt::Long qw/:config gnu_getopt no_ignore_case auto_abbrev/;
-use IPC::Open3;
-use Git;
-use Git::SVN::Editor qw//;
-use Git::SVN::Fetcher qw//;
-use Git::SVN::Ra qw//;
-use Git::SVN::Prompt qw//;
-use Memoize;  # core since 5.8.0, Jul 2002
-
-BEGIN {
-       # import functions from Git into our packages, en masse
-       no strict 'refs';
-       foreach (qw/command command_oneline command_noisy command_output_pipe
-                   command_input_pipe command_close_pipe
-                   command_bidi_pipe command_close_bidi_pipe/) {
-               for my $package ( qw(Git::SVN::Migration Git::SVN::Log Git::SVN),
-                       __PACKAGE__) {
-                       *{"${package}::$_"} = \&{"Git::$_"};
-               }
-       }
-       Memoize::memoize 'Git::config';
-       Memoize::memoize 'Git::config_bool';
-}
-
-my ($SVN);
 
 $sha1 = qr/[a-f\d]{40}/;
 $sha1_short = qr/[a-f\d]{4,40}/;
@@ -108,8 +116,11 @@ my ($_stdin, $_help, $_edit,
        $_version, $_fetch_all, $_no_rebase, $_fetch_parent,
        $_merge, $_strategy, $_preserve_merges, $_dry_run, $_local,
        $_prefix, $_no_checkout, $_url, $_verbose,
-       $_git_format, $_commit_url, $_tag, $_merge_info, $_interactive);
-$Git::SVN::_follow_parent = 1;
+       $_commit_url, $_tag, $_merge_info, $_interactive);
+
+# This is a refactoring artifact so Git::SVN can get at this git-svn switch.
+sub opt_prefix { return $_prefix || '' }
+
 $Git::SVN::Fetcher::_placeholder_filename = ".gitignore";
 $_q ||= 0;
 my %remote_opts = ( 'username=s' => \$Git::SVN::Prompt::_username,
@@ -269,7 +280,7 @@ my %cmd = (
                    { 'url' => \$_url, } ],
        'blame' => [ \&Git::SVN::Log::cmd_blame,
                    "Show what revision and author last modified each line of a file",
-                   { 'git-format' => \$_git_format } ],
+                   { 'git-format' => \$Git::SVN::Log::_git_format } ],
        'reset' => [ \&cmd_reset,
                     "Undo fetches back to the specified SVN revision",
                     { 'revision|r=s' => \$_revision,
@@ -367,9 +378,9 @@ Git::SVN::init_vars();
 eval {
        Git::SVN::verify_remotes_sanity();
        $cmd{$cmd}->[0]->(@ARGV);
+       post_fetch_checkout();
 };
 fatal $@ if $@;
-post_fetch_checkout();
 exit 0;
 
 ####################### primary functions ######################
@@ -775,6 +786,44 @@ sub populate_merge_info {
        return undef;
 }
 
+sub dcommit_rebase {
+       my ($is_last, $current, $fetched_ref, $svn_error) = @_;
+       my @diff;
+
+       if ($svn_error) {
+               print STDERR "\nERROR from SVN:\n",
+                               $svn_error->expanded_message, "\n";
+       }
+       unless ($_no_rebase) {
+               # we always want to rebase against the current HEAD,
+               # not any head that was passed to us
+               @diff = command('diff-tree', $current,
+                          $fetched_ref, '--');
+               my @finish;
+               if (@diff) {
+                       @finish = rebase_cmd();
+                       print STDERR "W: $current and ", $fetched_ref,
+                                    " differ, using @finish:\n",
+                                    join("\n", @diff), "\n";
+               } elsif ($is_last) {
+                       print "No changes between ", $current, " and ",
+                             $fetched_ref,
+                             "\nResetting to the latest ",
+                             $fetched_ref, "\n";
+                       @finish = qw/reset --mixed/;
+               }
+               command_noisy(@finish, $fetched_ref) if @finish;
+       }
+       if ($svn_error) {
+               die "ERROR: Not all changes have been committed into SVN"
+                       .($_no_rebase ? ".\n" : ", however the committed\n"
+                       ."ones (if any) seem to be successfully integrated "
+                       ."into the working tree.\n")
+                       ."Please see the above messages for details.\n";
+       }
+       return @diff;
+}
+
 sub cmd_dcommit {
        my $head = shift;
        command_noisy(qw/update-index --refresh/);
@@ -902,6 +951,7 @@ sub cmd_dcommit {
        }
 
        my $rewritten_parent;
+       my $current_head = command_oneline(qw/rev-parse HEAD/);
        Git::SVN::remove_username($expect_url);
        if (defined($_merge_info)) {
                $_merge_info =~ tr{ }{\n};
@@ -941,6 +991,14 @@ sub cmd_dcommit {
                                        },
                                        mergeinfo => $_merge_info,
                                        svn_path => '');
+
+                       my $err_handler = $SVN::Error::handler;
+                       $SVN::Error::handler = sub {
+                               my $err = shift;
+                               dcommit_rebase(1, $current_head, $gs->refname,
+                                       $err);
+                       };
+
                        if (!Git::SVN::Editor->new(\%ed_opts)->apply_diff) {
                                print "No changes\n$d~1 == $d\n";
                        } elsif ($parents->{$d} && @{$parents->{$d}}) {
@@ -948,31 +1006,19 @@ sub cmd_dcommit {
                                                               $parents->{$d};
                        }
                        $_fetch_all ? $gs->fetch_all : $gs->fetch;
+                       $SVN::Error::handler = $err_handler;
                        $last_rev = $cmt_rev;
                        next if $_no_rebase;
 
-                       # we always want to rebase against the current HEAD,
-                       # not any head that was passed to us
-                       my @diff = command('diff-tree', $d,
-                                          $gs->refname, '--');
-                       my @finish;
-                       if (@diff) {
-                               @finish = rebase_cmd();
-                               print STDERR "W: $d and ", $gs->refname,
-                                            " differ, using @finish:\n",
-                                            join("\n", @diff), "\n";
-                       } else {
-                               print "No changes between current HEAD and ",
-                                     $gs->refname,
-                                     "\nResetting to the latest ",
-                                     $gs->refname, "\n";
-                               @finish = qw/reset --mixed/;
-                       }
-                       command_noisy(@finish, $gs->refname);
+                       my @diff = dcommit_rebase(@$linear_refs == 0, $d,
+                                               $gs->refname, undef);
 
-                       $rewritten_parent = command_oneline(qw/rev-parse HEAD/);
+                       $rewritten_parent = command_oneline(qw/rev-parse/,
+                                                       $gs->refname);
 
                        if (@diff) {
+                               $current_head = command_oneline(qw/rev-parse
+                                                               HEAD/);
                                @refs = ();
                                my ($url_, $rev_, $uuid_, $gs_) =
                                              working_head_info('HEAD', \@refs);
@@ -1017,6 +1063,7 @@ sub cmd_dcommit {
                                }
                                $parents = \%p;
                                $linear_refs = \@l;
+                               undef $last_rev;
                        }
                }
        }
@@ -1193,7 +1240,7 @@ sub cmd_show_ignore {
        my ($url, $rev, $uuid, $gs) = working_head_info('HEAD');
        $gs ||= Git::SVN->new;
        my $r = (defined $_revision ? $_revision : $gs->ra->get_latest_revnum);
-       $gs->prop_walk($gs->{path}, $r, sub {
+       $gs->prop_walk($gs->path, $r, sub {
                my ($gs, $path, $props) = @_;
                print STDOUT "\n# $path\n";
                my $s = $props->{'svn:ignore'} or return;
@@ -1209,7 +1256,7 @@ sub cmd_show_externals {
        my ($url, $rev, $uuid, $gs) = working_head_info('HEAD');
        $gs ||= Git::SVN->new;
        my $r = (defined $_revision ? $_revision : $gs->ra->get_latest_revnum);
-       $gs->prop_walk($gs->{path}, $r, sub {
+       $gs->prop_walk($gs->path, $r, sub {
                my ($gs, $path, $props) = @_;
                print STDOUT "\n# $path\n";
                my $s = $props->{'svn:externals'} or return;
@@ -1224,7 +1271,7 @@ sub cmd_create_ignore {
        my ($url, $rev, $uuid, $gs) = working_head_info('HEAD');
        $gs ||= Git::SVN->new;
        my $r = (defined $_revision ? $_revision : $gs->ra->get_latest_revnum);
-       $gs->prop_walk($gs->{path}, $r, sub {
+       $gs->prop_walk($gs->path, $r, sub {
                my ($gs, $path, $props) = @_;
                # $path is of the form /path/to/dir/
                $path = '.' . $path;
@@ -1254,31 +1301,6 @@ sub cmd_mkdirs {
        $gs->mkemptydirs($_revision);
 }
 
-sub canonicalize_path {
-       my ($path) = @_;
-       my $dot_slash_added = 0;
-       if (substr($path, 0, 1) ne "/") {
-               $path = "./" . $path;
-               $dot_slash_added = 1;
-       }
-       # File::Spec->canonpath doesn't collapse x/../y into y (for a
-       # good reason), so let's do this manually.
-       $path =~ s#/+#/#g;
-       $path =~ s#/\.(?:/|$)#/#g;
-       $path =~ s#/[^/]+/\.\.##g;
-       $path =~ s#/$##g;
-       $path =~ s#^\./## if $dot_slash_added;
-       $path =~ s#^/##;
-       $path =~ s#^\.$##;
-       return $path;
-}
-
-sub canonicalize_url {
-       my ($url) = @_;
-       $url =~ s#^([^:]+://[^/]*/)(.*)$#$1 . canonicalize_path($2)#e;
-       return $url;
-}
-
 # get_svnprops(PATH)
 # ------------------
 # Helper for cmd_propget and cmd_proplist below.
@@ -1292,7 +1314,7 @@ sub get_svnprops {
        $path = $cmd_dir_prefix . $path;
        fatal("No such file or directory: $path") unless -e $path;
        my $is_dir = -d $path ? 1 : 0;
-       $path = $gs->{path} . '/' . $path;
+       $path = join_paths($gs->path, $path);
 
        # canonicalize the path (otherwise libsvn will abort or fail to
        # find the file)
@@ -1393,8 +1415,8 @@ sub cmd_commit_diff {
                        fatal("Needed URL or usable git-svn --id in ",
                              "the command-line\n", $usage);
                }
-               $url = $gs->{url};
-               $svn_path = $gs->{path};
+               $url = $gs->url;
+               $svn_path = $gs->path;
        }
        unless (defined $_revision) {
                fatal("-r|--revision is a required argument\n", $usage);
@@ -1428,24 +1450,6 @@ sub cmd_commit_diff {
        }
 }
 
-sub escape_uri_only {
-       my ($uri) = @_;
-       my @tmp;
-       foreach (split m{/}, $uri) {
-               s/([^~\w.%+-]|%(?![a-fA-F0-9]{2}))/sprintf("%%%02X",ord($1))/eg;
-               push @tmp, $_;
-       }
-       join('/', @tmp);
-}
-
-sub escape_url {
-       my ($url) = @_;
-       if ($url =~ m#^([^:]+)://([^/]*)(.*)$#) {
-               my ($scheme, $domain, $uri) = ($1, $2, escape_uri_only($3));
-               $url = "$scheme://$domain$uri";
-       }
-       $url;
-}
 
 sub cmd_info {
        my $path = canonicalize_path(defined($_[0]) ? $_[0] : ".");
@@ -1470,21 +1474,21 @@ sub cmd_info {
        # canonicalize_path() will return "" to make libsvn 1.5.x happy,
        $path = "." if $path eq "";
 
-       my $full_url = $url . ($fullpath eq "" ? "" : "/$fullpath");
+       my $full_url = canonicalize_url( add_path_to_url( $url, $fullpath ) );
 
        if ($_url) {
-               print escape_url($full_url), "\n";
+               print "$full_url\n";
                return;
        }
 
        my $result = "Path: $path\n";
        $result .= "Name: " . basename($path) . "\n" if $file_type ne "dir";
-       $result .= "URL: " . escape_url($full_url) . "\n";
+       $result .= "URL: $full_url\n";
 
        eval {
                my $repos_root = $gs->repos_root;
                Git::SVN::remove_username($repos_root);
-               $result .= "Repository Root: " . escape_url($repos_root) . "\n";
+               $result .= "Repository Root: " . canonicalize_url($repos_root) . "\n";
        };
        if ($@) {
                $result .= "Repository Root: (offline)\n";
@@ -1578,7 +1582,7 @@ sub cmd_reset {
 }
 
 sub cmd_gc {
-       if (!$can_compress) {
+       if (!can_compress()) {
                warn "Compress::Zlib could not be found; unhandled.log " .
                     "files will not be compressed.\n";
        }
@@ -1598,8 +1602,8 @@ sub rebase_cmd {
 
 sub post_fetch_checkout {
        return if $_no_checkout;
+       return if verify_ref('HEAD^0');
        my $gs = $Git::SVN::_head or return;
-       return if verify_ref('refs/heads/master^0');
 
        # look for "trunk" ref if it exists
        my $remote = Git::SVN::read_all_remotes()->{$gs->{repo_id}};
@@ -1612,9 +1616,8 @@ sub post_fetch_checkout {
                }
        }
 
-       my $valid_head = verify_ref('HEAD^0');
-       command_noisy(qw(update-ref refs/heads/master), $gs->refname);
-       return if ($valid_head || !verify_ref('HEAD^0'));
+       command_noisy(qw(update-ref HEAD), $gs->refname);
+       return unless verify_ref('HEAD^0');
 
        return if $ENV{GIT_DIR} !~ m#^(?:.*/)?\.git$#;
        my $index = $ENV{GIT_INDEX_FILE} || "$ENV{GIT_DIR}/index";
@@ -1632,7 +1635,9 @@ sub post_fetch_checkout {
 
 sub complete_svn_url {
        my ($url, $path) = @_;
-       $path =~ s#/+$##;
+       $path = canonicalize_path($path);
+
+       # If the path is not a URL...
        if ($path !~ m#^[a-z\+]+://#) {
                if (!defined $url || $url !~ m#^[a-z\+]+://#) {
                        fatal("E: '$path' is not a complete URL ",
@@ -1649,7 +1654,7 @@ sub complete_url_ls_init {
                print STDERR "W: $switch not specified\n";
                return;
        }
-       $repo_path =~ s#/+$##;
+       $repo_path = canonicalize_path($repo_path);
        if ($repo_path =~ m#^[a-z\+]+://#) {
                $ra = Git::SVN::Ra->new($repo_path);
                $repo_path = '';
@@ -1660,18 +1665,18 @@ sub complete_url_ls_init {
                              "and a separate URL is not specified");
                }
        }
-       my $url = $ra->{url};
+       my $url = $ra->url;
        my $gs = Git::SVN->init($url, undef, undef, undef, 1);
        my $k = "svn-remote.$gs->{repo_id}.url";
        my $orig_url = eval { command_oneline(qw/config --get/, $k) };
-       if ($orig_url && ($orig_url ne $gs->{url})) {
+       if ($orig_url && ($orig_url ne $gs->url)) {
                die "$k already set: $orig_url\n",
-                   "wanted to set to: $gs->{url}\n";
+                   "wanted to set to: $gs->url\n";
        }
-       command_oneline('config', $k, $gs->{url}) unless $orig_url;
-       my $remote_path = "$gs->{path}/$repo_path";
+       command_oneline('config', $k, $gs->url) unless $orig_url;
+
+       my $remote_path = join_paths( $gs->path, $repo_path );
        $remote_path =~ s{%([0-9A-F]{2})}{chr hex($1)}ieg;
-       $remote_path =~ s#/+#/#g;
        $remote_path =~ s#^/##g;
        $remote_path .= "/*" if $remote_path !~ /\*/;
        my ($n) = ($switch =~ /^--(\w+)/);
@@ -2014,13 +2019,13 @@ sub md5sum {
        } elsif (!$ref) {
                $md5->add($arg) or croak $!;
        } else {
-               ::fatal "Can't provide MD5 hash for unknown ref type: '", $ref, "'";
+               fatal "Can't provide MD5 hash for unknown ref type: '", $ref, "'";
        }
        return $md5->hexdigest();
 }
 
 sub gc_directory {
-       if ($can_compress && -f $_ && basename($_) eq "unhandled.log") {
+       if (can_compress() && -f $_ && basename($_) eq "unhandled.log") {
                my $out_filename = $_ . ".gz";
                open my $in_fh, "<", $_ or die "Unable to open $_: $!\n";
                binmode $in_fh;
@@ -2038,3035 +2043,6 @@ sub gc_directory {
        }
 }
 
-package Git::SVN;
-use strict;
-use warnings;
-use Fcntl qw/:DEFAULT :seek/;
-use constant rev_map_fmt => 'NH40';
-use vars qw/$default_repo_id $default_ref_id $_no_metadata $_follow_parent
-            $_repack $_repack_flags $_use_svm_props $_head
-            $_use_svnsync_props $no_reuse_existing $_minimize_url
-           $_use_log_author $_add_author_from $_localtime/;
-use Carp qw/croak/;
-use File::Path qw/mkpath/;
-use File::Copy qw/copy/;
-use IPC::Open3;
-use Time::Local;
-use Memoize;  # core since 5.8.0, Jul 2002
-use Memoize::Storable;
-use POSIX qw(:signal_h);
-my $can_use_yaml;
-BEGIN {
-       $can_use_yaml = eval { require Git::SVN::Memoize::YAML; 1};
-}
-
-my ($_gc_nr, $_gc_period);
-
-# properties that we do not log:
-my %SKIP_PROP;
-BEGIN {
-       %SKIP_PROP = map { $_ => 1 } qw/svn:wc:ra_dav:version-url
-                                       svn:special svn:executable
-                                       svn:entry:committed-rev
-                                       svn:entry:last-author
-                                       svn:entry:uuid
-                                       svn:entry:committed-date/;
-
-       # some options are read globally, but can be overridden locally
-       # per [svn-remote "..."] section.  Command-line options will *NOT*
-       # override options set in an [svn-remote "..."] section
-       no strict 'refs';
-       for my $option (qw/follow_parent no_metadata use_svm_props
-                          use_svnsync_props/) {
-               my $key = $option;
-               $key =~ tr/_//d;
-               my $prop = "-$option";
-               *$option = sub {
-                       my ($self) = @_;
-                       return $self->{$prop} if exists $self->{$prop};
-                       my $k = "svn-remote.$self->{repo_id}.$key";
-                       eval { command_oneline(qw/config --get/, $k) };
-                       if ($@) {
-                               $self->{$prop} = ${"Git::SVN::_$option"};
-                       } else {
-                               my $v = command_oneline(qw/config --bool/,$k);
-                               $self->{$prop} = $v eq 'false' ? 0 : 1;
-                       }
-                       return $self->{$prop};
-               }
-       }
-}
-
-
-my (%LOCKFILES, %INDEX_FILES);
-END {
-       unlink keys %LOCKFILES if %LOCKFILES;
-       unlink keys %INDEX_FILES if %INDEX_FILES;
-}
-
-sub resolve_local_globs {
-       my ($url, $fetch, $glob_spec) = @_;
-       return unless defined $glob_spec;
-       my $ref = $glob_spec->{ref};
-       my $path = $glob_spec->{path};
-       foreach (command(qw#for-each-ref --format=%(refname) refs/#)) {
-               next unless m#^$ref->{regex}$#;
-               my $p = $1;
-               my $pathname = desanitize_refname($path->full_path($p));
-               my $refname = desanitize_refname($ref->full_path($p));
-               if (my $existing = $fetch->{$pathname}) {
-                       if ($existing ne $refname) {
-                               die "Refspec conflict:\n",
-                                   "existing: $existing\n",
-                                   " globbed: $refname\n";
-                       }
-                       my $u = (::cmt_metadata("$refname"))[0];
-                       $u =~ s!^\Q$url\E(/|$)!! or die
-                         "$refname: '$url' not found in '$u'\n";
-                       if ($pathname ne $u) {
-                               warn "W: Refspec glob conflict ",
-                                    "(ref: $refname):\n",
-                                    "expected path: $pathname\n",
-                                    "    real path: $u\n",
-                                    "Continuing ahead with $u\n";
-                               next;
-                       }
-               } else {
-                       $fetch->{$pathname} = $refname;
-               }
-       }
-}
-
-sub parse_revision_argument {
-       my ($base, $head) = @_;
-       if (!defined $::_revision || $::_revision eq 'BASE:HEAD') {
-               return ($base, $head);
-       }
-       return ($1, $2) if ($::_revision =~ /^(\d+):(\d+)$/);
-       return ($::_revision, $::_revision) if ($::_revision =~ /^\d+$/);
-       return ($head, $head) if ($::_revision eq 'HEAD');
-       return ($base, $1) if ($::_revision =~ /^BASE:(\d+)$/);
-       return ($1, $head) if ($::_revision =~ /^(\d+):HEAD$/);
-       die "revision argument: $::_revision not understood by git-svn\n";
-}
-
-sub fetch_all {
-       my ($repo_id, $remotes) = @_;
-       if (ref $repo_id) {
-               my $gs = $repo_id;
-               $repo_id = undef;
-               $repo_id = $gs->{repo_id};
-       }
-       $remotes ||= read_all_remotes();
-       my $remote = $remotes->{$repo_id} or
-                    die "[svn-remote \"$repo_id\"] unknown\n";
-       my $fetch = $remote->{fetch};
-       my $url = $remote->{url} or die "svn-remote.$repo_id.url not defined\n";
-       my (@gs, @globs);
-       my $ra = Git::SVN::Ra->new($url);
-       my $uuid = $ra->get_uuid;
-       my $head = $ra->get_latest_revnum;
-
-       # ignore errors, $head revision may not even exist anymore
-       eval { $ra->get_log("", $head, 0, 1, 0, 1, sub { $head = $_[1] }) };
-       warn "W: $@\n" if $@;
-
-       my $base = defined $fetch ? $head : 0;
-
-       # read the max revs for wildcard expansion (branches/*, tags/*)
-       foreach my $t (qw/branches tags/) {
-               defined $remote->{$t} or next;
-               push @globs, @{$remote->{$t}};
-
-               my $max_rev = eval { tmp_config(qw/--int --get/,
-                                        "svn-remote.$repo_id.${t}-maxRev") };
-               if (defined $max_rev && ($max_rev < $base)) {
-                       $base = $max_rev;
-               } elsif (!defined $max_rev) {
-                       $base = 0;
-               }
-       }
-
-       if ($fetch) {
-               foreach my $p (sort keys %$fetch) {
-                       my $gs = Git::SVN->new($fetch->{$p}, $repo_id, $p);
-                       my $lr = $gs->rev_map_max;
-                       if (defined $lr) {
-                               $base = $lr if ($lr < $base);
-                       }
-                       push @gs, $gs;
-               }
-       }
-
-       ($base, $head) = parse_revision_argument($base, $head);
-       $ra->gs_fetch_loop_common($base, $head, \@gs, \@globs);
-}
-
-sub read_all_remotes {
-       my $r = {};
-       my $use_svm_props = eval { command_oneline(qw/config --bool
-           svn.useSvmProps/) };
-       $use_svm_props = $use_svm_props eq 'true' if $use_svm_props;
-       my $svn_refspec = qr{\s*(.*?)\s*:\s*(.+?)\s*};
-       foreach (grep { s/^svn-remote\.// } command(qw/config -l/)) {
-               if (m!^(.+)\.fetch=$svn_refspec$!) {
-                       my ($remote, $local_ref, $remote_ref) = ($1, $2, $3);
-                       die("svn-remote.$remote: remote ref '$remote_ref' "
-                           . "must start with 'refs/'\n")
-                               unless $remote_ref =~ m{^refs/};
-                       $local_ref = uri_decode($local_ref);
-                       $r->{$remote}->{fetch}->{$local_ref} = $remote_ref;
-                       $r->{$remote}->{svm} = {} if $use_svm_props;
-               } elsif (m!^(.+)\.usesvmprops=\s*(.*)\s*$!) {
-                       $r->{$1}->{svm} = {};
-               } elsif (m!^(.+)\.url=\s*(.*)\s*$!) {
-                       $r->{$1}->{url} = $2;
-               } elsif (m!^(.+)\.pushurl=\s*(.*)\s*$!) {
-                       $r->{$1}->{pushurl} = $2;
-               } elsif (m!^(.+)\.ignore-refs=\s*(.*)\s*$!) {
-                       $r->{$1}->{ignore_refs_regex} = $2;
-               } elsif (m!^(.+)\.(branches|tags)=$svn_refspec$!) {
-                       my ($remote, $t, $local_ref, $remote_ref) =
-                                                            ($1, $2, $3, $4);
-                       die("svn-remote.$remote: remote ref '$remote_ref' ($t) "
-                           . "must start with 'refs/'\n")
-                               unless $remote_ref =~ m{^refs/};
-                       $local_ref = uri_decode($local_ref);
-                       my $rs = {
-                           t => $t,
-                           remote => $remote,
-                           path => Git::SVN::GlobSpec->new($local_ref, 1),
-                           ref => Git::SVN::GlobSpec->new($remote_ref, 0) };
-                       if (length($rs->{ref}->{right}) != 0) {
-                               die "The '*' glob character must be the last ",
-                                   "character of '$remote_ref'\n";
-                       }
-                       push @{ $r->{$remote}->{$t} }, $rs;
-               }
-       }
-
-       map {
-               if (defined $r->{$_}->{svm}) {
-                       my $svm;
-                       eval {
-                               my $section = "svn-remote.$_";
-                               $svm = {
-                                       source => tmp_config('--get',
-                                           "$section.svm-source"),
-                                       replace => tmp_config('--get',
-                                           "$section.svm-replace"),
-                               }
-                       };
-                       $r->{$_}->{svm} = $svm;
-               }
-       } keys %$r;
-
-       foreach my $remote (keys %$r) {
-               foreach ( grep { defined $_ }
-                         map { $r->{$remote}->{$_} } qw(branches tags) ) {
-                       foreach my $rs ( @$_ ) {
-                               $rs->{ignore_refs_regex} =
-                                   $r->{$remote}->{ignore_refs_regex};
-                       }
-               }
-       }
-
-       $r;
-}
-
-sub init_vars {
-       $_gc_nr = $_gc_period = 1000;
-       if (defined $_repack || defined $_repack_flags) {
-              warn "Repack options are obsolete; they have no effect.\n";
-       }
-}
-
-sub verify_remotes_sanity {
-       return unless -d $ENV{GIT_DIR};
-       my %seen;
-       foreach (command(qw/config -l/)) {
-               if (m!^svn-remote\.(?:.+)\.fetch=.*:refs/remotes/(\S+)\s*$!) {
-                       if ($seen{$1}) {
-                               die "Remote ref refs/remote/$1 is tracked by",
-                                   "\n  \"$_\"\nand\n  \"$seen{$1}\"\n",
-                                   "Please resolve this ambiguity in ",
-                                   "your git configuration file before ",
-                                   "continuing\n";
-                       }
-                       $seen{$1} = $_;
-               }
-       }
-}
-
-sub find_existing_remote {
-       my ($url, $remotes) = @_;
-       return undef if $no_reuse_existing;
-       my $existing;
-       foreach my $repo_id (keys %$remotes) {
-               my $u = $remotes->{$repo_id}->{url} or next;
-               next if $u ne $url;
-               $existing = $repo_id;
-               last;
-       }
-       $existing;
-}
-
-sub init_remote_config {
-       my ($self, $url, $no_write) = @_;
-       $url =~ s!/+$!!; # strip trailing slash
-       my $r = read_all_remotes();
-       my $existing = find_existing_remote($url, $r);
-       if ($existing) {
-               unless ($no_write) {
-                       print STDERR "Using existing ",
-                                    "[svn-remote \"$existing\"]\n";
-               }
-               $self->{repo_id} = $existing;
-       } elsif ($_minimize_url) {
-               my $min_url = Git::SVN::Ra->new($url)->minimize_url;
-               $existing = find_existing_remote($min_url, $r);
-               if ($existing) {
-                       unless ($no_write) {
-                               print STDERR "Using existing ",
-                                            "[svn-remote \"$existing\"]\n";
-                       }
-                       $self->{repo_id} = $existing;
-               }
-               if ($min_url ne $url) {
-                       unless ($no_write) {
-                               print STDERR "Using higher level of URL: ",
-                                            "$url => $min_url\n";
-                       }
-                       my $old_path = $self->{path};
-                       $self->{path} = $url;
-                       $self->{path} =~ s!^\Q$min_url\E(/|$)!!;
-                       if (length $old_path) {
-                               $self->{path} .= "/$old_path";
-                       }
-                       $url = $min_url;
-               }
-       }
-       my $orig_url;
-       if (!$existing) {
-               # verify that we aren't overwriting anything:
-               $orig_url = eval {
-                       command_oneline('config', '--get',
-                                       "svn-remote.$self->{repo_id}.url")
-               };
-               if ($orig_url && ($orig_url ne $url)) {
-                       die "svn-remote.$self->{repo_id}.url already set: ",
-                           "$orig_url\nwanted to set to: $url\n";
-               }
-       }
-       my ($xrepo_id, $xpath) = find_ref($self->refname);
-       if (!$no_write && defined $xpath) {
-               die "svn-remote.$xrepo_id.fetch already set to track ",
-                   "$xpath:", $self->refname, "\n";
-       }
-       unless ($no_write) {
-               command_noisy('config',
-                             "svn-remote.$self->{repo_id}.url", $url);
-               $self->{path} =~ s{^/}{};
-               $self->{path} =~ s{%([0-9A-F]{2})}{chr hex($1)}ieg;
-               command_noisy('config', '--add',
-                             "svn-remote.$self->{repo_id}.fetch",
-                             "$self->{path}:".$self->refname);
-       }
-       $self->{url} = $url;
-}
-
-sub find_by_url { # repos_root and, path are optional
-       my ($class, $full_url, $repos_root, $path) = @_;
-
-       return undef unless defined $full_url;
-       remove_username($full_url);
-       remove_username($repos_root) if defined $repos_root;
-       my $remotes = read_all_remotes();
-       if (defined $full_url && defined $repos_root && !defined $path) {
-               $path = $full_url;
-               $path =~ s#^\Q$repos_root\E(?:/|$)##;
-       }
-       foreach my $repo_id (keys %$remotes) {
-               my $u = $remotes->{$repo_id}->{url} or next;
-               remove_username($u);
-               next if defined $repos_root && $repos_root ne $u;
-
-               my $fetch = $remotes->{$repo_id}->{fetch} || {};
-               foreach my $t (qw/branches tags/) {
-                       foreach my $globspec (@{$remotes->{$repo_id}->{$t}}) {
-                               resolve_local_globs($u, $fetch, $globspec);
-                       }
-               }
-               my $p = $path;
-               my $rwr = rewrite_root({repo_id => $repo_id});
-               my $svm = $remotes->{$repo_id}->{svm}
-                       if defined $remotes->{$repo_id}->{svm};
-               unless (defined $p) {
-                       $p = $full_url;
-                       my $z = $u;
-                       my $prefix = '';
-                       if ($rwr) {
-                               $z = $rwr;
-                               remove_username($z);
-                       } elsif (defined $svm) {
-                               $z = $svm->{source};
-                               $prefix = $svm->{replace};
-                               $prefix =~ s#^\Q$u\E(?:/|$)##;
-                               $prefix =~ s#/$##;
-                       }
-                       $p =~ s#^\Q$z\E(?:/|$)#$prefix# or next;
-               }
-               foreach my $f (keys %$fetch) {
-                       next if $f ne $p;
-                       return Git::SVN->new($fetch->{$f}, $repo_id, $f);
-               }
-       }
-       undef;
-}
-
-sub init {
-       my ($class, $url, $path, $repo_id, $ref_id, $no_write) = @_;
-       my $self = _new($class, $repo_id, $ref_id, $path);
-       if (defined $url) {
-               $self->init_remote_config($url, $no_write);
-       }
-       $self;
-}
-
-sub find_ref {
-       my ($ref_id) = @_;
-       foreach (command(qw/config -l/)) {
-               next unless m!^svn-remote\.(.+)\.fetch=
-                             \s*(.*?)\s*:\s*(.+?)\s*$!x;
-               my ($repo_id, $path, $ref) = ($1, $2, $3);
-               if ($ref eq $ref_id) {
-                       $path = '' if ($path =~ m#^\./?#);
-                       return ($repo_id, $path);
-               }
-       }
-       (undef, undef, undef);
-}
-
-sub new {
-       my ($class, $ref_id, $repo_id, $path) = @_;
-       if (defined $ref_id && !defined $repo_id && !defined $path) {
-               ($repo_id, $path) = find_ref($ref_id);
-               if (!defined $repo_id) {
-                       die "Could not find a \"svn-remote.*.fetch\" key ",
-                           "in the repository configuration matching: ",
-                           "$ref_id\n";
-               }
-       }
-       my $self = _new($class, $repo_id, $ref_id, $path);
-       if (!defined $self->{path} || !length $self->{path}) {
-               my $fetch = command_oneline('config', '--get',
-                                           "svn-remote.$repo_id.fetch",
-                                           ":$ref_id\$") or
-                    die "Failed to read \"svn-remote.$repo_id.fetch\" ",
-                        "\":$ref_id\$\" in config\n";
-               ($self->{path}, undef) = split(/\s*:\s*/, $fetch);
-       }
-       $self->{path} =~ s{/+}{/}g;
-       $self->{path} =~ s{\A/}{};
-       $self->{path} =~ s{/\z}{};
-       $self->{url} = command_oneline('config', '--get',
-                                      "svn-remote.$repo_id.url") or
-                  die "Failed to read \"svn-remote.$repo_id.url\" in config\n";
-       $self->{pushurl} = eval { command_oneline('config', '--get',
-                                 "svn-remote.$repo_id.pushurl") };
-       $self->rebuild;
-       $self;
-}
-
-sub refname {
-       my ($refname) = $_[0]->{ref_id} ;
-
-       # It cannot end with a slash /, we'll throw up on this because
-       # SVN can't have directories with a slash in their name, either:
-       if ($refname =~ m{/$}) {
-               die "ref: '$refname' ends with a trailing slash, this is ",
-                   "not permitted by git nor Subversion\n";
-       }
-
-       # It cannot have ASCII control character space, tilde ~, caret ^,
-       # colon :, question-mark ?, asterisk *, space, or open bracket [
-       # anywhere.
-       #
-       # Additionally, % must be escaped because it is used for escaping
-       # and we want our escaped refname to be reversible
-       $refname =~ s{([ \%~\^:\?\*\[\t])}{uc sprintf('%%%02x',ord($1))}eg;
-
-       # no slash-separated component can begin with a dot .
-       # /.* becomes /%2E*
-       $refname =~ s{/\.}{/%2E}g;
-
-       # It cannot have two consecutive dots .. anywhere
-       # .. becomes %2E%2E
-       $refname =~ s{\.\.}{%2E%2E}g;
-
-       # trailing dots and .lock are not allowed
-       # .$ becomes %2E and .lock becomes %2Elock
-       $refname =~ s{\.(?=$|lock$)}{%2E};
-
-       # the sequence @{ is used to access the reflog
-       # @{ becomes %40{
-       $refname =~ s{\@\{}{%40\{}g;
-
-       return $refname;
-}
-
-sub desanitize_refname {
-       my ($refname) = @_;
-       $refname =~ s{%(?:([0-9A-F]{2}))}{chr hex($1)}eg;
-       return $refname;
-}
-
-sub svm_uuid {
-       my ($self) = @_;
-       return $self->{svm}->{uuid} if $self->svm;
-       $self->ra;
-       unless ($self->{svm}) {
-               die "SVM UUID not cached, and reading remotely failed\n";
-       }
-       $self->{svm}->{uuid};
-}
-
-sub svm {
-       my ($self) = @_;
-       return $self->{svm} if $self->{svm};
-       my $svm;
-       # see if we have it in our config, first:
-       eval {
-               my $section = "svn-remote.$self->{repo_id}";
-               $svm = {
-                 source => tmp_config('--get', "$section.svm-source"),
-                 uuid => tmp_config('--get', "$section.svm-uuid"),
-                 replace => tmp_config('--get', "$section.svm-replace"),
-               }
-       };
-       if ($svm && $svm->{source} && $svm->{uuid} && $svm->{replace}) {
-               $self->{svm} = $svm;
-       }
-       $self->{svm};
-}
-
-sub _set_svm_vars {
-       my ($self, $ra) = @_;
-       return $ra if $self->svm;
-
-       my @err = ( "useSvmProps set, but failed to read SVM properties\n",
-                   "(svm:source, svm:uuid) ",
-                   "from the following URLs:\n" );
-       sub read_svm_props {
-               my ($self, $ra, $path, $r) = @_;
-               my $props = ($ra->get_dir($path, $r))[2];
-               my $src = $props->{'svm:source'};
-               my $uuid = $props->{'svm:uuid'};
-               return undef if (!$src || !$uuid);
-
-               chomp($src, $uuid);
-
-               $uuid =~ m{^[0-9a-f\-]{30,}$}i
-                   or die "doesn't look right - svm:uuid is '$uuid'\n";
-
-               # the '!' is used to mark the repos_root!/relative/path
-               $src =~ s{/?!/?}{/};
-               $src =~ s{/+$}{}; # no trailing slashes please
-               # username is of no interest
-               $src =~ s{(^[a-z\+]*://)[^/@]*@}{$1};
-
-               my $replace = $ra->{url};
-               $replace .= "/$path" if length $path;
-
-               my $section = "svn-remote.$self->{repo_id}";
-               tmp_config("$section.svm-source", $src);
-               tmp_config("$section.svm-replace", $replace);
-               tmp_config("$section.svm-uuid", $uuid);
-               $self->{svm} = {
-                       source => $src,
-                       uuid => $uuid,
-                       replace => $replace
-               };
-       }
-
-       my $r = $ra->get_latest_revnum;
-       my $path = $self->{path};
-       my %tried;
-       while (length $path) {
-               unless ($tried{"$self->{url}/$path"}) {
-                       return $ra if $self->read_svm_props($ra, $path, $r);
-                       $tried{"$self->{url}/$path"} = 1;
-               }
-               $path =~ s#/?[^/]+$##;
-       }
-       die "Path: '$path' should be ''\n" if $path ne '';
-       return $ra if $self->read_svm_props($ra, $path, $r);
-       $tried{"$self->{url}/$path"} = 1;
-
-       if ($ra->{repos_root} eq $self->{url}) {
-               die @err, (map { "  $_\n" } keys %tried), "\n";
-       }
-
-       # nope, make sure we're connected to the repository root:
-       my $ok;
-       my @tried_b;
-       $path = $ra->{svn_path};
-       $ra = Git::SVN::Ra->new($ra->{repos_root});
-       while (length $path) {
-               unless ($tried{"$ra->{url}/$path"}) {
-                       $ok = $self->read_svm_props($ra, $path, $r);
-                       last if $ok;
-                       $tried{"$ra->{url}/$path"} = 1;
-               }
-               $path =~ s#/?[^/]+$##;
-       }
-       die "Path: '$path' should be ''\n" if $path ne '';
-       $ok ||= $self->read_svm_props($ra, $path, $r);
-       $tried{"$ra->{url}/$path"} = 1;
-       if (!$ok) {
-               die @err, (map { "  $_\n" } keys %tried), "\n";
-       }
-       Git::SVN::Ra->new($self->{url});
-}
-
-sub svnsync {
-       my ($self) = @_;
-       return $self->{svnsync} if $self->{svnsync};
-
-       if ($self->no_metadata) {
-               die "Can't have both 'noMetadata' and ",
-                   "'useSvnsyncProps' options set!\n";
-       }
-       if ($self->rewrite_root) {
-               die "Can't have both 'useSvnsyncProps' and 'rewriteRoot' ",
-                   "options set!\n";
-       }
-       if ($self->rewrite_uuid) {
-               die "Can't have both 'useSvnsyncProps' and 'rewriteUUID' ",
-                   "options set!\n";
-       }
-
-       my $svnsync;
-       # see if we have it in our config, first:
-       eval {
-               my $section = "svn-remote.$self->{repo_id}";
-
-               my $url = tmp_config('--get', "$section.svnsync-url");
-               ($url) = ($url =~ m{^([a-z\+]+://\S+)$}) or
-                  die "doesn't look right - svn:sync-from-url is '$url'\n";
-
-               my $uuid = tmp_config('--get', "$section.svnsync-uuid");
-               ($uuid) = ($uuid =~ m{^([0-9a-f\-]{30,})$}i) or
-                  die "doesn't look right - svn:sync-from-uuid is '$uuid'\n";
-
-               $svnsync = { url => $url, uuid => $uuid }
-       };
-       if ($svnsync && $svnsync->{url} && $svnsync->{uuid}) {
-               return $self->{svnsync} = $svnsync;
-       }
-
-       my $err = "useSvnsyncProps set, but failed to read " .
-                 "svnsync property: svn:sync-from-";
-       my $rp = $self->ra->rev_proplist(0);
-
-       my $url = $rp->{'svn:sync-from-url'} or die $err . "url\n";
-       ($url) = ($url =~ m{^([a-z\+]+://\S+)$}) or
-                  die "doesn't look right - svn:sync-from-url is '$url'\n";
-
-       my $uuid = $rp->{'svn:sync-from-uuid'} or die $err . "uuid\n";
-       ($uuid) = ($uuid =~ m{^([0-9a-f\-]{30,})$}i) or
-                  die "doesn't look right - svn:sync-from-uuid is '$uuid'\n";
-
-       my $section = "svn-remote.$self->{repo_id}";
-       tmp_config('--add', "$section.svnsync-uuid", $uuid);
-       tmp_config('--add', "$section.svnsync-url", $url);
-       return $self->{svnsync} = { url => $url, uuid => $uuid };
-}
-
-# this allows us to memoize our SVN::Ra UUID locally and avoid a
-# remote lookup (useful for 'git svn log').
-sub ra_uuid {
-       my ($self) = @_;
-       unless ($self->{ra_uuid}) {
-               my $key = "svn-remote.$self->{repo_id}.uuid";
-               my $uuid = eval { tmp_config('--get', $key) };
-               if (!$@ && $uuid && $uuid =~ /^([a-f\d\-]{30,})$/i) {
-                       $self->{ra_uuid} = $uuid;
-               } else {
-                       die "ra_uuid called without URL\n" unless $self->{url};
-                       $self->{ra_uuid} = $self->ra->get_uuid;
-                       tmp_config('--add', $key, $self->{ra_uuid});
-               }
-       }
-       $self->{ra_uuid};
-}
-
-sub _set_repos_root {
-       my ($self, $repos_root) = @_;
-       my $k = "svn-remote.$self->{repo_id}.reposRoot";
-       $repos_root ||= $self->ra->{repos_root};
-       tmp_config($k, $repos_root);
-       $repos_root;
-}
-
-sub repos_root {
-       my ($self) = @_;
-       my $k = "svn-remote.$self->{repo_id}.reposRoot";
-       eval { tmp_config('--get', $k) } || $self->_set_repos_root;
-}
-
-sub ra {
-       my ($self) = shift;
-       my $ra = Git::SVN::Ra->new($self->{url});
-       $self->_set_repos_root($ra->{repos_root});
-       if ($self->use_svm_props && !$self->{svm}) {
-               if ($self->no_metadata) {
-                       die "Can't have both 'noMetadata' and ",
-                           "'useSvmProps' options set!\n";
-               } elsif ($self->use_svnsync_props) {
-                       die "Can't have both 'useSvnsyncProps' and ",
-                           "'useSvmProps' options set!\n";
-               }
-               $ra = $self->_set_svm_vars($ra);
-               $self->{-want_revprops} = 1;
-       }
-       $ra;
-}
-
-# prop_walk(PATH, REV, SUB)
-# -------------------------
-# Recursively traverse PATH at revision REV and invoke SUB for each
-# directory that contains a SVN property.  SUB will be invoked as
-# follows:  &SUB(gs, path, props);  where `gs' is this instance of
-# Git::SVN, `path' the path to the directory where the properties
-# `props' were found.  The `path' will be relative to point of checkout,
-# that is, if url://repo/trunk is the current Git branch, and that
-# directory contains a sub-directory `d', SUB will be invoked with `/d/'
-# as `path' (note the trailing `/').
-sub prop_walk {
-       my ($self, $path, $rev, $sub) = @_;
-
-       $path =~ s#^/##;
-       my ($dirent, undef, $props) = $self->ra->get_dir($path, $rev);
-       $path =~ s#^/*#/#g;
-       my $p = $path;
-       # Strip the irrelevant part of the path.
-       $p =~ s#^/+\Q$self->{path}\E(/|$)#/#;
-       # Ensure the path is terminated by a `/'.
-       $p =~ s#/*$#/#;
-
-       # The properties contain all the internal SVN stuff nobody
-       # (usually) cares about.
-       my $interesting_props = 0;
-       foreach (keys %{$props}) {
-               # If it doesn't start with `svn:', it must be a
-               # user-defined property.
-               ++$interesting_props and next if $_ !~ /^svn:/;
-               # FIXME: Fragile, if SVN adds new public properties,
-               # this needs to be updated.
-               ++$interesting_props if /^svn:(?:ignore|keywords|executable
-                                                |eol-style|mime-type
-                                                |externals|needs-lock)$/x;
-       }
-       &$sub($self, $p, $props) if $interesting_props;
-
-       foreach (sort keys %$dirent) {
-               next if $dirent->{$_}->{kind} != $SVN::Node::dir;
-               $self->prop_walk($self->{path} . $p . $_, $rev, $sub);
-       }
-}
-
-sub last_rev { ($_[0]->last_rev_commit)[0] }
-sub last_commit { ($_[0]->last_rev_commit)[1] }
-
-# returns the newest SVN revision number and newest commit SHA1
-sub last_rev_commit {
-       my ($self) = @_;
-       if (defined $self->{last_rev} && defined $self->{last_commit}) {
-               return ($self->{last_rev}, $self->{last_commit});
-       }
-       my $c = ::verify_ref($self->refname.'^0');
-       if ($c && !$self->use_svm_props && !$self->no_metadata) {
-               my $rev = (::cmt_metadata($c))[1];
-               if (defined $rev) {
-                       ($self->{last_rev}, $self->{last_commit}) = ($rev, $c);
-                       return ($rev, $c);
-               }
-       }
-       my $map_path = $self->map_path;
-       unless (-e $map_path) {
-               ($self->{last_rev}, $self->{last_commit}) = (undef, undef);
-               return (undef, undef);
-       }
-       my ($rev, $commit) = $self->rev_map_max(1);
-       ($self->{last_rev}, $self->{last_commit}) = ($rev, $commit);
-       return ($rev, $commit);
-}
-
-sub get_fetch_range {
-       my ($self, $min, $max) = @_;
-       $max ||= $self->ra->get_latest_revnum;
-       $min ||= $self->rev_map_max;
-       (++$min, $max);
-}
-
-sub tmp_config {
-       my (@args) = @_;
-       my $old_def_config = "$ENV{GIT_DIR}/svn/config";
-       my $config = "$ENV{GIT_DIR}/svn/.metadata";
-       if (! -f $config && -f $old_def_config) {
-               rename $old_def_config, $config or
-                      die "Failed rename $old_def_config => $config: $!\n";
-       }
-       my $old_config = $ENV{GIT_CONFIG};
-       $ENV{GIT_CONFIG} = $config;
-       $@ = undef;
-       my @ret = eval {
-               unless (-f $config) {
-                       mkfile($config);
-                       open my $fh, '>', $config or
-                           die "Can't open $config: $!\n";
-                       print $fh "; This file is used internally by ",
-                                 "git-svn\n" or die
-                                 "Couldn't write to $config: $!\n";
-                       print $fh "; You should not have to edit it\n" or
-                             die "Couldn't write to $config: $!\n";
-                       close $fh or die "Couldn't close $config: $!\n";
-               }
-               command('config', @args);
-       };
-       my $err = $@;
-       if (defined $old_config) {
-               $ENV{GIT_CONFIG} = $old_config;
-       } else {
-               delete $ENV{GIT_CONFIG};
-       }
-       die $err if $err;
-       wantarray ? @ret : $ret[0];
-}
-
-sub tmp_index_do {
-       my ($self, $sub) = @_;
-       my $old_index = $ENV{GIT_INDEX_FILE};
-       $ENV{GIT_INDEX_FILE} = $self->{index};
-       $@ = undef;
-       my @ret = eval {
-               my ($dir, $base) = ($self->{index} =~ m#^(.*?)/?([^/]+)$#);
-               mkpath([$dir]) unless -d $dir;
-               &$sub;
-       };
-       my $err = $@;
-       if (defined $old_index) {
-               $ENV{GIT_INDEX_FILE} = $old_index;
-       } else {
-               delete $ENV{GIT_INDEX_FILE};
-       }
-       die $err if $err;
-       wantarray ? @ret : $ret[0];
-}
-
-sub assert_index_clean {
-       my ($self, $treeish) = @_;
-
-       $self->tmp_index_do(sub {
-               command_noisy('read-tree', $treeish) unless -e $self->{index};
-               my $x = command_oneline('write-tree');
-               my ($y) = (command(qw/cat-file commit/, $treeish) =~
-                          /^tree ($::sha1)/mo);
-               return if $y eq $x;
-
-               warn "Index mismatch: $y != $x\nrereading $treeish\n";
-               unlink $self->{index} or die "unlink $self->{index}: $!\n";
-               command_noisy('read-tree', $treeish);
-               $x = command_oneline('write-tree');
-               if ($y ne $x) {
-                       ::fatal "trees ($treeish) $y != $x\n",
-                               "Something is seriously wrong...";
-               }
-       });
-}
-
-sub get_commit_parents {
-       my ($self, $log_entry) = @_;
-       my (%seen, @ret, @tmp);
-       # legacy support for 'set-tree'; this is only used by set_tree_cb:
-       if (my $ip = $self->{inject_parents}) {
-               if (my $commit = delete $ip->{$log_entry->{revision}}) {
-                       push @tmp, $commit;
-               }
-       }
-       if (my $cur = ::verify_ref($self->refname.'^0')) {
-               push @tmp, $cur;
-       }
-       if (my $ipd = $self->{inject_parents_dcommit}) {
-               if (my $commit = delete $ipd->{$log_entry->{revision}}) {
-                       push @tmp, @$commit;
-               }
-       }
-       push @tmp, $_ foreach (@{$log_entry->{parents}}, @tmp);
-       while (my $p = shift @tmp) {
-               next if $seen{$p};
-               $seen{$p} = 1;
-               push @ret, $p;
-       }
-       @ret;
-}
-
-sub rewrite_root {
-       my ($self) = @_;
-       return $self->{-rewrite_root} if exists $self->{-rewrite_root};
-       my $k = "svn-remote.$self->{repo_id}.rewriteRoot";
-       my $rwr = eval { command_oneline(qw/config --get/, $k) };
-       if ($rwr) {
-               $rwr =~ s#/+$##;
-               if ($rwr !~ m#^[a-z\+]+://#) {
-                       die "$rwr is not a valid URL (key: $k)\n";
-               }
-       }
-       $self->{-rewrite_root} = $rwr;
-}
-
-sub rewrite_uuid {
-       my ($self) = @_;
-       return $self->{-rewrite_uuid} if exists $self->{-rewrite_uuid};
-       my $k = "svn-remote.$self->{repo_id}.rewriteUUID";
-       my $rwid = eval { command_oneline(qw/config --get/, $k) };
-       if ($rwid) {
-               $rwid =~ s#/+$##;
-               if ($rwid !~ m#^[a-f0-9]{8}-(?:[a-f0-9]{4}-){3}[a-f0-9]{12}$#) {
-                       die "$rwid is not a valid UUID (key: $k)\n";
-               }
-       }
-       $self->{-rewrite_uuid} = $rwid;
-}
-
-sub metadata_url {
-       my ($self) = @_;
-       ($self->rewrite_root || $self->{url}) .
-          (length $self->{path} ? '/' . $self->{path} : '');
-}
-
-sub full_url {
-       my ($self) = @_;
-       $self->{url} . (length $self->{path} ? '/' . $self->{path} : '');
-}
-
-sub full_pushurl {
-       my ($self) = @_;
-       if ($self->{pushurl}) {
-               return $self->{pushurl} . (length $self->{path} ? '/' .
-                      $self->{path} : '');
-       } else {
-               return $self->full_url;
-       }
-}
-
-sub set_commit_header_env {
-       my ($log_entry) = @_;
-       my %env;
-       foreach my $ned (qw/NAME EMAIL DATE/) {
-               foreach my $ac (qw/AUTHOR COMMITTER/) {
-                       $env{"GIT_${ac}_${ned}"} = $ENV{"GIT_${ac}_${ned}"};
-               }
-       }
-
-       $ENV{GIT_AUTHOR_NAME} = $log_entry->{name};
-       $ENV{GIT_AUTHOR_EMAIL} = $log_entry->{email};
-       $ENV{GIT_AUTHOR_DATE} = $ENV{GIT_COMMITTER_DATE} = $log_entry->{date};
-
-       $ENV{GIT_COMMITTER_NAME} = (defined $log_entry->{commit_name})
-                                               ? $log_entry->{commit_name}
-                                               : $log_entry->{name};
-       $ENV{GIT_COMMITTER_EMAIL} = (defined $log_entry->{commit_email})
-                                               ? $log_entry->{commit_email}
-                                               : $log_entry->{email};
-       \%env;
-}
-
-sub restore_commit_header_env {
-       my ($env) = @_;
-       foreach my $ned (qw/NAME EMAIL DATE/) {
-               foreach my $ac (qw/AUTHOR COMMITTER/) {
-                       my $k = "GIT_${ac}_${ned}";
-                       if (defined $env->{$k}) {
-                               $ENV{$k} = $env->{$k};
-                       } else {
-                               delete $ENV{$k};
-                       }
-               }
-       }
-}
-
-sub gc {
-       command_noisy('gc', '--auto');
-};
-
-sub do_git_commit {
-       my ($self, $log_entry) = @_;
-       my $lr = $self->last_rev;
-       if (defined $lr && $lr >= $log_entry->{revision}) {
-               die "Last fetched revision of ", $self->refname,
-                   " was r$lr, but we are about to fetch: ",
-                   "r$log_entry->{revision}!\n";
-       }
-       if (my $c = $self->rev_map_get($log_entry->{revision})) {
-               croak "$log_entry->{revision} = $c already exists! ",
-                     "Why are we refetching it?\n";
-       }
-       my $old_env = set_commit_header_env($log_entry);
-       my $tree = $log_entry->{tree};
-       if (!defined $tree) {
-               $tree = $self->tmp_index_do(sub {
-                                           command_oneline('write-tree') });
-       }
-       die "Tree is not a valid sha1: $tree\n" if $tree !~ /^$::sha1$/o;
-
-       my @exec = ('git', 'commit-tree', $tree);
-       foreach ($self->get_commit_parents($log_entry)) {
-               push @exec, '-p', $_;
-       }
-       defined(my $pid = open3(my $msg_fh, my $out_fh, '>&STDERR', @exec))
-                                                                  or croak $!;
-       binmode $msg_fh;
-
-       # we always get UTF-8 from SVN, but we may want our commits in
-       # a different encoding.
-       if (my $enc = Git::config('i18n.commitencoding')) {
-               require Encode;
-               Encode::from_to($log_entry->{log}, 'UTF-8', $enc);
-       }
-       print $msg_fh $log_entry->{log} or croak $!;
-       restore_commit_header_env($old_env);
-       unless ($self->no_metadata) {
-               print $msg_fh "\ngit-svn-id: $log_entry->{metadata}\n"
-                             or croak $!;
-       }
-       $msg_fh->flush == 0 or croak $!;
-       close $msg_fh or croak $!;
-       chomp(my $commit = do { local $/; <$out_fh> });
-       close $out_fh or croak $!;
-       waitpid $pid, 0;
-       croak $? if $?;
-       if ($commit !~ /^$::sha1$/o) {
-               die "Failed to commit, invalid sha1: $commit\n";
-       }
-
-       $self->rev_map_set($log_entry->{revision}, $commit, 1);
-
-       $self->{last_rev} = $log_entry->{revision};
-       $self->{last_commit} = $commit;
-       print "r$log_entry->{revision}" unless $::_q > 1;
-       if (defined $log_entry->{svm_revision}) {
-                print " (\@$log_entry->{svm_revision})" unless $::_q > 1;
-                $self->rev_map_set($log_entry->{svm_revision}, $commit,
-                                  0, $self->svm_uuid);
-       }
-       print " = $commit ($self->{ref_id})\n" unless $::_q > 1;
-       if (--$_gc_nr == 0) {
-               $_gc_nr = $_gc_period;
-               gc();
-       }
-       return $commit;
-}
-
-sub match_paths {
-       my ($self, $paths, $r) = @_;
-       return 1 if $self->{path} eq '';
-       if (my $path = $paths->{"/$self->{path}"}) {
-               return ($path->{action} eq 'D') ? 0 : 1;
-       }
-       $self->{path_regex} ||= qr/^\/\Q$self->{path}\E\//;
-       if (grep /$self->{path_regex}/, keys %$paths) {
-               return 1;
-       }
-       my $c = '';
-       foreach (split m#/#, $self->{path}) {
-               $c .= "/$_";
-               next unless ($paths->{$c} &&
-                            ($paths->{$c}->{action} =~ /^[AR]$/));
-               if ($self->ra->check_path($self->{path}, $r) ==
-                   $SVN::Node::dir) {
-                       return 1;
-               }
-       }
-       return 0;
-}
-
-sub find_parent_branch {
-       my ($self, $paths, $rev) = @_;
-       return undef unless $self->follow_parent;
-       unless (defined $paths) {
-               my $err_handler = $SVN::Error::handler;
-               $SVN::Error::handler = \&Git::SVN::Ra::skip_unknown_revs;
-               $self->ra->get_log([$self->{path}], $rev, $rev, 0, 1, 1,
-                                  sub { $paths = $_[0] });
-               $SVN::Error::handler = $err_handler;
-       }
-       return undef unless defined $paths;
-
-       # look for a parent from another branch:
-       my @b_path_components = split m#/#, $self->{path};
-       my @a_path_components;
-       my $i;
-       while (@b_path_components) {
-               $i = $paths->{'/'.join('/', @b_path_components)};
-               last if $i && defined $i->{copyfrom_path};
-               unshift(@a_path_components, pop(@b_path_components));
-       }
-       return undef unless defined $i && defined $i->{copyfrom_path};
-       my $branch_from = $i->{copyfrom_path};
-       if (@a_path_components) {
-               print STDERR "branch_from: $branch_from => ";
-               $branch_from .= '/'.join('/', @a_path_components);
-               print STDERR $branch_from, "\n";
-       }
-       my $r = $i->{copyfrom_rev};
-       my $repos_root = $self->ra->{repos_root};
-       my $url = $self->ra->{url};
-       my $new_url = $url . $branch_from;
-       print STDERR  "Found possible branch point: ",
-                     "$new_url => ", $self->full_url, ", $r\n"
-                     unless $::_q > 1;
-       $branch_from =~ s#^/##;
-       my $gs = $self->other_gs($new_url, $url,
-                                $branch_from, $r, $self->{ref_id});
-       my ($r0, $parent) = $gs->find_rev_before($r, 1);
-       {
-               my ($base, $head);
-               if (!defined $r0 || !defined $parent) {
-                       ($base, $head) = parse_revision_argument(0, $r);
-               } else {
-                       if ($r0 < $r) {
-                               $gs->ra->get_log([$gs->{path}], $r0 + 1, $r, 1,
-                                       0, 1, sub { $base = $_[1] - 1 });
-                       }
-               }
-               if (defined $base && $base <= $r) {
-                       $gs->fetch($base, $r);
-               }
-               ($r0, $parent) = $gs->find_rev_before($r, 1);
-       }
-       if (defined $r0 && defined $parent) {
-               print STDERR "Found branch parent: ($self->{ref_id}) $parent\n"
-                            unless $::_q > 1;
-               my $ed;
-               if ($self->ra->can_do_switch) {
-                       $self->assert_index_clean($parent);
-                       print STDERR "Following parent with do_switch\n"
-                                    unless $::_q > 1;
-                       # do_switch works with svn/trunk >= r22312, but that
-                       # is not included with SVN 1.4.3 (the latest version
-                       # at the moment), so we can't rely on it
-                       $self->{last_rev} = $r0;
-                       $self->{last_commit} = $parent;
-                       $ed = Git::SVN::Fetcher->new($self, $gs->{path});
-                       $gs->ra->gs_do_switch($r0, $rev, $gs,
-                                             $self->full_url, $ed)
-                         or die "SVN connection failed somewhere...\n";
-               } elsif ($self->ra->trees_match($new_url, $r0,
-                                               $self->full_url, $rev)) {
-                       print STDERR "Trees match:\n",
-                                    "  $new_url\@$r0\n",
-                                    "  ${\$self->full_url}\@$rev\n",
-                                    "Following parent with no changes\n"
-                                    unless $::_q > 1;
-                       $self->tmp_index_do(sub {
-                           command_noisy('read-tree', $parent);
-                       });
-                       $self->{last_commit} = $parent;
-               } else {
-                       print STDERR "Following parent with do_update\n"
-                                    unless $::_q > 1;
-                       $ed = Git::SVN::Fetcher->new($self);
-                       $self->ra->gs_do_update($rev, $rev, $self, $ed)
-                         or die "SVN connection failed somewhere...\n";
-               }
-               print STDERR "Successfully followed parent\n" unless $::_q > 1;
-               return $self->make_log_entry($rev, [$parent], $ed);
-       }
-       return undef;
-}
-
-sub do_fetch {
-       my ($self, $paths, $rev) = @_;
-       my $ed;
-       my ($last_rev, @parents);
-       if (my $lc = $self->last_commit) {
-               # we can have a branch that was deleted, then re-added
-               # under the same name but copied from another path, in
-               # which case we'll have multiple parents (we don't
-               # want to break the original ref, nor lose copypath info):
-               if (my $log_entry = $self->find_parent_branch($paths, $rev)) {
-                       push @{$log_entry->{parents}}, $lc;
-                       return $log_entry;
-               }
-               $ed = Git::SVN::Fetcher->new($self);
-               $last_rev = $self->{last_rev};
-               $ed->{c} = $lc;
-               @parents = ($lc);
-       } else {
-               $last_rev = $rev;
-               if (my $log_entry = $self->find_parent_branch($paths, $rev)) {
-                       return $log_entry;
-               }
-               $ed = Git::SVN::Fetcher->new($self);
-       }
-       unless ($self->ra->gs_do_update($last_rev, $rev, $self, $ed)) {
-               die "SVN connection failed somewhere...\n";
-       }
-       $self->make_log_entry($rev, \@parents, $ed);
-}
-
-sub mkemptydirs {
-       my ($self, $r) = @_;
-
-       sub scan {
-               my ($r, $empty_dirs, $line) = @_;
-               if (defined $r && $line =~ /^r(\d+)$/) {
-                       return 0 if $1 > $r;
-               } elsif ($line =~ /^  \+empty_dir: (.+)$/) {
-                       $empty_dirs->{$1} = 1;
-               } elsif ($line =~ /^  \-empty_dir: (.+)$/) {
-                       my @d = grep {m[^\Q$1\E(/|$)]} (keys %$empty_dirs);
-                       delete @$empty_dirs{@d};
-               }
-               1; # continue
-       };
-
-       my %empty_dirs = ();
-       my $gz_file = "$self->{dir}/unhandled.log.gz";
-       if (-f $gz_file) {
-               if (!$can_compress) {
-                       warn "Compress::Zlib could not be found; ",
-                            "empty directories in $gz_file will not be read\n";
-               } else {
-                       my $gz = Compress::Zlib::gzopen($gz_file, "rb") or
-                               die "Unable to open $gz_file: $!\n";
-                       my $line;
-                       while ($gz->gzreadline($line) > 0) {
-                               scan($r, \%empty_dirs, $line) or last;
-                       }
-                       $gz->gzclose;
-               }
-       }
-
-       if (open my $fh, '<', "$self->{dir}/unhandled.log") {
-               binmode $fh or croak "binmode: $!";
-               while (<$fh>) {
-                       scan($r, \%empty_dirs, $_) or last;
-               }
-               close $fh;
-       }
-
-       my $strip = qr/\A\Q$self->{path}\E(?:\/|$)/;
-       foreach my $d (sort keys %empty_dirs) {
-               $d = uri_decode($d);
-               $d =~ s/$strip//;
-               next unless length($d);
-               next if -d $d;
-               if (-e $d) {
-                       warn "$d exists but is not a directory\n";
-               } else {
-                       print "creating empty directory: $d\n";
-                       mkpath([$d]);
-               }
-       }
-}
-
-sub get_untracked {
-       my ($self, $ed) = @_;
-       my @out;
-       my $h = $ed->{empty};
-       foreach (sort keys %$h) {
-               my $act = $h->{$_} ? '+empty_dir' : '-empty_dir';
-               push @out, "  $act: " . uri_encode($_);
-               warn "W: $act: $_\n";
-       }
-       foreach my $t (qw/dir_prop file_prop/) {
-               $h = $ed->{$t} or next;
-               foreach my $path (sort keys %$h) {
-                       my $ppath = $path eq '' ? '.' : $path;
-                       foreach my $prop (sort keys %{$h->{$path}}) {
-                               next if $SKIP_PROP{$prop};
-                               my $v = $h->{$path}->{$prop};
-                               my $t_ppath_prop = "$t: " .
-                                                   uri_encode($ppath) . ' ' .
-                                                   uri_encode($prop);
-                               if (defined $v) {
-                                       push @out, "  +$t_ppath_prop " .
-                                                  uri_encode($v);
-                               } else {
-                                       push @out, "  -$t_ppath_prop";
-                               }
-                       }
-               }
-       }
-       foreach my $t (qw/absent_file absent_directory/) {
-               $h = $ed->{$t} or next;
-               foreach my $parent (sort keys %$h) {
-                       foreach my $path (sort @{$h->{$parent}}) {
-                               push @out, "  $t: " .
-                                          uri_encode("$parent/$path");
-                               warn "W: $t: $parent/$path ",
-                                    "Insufficient permissions?\n";
-                       }
-               }
-       }
-       \@out;
-}
-
-sub get_tz {
-       # some systmes don't handle or mishandle %z, so be creative.
-       my $t = shift || time;
-       my $gm = timelocal(gmtime($t));
-       my $sign = qw( + + - )[ $t <=> $gm ];
-       return sprintf("%s%02d%02d", $sign, (gmtime(abs($t - $gm)))[2,1]);
-}
-
-# parse_svn_date(DATE)
-# --------------------
-# Given a date (in UTC) from Subversion, return a string in the format
-# "<TZ Offset> <local date/time>" that Git will use.
-#
-# By default the parsed date will be in UTC; if $Git::SVN::_localtime
-# is true we'll convert it to the local timezone instead.
-sub parse_svn_date {
-       my $date = shift || return '+0000 1970-01-01 00:00:00';
-       my ($Y,$m,$d,$H,$M,$S) = ($date =~ /^(\d{4})\-(\d\d)\-(\d\d)T
-                                           (\d\d)\:(\d\d)\:(\d\d)\.\d*Z$/x) or
-                                        croak "Unable to parse date: $date\n";
-       my $parsed_date;    # Set next.
-
-       if ($Git::SVN::_localtime) {
-               # Translate the Subversion datetime to an epoch time.
-               # Begin by switching ourselves to $date's timezone, UTC.
-               my $old_env_TZ = $ENV{TZ};
-               $ENV{TZ} = 'UTC';
-
-               my $epoch_in_UTC =
-                   POSIX::strftime('%s', $S, $M, $H, $d, $m - 1, $Y - 1900);
-
-               # Determine our local timezone (including DST) at the
-               # time of $epoch_in_UTC.  $Git::SVN::Log::TZ stored the
-               # value of TZ, if any, at the time we were run.
-               if (defined $Git::SVN::Log::TZ) {
-                       $ENV{TZ} = $Git::SVN::Log::TZ;
-               } else {
-                       delete $ENV{TZ};
-               }
-
-               my $our_TZ = get_tz();
-
-               # This converts $epoch_in_UTC into our local timezone.
-               my ($sec, $min, $hour, $mday, $mon, $year,
-                   $wday, $yday, $isdst) = localtime($epoch_in_UTC);
-
-               $parsed_date = sprintf('%s %04d-%02d-%02d %02d:%02d:%02d',
-                                      $our_TZ, $year + 1900, $mon + 1,
-                                      $mday, $hour, $min, $sec);
-
-               # Reset us to the timezone in effect when we entered
-               # this routine.
-               if (defined $old_env_TZ) {
-                       $ENV{TZ} = $old_env_TZ;
-               } else {
-                       delete $ENV{TZ};
-               }
-       } else {
-               $parsed_date = "+0000 $Y-$m-$d $H:$M:$S";
-       }
-
-       return $parsed_date;
-}
-
-sub other_gs {
-       my ($self, $new_url, $url,
-           $branch_from, $r, $old_ref_id) = @_;
-       my $gs = Git::SVN->find_by_url($new_url, $url, $branch_from);
-       unless ($gs) {
-               my $ref_id = $old_ref_id;
-               $ref_id =~ s/\@\d+-*$//;
-               $ref_id .= "\@$r";
-               # just grow a tail if we're not unique enough :x
-               $ref_id .= '-' while find_ref($ref_id);
-               my ($u, $p, $repo_id) = ($new_url, '', $ref_id);
-               if ($u =~ s#^\Q$url\E(/|$)##) {
-                       $p = $u;
-                       $u = $url;
-                       $repo_id = $self->{repo_id};
-               }
-               while (1) {
-                       # It is possible to tag two different subdirectories at
-                       # the same revision.  If the url for an existing ref
-                       # does not match, we must either find a ref with a
-                       # matching url or create a new ref by growing a tail.
-                       $gs = Git::SVN->init($u, $p, $repo_id, $ref_id, 1);
-                       my (undef, $max_commit) = $gs->rev_map_max(1);
-                       last if (!$max_commit);
-                       my ($url) = ::cmt_metadata($max_commit);
-                       last if ($url eq $gs->metadata_url);
-                       $ref_id .= '-';
-               }
-               print STDERR "Initializing parent: $ref_id\n" unless $::_q > 1;
-       }
-       $gs
-}
-
-sub call_authors_prog {
-       my ($orig_author) = @_;
-       $orig_author = command_oneline('rev-parse', '--sq-quote', $orig_author);
-       my $author = `$::_authors_prog $orig_author`;
-       if ($? != 0) {
-               die "$::_authors_prog failed with exit code $?\n"
-       }
-       if ($author =~ /^\s*(.+?)\s*<(.*)>\s*$/) {
-               my ($name, $email) = ($1, $2);
-               $email = undef if length $2 == 0;
-               return [$name, $email];
-       } else {
-               die "Author: $orig_author: $::_authors_prog returned "
-                       . "invalid author format: $author\n";
-       }
-}
-
-sub check_author {
-       my ($author) = @_;
-       if (!defined $author || length $author == 0) {
-               $author = '(no author)';
-       }
-       if (!defined $::users{$author}) {
-               if (defined $::_authors_prog) {
-                       $::users{$author} = call_authors_prog($author);
-               } elsif (defined $::_authors) {
-                       die "Author: $author not defined in $::_authors file\n";
-               }
-       }
-       $author;
-}
-
-sub find_extra_svk_parents {
-       my ($self, $ed, $tickets, $parents) = @_;
-       # aha!  svk:merge property changed...
-       my @tickets = split "\n", $tickets;
-       my @known_parents;
-       for my $ticket ( @tickets ) {
-               my ($uuid, $path, $rev) = split /:/, $ticket;
-               if ( $uuid eq $self->ra_uuid ) {
-                       my $url = $self->{url};
-                       my $repos_root = $url;
-                       my $branch_from = $path;
-                       $branch_from =~ s{^/}{};
-                       my $gs = $self->other_gs($repos_root."/".$branch_from,
-                                                $url,
-                                                $branch_from,
-                                                $rev,
-                                                $self->{ref_id});
-                       if ( my $commit = $gs->rev_map_get($rev, $uuid) ) {
-                               # wahey!  we found it, but it might be
-                               # an old one (!)
-                               push @known_parents, [ $rev, $commit ];
-                       }
-               }
-       }
-       # Ordering matters; highest-numbered commit merge tickets
-       # first, as they may account for later merge ticket additions
-       # or changes.
-       @known_parents = map {$_->[1]} sort {$b->[0] <=> $a->[0]} @known_parents;
-       for my $parent ( @known_parents ) {
-               my @cmd = ('rev-list', $parent, map { "^$_" } @$parents );
-               my ($msg_fh, $ctx) = command_output_pipe(@cmd);
-               my $new;
-               while ( <$msg_fh> ) {
-                       $new=1;last;
-               }
-               command_close_pipe($msg_fh, $ctx);
-               if ( $new ) {
-                       print STDERR
-                           "Found merge parent (svk:merge ticket): $parent\n";
-                       push @$parents, $parent;
-               }
-       }
-}
-
-sub lookup_svn_merge {
-       my $uuid = shift;
-       my $url = shift;
-       my $merge = shift;
-
-       my ($source, $revs) = split ":", $merge;
-       my $path = $source;
-       $path =~ s{^/}{};
-       my $gs = Git::SVN->find_by_url($url.$source, $url, $path);
-       if ( !$gs ) {
-               warn "Couldn't find revmap for $url$source\n";
-               return;
-       }
-       my @ranges = split ",", $revs;
-       my ($tip, $tip_commit);
-       my @merged_commit_ranges;
-       # find the tip
-       for my $range ( @ranges ) {
-               my ($bottom, $top) = split "-", $range;
-               $top ||= $bottom;
-               my $bottom_commit = $gs->find_rev_after( $bottom, 1, $top );
-               my $top_commit = $gs->find_rev_before( $top, 1, $bottom );
-
-               unless ($top_commit and $bottom_commit) {
-                       warn "W:unknown path/rev in svn:mergeinfo "
-                               ."dirprop: $source:$range\n";
-                       next;
-               }
-
-               if (scalar(command('rev-parse', "$bottom_commit^@"))) {
-                       push @merged_commit_ranges,
-                            "$bottom_commit^..$top_commit";
-               } else {
-                       push @merged_commit_ranges, "$top_commit";
-               }
-
-               if ( !defined $tip or $top > $tip ) {
-                       $tip = $top;
-                       $tip_commit = $top_commit;
-               }
-       }
-       return ($tip_commit, @merged_commit_ranges);
-}
-
-sub _rev_list {
-       my ($msg_fh, $ctx) = command_output_pipe(
-               "rev-list", @_,
-              );
-       my @rv;
-       while ( <$msg_fh> ) {
-               chomp;
-               push @rv, $_;
-       }
-       command_close_pipe($msg_fh, $ctx);
-       @rv;
-}
-
-sub check_cherry_pick {
-       my $base = shift;
-       my $tip = shift;
-       my $parents = shift;
-       my @ranges = @_;
-       my %commits = map { $_ => 1 }
-               _rev_list("--no-merges", $tip, "--not", $base, @$parents, "--");
-       for my $range ( @ranges ) {
-               delete @commits{_rev_list($range, "--")};
-       }
-       for my $commit (keys %commits) {
-               if (has_no_changes($commit)) {
-                       delete $commits{$commit};
-               }
-       }
-       return (keys %commits);
-}
-
-sub has_no_changes {
-       my $commit = shift;
-
-       my @revs = split / /, command_oneline(
-               qw(rev-list --parents -1 -m), $commit);
-
-       # Commits with no parents, e.g. the start of a partial branch,
-       # have changes by definition.
-       return 1 if (@revs < 2);
-
-       # Commits with multiple parents, e.g a merge, have no changes
-       # by definition.
-       return 0 if (@revs > 2);
-
-       return (command_oneline("rev-parse", "$commit^{tree}") eq
-               command_oneline("rev-parse", "$commit~1^{tree}"));
-}
-
-sub tie_for_persistent_memoization {
-       my $hash = shift;
-       my $path = shift;
-
-       if ($can_use_yaml) {
-               tie %$hash => 'Git::SVN::Memoize::YAML', "$path.yaml";
-       } else {
-               tie %$hash => 'Memoize::Storable', "$path.db", 'nstore';
-       }
-}
-
-# The GIT_DIR environment variable is not always set until after the command
-# line arguments are processed, so we can't memoize in a BEGIN block.
-{
-       my $memoized = 0;
-
-       sub memoize_svn_mergeinfo_functions {
-               return if $memoized;
-               $memoized = 1;
-
-               my $cache_path = "$ENV{GIT_DIR}/svn/.caches/";
-               mkpath([$cache_path]) unless -d $cache_path;
-
-               my %lookup_svn_merge_cache;
-               my %check_cherry_pick_cache;
-               my %has_no_changes_cache;
-
-               tie_for_persistent_memoization(\%lookup_svn_merge_cache,
-                   "$cache_path/lookup_svn_merge");
-               memoize 'lookup_svn_merge',
-                       SCALAR_CACHE => 'FAULT',
-                       LIST_CACHE => ['HASH' => \%lookup_svn_merge_cache],
-               ;
-
-               tie_for_persistent_memoization(\%check_cherry_pick_cache,
-                   "$cache_path/check_cherry_pick");
-               memoize 'check_cherry_pick',
-                       SCALAR_CACHE => 'FAULT',
-                       LIST_CACHE => ['HASH' => \%check_cherry_pick_cache],
-               ;
-
-               tie_for_persistent_memoization(\%has_no_changes_cache,
-                   "$cache_path/has_no_changes");
-               memoize 'has_no_changes',
-                       SCALAR_CACHE => ['HASH' => \%has_no_changes_cache],
-                       LIST_CACHE => 'FAULT',
-               ;
-       }
-
-       sub unmemoize_svn_mergeinfo_functions {
-               return if not $memoized;
-               $memoized = 0;
-
-               Memoize::unmemoize 'lookup_svn_merge';
-               Memoize::unmemoize 'check_cherry_pick';
-               Memoize::unmemoize 'has_no_changes';
-       }
-
-       Memoize::memoize 'Git::SVN::repos_root';
-}
-
-END {
-       # Force cache writeout explicitly instead of waiting for
-       # global destruction to avoid segfault in Storable:
-       # http://rt.cpan.org/Public/Bug/Display.html?id=36087
-       unmemoize_svn_mergeinfo_functions();
-}
-
-sub parents_exclude {
-       my $parents = shift;
-       my @commits = @_;
-       return unless @commits;
-
-       my @excluded;
-       my $excluded;
-       do {
-               my @cmd = ('rev-list', "-1", @commits, "--not", @$parents );
-               $excluded = command_oneline(@cmd);
-               if ( $excluded ) {
-                       my @new;
-                       my $found;
-                       for my $commit ( @commits ) {
-                               if ( $commit eq $excluded ) {
-                                       push @excluded, $commit;
-                                       $found++;
-                                       last;
-                               }
-                               else {
-                                       push @new, $commit;
-                               }
-                       }
-                       die "saw commit '$excluded' in rev-list output, "
-                               ."but we didn't ask for that commit (wanted: @commits --not @$parents)"
-                                       unless $found;
-                       @commits = @new;
-               }
-       }
-               while ($excluded and @commits);
-
-       return @excluded;
-}
-
-
-# note: this function should only be called if the various dirprops
-# have actually changed
-sub find_extra_svn_parents {
-       my ($self, $ed, $mergeinfo, $parents) = @_;
-       # aha!  svk:merge property changed...
-
-       memoize_svn_mergeinfo_functions();
-
-       # We first search for merged tips which are not in our
-       # history.  Then, we figure out which git revisions are in
-       # that tip, but not this revision.  If all of those revisions
-       # are now marked as merge, we can add the tip as a parent.
-       my @merges = split "\n", $mergeinfo;
-       my @merge_tips;
-       my $url = $self->{url};
-       my $uuid = $self->ra_uuid;
-       my %ranges;
-       for my $merge ( @merges ) {
-               my ($tip_commit, @ranges) =
-                       lookup_svn_merge( $uuid, $url, $merge );
-               unless (!$tip_commit or
-                               grep { $_ eq $tip_commit } @$parents ) {
-                       push @merge_tips, $tip_commit;
-                       $ranges{$tip_commit} = \@ranges;
-               } else {
-                       push @merge_tips, undef;
-               }
-       }
-
-       my %excluded = map { $_ => 1 }
-               parents_exclude($parents, grep { defined } @merge_tips);
-
-       # check merge tips for new parents
-       my @new_parents;
-       for my $merge_tip ( @merge_tips ) {
-               my $spec = shift @merges;
-               next unless $merge_tip and $excluded{$merge_tip};
-
-               my $ranges = $ranges{$merge_tip};
-
-               # check out 'new' tips
-               my $merge_base;
-               eval {
-                       $merge_base = command_oneline(
-                               "merge-base",
-                               @$parents, $merge_tip,
-                       );
-               };
-               if ($@) {
-                       die "An error occurred during merge-base"
-                               unless $@->isa("Git::Error::Command");
-
-                       warn "W: Cannot find common ancestor between ".
-                            "@$parents and $merge_tip. Ignoring merge info.\n";
-                       next;
-               }
-
-               # double check that there are no missing non-merge commits
-               my (@incomplete) = check_cherry_pick(
-                       $merge_base, $merge_tip,
-                       $parents,
-                       @$ranges,
-                      );
-
-               if ( @incomplete ) {
-                       warn "W:svn cherry-pick ignored ($spec) - missing "
-                               .@incomplete." commit(s) (eg $incomplete[0])\n";
-               } else {
-                       warn
-                               "Found merge parent (svn:mergeinfo prop): ",
-                                       $merge_tip, "\n";
-                       push @new_parents, $merge_tip;
-               }
-       }
-
-       # cater for merges which merge commits from multiple branches
-       if ( @new_parents > 1 ) {
-               for ( my $i = 0; $i <= $#new_parents; $i++ ) {
-                       for ( my $j = 0; $j <= $#new_parents; $j++ ) {
-                               next if $i == $j;
-                               next unless $new_parents[$i];
-                               next unless $new_parents[$j];
-                               my $revs = command_oneline(
-                                       "rev-list", "-1",
-                                       "$new_parents[$i]..$new_parents[$j]",
-                                      );
-                               if ( !$revs ) {
-                                       undef($new_parents[$j]);
-                               }
-                       }
-               }
-       }
-       push @$parents, grep { defined } @new_parents;
-}
-
-sub make_log_entry {
-       my ($self, $rev, $parents, $ed) = @_;
-       my $untracked = $self->get_untracked($ed);
-
-       my @parents = @$parents;
-       my $ps = $ed->{path_strip} || "";
-       for my $path ( grep { m/$ps/ } %{$ed->{dir_prop}} ) {
-               my $props = $ed->{dir_prop}{$path};
-               if ( $props->{"svk:merge"} ) {
-                       $self->find_extra_svk_parents
-                               ($ed, $props->{"svk:merge"}, \@parents);
-               }
-               if ( $props->{"svn:mergeinfo"} ) {
-                       $self->find_extra_svn_parents
-                               ($ed,
-                                $props->{"svn:mergeinfo"},
-                                \@parents);
-               }
-       }
-
-       open my $un, '>>', "$self->{dir}/unhandled.log" or croak $!;
-       print $un "r$rev\n" or croak $!;
-       print $un $_, "\n" foreach @$untracked;
-       my %log_entry = ( parents => \@parents, revision => $rev,
-                         log => '');
-
-       my $headrev;
-       my $logged = delete $self->{logged_rev_props};
-       if (!$logged || $self->{-want_revprops}) {
-               my $rp = $self->ra->rev_proplist($rev);
-               foreach (sort keys %$rp) {
-                       my $v = $rp->{$_};
-                       if (/^svn:(author|date|log)$/) {
-                               $log_entry{$1} = $v;
-                       } elsif ($_ eq 'svm:headrev') {
-                               $headrev = $v;
-                       } else {
-                               print $un "  rev_prop: ", uri_encode($_), ' ',
-                                         uri_encode($v), "\n";
-                       }
-               }
-       } else {
-               map { $log_entry{$_} = $logged->{$_} } keys %$logged;
-       }
-       close $un or croak $!;
-
-       $log_entry{date} = parse_svn_date($log_entry{date});
-       $log_entry{log} .= "\n";
-       my $author = $log_entry{author} = check_author($log_entry{author});
-       my ($name, $email) = defined $::users{$author} ? @{$::users{$author}}
-                                                      : ($author, undef);
-
-       my ($commit_name, $commit_email) = ($name, $email);
-       if ($_use_log_author) {
-               my $name_field;
-               if ($log_entry{log} =~ /From:\s+(.*\S)\s*\n/i) {
-                       $name_field = $1;
-               } elsif ($log_entry{log} =~ /Signed-off-by:\s+(.*\S)\s*\n/i) {
-                       $name_field = $1;
-               }
-               if (!defined $name_field) {
-                       if (!defined $email) {
-                               $email = $name;
-                       }
-               } elsif ($name_field =~ /(.*?)\s+<(.*)>/) {
-                       ($name, $email) = ($1, $2);
-               } elsif ($name_field =~ /(.*)@/) {
-                       ($name, $email) = ($1, $name_field);
-               } else {
-                       ($name, $email) = ($name_field, $name_field);
-               }
-       }
-       if (defined $headrev && $self->use_svm_props) {
-               if ($self->rewrite_root) {
-                       die "Can't have both 'useSvmProps' and 'rewriteRoot' ",
-                           "options set!\n";
-               }
-               if ($self->rewrite_uuid) {
-                       die "Can't have both 'useSvmProps' and 'rewriteUUID' ",
-                           "options set!\n";
-               }
-               my ($uuid, $r) = $headrev =~ m{^([a-f\d\-]{30,}):(\d+)$}i;
-               # we don't want "SVM: initializing mirror for junk" ...
-               return undef if $r == 0;
-               my $svm = $self->svm;
-               if ($uuid ne $svm->{uuid}) {
-                       die "UUID mismatch on SVM path:\n",
-                           "expected: $svm->{uuid}\n",
-                           "     got: $uuid\n";
-               }
-               my $full_url = $self->full_url;
-               $full_url =~ s#^\Q$svm->{replace}\E(/|$)#$svm->{source}$1# or
-                            die "Failed to replace '$svm->{replace}' with ",
-                                "'$svm->{source}' in $full_url\n";
-               # throw away username for storing in records
-               remove_username($full_url);
-               $log_entry{metadata} = "$full_url\@$r $uuid";
-               $log_entry{svm_revision} = $r;
-               $email ||= "$author\@$uuid";
-               $commit_email ||= "$author\@$uuid";
-       } elsif ($self->use_svnsync_props) {
-               my $full_url = $self->svnsync->{url};
-               $full_url .= "/$self->{path}" if length $self->{path};
-               remove_username($full_url);
-               my $uuid = $self->svnsync->{uuid};
-               $log_entry{metadata} = "$full_url\@$rev $uuid";
-               $email ||= "$author\@$uuid";
-               $commit_email ||= "$author\@$uuid";
-       } else {
-               my $url = $self->metadata_url;
-               remove_username($url);
-               my $uuid = $self->rewrite_uuid || $self->ra->get_uuid;
-               $log_entry{metadata} = "$url\@$rev " . $uuid;
-               $email ||= "$author\@" . $uuid;
-               $commit_email ||= "$author\@" . $uuid;
-       }
-       $log_entry{name} = $name;
-       $log_entry{email} = $email;
-       $log_entry{commit_name} = $commit_name;
-       $log_entry{commit_email} = $commit_email;
-       \%log_entry;
-}
-
-sub fetch {
-       my ($self, $min_rev, $max_rev, @parents) = @_;
-       my ($last_rev, $last_commit) = $self->last_rev_commit;
-       my ($base, $head) = $self->get_fetch_range($min_rev, $max_rev);
-       $self->ra->gs_fetch_loop_common($base, $head, [$self]);
-}
-
-sub set_tree_cb {
-       my ($self, $log_entry, $tree, $rev, $date, $author) = @_;
-       $self->{inject_parents} = { $rev => $tree };
-       $self->fetch(undef, undef);
-}
-
-sub set_tree {
-       my ($self, $tree) = (shift, shift);
-       my $log_entry = ::get_commit_entry($tree);
-       unless ($self->{last_rev}) {
-               ::fatal("Must have an existing revision to commit");
-       }
-       my %ed_opts = ( r => $self->{last_rev},
-                       log => $log_entry->{log},
-                       ra => $self->ra,
-                       tree_a => $self->{last_commit},
-                       tree_b => $tree,
-                       editor_cb => sub {
-                              $self->set_tree_cb($log_entry, $tree, @_) },
-                       svn_path => $self->{path} );
-       if (!Git::SVN::Editor->new(\%ed_opts)->apply_diff) {
-               print "No changes\nr$self->{last_rev} = $tree\n";
-       }
-}
-
-sub rebuild_from_rev_db {
-       my ($self, $path) = @_;
-       my $r = -1;
-       open my $fh, '<', $path or croak "open: $!";
-       binmode $fh or croak "binmode: $!";
-       while (<$fh>) {
-               length($_) == 41 or croak "inconsistent size in ($_) != 41";
-               chomp($_);
-               ++$r;
-               next if $_ eq ('0' x 40);
-               $self->rev_map_set($r, $_);
-               print "r$r = $_\n";
-       }
-       close $fh or croak "close: $!";
-       unlink $path or croak "unlink: $!";
-}
-
-sub rebuild {
-       my ($self) = @_;
-       my $map_path = $self->map_path;
-       my $partial = (-e $map_path && ! -z $map_path);
-       return unless ::verify_ref($self->refname.'^0');
-       if (!$partial && ($self->use_svm_props || $self->no_metadata)) {
-               my $rev_db = $self->rev_db_path;
-               $self->rebuild_from_rev_db($rev_db);
-               if ($self->use_svm_props) {
-                       my $svm_rev_db = $self->rev_db_path($self->svm_uuid);
-                       $self->rebuild_from_rev_db($svm_rev_db);
-               }
-               $self->unlink_rev_db_symlink;
-               return;
-       }
-       print "Rebuilding $map_path ...\n" if (!$partial);
-       my ($base_rev, $head) = ($partial ? $self->rev_map_max_norebuild(1) :
-               (undef, undef));
-       my ($log, $ctx) =
-           command_output_pipe(qw/rev-list --pretty=raw --reverse/,
-                               ($head ? "$head.." : "") . $self->refname,
-                               '--');
-       my $metadata_url = $self->metadata_url;
-       remove_username($metadata_url);
-       my $svn_uuid = $self->rewrite_uuid || $self->ra_uuid;
-       my $c;
-       while (<$log>) {
-               if ( m{^commit ($::sha1)$} ) {
-                       $c = $1;
-                       next;
-               }
-               next unless s{^\s*(git-svn-id:)}{$1};
-               my ($url, $rev, $uuid) = ::extract_metadata($_);
-               remove_username($url);
-
-               # ignore merges (from set-tree)
-               next if (!defined $rev || !$uuid);
-
-               # if we merged or otherwise started elsewhere, this is
-               # how we break out of it
-               if (($uuid ne $svn_uuid) ||
-                   ($metadata_url && $url && ($url ne $metadata_url))) {
-                       next;
-               }
-               if ($partial && $head) {
-                       print "Partial-rebuilding $map_path ...\n";
-                       print "Currently at $base_rev = $head\n";
-                       $head = undef;
-               }
-
-               $self->rev_map_set($rev, $c);
-               print "r$rev = $c\n";
-       }
-       command_close_pipe($log, $ctx);
-       print "Done rebuilding $map_path\n" if (!$partial || !$head);
-       my $rev_db_path = $self->rev_db_path;
-       if (-f $self->rev_db_path) {
-               unlink $self->rev_db_path or croak "unlink: $!";
-       }
-       $self->unlink_rev_db_symlink;
-}
-
-# rev_map:
-# Tie::File seems to be prone to offset errors if revisions get sparse,
-# it's not that fast, either.  Tie::File is also not in Perl 5.6.  So
-# one of my favorite modules is out :<  Next up would be one of the DBM
-# modules, but I'm not sure which is most portable...
-#
-# This is the replacement for the rev_db format, which was too big
-# and inefficient for large repositories with a lot of sparse history
-# (mainly tags)
-#
-# The format is this:
-#   - 24 bytes for every record,
-#     * 4 bytes for the integer representing an SVN revision number
-#     * 20 bytes representing the sha1 of a git commit
-#   - No empty padding records like the old format
-#     (except the last record, which can be overwritten)
-#   - new records are written append-only since SVN revision numbers
-#     increase monotonically
-#   - lookups on SVN revision number are done via a binary search
-#   - Piping the file to xxd -c24 is a good way of dumping it for
-#     viewing or editing (piped back through xxd -r), should the need
-#     ever arise.
-#   - The last record can be padding revision with an all-zero sha1
-#     This is used to optimize fetch performance when using multiple
-#     "fetch" directives in .git/config
-#
-# These files are disposable unless noMetadata or useSvmProps is set
-
-sub _rev_map_set {
-       my ($fh, $rev, $commit) = @_;
-
-       binmode $fh or croak "binmode: $!";
-       my $size = (stat($fh))[7];
-       ($size % 24) == 0 or croak "inconsistent size: $size";
-
-       my $wr_offset = 0;
-       if ($size > 0) {
-               sysseek($fh, -24, SEEK_END) or croak "seek: $!";
-               my $read = sysread($fh, my $buf, 24) or croak "read: $!";
-               $read == 24 or croak "read only $read bytes (!= 24)";
-               my ($last_rev, $last_commit) = unpack(rev_map_fmt, $buf);
-               if ($last_commit eq ('0' x40)) {
-                       if ($size >= 48) {
-                               sysseek($fh, -48, SEEK_END) or croak "seek: $!";
-                               $read = sysread($fh, $buf, 24) or
-                                   croak "read: $!";
-                               $read == 24 or
-                                   croak "read only $read bytes (!= 24)";
-                               ($last_rev, $last_commit) =
-                                   unpack(rev_map_fmt, $buf);
-                               if ($last_commit eq ('0' x40)) {
-                                       croak "inconsistent .rev_map\n";
-                               }
-                       }
-                       if ($last_rev >= $rev) {
-                               croak "last_rev is higher!: $last_rev >= $rev";
-                       }
-                       $wr_offset = -24;
-               }
-       }
-       sysseek($fh, $wr_offset, SEEK_END) or croak "seek: $!";
-       syswrite($fh, pack(rev_map_fmt, $rev, $commit), 24) == 24 or
-         croak "write: $!";
-}
-
-sub _rev_map_reset {
-       my ($fh, $rev, $commit) = @_;
-       my $c = _rev_map_get($fh, $rev);
-       $c eq $commit or die "_rev_map_reset(@_) commit $c does not match!\n";
-       my $offset = sysseek($fh, 0, SEEK_CUR) or croak "seek: $!";
-       truncate $fh, $offset or croak "truncate: $!";
-}
-
-sub mkfile {
-       my ($path) = @_;
-       unless (-e $path) {
-               my ($dir, $base) = ($path =~ m#^(.*?)/?([^/]+)$#);
-               mkpath([$dir]) unless -d $dir;
-               open my $fh, '>>', $path or die "Couldn't create $path: $!\n";
-               close $fh or die "Couldn't close (create) $path: $!\n";
-       }
-}
-
-sub rev_map_set {
-       my ($self, $rev, $commit, $update_ref, $uuid) = @_;
-       defined $commit or die "missing arg3\n";
-       length $commit == 40 or die "arg3 must be a full SHA1 hexsum\n";
-       my $db = $self->map_path($uuid);
-       my $db_lock = "$db.lock";
-       my $sigmask;
-       $update_ref ||= 0;
-       if ($update_ref) {
-               $sigmask = POSIX::SigSet->new();
-               my $signew = POSIX::SigSet->new(SIGINT, SIGHUP, SIGTERM,
-                       SIGALRM, SIGUSR1, SIGUSR2);
-               sigprocmask(SIG_BLOCK, $signew, $sigmask) or
-                       croak "Can't block signals: $!";
-       }
-       mkfile($db);
-
-       $LOCKFILES{$db_lock} = 1;
-       my $sync;
-       # both of these options make our .rev_db file very, very important
-       # and we can't afford to lose it because rebuild() won't work
-       if ($self->use_svm_props || $self->no_metadata) {
-               $sync = 1;
-               copy($db, $db_lock) or die "rev_map_set(@_): ",
-                                          "Failed to copy: ",
-                                          "$db => $db_lock ($!)\n";
-       } else {
-               rename $db, $db_lock or die "rev_map_set(@_): ",
-                                           "Failed to rename: ",
-                                           "$db => $db_lock ($!)\n";
-       }
-
-       sysopen(my $fh, $db_lock, O_RDWR | O_CREAT)
-            or croak "Couldn't open $db_lock: $!\n";
-       $update_ref eq 'reset' ? _rev_map_reset($fh, $rev, $commit) :
-                                _rev_map_set($fh, $rev, $commit);
-       if ($sync) {
-               $fh->flush or die "Couldn't flush $db_lock: $!\n";
-               $fh->sync or die "Couldn't sync $db_lock: $!\n";
-       }
-       close $fh or croak $!;
-       if ($update_ref) {
-               $_head = $self;
-               my $note = "";
-               $note = " ($update_ref)" if ($update_ref !~ /^\d*$/);
-               command_noisy('update-ref', '-m', "r$rev$note",
-                             $self->refname, $commit);
-       }
-       rename $db_lock, $db or die "rev_map_set(@_): ", "Failed to rename: ",
-                                   "$db_lock => $db ($!)\n";
-       delete $LOCKFILES{$db_lock};
-       if ($update_ref) {
-               sigprocmask(SIG_SETMASK, $sigmask) or
-                       croak "Can't restore signal mask: $!";
-       }
-}
-
-# If want_commit, this will return an array of (rev, commit) where
-# commit _must_ be a valid commit in the archive.
-# Otherwise, it'll return the max revision (whether or not the
-# commit is valid or just a 0x40 placeholder).
-sub rev_map_max {
-       my ($self, $want_commit) = @_;
-       $self->rebuild;
-       my ($r, $c) = $self->rev_map_max_norebuild($want_commit);
-       $want_commit ? ($r, $c) : $r;
-}
-
-sub rev_map_max_norebuild {
-       my ($self, $want_commit) = @_;
-       my $map_path = $self->map_path;
-       stat $map_path or return $want_commit ? (0, undef) : 0;
-       sysopen(my $fh, $map_path, O_RDONLY) or croak "open: $!";
-       binmode $fh or croak "binmode: $!";
-       my $size = (stat($fh))[7];
-       ($size % 24) == 0 or croak "inconsistent size: $size";
-
-       if ($size == 0) {
-               close $fh or croak "close: $!";
-               return $want_commit ? (0, undef) : 0;
-       }
-
-       sysseek($fh, -24, SEEK_END) or croak "seek: $!";
-       sysread($fh, my $buf, 24) == 24 or croak "read: $!";
-       my ($r, $c) = unpack(rev_map_fmt, $buf);
-       if ($want_commit && $c eq ('0' x40)) {
-               if ($size < 48) {
-                       return $want_commit ? (0, undef) : 0;
-               }
-               sysseek($fh, -48, SEEK_END) or croak "seek: $!";
-               sysread($fh, $buf, 24) == 24 or croak "read: $!";
-               ($r, $c) = unpack(rev_map_fmt, $buf);
-               if ($c eq ('0'x40)) {
-                       croak "Penultimate record is all-zeroes in $map_path";
-               }
-       }
-       close $fh or croak "close: $!";
-       $want_commit ? ($r, $c) : $r;
-}
-
-sub rev_map_get {
-       my ($self, $rev, $uuid) = @_;
-       my $map_path = $self->map_path($uuid);
-       return undef unless -e $map_path;
-
-       sysopen(my $fh, $map_path, O_RDONLY) or croak "open: $!";
-       my $c = _rev_map_get($fh, $rev);
-       close($fh) or croak "close: $!";
-       $c
-}
-
-sub _rev_map_get {
-       my ($fh, $rev) = @_;
-
-       binmode $fh or croak "binmode: $!";
-       my $size = (stat($fh))[7];
-       ($size % 24) == 0 or croak "inconsistent size: $size";
-
-       if ($size == 0) {
-               return undef;
-       }
-
-       my ($l, $u) = (0, $size - 24);
-       my ($r, $c, $buf);
-
-       while ($l <= $u) {
-               my $i = int(($l/24 + $u/24) / 2) * 24;
-               sysseek($fh, $i, SEEK_SET) or croak "seek: $!";
-               sysread($fh, my $buf, 24) == 24 or croak "read: $!";
-               my ($r, $c) = unpack(rev_map_fmt, $buf);
-
-               if ($r < $rev) {
-                       $l = $i + 24;
-               } elsif ($r > $rev) {
-                       $u = $i - 24;
-               } else { # $r == $rev
-                       return $c eq ('0' x 40) ? undef : $c;
-               }
-       }
-       undef;
-}
-
-# Finds the first svn revision that exists on (if $eq_ok is true) or
-# before $rev for the current branch.  It will not search any lower
-# than $min_rev.  Returns the git commit hash and svn revision number
-# if found, else (undef, undef).
-sub find_rev_before {
-       my ($self, $rev, $eq_ok, $min_rev) = @_;
-       --$rev unless $eq_ok;
-       $min_rev ||= 1;
-       my $max_rev = $self->rev_map_max;
-       $rev = $max_rev if ($rev > $max_rev);
-       while ($rev >= $min_rev) {
-               if (my $c = $self->rev_map_get($rev)) {
-                       return ($rev, $c);
-               }
-               --$rev;
-       }
-       return (undef, undef);
-}
-
-# Finds the first svn revision that exists on (if $eq_ok is true) or
-# after $rev for the current branch.  It will not search any higher
-# than $max_rev.  Returns the git commit hash and svn revision number
-# if found, else (undef, undef).
-sub find_rev_after {
-       my ($self, $rev, $eq_ok, $max_rev) = @_;
-       ++$rev unless $eq_ok;
-       $max_rev ||= $self->rev_map_max;
-       while ($rev <= $max_rev) {
-               if (my $c = $self->rev_map_get($rev)) {
-                       return ($rev, $c);
-               }
-               ++$rev;
-       }
-       return (undef, undef);
-}
-
-sub _new {
-       my ($class, $repo_id, $ref_id, $path) = @_;
-       unless (defined $repo_id && length $repo_id) {
-               $repo_id = $Git::SVN::default_repo_id;
-       }
-       unless (defined $ref_id && length $ref_id) {
-               $_prefix = '' unless defined($_prefix);
-               $_[2] = $ref_id =
-                            "refs/remotes/$_prefix$Git::SVN::default_ref_id";
-       }
-       $_[1] = $repo_id;
-       my $dir = "$ENV{GIT_DIR}/svn/$ref_id";
-
-       # Older repos imported by us used $GIT_DIR/svn/foo instead of
-       # $GIT_DIR/svn/refs/remotes/foo when tracking refs/remotes/foo
-       if ($ref_id =~ m{^refs/remotes/(.*)}) {
-               my $old_dir = "$ENV{GIT_DIR}/svn/$1";
-               if (-d $old_dir && ! -d $dir) {
-                       $dir = $old_dir;
-               }
-       }
-
-       $_[3] = $path = '' unless (defined $path);
-       mkpath([$dir]);
-       bless {
-               ref_id => $ref_id, dir => $dir, index => "$dir/index",
-               path => $path, config => "$ENV{GIT_DIR}/svn/config",
-               map_root => "$dir/.rev_map", repo_id => $repo_id }, $class;
-}
-
-# for read-only access of old .rev_db formats
-sub unlink_rev_db_symlink {
-       my ($self) = @_;
-       my $link = $self->rev_db_path;
-       $link =~ s/\.[\w-]+$// or croak "missing UUID at the end of $link";
-       if (-l $link) {
-               unlink $link or croak "unlink: $link failed!";
-       }
-}
-
-sub rev_db_path {
-       my ($self, $uuid) = @_;
-       my $db_path = $self->map_path($uuid);
-       $db_path =~ s{/\.rev_map\.}{/\.rev_db\.}
-           or croak "map_path: $db_path does not contain '/.rev_map.' !";
-       $db_path;
-}
-
-# the new replacement for .rev_db
-sub map_path {
-       my ($self, $uuid) = @_;
-       $uuid ||= $self->ra_uuid;
-       "$self->{map_root}.$uuid";
-}
-
-sub uri_encode {
-       my ($f) = @_;
-       $f =~ s#([^a-zA-Z0-9\*!\:_\./\-])#uc sprintf("%%%02x",ord($1))#eg;
-       $f
-}
-
-sub uri_decode {
-       my ($f) = @_;
-       $f =~ s#%([0-9a-fA-F]{2})#chr(hex($1))#eg;
-       $f
-}
-
-sub remove_username {
-       $_[0] =~ s{^([^:]*://)[^@]+@}{$1};
-}
-
-package Git::SVN::Log;
-use strict;
-use warnings;
-use POSIX qw/strftime/;
-use constant commit_log_separator => ('-' x 72) . "\n";
-use vars qw/$TZ $limit $color $pager $non_recursive $verbose $oneline
-            %rusers $show_commit $incremental/;
-my $l_fmt;
-
-sub cmt_showable {
-       my ($c) = @_;
-       return 1 if defined $c->{r};
-
-       # big commit message got truncated by the 16k pretty buffer in rev-list
-       if ($c->{l} && $c->{l}->[-1] eq "...\n" &&
-                               $c->{a_raw} =~ /\@([a-f\d\-]+)>$/) {
-               @{$c->{l}} = ();
-               my @log = command(qw/cat-file commit/, $c->{c});
-
-               # shift off the headers
-               shift @log while ($log[0] ne '');
-               shift @log;
-
-               # TODO: make $c->{l} not have a trailing newline in the future
-               @{$c->{l}} = map { "$_\n" } grep !/^git-svn-id: /, @log;
-
-               (undef, $c->{r}, undef) = ::extract_metadata(
-                               (grep(/^git-svn-id: /, @log))[-1]);
-       }
-       return defined $c->{r};
-}
-
-sub log_use_color {
-       return $color || Git->repository->get_colorbool('color.diff');
-}
-
-sub git_svn_log_cmd {
-       my ($r_min, $r_max, @args) = @_;
-       my $head = 'HEAD';
-       my (@files, @log_opts);
-       foreach my $x (@args) {
-               if ($x eq '--' || @files) {
-                       push @files, $x;
-               } else {
-                       if (::verify_ref("$x^0")) {
-                               $head = $x;
-                       } else {
-                               push @log_opts, $x;
-                       }
-               }
-       }
-
-       my ($url, $rev, $uuid, $gs) = ::working_head_info($head);
-       $gs ||= Git::SVN->_new;
-       my @cmd = (qw/log --abbrev-commit --pretty=raw --default/,
-                  $gs->refname);
-       push @cmd, '-r' unless $non_recursive;
-       push @cmd, qw/--raw --name-status/ if $verbose;
-       push @cmd, '--color' if log_use_color();
-       push @cmd, @log_opts;
-       if (defined $r_max && $r_max == $r_min) {
-               push @cmd, '--max-count=1';
-               if (my $c = $gs->rev_map_get($r_max)) {
-                       push @cmd, $c;
-               }
-       } elsif (defined $r_max) {
-               if ($r_max < $r_min) {
-                       ($r_min, $r_max) = ($r_max, $r_min);
-               }
-               my (undef, $c_max) = $gs->find_rev_before($r_max, 1, $r_min);
-               my (undef, $c_min) = $gs->find_rev_after($r_min, 1, $r_max);
-               # If there are no commits in the range, both $c_max and $c_min
-               # will be undefined.  If there is at least 1 commit in the
-               # range, both will be defined.
-               return () if !defined $c_min || !defined $c_max;
-               if ($c_min eq $c_max) {
-                       push @cmd, '--max-count=1', $c_min;
-               } else {
-                       push @cmd, '--boundary', "$c_min..$c_max";
-               }
-       }
-       return (@cmd, @files);
-}
-
-# adapted from pager.c
-sub config_pager {
-       if (! -t *STDOUT) {
-               $ENV{GIT_PAGER_IN_USE} = 'false';
-               $pager = undef;
-               return;
-       }
-       chomp($pager = command_oneline(qw(var GIT_PAGER)));
-       if ($pager eq 'cat') {
-               $pager = undef;
-       }
-       $ENV{GIT_PAGER_IN_USE} = defined($pager);
-}
-
-sub run_pager {
-       return unless defined $pager;
-       pipe my ($rfd, $wfd) or return;
-       defined(my $pid = fork) or ::fatal "Can't fork: $!";
-       if (!$pid) {
-               open STDOUT, '>&', $wfd or
-                                    ::fatal "Can't redirect to stdout: $!";
-               return;
-       }
-       open STDIN, '<&', $rfd or ::fatal "Can't redirect stdin: $!";
-       $ENV{LESS} ||= 'FRSX';
-       exec $pager or ::fatal "Can't run pager: $! ($pager)";
-}
-
-sub format_svn_date {
-       my $t = shift || time;
-       my $gmoff = Git::SVN::get_tz($t);
-       return strftime("%Y-%m-%d %H:%M:%S $gmoff (%a, %d %b %Y)", localtime($t));
-}
-
-sub parse_git_date {
-       my ($t, $tz) = @_;
-       # Date::Parse isn't in the standard Perl distro :(
-       if ($tz =~ s/^\+//) {
-               $t += tz_to_s_offset($tz);
-       } elsif ($tz =~ s/^\-//) {
-               $t -= tz_to_s_offset($tz);
-       }
-       return $t;
-}
-
-sub set_local_timezone {
-       if (defined $TZ) {
-               $ENV{TZ} = $TZ;
-       } else {
-               delete $ENV{TZ};
-       }
-}
-
-sub tz_to_s_offset {
-       my ($tz) = @_;
-       $tz =~ s/(\d\d)$//;
-       return ($1 * 60) + ($tz * 3600);
-}
-
-sub get_author_info {
-       my ($dest, $author, $t, $tz) = @_;
-       $author =~ s/(?:^\s*|\s*$)//g;
-       $dest->{a_raw} = $author;
-       my $au;
-       if ($::_authors) {
-               $au = $rusers{$author} || undef;
-       }
-       if (!$au) {
-               ($au) = ($author =~ /<([^>]+)\@[^>]+>$/);
-       }
-       $dest->{t} = $t;
-       $dest->{tz} = $tz;
-       $dest->{a} = $au;
-       $dest->{t_utc} = parse_git_date($t, $tz);
-}
-
-sub process_commit {
-       my ($c, $r_min, $r_max, $defer) = @_;
-       if (defined $r_min && defined $r_max) {
-               if ($r_min == $c->{r} && $r_min == $r_max) {
-                       show_commit($c);
-                       return 0;
-               }
-               return 1 if $r_min == $r_max;
-               if ($r_min < $r_max) {
-                       # we need to reverse the print order
-                       return 0 if (defined $limit && --$limit < 0);
-                       push @$defer, $c;
-                       return 1;
-               }
-               if ($r_min != $r_max) {
-                       return 1 if ($r_min < $c->{r});
-                       return 1 if ($r_max > $c->{r});
-               }
-       }
-       return 0 if (defined $limit && --$limit < 0);
-       show_commit($c);
-       return 1;
-}
-
-sub show_commit {
-       my $c = shift;
-       if ($oneline) {
-               my $x = "\n";
-               if (my $l = $c->{l}) {
-                       while ($l->[0] =~ /^\s*$/) { shift @$l }
-                       $x = $l->[0];
-               }
-               $l_fmt ||= 'A' . length($c->{r});
-               print 'r',pack($l_fmt, $c->{r}),' | ';
-               print "$c->{c} | " if $show_commit;
-               print $x;
-       } else {
-               show_commit_normal($c);
-       }
-}
-
-sub show_commit_changed_paths {
-       my ($c) = @_;
-       return unless $c->{changed};
-       print "Changed paths:\n", @{$c->{changed}};
-}
-
-sub show_commit_normal {
-       my ($c) = @_;
-       print commit_log_separator, "r$c->{r} | ";
-       print "$c->{c} | " if $show_commit;
-       print "$c->{a} | ", format_svn_date($c->{t_utc}), ' | ';
-       my $nr_line = 0;
-
-       if (my $l = $c->{l}) {
-               while ($l->[$#$l] eq "\n" && $#$l > 0
-                                         && $l->[($#$l - 1)] eq "\n") {
-                       pop @$l;
-               }
-               $nr_line = scalar @$l;
-               if (!$nr_line) {
-                       print "1 line\n\n\n";
-               } else {
-                       if ($nr_line == 1) {
-                               $nr_line = '1 line';
-                       } else {
-                               $nr_line .= ' lines';
-                       }
-                       print $nr_line, "\n";
-                       show_commit_changed_paths($c);
-                       print "\n";
-                       print $_ foreach @$l;
-               }
-       } else {
-               print "1 line\n";
-               show_commit_changed_paths($c);
-               print "\n";
-
-       }
-       foreach my $x (qw/raw stat diff/) {
-               if ($c->{$x}) {
-                       print "\n";
-                       print $_ foreach @{$c->{$x}}
-               }
-       }
-}
-
-sub cmd_show_log {
-       my (@args) = @_;
-       my ($r_min, $r_max);
-       my $r_last = -1; # prevent dupes
-       set_local_timezone();
-       if (defined $::_revision) {
-               if ($::_revision =~ /^(\d+):(\d+)$/) {
-                       ($r_min, $r_max) = ($1, $2);
-               } elsif ($::_revision =~ /^\d+$/) {
-                       $r_min = $r_max = $::_revision;
-               } else {
-                       ::fatal "-r$::_revision is not supported, use ",
-                               "standard 'git log' arguments instead";
-               }
-       }
-
-       config_pager();
-       @args = git_svn_log_cmd($r_min, $r_max, @args);
-       if (!@args) {
-               print commit_log_separator unless $incremental || $oneline;
-               return;
-       }
-       my $log = command_output_pipe(@args);
-       run_pager();
-       my (@k, $c, $d, $stat);
-       my $esc_color = qr/(?:\033\[(?:(?:\d+;)*\d*)?m)*/;
-       while (<$log>) {
-               if (/^${esc_color}commit (?:- )?($::sha1_short)/o) {
-                       my $cmt = $1;
-                       if ($c && cmt_showable($c) && $c->{r} != $r_last) {
-                               $r_last = $c->{r};
-                               process_commit($c, $r_min, $r_max, \@k) or
-                                                               goto out;
-                       }
-                       $d = undef;
-                       $c = { c => $cmt };
-               } elsif (/^${esc_color}author (.+) (\d+) ([\-\+]?\d+)$/o) {
-                       get_author_info($c, $1, $2, $3);
-               } elsif (/^${esc_color}(?:tree|parent|committer) /o) {
-                       # ignore
-               } elsif (/^${esc_color}:\d{6} \d{6} $::sha1_short/o) {
-                       push @{$c->{raw}}, $_;
-               } elsif (/^${esc_color}[ACRMDT]\t/) {
-                       # we could add $SVN->{svn_path} here, but that requires
-                       # remote access at the moment (repo_path_split)...
-                       s#^(${esc_color})([ACRMDT])\t#$1   $2 #o;
-                       push @{$c->{changed}}, $_;
-               } elsif (/^${esc_color}diff /o) {
-                       $d = 1;
-                       push @{$c->{diff}}, $_;
-               } elsif ($d) {
-                       push @{$c->{diff}}, $_;
-               } elsif (/^\ .+\ \|\s*\d+\ $esc_color[\+\-]*
-                         $esc_color*[\+\-]*$esc_color$/x) {
-                       $stat = 1;
-                       push @{$c->{stat}}, $_;
-               } elsif ($stat && /^ \d+ files changed, \d+ insertions/) {
-                       push @{$c->{stat}}, $_;
-                       $stat = undef;
-               } elsif (/^${esc_color}    (git-svn-id:.+)$/o) {
-                       ($c->{url}, $c->{r}, undef) = ::extract_metadata($1);
-               } elsif (s/^${esc_color}    //o) {
-                       push @{$c->{l}}, $_;
-               }
-       }
-       if ($c && defined $c->{r} && $c->{r} != $r_last) {
-               $r_last = $c->{r};
-               process_commit($c, $r_min, $r_max, \@k);
-       }
-       if (@k) {
-               ($r_min, $r_max) = ($r_max, $r_min);
-               process_commit($_, $r_min, $r_max) foreach reverse @k;
-       }
-out:
-       close $log;
-       print commit_log_separator unless $incremental || $oneline;
-}
-
-sub cmd_blame {
-       my $path = pop;
-
-       config_pager();
-       run_pager();
-
-       my ($fh, $ctx, $rev);
-
-       if ($_git_format) {
-               ($fh, $ctx) = command_output_pipe('blame', @_, $path);
-               while (my $line = <$fh>) {
-                       if ($line =~ /^\^?([[:xdigit:]]+)\s/) {
-                               # Uncommitted edits show up as a rev ID of
-                               # all zeros, which we can't look up with
-                               # cmt_metadata
-                               if ($1 !~ /^0+$/) {
-                                       (undef, $rev, undef) =
-                                               ::cmt_metadata($1);
-                                       $rev = '0' if (!$rev);
-                               } else {
-                                       $rev = '0';
-                               }
-                               $rev = sprintf('%-10s', $rev);
-                               $line =~ s/^\^?[[:xdigit:]]+(\s)/$rev$1/;
-                       }
-                       print $line;
-               }
-       } else {
-               ($fh, $ctx) = command_output_pipe('blame', '-p', @_, 'HEAD',
-                                                 '--', $path);
-               my ($sha1);
-               my %authors;
-               my @buffer;
-               my %dsha; #distinct sha keys
-
-               while (my $line = <$fh>) {
-                       push @buffer, $line;
-                       if ($line =~ /^([[:xdigit:]]{40})\s\d+\s\d+/) {
-                               $dsha{$1} = 1;
-                       }
-               }
-
-               my $s2r = ::cmt_sha2rev_batch([keys %dsha]);
-
-               foreach my $line (@buffer) {
-                       if ($line =~ /^([[:xdigit:]]{40})\s\d+\s\d+/) {
-                               $rev = $s2r->{$1};
-                               $rev = '0' if (!$rev)
-                       }
-                       elsif ($line =~ /^author (.*)/) {
-                               $authors{$rev} = $1;
-                               $authors{$rev} =~ s/\s/_/g;
-                       }
-                       elsif ($line =~ /^\t(.*)$/) {
-                               printf("%6s %10s %s\n", $rev, $authors{$rev}, $1);
-                       }
-               }
-       }
-       command_close_pipe($fh, $ctx);
-}
-
-package Git::SVN::Migration;
-# these version numbers do NOT correspond to actual version numbers
-# of git nor git-svn.  They are just relative.
-#
-# v0 layout: .git/$id/info/url, refs/heads/$id-HEAD
-#
-# v1 layout: .git/$id/info/url, refs/remotes/$id
-#
-# v2 layout: .git/svn/$id/info/url, refs/remotes/$id
-#
-# v3 layout: .git/svn/$id, refs/remotes/$id
-#            - info/url may remain for backwards compatibility
-#            - this is what we migrate up to this layout automatically,
-#            - this will be used by git svn init on single branches
-# v3.1 layout (auto migrated):
-#            - .rev_db => .rev_db.$UUID, .rev_db will remain as a symlink
-#              for backwards compatibility
-#
-# v4 layout: .git/svn/$repo_id/$id, refs/remotes/$repo_id/$id
-#            - this is only created for newly multi-init-ed
-#              repositories.  Similar in spirit to the
-#              --use-separate-remotes option in git-clone (now default)
-#            - we do not automatically migrate to this (following
-#              the example set by core git)
-#
-# v5 layout: .rev_db.$UUID => .rev_map.$UUID
-#            - newer, more-efficient format that uses 24-bytes per record
-#              with no filler space.
-#            - use xxd -c24 < .rev_map.$UUID to view and debug
-#            - This is a one-way migration, repositories updated to the
-#              new format will not be able to use old git-svn without
-#              rebuilding the .rev_db.  Rebuilding the rev_db is not
-#              possible if noMetadata or useSvmProps are set; but should
-#              be no problem for users that use the (sensible) defaults.
-use strict;
-use warnings;
-use Carp qw/croak/;
-use File::Path qw/mkpath/;
-use File::Basename qw/dirname basename/;
-use vars qw/$_minimize/;
-
-sub migrate_from_v0 {
-       my $git_dir = $ENV{GIT_DIR};
-       return undef unless -d $git_dir;
-       my ($fh, $ctx) = command_output_pipe(qw/rev-parse --symbolic --all/);
-       my $migrated = 0;
-       while (<$fh>) {
-               chomp;
-               my ($id, $orig_ref) = ($_, $_);
-               next unless $id =~ s#^refs/heads/(.+)-HEAD$#$1#;
-               next unless -f "$git_dir/$id/info/url";
-               my $new_ref = "refs/remotes/$id";
-               if (::verify_ref("$new_ref^0")) {
-                       print STDERR "W: $orig_ref is probably an old ",
-                                    "branch used by an ancient version of ",
-                                    "git-svn.\n",
-                                    "However, $new_ref also exists.\n",
-                                    "We will not be able ",
-                                    "to use this branch until this ",
-                                    "ambiguity is resolved.\n";
-                       next;
-               }
-               print STDERR "Migrating from v0 layout...\n" if !$migrated;
-               print STDERR "Renaming ref: $orig_ref => $new_ref\n";
-               command_noisy('update-ref', $new_ref, $orig_ref);
-               command_noisy('update-ref', '-d', $orig_ref, $orig_ref);
-               $migrated++;
-       }
-       command_close_pipe($fh, $ctx);
-       print STDERR "Done migrating from v0 layout...\n" if $migrated;
-       $migrated;
-}
-
-sub migrate_from_v1 {
-       my $git_dir = $ENV{GIT_DIR};
-       my $migrated = 0;
-       return $migrated unless -d $git_dir;
-       my $svn_dir = "$git_dir/svn";
-
-       # just in case somebody used 'svn' as their $id at some point...
-       return $migrated if -d $svn_dir && ! -f "$svn_dir/info/url";
-
-       print STDERR "Migrating from a git-svn v1 layout...\n";
-       mkpath([$svn_dir]);
-       print STDERR "Data from a previous version of git-svn exists, but\n\t",
-                    "$svn_dir\n\t(required for this version ",
-                    "($::VERSION) of git-svn) does not exist.\n";
-       my ($fh, $ctx) = command_output_pipe(qw/rev-parse --symbolic --all/);
-       while (<$fh>) {
-               my $x = $_;
-               next unless $x =~ s#^refs/remotes/##;
-               chomp $x;
-               next unless -f "$git_dir/$x/info/url";
-               my $u = eval { ::file_to_s("$git_dir/$x/info/url") };
-               next unless $u;
-               my $dn = dirname("$git_dir/svn/$x");
-               mkpath([$dn]) unless -d $dn;
-               if ($x eq 'svn') { # they used 'svn' as GIT_SVN_ID:
-                       mkpath(["$git_dir/svn/svn"]);
-                       print STDERR " - $git_dir/$x/info => ",
-                                       "$git_dir/svn/$x/info\n";
-                       rename "$git_dir/$x/info", "$git_dir/svn/$x/info" or
-                              croak "$!: $x";
-                       # don't worry too much about these, they probably
-                       # don't exist with repos this old (save for index,
-                       # and we can easily regenerate that)
-                       foreach my $f (qw/unhandled.log index .rev_db/) {
-                               rename "$git_dir/$x/$f", "$git_dir/svn/$x/$f";
-                       }
-               } else {
-                       print STDERR " - $git_dir/$x => $git_dir/svn/$x\n";
-                       rename "$git_dir/$x", "$git_dir/svn/$x" or
-                              croak "$!: $x";
-               }
-               $migrated++;
-       }
-       command_close_pipe($fh, $ctx);
-       print STDERR "Done migrating from a git-svn v1 layout\n";
-       $migrated;
-}
-
-sub read_old_urls {
-       my ($l_map, $pfx, $path) = @_;
-       my @dir;
-       foreach (<$path/*>) {
-               if (-r "$_/info/url") {
-                       $pfx .= '/' if $pfx && $pfx !~ m!/$!;
-                       my $ref_id = $pfx . basename $_;
-                       my $url = ::file_to_s("$_/info/url");
-                       $l_map->{$ref_id} = $url;
-               } elsif (-d $_) {
-                       push @dir, $_;
-               }
-       }
-       foreach (@dir) {
-               my $x = $_;
-               $x =~ s!^\Q$ENV{GIT_DIR}\E/svn/!!o;
-               read_old_urls($l_map, $x, $_);
-       }
-}
-
-sub migrate_from_v2 {
-       my @cfg = command(qw/config -l/);
-       return if grep /^svn-remote\..+\.url=/, @cfg;
-       my %l_map;
-       read_old_urls(\%l_map, '', "$ENV{GIT_DIR}/svn");
-       my $migrated = 0;
-
-       foreach my $ref_id (sort keys %l_map) {
-               eval { Git::SVN->init($l_map{$ref_id}, '', undef, $ref_id) };
-               if ($@) {
-                       Git::SVN->init($l_map{$ref_id}, '', $ref_id, $ref_id);
-               }
-               $migrated++;
-       }
-       $migrated;
-}
-
-sub minimize_connections {
-       my $r = Git::SVN::read_all_remotes();
-       my $new_urls = {};
-       my $root_repos = {};
-       foreach my $repo_id (keys %$r) {
-               my $url = $r->{$repo_id}->{url} or next;
-               my $fetch = $r->{$repo_id}->{fetch} or next;
-               my $ra = Git::SVN::Ra->new($url);
-
-               # skip existing cases where we already connect to the root
-               if (($ra->{url} eq $ra->{repos_root}) ||
-                   ($ra->{repos_root} eq $repo_id)) {
-                       $root_repos->{$ra->{url}} = $repo_id;
-                       next;
-               }
-
-               my $root_ra = Git::SVN::Ra->new($ra->{repos_root});
-               my $root_path = $ra->{url};
-               $root_path =~ s#^\Q$ra->{repos_root}\E(/|$)##;
-               foreach my $path (keys %$fetch) {
-                       my $ref_id = $fetch->{$path};
-                       my $gs = Git::SVN->new($ref_id, $repo_id, $path);
-
-                       # make sure we can read when connecting to
-                       # a higher level of a repository
-                       my ($last_rev, undef) = $gs->last_rev_commit;
-                       if (!defined $last_rev) {
-                               $last_rev = eval {
-                                       $root_ra->get_latest_revnum;
-                               };
-                               next if $@;
-                       }
-                       my $new = $root_path;
-                       $new .= length $path ? "/$path" : '';
-                       eval {
-                               $root_ra->get_log([$new], $last_rev, $last_rev,
-                                                 0, 0, 1, sub { });
-                       };
-                       next if $@;
-                       $new_urls->{$ra->{repos_root}}->{$new} =
-                               { ref_id => $ref_id,
-                                 old_repo_id => $repo_id,
-                                 old_path => $path };
-               }
-       }
-
-       my @emptied;
-       foreach my $url (keys %$new_urls) {
-               # see if we can re-use an existing [svn-remote "repo_id"]
-               # instead of creating a(n ugly) new section:
-               my $repo_id = $root_repos->{$url} || $url;
-
-               my $fetch = $new_urls->{$url};
-               foreach my $path (keys %$fetch) {
-                       my $x = $fetch->{$path};
-                       Git::SVN->init($url, $path, $repo_id, $x->{ref_id});
-                       my $pfx = "svn-remote.$x->{old_repo_id}";
-
-                       my $old_fetch = quotemeta("$x->{old_path}:".
-                                                 "$x->{ref_id}");
-                       command_noisy(qw/config --unset/,
-                                     "$pfx.fetch", '^'. $old_fetch . '$');
-                       delete $r->{$x->{old_repo_id}}->
-                              {fetch}->{$x->{old_path}};
-                       if (!keys %{$r->{$x->{old_repo_id}}->{fetch}}) {
-                               command_noisy(qw/config --unset/,
-                                             "$pfx.url");
-                               push @emptied, $x->{old_repo_id}
-                       }
-               }
-       }
-       if (@emptied) {
-               my $file = $ENV{GIT_CONFIG} || "$ENV{GIT_DIR}/config";
-               print STDERR <<EOF;
-The following [svn-remote] sections in your config file ($file) are empty
-and can be safely removed:
-EOF
-               print STDERR "[svn-remote \"$_\"]\n" foreach @emptied;
-       }
-}
-
-sub migration_check {
-       migrate_from_v0();
-       migrate_from_v1();
-       migrate_from_v2();
-       minimize_connections() if $_minimize;
-}
-
-package Git::IndexInfo;
-use strict;
-use warnings;
-use Git qw/command_input_pipe command_close_pipe/;
-
-sub new {
-       my ($class) = @_;
-       my ($gui, $ctx) = command_input_pipe(qw/update-index -z --index-info/);
-       bless { gui => $gui, ctx => $ctx, nr => 0}, $class;
-}
-
-sub remove {
-       my ($self, $path) = @_;
-       if (print { $self->{gui} } '0 ', 0 x 40, "\t", $path, "\0") {
-               return ++$self->{nr};
-       }
-       undef;
-}
-
-sub update {
-       my ($self, $mode, $hash, $path) = @_;
-       if (print { $self->{gui} } $mode, ' ', $hash, "\t", $path, "\0") {
-               return ++$self->{nr};
-       }
-       undef;
-}
-
-sub DESTROY {
-       my ($self) = @_;
-       command_close_pipe($self->{gui}, $self->{ctx});
-}
-
-package Git::SVN::GlobSpec;
-use strict;
-use warnings;
-
-sub new {
-       my ($class, $glob, $pattern_ok) = @_;
-       my $re = $glob;
-       $re =~ s!/+$!!g; # no need for trailing slashes
-       my (@left, @right, @patterns);
-       my $state = "left";
-       my $die_msg = "Only one set of wildcard directories " .
-                               "(e.g. '*' or '*/*/*') is supported: '$glob'\n";
-       for my $part (split(m|/|, $glob)) {
-               if ($part =~ /\*/ && $part ne "*") {
-                       die "Invalid pattern in '$glob': $part\n";
-               } elsif ($pattern_ok && $part =~ /[{}]/ &&
-                        $part !~ /^\{[^{}]+\}/) {
-                       die "Invalid pattern in '$glob': $part\n";
-               }
-               if ($part eq "*") {
-                       die $die_msg if $state eq "right";
-                       $state = "pattern";
-                       push(@patterns, "[^/]*");
-               } elsif ($pattern_ok && $part =~ /^\{(.*)\}$/) {
-                       die $die_msg if $state eq "right";
-                       $state = "pattern";
-                       my $p = quotemeta($1);
-                       $p =~ s/\\,/|/g;
-                       push(@patterns, "(?:$p)");
-               } else {
-                       if ($state eq "left") {
-                               push(@left, $part);
-                       } else {
-                               push(@right, $part);
-                               $state = "right";
-                       }
-               }
-       }
-       my $depth = @patterns;
-       if ($depth == 0) {
-               die "One '*' is needed in glob: '$glob'\n";
-       }
-       my $left = join('/', @left);
-       my $right = join('/', @right);
-       $re = join('/', @patterns);
-       $re = join('\/',
-                  grep(length, quotemeta($left), "($re)", quotemeta($right)));
-       my $left_re = qr/^\/\Q$left\E(\/|$)/;
-       bless { left => $left, right => $right, left_regex => $left_re,
-               regex => qr/$re/, glob => $glob, depth => $depth }, $class;
-}
-
-sub full_path {
-       my ($self, $path) = @_;
-       return (length $self->{left} ? "$self->{left}/" : '') .
-              $path . (length $self->{right} ? "/$self->{right}" : '');
-}
-
 __END__
 
 Data structures:
diff --git a/git.c b/git.c
index d232de92e496bd5750015edce22d3b67f236b605..8788b32ccd891eb4db25fd6f1232935635d5a153 100644 (file)
--- a/git.c
+++ b/git.c
@@ -256,8 +256,6 @@ static int handle_alias(int *argcp, const char ***argv)
        return ret;
 }
 
-const char git_version_string[] = GIT_VERSION;
-
 #define RUN_SETUP              (1<<0)
 #define RUN_SETUP_GENTLY       (1<<1)
 #define USE_PAGER              (1<<2)
@@ -353,6 +351,7 @@ static void handle_internal_command(int argc, const char **argv)
                { "commit-tree", cmd_commit_tree, RUN_SETUP },
                { "config", cmd_config, RUN_SETUP_GENTLY },
                { "count-objects", cmd_count_objects, RUN_SETUP },
+               { "credential", cmd_credential, RUN_SETUP_GENTLY },
                { "describe", cmd_describe, RUN_SETUP },
                { "diff", cmd_diff },
                { "diff-files", cmd_diff_files, RUN_SETUP | NEED_WORK_TREE },
index 6f24f53d217884607f1bf04c4b2f715cf6ad78ac..d93bd990a9d7fc9ad7c926e25f5d58f4e7514260 100755 (executable)
@@ -11533,6 +11533,11 @@ if {[catch {package require Tk 8.4} err]} {
     exit 1
 }
 
+# Unset GIT_TRACE var if set
+if { [info exists ::env(GIT_TRACE)] } {
+    unset ::env(GIT_TRACE)
+}
+
 # defaults...
 set wrcomcmd "git diff-tree --stdin -p --pretty"
 
index a40ed0ceb0756d85e26afaabf6d46b7c9105f576..10ed9e51a5880430f7f109ff83f950a768a7c530 100755 (executable)
@@ -4489,30 +4489,33 @@ sub git_print_log {
        }
 
        # print log
-       my $signoff = 0;
-       my $empty = 0;
+       my $skip_blank_line = 0;
        foreach my $line (@$log) {
-               if ($line =~ m/^ *(signed[ \-]off[ \-]by[ :]|acked[ \-]by[ :]|cc[ :])/i) {
-                       $signoff = 1;
-                       $empty = 0;
+               if ($line =~ m/^\s*([A-Z][-A-Za-z]*-[Bb]y|C[Cc]): /) {
                        if (! $opts{'-remove_signoff'}) {
                                print "<span class=\"signoff\">" . esc_html($line) . "</span><br/>\n";
-                               next;
-                       } else {
-                               # remove signoff lines
-                               next;
+                               $skip_blank_line = 1;
                        }
-               } else {
-                       $signoff = 0;
+                       next;
+               }
+
+               if ($line =~ m,\s*([a-z]*link): (https?://\S+),i) {
+                       if (! $opts{'-remove_signoff'}) {
+                               print "<span class=\"signoff\">" . esc_html($1) . ": " .
+                                       "<a href=\"" . esc_html($2) . "\">" . esc_html($2) . "</a>" .
+                                       "</span><br/>\n";
+                               $skip_blank_line = 1;
+                       }
+                       next;
                }
 
                # print only one empty line
                # do not print empty line after signoff
                if ($line eq "") {
-                       next if ($empty || $signoff);
-                       $empty = 1;
+                       next if ($skip_blank_line);
+                       $skip_blank_line = 1;
                } else {
-                       $empty = 0;
+                       $skip_blank_line = 0;
                }
 
                print format_log_line_html($line) . "<br/>\n";
@@ -4520,7 +4523,7 @@ sub git_print_log {
 
        if ($opts{'-final_empty_line'}) {
                # end with single empty line
-               print "<br/>\n" unless $empty;
+               print "<br/>\n" unless $skip_blank_line;
        }
 }
 
@@ -8025,7 +8028,7 @@ sub git_feed {
                %latest_commit = %{$commitlist[0]};
                my $latest_epoch = $latest_commit{'committer_epoch'};
                exit_if_unmodified_since($latest_epoch);
-               %latest_date = parse_date($latest_epoch, $latest_commit{'comitter_tz'});
+               %latest_date = parse_date($latest_epoch, $latest_commit{'committer_tz'});
        }
        print $cgi->header(
                -type => $content_type,
diff --git a/graph.c b/graph.c
index 7e0a099f8329757b24770ec6788bf83a8398d76d..e864fe2c6a21379398e454e60627e78a63a09462 100644 (file)
--- a/graph.c
+++ b/graph.c
@@ -7,6 +7,34 @@
 
 /* Internal API */
 
+/*
+ * Output the next line for a graph.
+ * This formats the next graph line into the specified strbuf.  It is not
+ * terminated with a newline.
+ *
+ * Returns 1 if the line includes the current commit, and 0 otherwise.
+ * graph_next_line() will return 1 exactly once for each time
+ * graph_update() is called.
+ */
+static int graph_next_line(struct git_graph *graph, struct strbuf *sb);
+
+/*
+ * Set up a custom scheme for column colors.
+ *
+ * The default column color scheme inserts ANSI color escapes to colorize
+ * the graph. The various color escapes are stored in an array of strings
+ * where each entry corresponds to a color, except for the last entry,
+ * which denotes the escape for resetting the color back to the default.
+ * When generating the graph, strings from this array are inserted before
+ * and after the various column characters.
+ *
+ * This function allows you to enable a custom array of color escapes.
+ * The 'colors_max' argument is the index of the last "reset" entry.
+ *
+ * This functions must be called BEFORE graph_init() is called.
+ */
+static void graph_set_column_colors(const char **colors, unsigned short colors_max);
+
 /*
  * Output a padding line in the graph.
  * This is similar to graph_next_line().  However, it is guaranteed to
@@ -62,7 +90,7 @@ enum graph_state {
 static const char **column_colors;
 static unsigned short column_colors_max;
 
-void graph_set_column_colors(const char **colors, unsigned short colors_max)
+static void graph_set_column_colors(const char **colors, unsigned short colors_max)
 {
        column_colors = colors;
        column_colors_max = colors_max;
@@ -1116,7 +1144,7 @@ static void graph_output_collapsing_line(struct git_graph *graph, struct strbuf
                graph_update_state(graph, GRAPH_PADDING);
 }
 
-int graph_next_line(struct git_graph *graph, struct strbuf *sb)
+static int graph_next_line(struct git_graph *graph, struct strbuf *sb)
 {
        switch (graph->state) {
        case GRAPH_PADDING:
diff --git a/graph.h b/graph.h
index aff960c7e8f63f49e3ec16afb0b891cf257ce999..19b0f6631654f428cb76e9493325646163899a0b 100644 (file)
--- a/graph.h
+++ b/graph.h
@@ -4,22 +4,6 @@
 /* A graph is a pointer to this opaque structure */
 struct git_graph;
 
-/*
- * Set up a custom scheme for column colors.
- *
- * The default column color scheme inserts ANSI color escapes to colorize
- * the graph. The various color escapes are stored in an array of strings
- * where each entry corresponds to a color, except for the last entry,
- * which denotes the escape for resetting the color back to the default.
- * When generating the graph, strings from this array are inserted before
- * and after the various column characters.
- *
- * This function allows you to enable a custom array of color escapes.
- * The 'colors_max' argument is the index of the last "reset" entry.
- *
- * This functions must be called BEFORE graph_init() is called.
- */
-void graph_set_column_colors(const char **colors, unsigned short colors_max);
 
 /*
  * Create a new struct git_graph.
@@ -49,17 +33,6 @@ void graph_update(struct git_graph *graph, struct commit *commit);
  */
 int graph_is_commit_finished(struct git_graph const *graph);
 
-/*
- * Output the next line for a graph.
- * This formats the next graph line into the specified strbuf.  It is not
- * terminated with a newline.
- *
- * Returns 1 if the line includes the current commit, and 0 otherwise.
- * graph_next_line() will return 1 exactly once for each time
- * graph_update() is called.
- */
-int graph_next_line(struct git_graph *graph, struct strbuf *sb);
-
 
 /*
  * graph_show_*: helper functions for printing to stdout
diff --git a/grep.c b/grep.c
index 04e3ec6c6e90e8bd96495c7b40bcb014384b07d8..4bd1b8b1dd67e4f5c2223536b435198ce67463ba 100644 (file)
--- a/grep.c
+++ b/grep.c
@@ -3,6 +3,187 @@
 #include "userdiff.h"
 #include "xdiff-interface.h"
 
+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,
                                        enum grep_pat_token t,
@@ -60,6 +241,8 @@ void append_header_grep_pattern(struct grep_opt *opt,
 {
        struct grep_pat *p = create_grep_pat(pat, strlen(pat), "header", 0,
                                             GREP_PATTERN_HEAD, field);
+       if (field == GREP_HEADER_REFLOG)
+               opt->use_reflog_filter = 1;
        do_append_grep_pat(&opt->header_tail, p);
 }
 
@@ -332,6 +515,87 @@ static struct grep_expr *compile_pattern_expr(struct grep_pat **list)
        return compile_pattern_or(list);
 }
 
+static void indent(int in)
+{
+       while (in-- > 0)
+               fputc(' ', stderr);
+}
+
+static void dump_grep_pat(struct grep_pat *p)
+{
+       switch (p->token) {
+       case GREP_AND: fprintf(stderr, "*and*"); break;
+       case GREP_OPEN_PAREN: fprintf(stderr, "*(*"); break;
+       case GREP_CLOSE_PAREN: fprintf(stderr, "*)*"); break;
+       case GREP_NOT: fprintf(stderr, "*not*"); break;
+       case GREP_OR: fprintf(stderr, "*or*"); break;
+
+       case GREP_PATTERN: fprintf(stderr, "pattern"); break;
+       case GREP_PATTERN_HEAD: fprintf(stderr, "pattern_head"); break;
+       case GREP_PATTERN_BODY: fprintf(stderr, "pattern_body"); break;
+       }
+
+       switch (p->token) {
+       default: break;
+       case GREP_PATTERN_HEAD:
+               fprintf(stderr, "<head %d>", p->field); break;
+       case GREP_PATTERN_BODY:
+               fprintf(stderr, "<body>"); break;
+       }
+       switch (p->token) {
+       default: break;
+       case GREP_PATTERN_HEAD:
+       case GREP_PATTERN_BODY:
+       case GREP_PATTERN:
+               fprintf(stderr, "%.*s", (int)p->patternlen, p->pattern);
+               break;
+       }
+       fputc('\n', stderr);
+}
+
+static void dump_grep_expression_1(struct grep_expr *x, int in)
+{
+       indent(in);
+       switch (x->node) {
+       case GREP_NODE_TRUE:
+               fprintf(stderr, "true\n");
+               break;
+       case GREP_NODE_ATOM:
+               dump_grep_pat(x->u.atom);
+               break;
+       case GREP_NODE_NOT:
+               fprintf(stderr, "(not\n");
+               dump_grep_expression_1(x->u.unary, in+1);
+               indent(in);
+               fprintf(stderr, ")\n");
+               break;
+       case GREP_NODE_AND:
+               fprintf(stderr, "(and\n");
+               dump_grep_expression_1(x->u.binary.left, in+1);
+               dump_grep_expression_1(x->u.binary.right, in+1);
+               indent(in);
+               fprintf(stderr, ")\n");
+               break;
+       case GREP_NODE_OR:
+               fprintf(stderr, "(or\n");
+               dump_grep_expression_1(x->u.binary.left, in+1);
+               dump_grep_expression_1(x->u.binary.right, in+1);
+               indent(in);
+               fprintf(stderr, ")\n");
+               break;
+       }
+}
+
+static void dump_grep_expression(struct grep_opt *opt)
+{
+       struct grep_expr *x = opt->pattern_expression;
+
+       if (opt->all_match)
+               fprintf(stderr, "[all-match]\n");
+       dump_grep_expression_1(x, 0);
+       fflush(NULL);
+}
+
 static struct grep_expr *grep_true_expr(void)
 {
        struct grep_expr *z = xcalloc(1, sizeof(*z));
@@ -395,7 +659,23 @@ static struct grep_expr *prep_header_patterns(struct grep_opt *opt)
        return header_expr;
 }
 
-void compile_grep_patterns(struct grep_opt *opt)
+static struct grep_expr *grep_splice_or(struct grep_expr *x, struct grep_expr *y)
+{
+       struct grep_expr *z = x;
+
+       while (x) {
+               assert(x->node == GREP_NODE_OR);
+               if (x->u.binary.right &&
+                   x->u.binary.right->node == GREP_NODE_TRUE) {
+                       x->u.binary.right = y;
+                       break;
+               }
+               x = x->u.binary.right;
+       }
+       return z;
+}
+
+static void compile_grep_patterns_real(struct grep_opt *opt)
 {
        struct grep_pat *p;
        struct grep_expr *header_expr = prep_header_patterns(opt);
@@ -415,7 +695,7 @@ void compile_grep_patterns(struct grep_opt *opt)
 
        if (opt->all_match || header_expr)
                opt->extended = 1;
-       else if (!opt->extended)
+       else if (!opt->extended && !opt->debug)
                return;
 
        p = opt->pattern_list;
@@ -429,12 +709,22 @@ void compile_grep_patterns(struct grep_opt *opt)
 
        if (!opt->pattern_expression)
                opt->pattern_expression = header_expr;
+       else if (opt->all_match)
+               opt->pattern_expression = grep_splice_or(header_expr,
+                                                        opt->pattern_expression);
        else
                opt->pattern_expression = grep_or_expr(opt->pattern_expression,
                                                       header_expr);
        opt->all_match = 1;
 }
 
+void compile_grep_patterns(struct grep_opt *opt)
+{
+       compile_grep_patterns_real(opt);
+       if (opt->debug)
+               dump_grep_expression(opt);
+}
+
 static void free_pattern_expr(struct grep_expr *x)
 {
        switch (x->node) {
@@ -586,6 +876,7 @@ static struct {
 } header_field[] = {
        { "author ", 7 },
        { "committer ", 10 },
+       { "reflog ", 7 },
 };
 
 static int match_one_pattern(struct grep_pat *p, char *bol, char *eol,
@@ -609,7 +900,14 @@ static int match_one_pattern(struct grep_pat *p, char *bol, char *eol,
                if (strncmp(bol, field, len))
                        return 0;
                bol += len;
-               saved_ch = strip_timestamp(bol, &eol);
+               switch (p->field) {
+               case GREP_HEADER_AUTHOR:
+               case GREP_HEADER_COMMITTER:
+                       saved_ch = strip_timestamp(bol, &eol);
+                       break;
+               default:
+                       break;
+               }
        }
 
  again:
@@ -1252,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;
 
@@ -1263,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;
@@ -1288,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);
@@ -1358,7 +1660,7 @@ static int grep_source_load_file(struct grep_source *gs)
        return 0;
 }
 
-int grep_source_load(struct grep_source *gs)
+static int grep_source_load(struct grep_source *gs)
 {
        if (gs->buf)
                return 0;
@@ -1380,13 +1682,14 @@ 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();
 }
 
-int grep_source_is_binary(struct grep_source *gs)
+static int grep_source_is_binary(struct grep_source *gs)
 {
        grep_source_load_driver(gs);
        if (gs->driver->binary != -1)
diff --git a/grep.h b/grep.h
index ed7de6bec8e604a7b3dcb9f9a19053696b7c3fdf..8fc854f400802c3329fc3c028942de55b820ac90 100644 (file)
--- a/grep.h
+++ b/grep.h
@@ -29,9 +29,12 @@ enum grep_context {
 
 enum grep_header_field {
        GREP_HEADER_AUTHOR = 0,
-       GREP_HEADER_COMMITTER
+       GREP_HEADER_COMMITTER,
+       GREP_HEADER_REFLOG,
+
+       /* Must be at the end of the enum */
+       GREP_HEADER_FIELD_MAX
 };
-#define GREP_HEADER_FIELD_MAX (GREP_HEADER_COMMITTER + 1)
 
 struct grep_pat {
        struct grep_pat *next;
@@ -58,6 +61,14 @@ enum grep_expr_node {
        GREP_NODE_OR
 };
 
+enum grep_pattern_type {
+       GREP_PATTERN_TYPE_UNSPECIFIED = 0,
+       GREP_PATTERN_TYPE_BRE,
+       GREP_PATTERN_TYPE_ERE,
+       GREP_PATTERN_TYPE_FIXED,
+       GREP_PATTERN_TYPE_PCRE
+};
+
 struct grep_expr {
        enum grep_expr_node node;
        unsigned hit;
@@ -90,11 +101,13 @@ struct grep_opt {
        int word_regexp;
        int fixed;
        int all_match;
+       int debug;
 #define GREP_BINARY_DEFAULT    0
 #define GREP_BINARY_NOMATCH    1
 #define GREP_BINARY_TEXT       2
        int binary;
        int extended;
+       int use_reflog_filter;
        int pcre;
        int relative;
        int pathname;
@@ -103,6 +116,8 @@ struct grep_opt {
        int max_depth;
        int funcname;
        int funcbody;
+       int extended_regexp_option;
+       int pattern_type_option;
        char color_context[COLOR_MAXLEN];
        char color_filename[COLOR_MAXLEN];
        char color_function[COLOR_MAXLEN];
@@ -123,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 *);
@@ -143,16 +164,17 @@ 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);
-int grep_source_load(struct grep_source *gs);
+                     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);
-int grep_source_is_binary(struct grep_source *gs);
+
 
 int grep_source(struct grep_opt *opt, struct grep_source *gs);
 
diff --git a/help.c b/help.c
index 6012c07b735a541659cd75e2334563aeb933bfcb..2a42ec6d1f312b573d7b1da1a15471d21efc5b4d 100644 (file)
--- a/help.c
+++ b/help.c
@@ -6,6 +6,7 @@
 #include "common-cmds.h"
 #include "string-list.h"
 #include "column.h"
+#include "version.h"
 
 void add_cmdname(struct cmdnames *cmds, const char *name, int len)
 {
@@ -43,9 +44,12 @@ static void uniq(struct cmdnames *cmds)
        if (!cmds->cnt)
                return;
 
-       for (i = j = 1; i < cmds->cnt; i++)
-               if (strcmp(cmds->names[i]->name, cmds->names[i-1]->name))
+       for (i = j = 1; i < cmds->cnt; i++) {
+               if (!strcmp(cmds->names[i]->name, cmds->names[j-1]->name))
+                       free(cmds->names[i]);
+               else
                        cmds->names[j++] = cmds->names[i];
+       }
 
        cmds->cnt = j;
 }
@@ -60,9 +64,10 @@ void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes)
                cmp = strcmp(cmds->names[ci]->name, excludes->names[ei]->name);
                if (cmp < 0)
                        cmds->names[cj++] = cmds->names[ci++];
-               else if (cmp == 0)
-                       ci++, ei++;
-               else if (cmp > 0)
+               else if (cmp == 0) {
+                       ei++;
+                       free(cmds->names[ci++]);
+               } else if (cmp > 0)
                        ei++;
        }
 
index a832ca77a31245e8ef9c71adcc0d7110fcda1e5c..8701c1215d21cd0413c1d69be91b309984cf6b1f 100644 (file)
@@ -1610,9 +1610,8 @@ static int verify_merge_base(unsigned char *head_sha1, struct ref *remote)
 {
        struct commit *head = lookup_commit_or_die(head_sha1, "HEAD");
        struct commit *branch = lookup_commit_or_die(remote->old_sha1, remote->name);
-       struct commit_list *merge_bases = get_merge_bases(head, branch, 1);
 
-       return (merge_bases && !merge_bases->next && merge_bases->item == branch);
+       return in_merge_bases(branch, head);
 }
 
 static int delete_remote_branch(const char *pattern, int force)
index 51a906e9e3316582561304995e1a1bbbdcd6ca7c..1516c5eb290746bad4551515fda7930d2f55d32b 100644 (file)
@@ -396,7 +396,7 @@ static int fetch_indices(struct walker *walker, struct alt_base *repo)
        return ret;
 }
 
-static int fetch_pack(struct walker *walker, struct alt_base *repo, unsigned char *sha1)
+static int http_fetch_pack(struct walker *walker, struct alt_base *repo, unsigned char *sha1)
 {
        struct packed_git *target;
        int ret;
@@ -524,7 +524,7 @@ static int fetch(struct walker *walker, unsigned char *sha1)
        if (!fetch_object(walker, altbase, sha1))
                return 0;
        while (altbase) {
-               if (!fetch_pack(walker, altbase, sha1))
+               if (!http_fetch_pack(walker, altbase, sha1))
                        return 0;
                fetch_alternates(walker, data->alt->base);
                altbase = altbase->next;
diff --git a/http.c b/http.c
index 0a27b146adb15ad97407ed2c196878058f0ccec8..98c0b2b362c531234ac9d02d922d23958f6d90cf 100644 (file)
--- a/http.c
+++ b/http.c
@@ -4,6 +4,7 @@
 #include "run-command.h"
 #include "url.h"
 #include "credential.h"
+#include "version.h"
 
 int active_requests;
 int http_is_verbose;
@@ -299,7 +300,7 @@ static CURL *get_curl_handle(void)
                curl_easy_setopt(result, CURLOPT_VERBOSE, 1);
 
        curl_easy_setopt(result, CURLOPT_USERAGENT,
-               user_agent ? user_agent : GIT_HTTP_USER_AGENT);
+               user_agent ? user_agent : git_user_agent());
 
        if (curl_ftp_no_epsv)
                curl_easy_setopt(result, CURLOPT_FTP_USE_EPSV, 0);
@@ -744,10 +745,8 @@ 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)
+int handle_curl_result(struct slot_results *results)
 {
-       struct slot_results *results = slot->results;
-
        if (results->curl_result == CURLE_OK) {
                credential_approve(&http_auth);
                return HTTP_OK;
@@ -759,14 +758,15 @@ 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 {
+#if LIBCURL_VERSION_NUM >= 0x070c00
                if (!curl_errorstr[0])
                        strlcpy(curl_errorstr,
                                curl_easy_strerror(results->curl_result),
                                sizeof(curl_errorstr));
+#endif
                return HTTP_ERROR;
        }
 }
@@ -815,10 +815,11 @@ static int http_request(const char *url, void *result, int target, int options)
 
        curl_easy_setopt(slot->curl, CURLOPT_URL, url);
        curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, headers);
+       curl_easy_setopt(slot->curl, CURLOPT_ENCODING, "gzip");
 
        if (start_active_slot(slot)) {
                run_active_slot(slot);
-               ret = handle_curl_result(slot);
+               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 12de25597df4077a52a44dace83093091514c10d..0a80d303e369b4adf77ca131c732ba39a990610d 100644 (file)
--- a/http.h
+++ b/http.h
@@ -78,7 +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);
+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 484e0a980308fd2201bf443815a58c41bea17073..a4bf206e2f88da3a7ee31a04c5c0dda2b1547baa 100644 (file)
--- a/ident.c
+++ b/ident.c
@@ -93,7 +93,7 @@ static void copy_email(const struct passwd *pw, struct strbuf *email)
        add_domainname(email);
 }
 
-const char *ident_default_name(void)
+static const char *ident_default_name(void)
 {
        if (!git_default_name.len) {
                copy_gecos(xgetpwuid_self(), &git_default_name);
@@ -117,7 +117,7 @@ const char *ident_default_email(void)
        return git_default_email.buf;
 }
 
-const char *ident_default_date(void)
+static const char *ident_default_date(void)
 {
        if (!git_default_date[0])
                datestamp(git_default_date, sizeof(git_default_date));
index f3f7692158666ffd2ab6f65f4040462e4a7d2d00..acea33bf1babfe541c319081f14625ac779bb582 100644 (file)
@@ -35,7 +35,7 @@ struct ll_merge_driver {
  */
 static int ll_binary_merge(const struct ll_merge_driver *drv_unused,
                           mmbuffer_t *result,
-                          const char *path_unused,
+                          const char *path,
                           mmfile_t *orig, const char *orig_name,
                           mmfile_t *src1, const char *name1,
                           mmfile_t *src2, const char *name2,
@@ -46,16 +46,34 @@ static int ll_binary_merge(const struct ll_merge_driver *drv_unused,
        assert(opts);
 
        /*
-        * The tentative merge result is "ours" for the final round,
-        * or common ancestor for an internal merge.  Still return
-        * "conflicted merge" status.
+        * The tentative merge result is the or common ancestor for an internal merge.
         */
-       stolen = opts->virtual_ancestor ? orig : src1;
+       if (opts->virtual_ancestor) {
+               stolen = orig;
+       } else {
+               switch (opts->variant) {
+               default:
+                       warning("Cannot merge binary files: %s (%s vs. %s)",
+                               path, name1, name2);
+                       /* fallthru */
+               case XDL_MERGE_FAVOR_OURS:
+                       stolen = src1;
+                       break;
+               case XDL_MERGE_FAVOR_THEIRS:
+                       stolen = src2;
+                       break;
+               }
+       }
 
        result->ptr = stolen->ptr;
        result->size = stolen->size;
        stolen->ptr = NULL;
-       return 1;
+
+       /*
+        * With -Xtheirs or -Xours, we have cleanly merged;
+        * otherwise we got a conflict.
+        */
+       return (opts->variant ? 0 : 1);
 }
 
 static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,
@@ -73,8 +91,6 @@ static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,
        if (buffer_is_binary(orig->ptr, orig->size) ||
            buffer_is_binary(src1->ptr, src1->size) ||
            buffer_is_binary(src2->ptr, src2->size)) {
-               warning("Cannot merge binary files: %s (%s vs. %s)",
-                       path, name1, name2);
                return ll_binary_merge(drv_unused, result,
                                       path,
                                       orig, orig_name,
index 47aa41924507f7603aab5e35abb51b3956a33dad..ea4b471edeb5ca9b29a8138f6f831a5e6a15a9e8 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);
index e02da3556d08f02abf87cb1ece75a2e1d0c8ab78..d8820604ca3535ce25796012412fe69f1cbdd37b 100644 (file)
@@ -187,7 +187,7 @@ static void output_commit_title(struct merge_options *o, struct commit *commit)
        else {
                printf("%s ", find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV));
                if (parse_commit(commit) != 0)
-                       printf("(bad commit)\n");
+                       printf(_("(bad commit)\n"));
                else {
                        const char *title;
                        int len = find_commit_subject(commit->buffer, &title);
@@ -203,7 +203,7 @@ static int add_cacheinfo(unsigned int mode, const unsigned char *sha1,
        struct cache_entry *ce;
        ce = make_cache_entry(mode, sha1 ? sha1 : null_sha1, path, stage, refresh);
        if (!ce)
-               return error("addinfo_cache failed for path '%s'", path);
+               return error(_("addinfo_cache failed for path '%s'"), path);
        return add_cache_entry(ce, options);
 }
 
@@ -265,7 +265,7 @@ struct tree *write_tree_from_memory(struct merge_options *o)
        if (!cache_tree_fully_valid(active_cache_tree) &&
            cache_tree_update(active_cache_tree,
                              active_cache, active_nr, 0) < 0)
-               die("error building trees");
+               die(_("error building trees"));
 
        result = lookup_tree(active_cache_tree->sha1);
 
@@ -669,7 +669,7 @@ static int would_lose_untracked(const char *path)
 static int make_room_for_path(struct merge_options *o, const char *path)
 {
        int status, i;
-       const char *msg = "failed to create path '%s'%s";
+       const char *msg = _("failed to create path '%s'%s");
 
        /* Unlink any D/F conflict files that are in the way */
        for (i = 0; i < o->df_conflict_file_set.nr; i++) {
@@ -680,7 +680,7 @@ static int make_room_for_path(struct merge_options *o, const char *path)
                    path[df_pathlen] == '/' &&
                    strncmp(path, df_path, df_pathlen) == 0) {
                        output(o, 3,
-                              "Removing %s to make room for subdirectory\n",
+                              _("Removing %s to make room for subdirectory\n"),
                               df_path);
                        unlink(df_path);
                        unsorted_string_list_delete_item(&o->df_conflict_file_set,
@@ -694,7 +694,7 @@ static int make_room_for_path(struct merge_options *o, const char *path)
        if (status) {
                if (status == -3) {
                        /* something else exists */
-                       error(msg, path, ": perhaps a D/F conflict?");
+                       error(msg, path, _(": perhaps a D/F conflict?"));
                        return -1;
                }
                die(msg, path, "");
@@ -705,7 +705,7 @@ static int make_room_for_path(struct merge_options *o, const char *path)
         * tracking it.
         */
        if (would_lose_untracked(path))
-               return error("refusing to lose untracked file at '%s'",
+               return error(_("refusing to lose untracked file at '%s'"),
                             path);
 
        /* Successful unlink is good.. */
@@ -715,7 +715,7 @@ static int make_room_for_path(struct merge_options *o, const char *path)
        if (errno == ENOENT)
                return 0;
        /* .. but not some other error (who really cares what?) */
-       return error(msg, path, ": perhaps a D/F conflict?");
+       return error(msg, path, _(": perhaps a D/F conflict?"));
 }
 
 static void update_file_flags(struct merge_options *o,
@@ -745,9 +745,9 @@ static void update_file_flags(struct merge_options *o,
 
                buf = read_sha1_file(sha, &type, &size);
                if (!buf)
-                       die("cannot read object %s '%s'", sha1_to_hex(sha), path);
+                       die(_("cannot read object %s '%s'"), sha1_to_hex(sha), path);
                if (type != OBJ_BLOB)
-                       die("blob expected for %s '%s'", sha1_to_hex(sha), path);
+                       die(_("blob expected for %s '%s'"), sha1_to_hex(sha), path);
                if (S_ISREG(mode)) {
                        struct strbuf strbuf = STRBUF_INIT;
                        if (convert_to_working_tree(path, buf, size, &strbuf)) {
@@ -770,7 +770,7 @@ static void update_file_flags(struct merge_options *o,
                                mode = 0666;
                        fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, mode);
                        if (fd < 0)
-                               die_errno("failed to open '%s'", path);
+                               die_errno(_("failed to open '%s'"), path);
                        write_in_full(fd, buf, size);
                        close(fd);
                } else if (S_ISLNK(mode)) {
@@ -778,10 +778,10 @@ static void update_file_flags(struct merge_options *o,
                        safe_create_leading_directories_const(path);
                        unlink(path);
                        if (symlink(lnk, path))
-                               die_errno("failed to symlink '%s'", path);
+                               die_errno(_("failed to symlink '%s'"), path);
                        free(lnk);
                } else
-                       die("do not know what to do with %06o %s '%s'",
+                       die(_("do not know what to do with %06o %s '%s'"),
                            mode, sha1_to_hex(sha), path);
                free(buf);
        }
@@ -844,14 +844,14 @@ static int merge_3way(struct merge_options *o,
        if (strcmp(a->path, b->path) ||
            (o->ancestor != NULL && strcmp(a->path, one->path) != 0)) {
                base_name = o->ancestor == NULL ? NULL :
-                       xstrdup(mkpath("%s:%s", o->ancestor, one->path));
-               name1 = xstrdup(mkpath("%s:%s", branch1, a->path));
-               name2 = xstrdup(mkpath("%s:%s", branch2, b->path));
+                       mkpathdup("%s:%s", o->ancestor, one->path);
+               name1 = mkpathdup("%s:%s", branch1, a->path);
+               name2 = mkpathdup("%s:%s", branch2, b->path);
        } else {
                base_name = o->ancestor == NULL ? NULL :
-                       xstrdup(mkpath("%s", o->ancestor));
-               name1 = xstrdup(mkpath("%s", branch1));
-               name2 = xstrdup(mkpath("%s", branch2));
+                       mkpathdup("%s", o->ancestor);
+               name1 = mkpathdup("%s", branch1);
+               name2 = mkpathdup("%s", branch2);
        }
 
        read_mmblob(&orig, one->sha1);
@@ -861,6 +861,7 @@ static int merge_3way(struct merge_options *o,
        merge_status = ll_merge(result_buf, a->path, &orig, base_name,
                                &src1, name1, &src2, name2, &ll_opts);
 
+       free(base_name);
        free(name1);
        free(name2);
        free(orig.ptr);
@@ -918,11 +919,11 @@ static struct merge_file_info merge_file_1(struct merge_options *o,
                                                  branch1, branch2);
 
                        if ((merge_status < 0) || !result_buf.ptr)
-                               die("Failed to execute internal merge");
+                               die(_("Failed to execute internal merge"));
 
                        if (write_sha1_file(result_buf.ptr, result_buf.size,
                                            blob_type, result.sha))
-                               die("Unable to add %s to database",
+                               die(_("Unable to add %s to database"),
                                    a->path);
 
                        free(result_buf.ptr);
@@ -938,7 +939,7 @@ static struct merge_file_info merge_file_1(struct merge_options *o,
                        if (!sha_eq(a->sha1, b->sha1))
                                result.clean = 0;
                } else {
-                       die("unsupported object type in the tree");
+                       die(_("unsupported object type in the tree"));
                }
        }
 
@@ -1016,22 +1017,32 @@ static void handle_change_delete(struct merge_options *o,
                remove_file_from_cache(path);
                update_file(o, 0, o_sha, o_mode, renamed ? renamed : path);
        } else if (!a_sha) {
-               output(o, 1, "CONFLICT (%s/delete): %s deleted in %s "
-                      "and %s in %s. Version %s of %s left in tree%s%s.",
-                      change, path, o->branch1,
-                      change_past, o->branch2, o->branch2, path,
-                      NULL == renamed ? "" : " at ",
-                      NULL == renamed ? "" : renamed);
-               update_file(o, 0, b_sha, b_mode, renamed ? renamed : path);
+               if (!renamed) {
+                       output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s "
+                              "and %s in %s. Version %s of %s left in tree."),
+                              change, path, o->branch1, change_past,
+                              o->branch2, o->branch2, path);
+                       update_file(o, 0, b_sha, b_mode, path);
+               } else {
+                       output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s "
+                              "and %s in %s. Version %s of %s left in tree at %s."),
+                              change, path, o->branch1, change_past,
+                              o->branch2, o->branch2, path, renamed);
+                       update_file(o, 0, b_sha, b_mode, renamed);
+               }
        } else {
-               output(o, 1, "CONFLICT (%s/delete): %s deleted in %s "
-                      "and %s in %s. Version %s of %s left in tree%s%s.",
-                      change, path, o->branch2,
-                      change_past, o->branch1, o->branch1, path,
-                      NULL == renamed ? "" : " at ",
-                      NULL == renamed ? "" : renamed);
-               if (renamed)
+               if (!renamed) {
+                       output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s "
+                              "and %s in %s. Version %s of %s left in tree."),
+                              change, path, o->branch2, change_past,
+                              o->branch1, o->branch1, path);
+               } else {
+                       output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s "
+                              "and %s in %s. Version %s of %s left in tree at %s."),
+                              change, path, o->branch2, change_past,
+                              o->branch1, o->branch1, path, renamed);
                        update_file(o, 0, a_sha, a_mode, renamed);
+               }
                /*
                 * No need to call update_file() on path when !renamed, since
                 * that would needlessly touch path.  We could call
@@ -1067,7 +1078,7 @@ static void conflict_rename_delete(struct merge_options *o,
                             orig->sha1, orig->mode,
                             a_sha, a_mode,
                             b_sha, b_mode,
-                            "rename", "renamed");
+                            _("rename"), _("renamed"));
 
        if (o->call_depth) {
                remove_file_from_cache(dest->path);
@@ -1123,7 +1134,7 @@ static void handle_file(struct merge_options *o,
        } else {
                if (dir_in_way(rename->path, !o->call_depth)) {
                        dst_name = unique_path(o, rename->path, cur_branch);
-                       output(o, 1, "%s is a directory in %s adding as %s instead",
+                       output(o, 1, _("%s is a directory in %s adding as %s instead"),
                               rename->path, other_branch, dst_name);
                }
        }
@@ -1145,12 +1156,12 @@ static void conflict_rename_rename_1to2(struct merge_options *o,
        struct diff_filespec *a = ci->pair1->two;
        struct diff_filespec *b = ci->pair2->two;
 
-       output(o, 1, "CONFLICT (rename/rename): "
+       output(o, 1, _("CONFLICT (rename/rename): "
               "Rename \"%s\"->\"%s\" in branch \"%s\" "
-              "rename \"%s\"->\"%s\" in \"%s\"%s",
+              "rename \"%s\"->\"%s\" in \"%s\"%s"),
               one->path, a->path, ci->branch1,
               one->path, b->path, ci->branch2,
-              o->call_depth ? " (left unresolved)" : "");
+              o->call_depth ? _(" (left unresolved)") : "");
        if (o->call_depth) {
                struct merge_file_info mfi;
                struct diff_filespec other;
@@ -1204,9 +1215,9 @@ static void conflict_rename_rename_2to1(struct merge_options *o,
        struct merge_file_info mfi_c1;
        struct merge_file_info mfi_c2;
 
-       output(o, 1, "CONFLICT (rename/rename): "
+       output(o, 1, _("CONFLICT (rename/rename): "
               "Rename %s->%s in %s. "
-              "Rename %s->%s in %s",
+              "Rename %s->%s in %s"),
               a->path, c1->path, ci->branch1,
               b->path, c2->path, ci->branch2);
 
@@ -1234,7 +1245,7 @@ static void conflict_rename_rename_2to1(struct merge_options *o,
        } else {
                char *new_path1 = unique_path(o, path, ci->branch1);
                char *new_path2 = unique_path(o, path, ci->branch2);
-               output(o, 1, "Renaming %s to %s and %s to %s instead",
+               output(o, 1, _("Renaming %s to %s and %s to %s instead"),
                       a->path, new_path1, b->path, new_path2);
                remove_file(o, 0, path, 0);
                update_file(o, 0, mfi_c1.sha, mfi_c1.mode, new_path1);
@@ -1433,8 +1444,8 @@ static int process_renames(struct merge_options *o,
                        } else if (!sha_eq(dst_other.sha1, null_sha1)) {
                                clean_merge = 0;
                                try_merge = 1;
-                               output(o, 1, "CONFLICT (rename/add): Rename %s->%s in %s. "
-                                      "%s added in %s",
+                               output(o, 1, _("CONFLICT (rename/add): Rename %s->%s in %s. "
+                                      "%s added in %s"),
                                       ren1_src, ren1_dst, branch1,
                                       ren1_dst, branch2);
                                if (o->call_depth) {
@@ -1443,12 +1454,12 @@ static int process_renames(struct merge_options *o,
                                                         ren1->pair->two->sha1, ren1->pair->two->mode,
                                                         dst_other.sha1, dst_other.mode,
                                                         branch1, branch2);
-                                       output(o, 1, "Adding merged %s", ren1_dst);
+                                       output(o, 1, _("Adding merged %s"), ren1_dst);
                                        update_file(o, 0, mfi.sha, mfi.mode, ren1_dst);
                                        try_merge = 0;
                                } else {
                                        char *new_path = unique_path(o, ren1_dst, branch2);
-                                       output(o, 1, "Adding as %s instead", new_path);
+                                       output(o, 1, _("Adding as %s instead"), new_path);
                                        update_file(o, 0, dst_other.sha1, dst_other.mode, new_path);
                                        free(new_path);
                                }
@@ -1499,10 +1510,10 @@ static int read_sha1_strbuf(const unsigned char *sha1, struct strbuf *dst)
        unsigned long size;
        buf = read_sha1_file(sha1, &type, &size);
        if (!buf)
-               return error("cannot read object %s", sha1_to_hex(sha1));
+               return error(_("cannot read object %s"), sha1_to_hex(sha1));
        if (type != OBJ_BLOB) {
                free(buf);
-               return error("object %s is not a blob", sha1_to_hex(sha1));
+               return error(_("object %s is not a blob"), sha1_to_hex(sha1));
        }
        strbuf_attach(dst, buf, size, size + 1);
        return 0;
@@ -1550,7 +1561,7 @@ static void handle_modify_delete(struct merge_options *o,
                             o_sha, o_mode,
                             a_sha, a_mode,
                             b_sha, b_mode,
-                            "modify", "modified");
+                            _("modify"), _("modified"));
 }
 
 static int merge_content(struct merge_options *o,
@@ -1560,14 +1571,14 @@ static int merge_content(struct merge_options *o,
                         unsigned char *b_sha, int b_mode,
                         struct rename_conflict_info *rename_conflict_info)
 {
-       const char *reason = "content";
+       const char *reason = _("content");
        const char *path1 = NULL, *path2 = NULL;
        struct merge_file_info mfi;
        struct diff_filespec one, a, b;
        unsigned df_conflict_remains = 0;
 
        if (!o_sha) {
-               reason = "add/add";
+               reason = _("add/add");
                o_sha = (unsigned char *)null_sha1;
        }
        one.path = a.path = b.path = (char *)path;
@@ -1601,7 +1612,7 @@ static int merge_content(struct merge_options *o,
        if (mfi.clean && !df_conflict_remains &&
            sha_eq(mfi.sha, a_sha) && mfi.mode == a_mode) {
                int path_renamed_outside_HEAD;
-               output(o, 3, "Skipped %s (merged same as existing)", path);
+               output(o, 3, _("Skipped %s (merged same as existing)"), path);
                /*
                 * The content merge resulted in the same file contents we
                 * already had.  We can return early if those file contents
@@ -1615,12 +1626,12 @@ static int merge_content(struct merge_options *o,
                        return mfi.clean;
                }
        } else
-               output(o, 2, "Auto-merging %s", path);
+               output(o, 2, _("Auto-merging %s"), path);
 
        if (!mfi.clean) {
                if (S_ISGITLINK(mfi.mode))
-                       reason = "submodule";
-               output(o, 1, "CONFLICT (%s): Merge conflict in %s",
+                       reason = _("submodule");
+               output(o, 1, _("CONFLICT (%s): Merge conflict in %s"),
                                reason, path);
                if (rename_conflict_info && !df_conflict_remains)
                        update_stages(path, &one, &a, &b);
@@ -1646,7 +1657,7 @@ static int merge_content(struct merge_options *o,
 
                }
                new_path = unique_path(o, path, rename_conflict_info->branch1);
-               output(o, 1, "Adding as %s instead", new_path);
+               output(o, 1, _("Adding as %s instead"), new_path);
                update_file(o, 0, mfi.sha, mfi.mode, new_path);
                free(new_path);
                mfi.clean = 0;
@@ -1710,7 +1721,7 @@ static int process_entry(struct merge_options *o,
                        /* Deleted in both or deleted in one and
                         * unchanged in the other */
                        if (a_sha)
-                               output(o, 2, "Removing %s", path);
+                               output(o, 2, _("Removing %s"), path);
                        /* do not touch working file if it did not exist */
                        remove_file(o, 1, path, !a_sha);
                } else {
@@ -1735,19 +1746,19 @@ static int process_entry(struct merge_options *o,
                        other_branch = o->branch2;
                        mode = a_mode;
                        sha = a_sha;
-                       conf = "file/directory";
+                       conf = _("file/directory");
                } else {
                        add_branch = o->branch2;
                        other_branch = o->branch1;
                        mode = b_mode;
                        sha = b_sha;
-                       conf = "directory/file";
+                       conf = _("directory/file");
                }
                if (dir_in_way(path, !o->call_depth)) {
                        char *new_path = unique_path(o, path, add_branch);
                        clean_merge = 0;
-                       output(o, 1, "CONFLICT (%s): There is a directory with name %s in %s. "
-                              "Adding %s as %s",
+                       output(o, 1, _("CONFLICT (%s): There is a directory with name %s in %s. "
+                              "Adding %s as %s"),
                               conf, path, other_branch, path, new_path);
                        if (o->call_depth)
                                remove_file_from_cache(path);
@@ -1756,7 +1767,7 @@ static int process_entry(struct merge_options *o,
                                remove_file_from_cache(path);
                        free(new_path);
                } else {
-                       output(o, 2, "Adding %s", path);
+                       output(o, 2, _("Adding %s"), path);
                        /* do not overwrite file if already present */
                        update_file_flags(o, sha, mode, path, 1, !a_sha);
                }
@@ -1773,7 +1784,7 @@ static int process_entry(struct merge_options *o,
                 */
                remove_file(o, 1, path, !a_mode);
        } else
-               die("Fatal merge failure, shouldn't happen.");
+               die(_("Fatal merge failure, shouldn't happen."));
 
        return clean_merge;
 }
@@ -1792,7 +1803,7 @@ int merge_trees(struct merge_options *o,
        }
 
        if (sha_eq(common->object.sha1, merge->object.sha1)) {
-               output(o, 0, "Already up-to-date!");
+               output(o, 0, _("Already up-to-date!"));
                *result = head;
                return 1;
        }
@@ -1801,7 +1812,7 @@ int merge_trees(struct merge_options *o,
 
        if (code != 0) {
                if (show(o, 4) || o->call_depth)
-                       die("merging of trees %s and %s failed",
+                       die(_("merging of trees %s and %s failed"),
                            sha1_to_hex(head->object.sha1),
                            sha1_to_hex(merge->object.sha1));
                else
@@ -1831,7 +1842,7 @@ int merge_trees(struct merge_options *o,
                for (i = 0; i < entries->nr; i++) {
                        struct stage_data *e = entries->items[i].util;
                        if (!e->processed)
-                               die("Unprocessed path??? %s",
+                               die(_("Unprocessed path??? %s"),
                                    entries->items[i].string);
                }
 
@@ -1876,7 +1887,7 @@ int merge_recursive(struct merge_options *o,
        int clean;
 
        if (show(o, 4)) {
-               output(o, 4, "Merging:");
+               output(o, 4, _("Merging:"));
                output_commit_title(o, h1);
                output_commit_title(o, h2);
        }
@@ -1887,7 +1898,10 @@ int merge_recursive(struct merge_options *o,
        }
 
        if (show(o, 5)) {
-               output(o, 5, "found %u common ancestor(s):", commit_list_count(ca));
+               unsigned cnt = commit_list_count(ca);
+
+               output(o, 5, Q_("found %u common ancestor:",
+                               "found %u common ancestors:", cnt), cnt);
                for (iter = ca; iter; iter = iter->next)
                        output_commit_title(o, iter->item);
        }
@@ -1923,7 +1937,7 @@ int merge_recursive(struct merge_options *o,
                o->call_depth--;
 
                if (!merged_common_ancestors)
-                       die("merge returned no commit");
+                       die(_("merge returned no commit"));
        }
 
        discard_cache();
@@ -1980,7 +1994,7 @@ int merge_recursive_generic(struct merge_options *o,
                for (i = 0; i < num_base_list; ++i) {
                        struct commit *base;
                        if (!(base = get_ref(base_list[i], sha1_to_hex(base_list[i]))))
-                               return error("Could not parse object '%s'",
+                               return error(_("Could not parse object '%s'"),
                                        sha1_to_hex(base_list[i]));
                        commit_list_insert(base, &ca);
                }
@@ -1992,7 +2006,7 @@ int merge_recursive_generic(struct merge_options *o,
        if (active_cache_changed &&
                        (write_cache(index_fd, active_cache, active_nr) ||
                         commit_locked_index(lock)))
-               return error("Unable to write index.");
+               return error(_("Unable to write index."));
 
        return clean ? 0 : 1;
 }
diff --git a/mergetools/codecompare b/mergetools/codecompare
new file mode 100644 (file)
index 0000000..3f0486b
--- /dev/null
@@ -0,0 +1,25 @@
+diff_cmd () {
+       "$merge_tool_path" "$LOCAL" "$REMOTE"
+}
+
+merge_cmd () {
+       touch "$BACKUP"
+       if $base_present
+       then
+               "$merge_tool_path" -MF="$LOCAL" -TF="$REMOTE" -BF="$BASE" \
+                       -RF="$MERGED"
+       else
+               "$merge_tool_path" -MF="$LOCAL" -TF="$REMOTE" \
+                       -RF="$MERGED"
+       fi
+       check_unchanged
+}
+
+translate_merge_tool_path() {
+       if merge_mode
+       then
+               echo CodeMerge
+       else
+               echo CodeCompare
+       fi
+}
index 1d8f2a3dd3d0370461423007ed2198918836181b..21e63ecc3e019252c5c9ab5c26b1ea72f5952cc7 100644 (file)
@@ -8,36 +8,12 @@ can_diff () {
 }
 
 diff_cmd () {
-       merge_tool_cmd="$(get_merge_tool_cmd "$1")"
-       if test -z "$merge_tool_cmd"
-       then
-               status=1
-               break
-       fi
-       ( eval $merge_tool_cmd )
-       status=$?
+       status=1
        return $status
 }
 
 merge_cmd () {
-       merge_tool_cmd="$(get_merge_tool_cmd "$1")"
-       if test -z "$merge_tool_cmd"
-       then
-               status=1
-               break
-       fi
-       trust_exit_code="$(git config --bool \
-               mergetool."$1".trustExitCode || echo false)"
-       if test "$trust_exit_code" = "false"
-       then
-               touch "$BACKUP"
-               ( eval $merge_tool_cmd )
-               status=$?
-               check_unchanged
-       else
-               ( eval $merge_tool_cmd )
-               status=$?
-       fi
+       status=1
        return $status
 }
 
index 1a45c1b0c5128335fc340e7d6409b4e772419a07..295361a8aa7d075bbb9fdb8173858e37f9a43211 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 () {
index 7d62904f619fcd775f7ed7e7cff00d44005f3a5b..0f67bd3f9605aa7a3c98b88b4ae4aae037ace3d7 100644 (file)
@@ -522,8 +522,10 @@ static int merge_from_diffs(struct notes_merge_options *o,
        free(changes);
 
        if (o->verbosity >= 4)
-               printf("Merge result: %i unmerged notes and a %s notes tree\n",
-                       conflicts, t->dirty ? "dirty" : "clean");
+               printf(t->dirty ?
+                      "Merge result: %i unmerged notes and a dirty notes tree\n" :
+                      "Merge result: %i unmerged notes and a clean notes tree\n",
+                      conflicts);
 
        return conflicts ? -1 : 1;
 }
diff --git a/notes.c b/notes.c
index 93e9868d5d1aa536b70e981d3a4cd3c7969764d3..bc454e1eab2b0e1d264cee7bb1f84bdb3bb14237 100644 (file)
--- a/notes.c
+++ b/notes.c
@@ -1196,8 +1196,18 @@ void free_notes(struct notes_tree *t)
        memset(t, 0, sizeof(struct notes_tree));
 }
 
-void format_note(struct notes_tree *t, const unsigned char *object_sha1,
-               struct strbuf *sb, const char *output_encoding, int flags)
+/*
+ * Fill the given strbuf with the notes associated with the given object.
+ *
+ * If the given notes_tree structure is not initialized, it will be auto-
+ * initialized to the default value (see documentation for init_notes() above).
+ * 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.
+ */
+static void format_note(struct notes_tree *t, const unsigned char *object_sha1,
+                       struct strbuf *sb, const char *output_encoding, int flags)
 {
        static const char utf8[] = "utf-8";
        const unsigned char *sha1;
diff --git a/notes.h b/notes.h
index c716694b9e2ec89a59b98d1828fd78f59471e2c4..3592b19d2d9e5c67d9f55c8ad675ded086cbce17 100644 (file)
--- a/notes.h
+++ b/notes.h
@@ -241,20 +241,6 @@ void free_notes(struct notes_tree *t);
 #define NOTES_SHOW_HEADER 1
 #define NOTES_INDENT 2
 
-/*
- * Fill the given strbuf with the notes associated with the given object.
- *
- * If the given notes_tree structure is not initialized, it will be auto-
- * initialized to the default value (see documentation for init_notes() above).
- * If the given notes_tree is NULL, the internal/default notes_tree will be
- * used instead.
- *
- * 'flags' is a bitwise combination of the above formatting flags.
- */
-void format_note(struct notes_tree *t, const unsigned char *object_sha1,
-               struct strbuf *sb, const char *output_encoding, int flags);
-
-
 struct string_list;
 
 struct display_notes_opt {
diff --git a/pager.c b/pager.c
index 4dcb08d9674c252cbe2c2725f92eca2a0350dc93..c0b4387d969476232a4e00a7acf9b06dc4ef6edc 100644 (file)
--- a/pager.c
+++ b/pager.c
  * 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 +78,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;
 
index ab70c29c49b28eac1de3d7dd32814fa1e8544059..c1c66bd408c50685c06fe7ff1e1c6a78c26be1b1 100644 (file)
@@ -476,6 +476,7 @@ int parse_options(int argc, const char **argv, const char *prefix,
                usage_with_options(usagestr, options);
        }
 
+       precompose_argv(argc, argv);
        return parse_options_end(&ctx);
 }
 
index 77a4a8b2e6d2f6bc08be74b39ee6dd4964828763..71a39c60d942601a1cf30e218df56777742d5580 100644 (file)
@@ -238,6 +238,6 @@ extern int parse_opt_noop_cb(const struct option *, const char *, int);
 #define OPT__COLOR(var, h) \
        OPT_COLOR_FLAG(0, "color", (var), (h))
 #define OPT_COLUMN(s, l, v, h) \
-       { OPTION_CALLBACK, (s), (l), (v), "style", (h), PARSE_OPT_OPTARG, parseopt_column_callback }
+       { OPTION_CALLBACK, (s), (l), (v), N_("style"), (h), PARSE_OPT_OPTARG, parseopt_column_callback }
 
 #endif
diff --git a/path.c b/path.c
index 6f2aa699ad63c2f7c65632761efbaebb7f461868..cbbdf7d6ba68160a3a9936976e53d773d181ceac 100644 (file)
--- a/path.c
+++ b/path.c
@@ -48,7 +48,7 @@ char *mksnpath(char *buf, size_t n, const char *fmt, ...)
        return cleanup_path(buf);
 }
 
-static char *git_vsnpath(char *buf, size_t n, const char *fmt, va_list args)
+static char *vsnpath(char *buf, size_t n, const char *fmt, va_list args)
 {
        const char *git_dir = get_git_dir();
        size_t len;
@@ -70,21 +70,37 @@ bad:
 
 char *git_snpath(char *buf, size_t n, const char *fmt, ...)
 {
+       char *ret;
        va_list args;
        va_start(args, fmt);
-       (void)git_vsnpath(buf, n, fmt, args);
+       ret = vsnpath(buf, n, fmt, args);
        va_end(args);
-       return buf;
+       return ret;
 }
 
 char *git_pathdup(const char *fmt, ...)
 {
-       char path[PATH_MAX];
+       char path[PATH_MAX], *ret;
+       va_list args;
+       va_start(args, fmt);
+       ret = vsnpath(path, sizeof(path), fmt, args);
+       va_end(args);
+       return xstrdup(ret);
+}
+
+char *mkpathdup(const char *fmt, ...)
+{
+       char *path;
+       struct strbuf sb = STRBUF_INIT;
        va_list args;
+
        va_start(args, fmt);
-       (void)git_vsnpath(path, sizeof(path), fmt, args);
+       strbuf_vaddf(&sb, fmt, args);
        va_end(args);
-       return xstrdup(path);
+       path = xstrdup(cleanup_path(sb.buf));
+
+       strbuf_release(&sb);
+       return path;
 }
 
 char *mkpath(const char *fmt, ...)
@@ -103,23 +119,40 @@ char *mkpath(const char *fmt, ...)
 
 char *git_path(const char *fmt, ...)
 {
-       const char *git_dir = get_git_dir();
        char *pathname = get_pathname();
        va_list args;
-       unsigned len;
+       char *ret;
 
-       len = strlen(git_dir);
-       if (len > PATH_MAX-100)
-               return bad_path;
-       memcpy(pathname, git_dir, len);
-       if (len && git_dir[len-1] != '/')
-               pathname[len++] = '/';
        va_start(args, fmt);
-       len += vsnprintf(pathname + len, PATH_MAX - len, fmt, args);
+       ret = vsnpath(pathname, PATH_MAX, fmt, args);
        va_end(args);
-       if (len >= PATH_MAX)
-               return bad_path;
-       return cleanup_path(pathname);
+       return ret;
+}
+
+void home_config_paths(char **global, char **xdg, char *file)
+{
+       char *xdg_home = getenv("XDG_CONFIG_HOME");
+       char *home = getenv("HOME");
+       char *to_free = NULL;
+
+       if (!home) {
+               if (global)
+                       *global = NULL;
+       } else {
+               if (!xdg_home) {
+                       to_free = mkpathdup("%s/.config", home);
+                       xdg_home = to_free;
+               }
+               if (global)
+                       *global = mkpathdup("%s/.gitconfig", home);
+       }
+
+       if (!xdg_home)
+               *xdg = NULL;
+       else
+               *xdg = mkpathdup("%s/git/%s", xdg_home, file);
+
+       free(to_free);
 }
 
 char *git_path_submodule(const char *path, const char *fmt, ...)
index d5c6e22d0f74e075a49dd50cde6cbee5049a336c..0f1fc27f862f61015db843f272e61b29c14223af 100644 (file)
@@ -5,3 +5,4 @@ MYMETA.yml
 blib
 blibdirs
 pm_to_blib
+PM.stamp
diff --git a/perl/Git/IndexInfo.pm b/perl/Git/IndexInfo.pm
new file mode 100644 (file)
index 0000000..a43108c
--- /dev/null
@@ -0,0 +1,33 @@
+package Git::IndexInfo;
+use strict;
+use warnings;
+use Git qw/command_input_pipe command_close_pipe/;
+
+sub new {
+       my ($class) = @_;
+       my ($gui, $ctx) = command_input_pipe(qw/update-index -z --index-info/);
+       bless { gui => $gui, ctx => $ctx, nr => 0}, $class;
+}
+
+sub remove {
+       my ($self, $path) = @_;
+       if (print { $self->{gui} } '0 ', 0 x 40, "\t", $path, "\0") {
+               return ++$self->{nr};
+       }
+       undef;
+}
+
+sub update {
+       my ($self, $mode, $hash, $path) = @_;
+       if (print { $self->{gui} } $mode, ' ', $hash, "\t", $path, "\0") {
+               return ++$self->{nr};
+       }
+       undef;
+}
+
+sub DESTROY {
+       my ($self) = @_;
+       command_close_pipe($self->{gui}, $self->{ctx});
+}
+
+1;
diff --git a/perl/Git/SVN.pm b/perl/Git/SVN.pm
new file mode 100644 (file)
index 0000000..59215fa
--- /dev/null
@@ -0,0 +1,2394 @@
+package Git::SVN;
+use strict;
+use warnings;
+use Fcntl qw/:DEFAULT :seek/;
+use constant rev_map_fmt => 'NH40';
+use vars qw/$_no_metadata
+            $_repack $_repack_flags $_use_svm_props $_head
+            $_use_svnsync_props $no_reuse_existing
+           $_use_log_author $_add_author_from $_localtime/;
+use Carp qw/croak/;
+use File::Path qw/mkpath/;
+use File::Copy qw/copy/;
+use IPC::Open3;
+use Time::Local;
+use Memoize;  # core since 5.8.0, Jul 2002
+use Memoize::Storable;
+use POSIX qw(:signal_h);
+
+use Git qw(
+    command
+    command_oneline
+    command_noisy
+    command_output_pipe
+    command_close_pipe
+);
+use Git::SVN::Utils qw(
+       fatal
+       can_compress
+       join_paths
+       canonicalize_path
+       canonicalize_url
+       add_path_to_url
+);
+
+my $can_use_yaml;
+BEGIN {
+       $can_use_yaml = eval { require Git::SVN::Memoize::YAML; 1};
+}
+
+our $_follow_parent  = 1;
+our $_minimize_url   = 'unset';
+our $default_repo_id = 'svn';
+our $default_ref_id  = $ENV{GIT_SVN_ID} || 'git-svn';
+
+my ($_gc_nr, $_gc_period);
+
+# properties that we do not log:
+my %SKIP_PROP;
+BEGIN {
+       %SKIP_PROP = map { $_ => 1 } qw/svn:wc:ra_dav:version-url
+                                       svn:special svn:executable
+                                       svn:entry:committed-rev
+                                       svn:entry:last-author
+                                       svn:entry:uuid
+                                       svn:entry:committed-date/;
+
+       # some options are read globally, but can be overridden locally
+       # per [svn-remote "..."] section.  Command-line options will *NOT*
+       # override options set in an [svn-remote "..."] section
+       no strict 'refs';
+       for my $option (qw/follow_parent no_metadata use_svm_props
+                          use_svnsync_props/) {
+               my $key = $option;
+               $key =~ tr/_//d;
+               my $prop = "-$option";
+               *$option = sub {
+                       my ($self) = @_;
+                       return $self->{$prop} if exists $self->{$prop};
+                       my $k = "svn-remote.$self->{repo_id}.$key";
+                       eval { command_oneline(qw/config --get/, $k) };
+                       if ($@) {
+                               $self->{$prop} = ${"Git::SVN::_$option"};
+                       } else {
+                               my $v = command_oneline(qw/config --bool/,$k);
+                               $self->{$prop} = $v eq 'false' ? 0 : 1;
+                       }
+                       return $self->{$prop};
+               }
+       }
+}
+
+
+my (%LOCKFILES, %INDEX_FILES);
+END {
+       unlink keys %LOCKFILES if %LOCKFILES;
+       unlink keys %INDEX_FILES if %INDEX_FILES;
+}
+
+sub resolve_local_globs {
+       my ($url, $fetch, $glob_spec) = @_;
+       return unless defined $glob_spec;
+       my $ref = $glob_spec->{ref};
+       my $path = $glob_spec->{path};
+       foreach (command(qw#for-each-ref --format=%(refname) refs/#)) {
+               next unless m#^$ref->{regex}$#;
+               my $p = $1;
+               my $pathname = desanitize_refname($path->full_path($p));
+               my $refname = desanitize_refname($ref->full_path($p));
+               if (my $existing = $fetch->{$pathname}) {
+                       if ($existing ne $refname) {
+                               die "Refspec conflict:\n",
+                                   "existing: $existing\n",
+                                   " globbed: $refname\n";
+                       }
+                       my $u = (::cmt_metadata("$refname"))[0];
+                       $u =~ s!^\Q$url\E(/|$)!! or die
+                         "$refname: '$url' not found in '$u'\n";
+                       if ($pathname ne $u) {
+                               warn "W: Refspec glob conflict ",
+                                    "(ref: $refname):\n",
+                                    "expected path: $pathname\n",
+                                    "    real path: $u\n",
+                                    "Continuing ahead with $u\n";
+                               next;
+                       }
+               } else {
+                       $fetch->{$pathname} = $refname;
+               }
+       }
+}
+
+sub parse_revision_argument {
+       my ($base, $head) = @_;
+       if (!defined $::_revision || $::_revision eq 'BASE:HEAD') {
+               return ($base, $head);
+       }
+       return ($1, $2) if ($::_revision =~ /^(\d+):(\d+)$/);
+       return ($::_revision, $::_revision) if ($::_revision =~ /^\d+$/);
+       return ($head, $head) if ($::_revision eq 'HEAD');
+       return ($base, $1) if ($::_revision =~ /^BASE:(\d+)$/);
+       return ($1, $head) if ($::_revision =~ /^(\d+):HEAD$/);
+       die "revision argument: $::_revision not understood by git-svn\n";
+}
+
+sub fetch_all {
+       my ($repo_id, $remotes) = @_;
+       if (ref $repo_id) {
+               my $gs = $repo_id;
+               $repo_id = undef;
+               $repo_id = $gs->{repo_id};
+       }
+       $remotes ||= read_all_remotes();
+       my $remote = $remotes->{$repo_id} or
+                    die "[svn-remote \"$repo_id\"] unknown\n";
+       my $fetch = $remote->{fetch};
+       my $url = $remote->{url} or die "svn-remote.$repo_id.url not defined\n";
+       my (@gs, @globs);
+       my $ra = Git::SVN::Ra->new($url);
+       my $uuid = $ra->get_uuid;
+       my $head = $ra->get_latest_revnum;
+
+       # ignore errors, $head revision may not even exist anymore
+       eval { $ra->get_log("", $head, 0, 1, 0, 1, sub { $head = $_[1] }) };
+       warn "W: $@\n" if $@;
+
+       my $base = defined $fetch ? $head : 0;
+
+       # read the max revs for wildcard expansion (branches/*, tags/*)
+       foreach my $t (qw/branches tags/) {
+               defined $remote->{$t} or next;
+               push @globs, @{$remote->{$t}};
+
+               my $max_rev = eval { tmp_config(qw/--int --get/,
+                                        "svn-remote.$repo_id.${t}-maxRev") };
+               if (defined $max_rev && ($max_rev < $base)) {
+                       $base = $max_rev;
+               } elsif (!defined $max_rev) {
+                       $base = 0;
+               }
+       }
+
+       if ($fetch) {
+               foreach my $p (sort keys %$fetch) {
+                       my $gs = Git::SVN->new($fetch->{$p}, $repo_id, $p);
+                       my $lr = $gs->rev_map_max;
+                       if (defined $lr) {
+                               $base = $lr if ($lr < $base);
+                       }
+                       push @gs, $gs;
+               }
+       }
+
+       ($base, $head) = parse_revision_argument($base, $head);
+       $ra->gs_fetch_loop_common($base, $head, \@gs, \@globs);
+}
+
+sub read_all_remotes {
+       my $r = {};
+       my $use_svm_props = eval { command_oneline(qw/config --bool
+           svn.useSvmProps/) };
+       $use_svm_props = $use_svm_props eq 'true' if $use_svm_props;
+       my $svn_refspec = qr{\s*(.*?)\s*:\s*(.+?)\s*};
+       foreach (grep { s/^svn-remote\.// } command(qw/config -l/)) {
+               if (m!^(.+)\.fetch=$svn_refspec$!) {
+                       my ($remote, $local_ref, $remote_ref) = ($1, $2, $3);
+                       die("svn-remote.$remote: remote ref '$remote_ref' "
+                           . "must start with 'refs/'\n")
+                               unless $remote_ref =~ m{^refs/};
+                       $local_ref = uri_decode($local_ref);
+                       $r->{$remote}->{fetch}->{$local_ref} = $remote_ref;
+                       $r->{$remote}->{svm} = {} if $use_svm_props;
+               } elsif (m!^(.+)\.usesvmprops=\s*(.*)\s*$!) {
+                       $r->{$1}->{svm} = {};
+               } elsif (m!^(.+)\.url=\s*(.*)\s*$!) {
+                       $r->{$1}->{url} = canonicalize_url($2);
+               } elsif (m!^(.+)\.pushurl=\s*(.*)\s*$!) {
+                       $r->{$1}->{pushurl} = canonicalize_url($2);
+               } elsif (m!^(.+)\.ignore-refs=\s*(.*)\s*$!) {
+                       $r->{$1}->{ignore_refs_regex} = $2;
+               } elsif (m!^(.+)\.(branches|tags)=$svn_refspec$!) {
+                       my ($remote, $t, $local_ref, $remote_ref) =
+                                                            ($1, $2, $3, $4);
+                       die("svn-remote.$remote: remote ref '$remote_ref' ($t) "
+                           . "must start with 'refs/'\n")
+                               unless $remote_ref =~ m{^refs/};
+                       $local_ref = uri_decode($local_ref);
+
+                       require Git::SVN::GlobSpec;
+                       my $rs = {
+                           t => $t,
+                           remote => $remote,
+                           path => Git::SVN::GlobSpec->new($local_ref, 1),
+                           ref => Git::SVN::GlobSpec->new($remote_ref, 0) };
+                       if (length($rs->{ref}->{right}) != 0) {
+                               die "The '*' glob character must be the last ",
+                                   "character of '$remote_ref'\n";
+                       }
+                       push @{ $r->{$remote}->{$t} }, $rs;
+               }
+       }
+
+       map {
+               if (defined $r->{$_}->{svm}) {
+                       my $svm;
+                       eval {
+                               my $section = "svn-remote.$_";
+                               $svm = {
+                                       source => tmp_config('--get',
+                                           "$section.svm-source"),
+                                       replace => tmp_config('--get',
+                                           "$section.svm-replace"),
+                               }
+                       };
+                       $r->{$_}->{svm} = $svm;
+               }
+       } keys %$r;
+
+       foreach my $remote (keys %$r) {
+               foreach ( grep { defined $_ }
+                         map { $r->{$remote}->{$_} } qw(branches tags) ) {
+                       foreach my $rs ( @$_ ) {
+                               $rs->{ignore_refs_regex} =
+                                   $r->{$remote}->{ignore_refs_regex};
+                       }
+               }
+       }
+
+       $r;
+}
+
+sub init_vars {
+       $_gc_nr = $_gc_period = 1000;
+       if (defined $_repack || defined $_repack_flags) {
+              warn "Repack options are obsolete; they have no effect.\n";
+       }
+}
+
+sub verify_remotes_sanity {
+       return unless -d $ENV{GIT_DIR};
+       my %seen;
+       foreach (command(qw/config -l/)) {
+               if (m!^svn-remote\.(?:.+)\.fetch=.*:refs/remotes/(\S+)\s*$!) {
+                       if ($seen{$1}) {
+                               die "Remote ref refs/remote/$1 is tracked by",
+                                   "\n  \"$_\"\nand\n  \"$seen{$1}\"\n",
+                                   "Please resolve this ambiguity in ",
+                                   "your git configuration file before ",
+                                   "continuing\n";
+                       }
+                       $seen{$1} = $_;
+               }
+       }
+}
+
+sub find_existing_remote {
+       my ($url, $remotes) = @_;
+       return undef if $no_reuse_existing;
+       my $existing;
+       foreach my $repo_id (keys %$remotes) {
+               my $u = $remotes->{$repo_id}->{url} or next;
+               next if $u ne $url;
+               $existing = $repo_id;
+               last;
+       }
+       $existing;
+}
+
+sub init_remote_config {
+       my ($self, $url, $no_write) = @_;
+       $url = canonicalize_url($url);
+       my $r = read_all_remotes();
+       my $existing = find_existing_remote($url, $r);
+       if ($existing) {
+               unless ($no_write) {
+                       print STDERR "Using existing ",
+                                    "[svn-remote \"$existing\"]\n";
+               }
+               $self->{repo_id} = $existing;
+       } elsif ($_minimize_url) {
+               my $min_url = Git::SVN::Ra->new($url)->minimize_url;
+               $existing = find_existing_remote($min_url, $r);
+               if ($existing) {
+                       unless ($no_write) {
+                               print STDERR "Using existing ",
+                                            "[svn-remote \"$existing\"]\n";
+                       }
+                       $self->{repo_id} = $existing;
+               }
+               if ($min_url ne $url) {
+                       unless ($no_write) {
+                               print STDERR "Using higher level of URL: ",
+                                            "$url => $min_url\n";
+                       }
+                       my $old_path = $self->path;
+                       $url =~ s!^\Q$min_url\E(/|$)!!;
+                       $url = join_paths($url, $old_path);
+                       $self->path($url);
+                       $url = $min_url;
+               }
+       }
+       my $orig_url;
+       if (!$existing) {
+               # verify that we aren't overwriting anything:
+               $orig_url = eval {
+                       command_oneline('config', '--get',
+                                       "svn-remote.$self->{repo_id}.url")
+               };
+               if ($orig_url && ($orig_url ne $url)) {
+                       die "svn-remote.$self->{repo_id}.url already set: ",
+                           "$orig_url\nwanted to set to: $url\n";
+               }
+       }
+       my ($xrepo_id, $xpath) = find_ref($self->refname);
+       if (!$no_write && defined $xpath) {
+               die "svn-remote.$xrepo_id.fetch already set to track ",
+                   "$xpath:", $self->refname, "\n";
+       }
+       unless ($no_write) {
+               command_noisy('config',
+                             "svn-remote.$self->{repo_id}.url", $url);
+               my $path = $self->path;
+               $path =~ s{^/}{};
+               $path =~ s{%([0-9A-F]{2})}{chr hex($1)}ieg;
+               $self->path($path);
+               command_noisy('config', '--add',
+                             "svn-remote.$self->{repo_id}.fetch",
+                             $self->path.":".$self->refname);
+       }
+       $self->url($url);
+}
+
+sub find_by_url { # repos_root and, path are optional
+       my ($class, $full_url, $repos_root, $path) = @_;
+
+       $full_url = canonicalize_url($full_url);
+
+       return undef unless defined $full_url;
+       remove_username($full_url);
+       remove_username($repos_root) if defined $repos_root;
+       my $remotes = read_all_remotes();
+       if (defined $full_url && defined $repos_root && !defined $path) {
+               $path = $full_url;
+               $path =~ s#^\Q$repos_root\E(?:/|$)##;
+       }
+       foreach my $repo_id (keys %$remotes) {
+               my $u = $remotes->{$repo_id}->{url} or next;
+               remove_username($u);
+               next if defined $repos_root && $repos_root ne $u;
+
+               my $fetch = $remotes->{$repo_id}->{fetch} || {};
+               foreach my $t (qw/branches tags/) {
+                       foreach my $globspec (@{$remotes->{$repo_id}->{$t}}) {
+                               resolve_local_globs($u, $fetch, $globspec);
+                       }
+               }
+               my $p = $path;
+               my $rwr = rewrite_root({repo_id => $repo_id});
+               my $svm = $remotes->{$repo_id}->{svm}
+                       if defined $remotes->{$repo_id}->{svm};
+               unless (defined $p) {
+                       $p = $full_url;
+                       my $z = $u;
+                       my $prefix = '';
+                       if ($rwr) {
+                               $z = $rwr;
+                               remove_username($z);
+                       } elsif (defined $svm) {
+                               $z = $svm->{source};
+                               $prefix = $svm->{replace};
+                               $prefix =~ s#^\Q$u\E(?:/|$)##;
+                               $prefix =~ s#/$##;
+                       }
+                       $p =~ s#^\Q$z\E(?:/|$)#$prefix# or next;
+               }
+
+               # remote fetch paths are not URI escaped.  Decode ours
+               # so they match
+               $p = uri_decode($p);
+
+               foreach my $f (keys %$fetch) {
+                       next if $f ne $p;
+                       return Git::SVN->new($fetch->{$f}, $repo_id, $f);
+               }
+       }
+       undef;
+}
+
+sub init {
+       my ($class, $url, $path, $repo_id, $ref_id, $no_write) = @_;
+       my $self = _new($class, $repo_id, $ref_id, $path);
+       if (defined $url) {
+               $self->init_remote_config($url, $no_write);
+       }
+       $self;
+}
+
+sub find_ref {
+       my ($ref_id) = @_;
+       foreach (command(qw/config -l/)) {
+               next unless m!^svn-remote\.(.+)\.fetch=
+                             \s*(.*?)\s*:\s*(.+?)\s*$!x;
+               my ($repo_id, $path, $ref) = ($1, $2, $3);
+               if ($ref eq $ref_id) {
+                       $path = '' if ($path =~ m#^\./?#);
+                       return ($repo_id, $path);
+               }
+       }
+       (undef, undef, undef);
+}
+
+sub new {
+       my ($class, $ref_id, $repo_id, $path) = @_;
+       if (defined $ref_id && !defined $repo_id && !defined $path) {
+               ($repo_id, $path) = find_ref($ref_id);
+               if (!defined $repo_id) {
+                       die "Could not find a \"svn-remote.*.fetch\" key ",
+                           "in the repository configuration matching: ",
+                           "$ref_id\n";
+               }
+       }
+       my $self = _new($class, $repo_id, $ref_id, $path);
+       if (!defined $self->path || !length $self->path) {
+               my $fetch = command_oneline('config', '--get',
+                                           "svn-remote.$repo_id.fetch",
+                                           ":$ref_id\$") or
+                    die "Failed to read \"svn-remote.$repo_id.fetch\" ",
+                        "\":$ref_id\$\" in config\n";
+               my($path) = split(/\s*:\s*/, $fetch);
+               $self->path($path);
+       }
+       {
+               my $path = $self->path;
+               $path =~ s{\A/}{};
+               $path =~ s{/\z}{};
+               $self->path($path);
+       }
+       my $url = command_oneline('config', '--get',
+                                 "svn-remote.$repo_id.url") or
+                  die "Failed to read \"svn-remote.$repo_id.url\" in config\n";
+       $self->url($url);
+       $self->{pushurl} = eval { command_oneline('config', '--get',
+                                 "svn-remote.$repo_id.pushurl") };
+       $self->rebuild;
+       $self;
+}
+
+sub refname {
+       my ($refname) = $_[0]->{ref_id} ;
+
+       # It cannot end with a slash /, we'll throw up on this because
+       # SVN can't have directories with a slash in their name, either:
+       if ($refname =~ m{/$}) {
+               die "ref: '$refname' ends with a trailing slash, this is ",
+                   "not permitted by git nor Subversion\n";
+       }
+
+       # It cannot have ASCII control character space, tilde ~, caret ^,
+       # colon :, question-mark ?, asterisk *, space, or open bracket [
+       # anywhere.
+       #
+       # Additionally, % must be escaped because it is used for escaping
+       # and we want our escaped refname to be reversible
+       $refname =~ s{([ \%~\^:\?\*\[\t])}{uc sprintf('%%%02x',ord($1))}eg;
+
+       # no slash-separated component can begin with a dot .
+       # /.* becomes /%2E*
+       $refname =~ s{/\.}{/%2E}g;
+
+       # It cannot have two consecutive dots .. anywhere
+       # .. becomes %2E%2E
+       $refname =~ s{\.\.}{%2E%2E}g;
+
+       # trailing dots and .lock are not allowed
+       # .$ becomes %2E and .lock becomes %2Elock
+       $refname =~ s{\.(?=$|lock$)}{%2E};
+
+       # the sequence @{ is used to access the reflog
+       # @{ becomes %40{
+       $refname =~ s{\@\{}{%40\{}g;
+
+       return $refname;
+}
+
+sub desanitize_refname {
+       my ($refname) = @_;
+       $refname =~ s{%(?:([0-9A-F]{2}))}{chr hex($1)}eg;
+       return $refname;
+}
+
+sub svm_uuid {
+       my ($self) = @_;
+       return $self->{svm}->{uuid} if $self->svm;
+       $self->ra;
+       unless ($self->{svm}) {
+               die "SVM UUID not cached, and reading remotely failed\n";
+       }
+       $self->{svm}->{uuid};
+}
+
+sub svm {
+       my ($self) = @_;
+       return $self->{svm} if $self->{svm};
+       my $svm;
+       # see if we have it in our config, first:
+       eval {
+               my $section = "svn-remote.$self->{repo_id}";
+               $svm = {
+                 source => tmp_config('--get', "$section.svm-source"),
+                 uuid => tmp_config('--get', "$section.svm-uuid"),
+                 replace => tmp_config('--get', "$section.svm-replace"),
+               }
+       };
+       if ($svm && $svm->{source} && $svm->{uuid} && $svm->{replace}) {
+               $self->{svm} = $svm;
+       }
+       $self->{svm};
+}
+
+sub _set_svm_vars {
+       my ($self, $ra) = @_;
+       return $ra if $self->svm;
+
+       my @err = ( "useSvmProps set, but failed to read SVM properties\n",
+                   "(svm:source, svm:uuid) ",
+                   "from the following URLs:\n" );
+       sub read_svm_props {
+               my ($self, $ra, $path, $r) = @_;
+               my $props = ($ra->get_dir($path, $r))[2];
+               my $src = $props->{'svm:source'};
+               my $uuid = $props->{'svm:uuid'};
+               return undef if (!$src || !$uuid);
+
+               chomp($src, $uuid);
+
+               $uuid =~ m{^[0-9a-f\-]{30,}$}i
+                   or die "doesn't look right - svm:uuid is '$uuid'\n";
+
+               # the '!' is used to mark the repos_root!/relative/path
+               $src =~ s{/?!/?}{/};
+               $src =~ s{/+$}{}; # no trailing slashes please
+               # username is of no interest
+               $src =~ s{(^[a-z\+]*://)[^/@]*@}{$1};
+
+               my $replace = add_path_to_url($ra->url, $path);
+
+               my $section = "svn-remote.$self->{repo_id}";
+               tmp_config("$section.svm-source", $src);
+               tmp_config("$section.svm-replace", $replace);
+               tmp_config("$section.svm-uuid", $uuid);
+               $self->{svm} = {
+                       source => $src,
+                       uuid => $uuid,
+                       replace => $replace
+               };
+       }
+
+       my $r = $ra->get_latest_revnum;
+       my $path = $self->path;
+       my %tried;
+       while (length $path) {
+               my $try = add_path_to_url($self->url, $path);
+               unless ($tried{$try}) {
+                       return $ra if $self->read_svm_props($ra, $path, $r);
+                       $tried{$try} = 1;
+               }
+               $path =~ s#/?[^/]+$##;
+       }
+       die "Path: '$path' should be ''\n" if $path ne '';
+       return $ra if $self->read_svm_props($ra, $path, $r);
+       $tried{ add_path_to_url($self->url, $path) } = 1;
+
+       if ($ra->{repos_root} eq $self->url) {
+               die @err, (map { "  $_\n" } keys %tried), "\n";
+       }
+
+       # nope, make sure we're connected to the repository root:
+       my $ok;
+       my @tried_b;
+       $path = $ra->{svn_path};
+       $ra = Git::SVN::Ra->new($ra->{repos_root});
+       while (length $path) {
+               my $try = add_path_to_url($ra->url, $path);
+               unless ($tried{$try}) {
+                       $ok = $self->read_svm_props($ra, $path, $r);
+                       last if $ok;
+                       $tried{$try} = 1;
+               }
+               $path =~ s#/?[^/]+$##;
+       }
+       die "Path: '$path' should be ''\n" if $path ne '';
+       $ok ||= $self->read_svm_props($ra, $path, $r);
+       $tried{ add_path_to_url($ra->url, $path) } = 1;
+       if (!$ok) {
+               die @err, (map { "  $_\n" } keys %tried), "\n";
+       }
+       Git::SVN::Ra->new($self->url);
+}
+
+sub svnsync {
+       my ($self) = @_;
+       return $self->{svnsync} if $self->{svnsync};
+
+       if ($self->no_metadata) {
+               die "Can't have both 'noMetadata' and ",
+                   "'useSvnsyncProps' options set!\n";
+       }
+       if ($self->rewrite_root) {
+               die "Can't have both 'useSvnsyncProps' and 'rewriteRoot' ",
+                   "options set!\n";
+       }
+       if ($self->rewrite_uuid) {
+               die "Can't have both 'useSvnsyncProps' and 'rewriteUUID' ",
+                   "options set!\n";
+       }
+
+       my $svnsync;
+       # see if we have it in our config, first:
+       eval {
+               my $section = "svn-remote.$self->{repo_id}";
+
+               my $url = tmp_config('--get', "$section.svnsync-url");
+               ($url) = ($url =~ m{^([a-z\+]+://\S+)$}) or
+                  die "doesn't look right - svn:sync-from-url is '$url'\n";
+
+               my $uuid = tmp_config('--get', "$section.svnsync-uuid");
+               ($uuid) = ($uuid =~ m{^([0-9a-f\-]{30,})$}i) or
+                  die "doesn't look right - svn:sync-from-uuid is '$uuid'\n";
+
+               $svnsync = { url => $url, uuid => $uuid }
+       };
+       if ($svnsync && $svnsync->{url} && $svnsync->{uuid}) {
+               return $self->{svnsync} = $svnsync;
+       }
+
+       my $err = "useSvnsyncProps set, but failed to read " .
+                 "svnsync property: svn:sync-from-";
+       my $rp = $self->ra->rev_proplist(0);
+
+       my $url = $rp->{'svn:sync-from-url'} or die $err . "url\n";
+       ($url) = ($url =~ m{^([a-z\+]+://\S+)$}) or
+                  die "doesn't look right - svn:sync-from-url is '$url'\n";
+
+       my $uuid = $rp->{'svn:sync-from-uuid'} or die $err . "uuid\n";
+       ($uuid) = ($uuid =~ m{^([0-9a-f\-]{30,})$}i) or
+                  die "doesn't look right - svn:sync-from-uuid is '$uuid'\n";
+
+       my $section = "svn-remote.$self->{repo_id}";
+       tmp_config('--add', "$section.svnsync-uuid", $uuid);
+       tmp_config('--add', "$section.svnsync-url", $url);
+       return $self->{svnsync} = { url => $url, uuid => $uuid };
+}
+
+# this allows us to memoize our SVN::Ra UUID locally and avoid a
+# remote lookup (useful for 'git svn log').
+sub ra_uuid {
+       my ($self) = @_;
+       unless ($self->{ra_uuid}) {
+               my $key = "svn-remote.$self->{repo_id}.uuid";
+               my $uuid = eval { tmp_config('--get', $key) };
+               if (!$@ && $uuid && $uuid =~ /^([a-f\d\-]{30,})$/i) {
+                       $self->{ra_uuid} = $uuid;
+               } else {
+                       die "ra_uuid called without URL\n" unless $self->url;
+                       $self->{ra_uuid} = $self->ra->get_uuid;
+                       tmp_config('--add', $key, $self->{ra_uuid});
+               }
+       }
+       $self->{ra_uuid};
+}
+
+sub _set_repos_root {
+       my ($self, $repos_root) = @_;
+       my $k = "svn-remote.$self->{repo_id}.reposRoot";
+       $repos_root ||= $self->ra->{repos_root};
+       tmp_config($k, $repos_root);
+       $repos_root;
+}
+
+sub repos_root {
+       my ($self) = @_;
+       my $k = "svn-remote.$self->{repo_id}.reposRoot";
+       eval { tmp_config('--get', $k) } || $self->_set_repos_root;
+}
+
+sub ra {
+       my ($self) = shift;
+       my $ra = Git::SVN::Ra->new($self->url);
+       $self->_set_repos_root($ra->{repos_root});
+       if ($self->use_svm_props && !$self->{svm}) {
+               if ($self->no_metadata) {
+                       die "Can't have both 'noMetadata' and ",
+                           "'useSvmProps' options set!\n";
+               } elsif ($self->use_svnsync_props) {
+                       die "Can't have both 'useSvnsyncProps' and ",
+                           "'useSvmProps' options set!\n";
+               }
+               $ra = $self->_set_svm_vars($ra);
+               $self->{-want_revprops} = 1;
+       }
+       $ra;
+}
+
+# prop_walk(PATH, REV, SUB)
+# -------------------------
+# Recursively traverse PATH at revision REV and invoke SUB for each
+# directory that contains a SVN property.  SUB will be invoked as
+# follows:  &SUB(gs, path, props);  where `gs' is this instance of
+# Git::SVN, `path' the path to the directory where the properties
+# `props' were found.  The `path' will be relative to point of checkout,
+# that is, if url://repo/trunk is the current Git branch, and that
+# directory contains a sub-directory `d', SUB will be invoked with `/d/'
+# as `path' (note the trailing `/').
+sub prop_walk {
+       my ($self, $path, $rev, $sub) = @_;
+
+       $path =~ s#^/##;
+       my ($dirent, undef, $props) = $self->ra->get_dir($path, $rev);
+       $path =~ s#^/*#/#g;
+       my $p = $path;
+       # Strip the irrelevant part of the path.
+       $p =~ s#^/+\Q@{[$self->path]}\E(/|$)#/#;
+       # Ensure the path is terminated by a `/'.
+       $p =~ s#/*$#/#;
+
+       # The properties contain all the internal SVN stuff nobody
+       # (usually) cares about.
+       my $interesting_props = 0;
+       foreach (keys %{$props}) {
+               # If it doesn't start with `svn:', it must be a
+               # user-defined property.
+               ++$interesting_props and next if $_ !~ /^svn:/;
+               # FIXME: Fragile, if SVN adds new public properties,
+               # this needs to be updated.
+               ++$interesting_props if /^svn:(?:ignore|keywords|executable
+                                                |eol-style|mime-type
+                                                |externals|needs-lock)$/x;
+       }
+       &$sub($self, $p, $props) if $interesting_props;
+
+       foreach (sort keys %$dirent) {
+               next if $dirent->{$_}->{kind} != $SVN::Node::dir;
+               $self->prop_walk($self->path . $p . $_, $rev, $sub);
+       }
+}
+
+sub last_rev { ($_[0]->last_rev_commit)[0] }
+sub last_commit { ($_[0]->last_rev_commit)[1] }
+
+# returns the newest SVN revision number and newest commit SHA1
+sub last_rev_commit {
+       my ($self) = @_;
+       if (defined $self->{last_rev} && defined $self->{last_commit}) {
+               return ($self->{last_rev}, $self->{last_commit});
+       }
+       my $c = ::verify_ref($self->refname.'^0');
+       if ($c && !$self->use_svm_props && !$self->no_metadata) {
+               my $rev = (::cmt_metadata($c))[1];
+               if (defined $rev) {
+                       ($self->{last_rev}, $self->{last_commit}) = ($rev, $c);
+                       return ($rev, $c);
+               }
+       }
+       my $map_path = $self->map_path;
+       unless (-e $map_path) {
+               ($self->{last_rev}, $self->{last_commit}) = (undef, undef);
+               return (undef, undef);
+       }
+       my ($rev, $commit) = $self->rev_map_max(1);
+       ($self->{last_rev}, $self->{last_commit}) = ($rev, $commit);
+       return ($rev, $commit);
+}
+
+sub get_fetch_range {
+       my ($self, $min, $max) = @_;
+       $max ||= $self->ra->get_latest_revnum;
+       $min ||= $self->rev_map_max;
+       (++$min, $max);
+}
+
+sub tmp_config {
+       my (@args) = @_;
+       my $old_def_config = "$ENV{GIT_DIR}/svn/config";
+       my $config = "$ENV{GIT_DIR}/svn/.metadata";
+       if (! -f $config && -f $old_def_config) {
+               rename $old_def_config, $config or
+                      die "Failed rename $old_def_config => $config: $!\n";
+       }
+       my $old_config = $ENV{GIT_CONFIG};
+       $ENV{GIT_CONFIG} = $config;
+       $@ = undef;
+       my @ret = eval {
+               unless (-f $config) {
+                       mkfile($config);
+                       open my $fh, '>', $config or
+                           die "Can't open $config: $!\n";
+                       print $fh "; This file is used internally by ",
+                                 "git-svn\n" or die
+                                 "Couldn't write to $config: $!\n";
+                       print $fh "; You should not have to edit it\n" or
+                             die "Couldn't write to $config: $!\n";
+                       close $fh or die "Couldn't close $config: $!\n";
+               }
+               command('config', @args);
+       };
+       my $err = $@;
+       if (defined $old_config) {
+               $ENV{GIT_CONFIG} = $old_config;
+       } else {
+               delete $ENV{GIT_CONFIG};
+       }
+       die $err if $err;
+       wantarray ? @ret : $ret[0];
+}
+
+sub tmp_index_do {
+       my ($self, $sub) = @_;
+       my $old_index = $ENV{GIT_INDEX_FILE};
+       $ENV{GIT_INDEX_FILE} = $self->{index};
+       $@ = undef;
+       my @ret = eval {
+               my ($dir, $base) = ($self->{index} =~ m#^(.*?)/?([^/]+)$#);
+               mkpath([$dir]) unless -d $dir;
+               &$sub;
+       };
+       my $err = $@;
+       if (defined $old_index) {
+               $ENV{GIT_INDEX_FILE} = $old_index;
+       } else {
+               delete $ENV{GIT_INDEX_FILE};
+       }
+       die $err if $err;
+       wantarray ? @ret : $ret[0];
+}
+
+sub assert_index_clean {
+       my ($self, $treeish) = @_;
+
+       $self->tmp_index_do(sub {
+               command_noisy('read-tree', $treeish) unless -e $self->{index};
+               my $x = command_oneline('write-tree');
+               my ($y) = (command(qw/cat-file commit/, $treeish) =~
+                          /^tree ($::sha1)/mo);
+               return if $y eq $x;
+
+               warn "Index mismatch: $y != $x\nrereading $treeish\n";
+               unlink $self->{index} or die "unlink $self->{index}: $!\n";
+               command_noisy('read-tree', $treeish);
+               $x = command_oneline('write-tree');
+               if ($y ne $x) {
+                       fatal "trees ($treeish) $y != $x\n",
+                             "Something is seriously wrong...";
+               }
+       });
+}
+
+sub get_commit_parents {
+       my ($self, $log_entry) = @_;
+       my (%seen, @ret, @tmp);
+       # legacy support for 'set-tree'; this is only used by set_tree_cb:
+       if (my $ip = $self->{inject_parents}) {
+               if (my $commit = delete $ip->{$log_entry->{revision}}) {
+                       push @tmp, $commit;
+               }
+       }
+       if (my $cur = ::verify_ref($self->refname.'^0')) {
+               push @tmp, $cur;
+       }
+       if (my $ipd = $self->{inject_parents_dcommit}) {
+               if (my $commit = delete $ipd->{$log_entry->{revision}}) {
+                       push @tmp, @$commit;
+               }
+       }
+       push @tmp, $_ foreach (@{$log_entry->{parents}}, @tmp);
+       while (my $p = shift @tmp) {
+               next if $seen{$p};
+               $seen{$p} = 1;
+               push @ret, $p;
+       }
+       @ret;
+}
+
+sub rewrite_root {
+       my ($self) = @_;
+       return $self->{-rewrite_root} if exists $self->{-rewrite_root};
+       my $k = "svn-remote.$self->{repo_id}.rewriteRoot";
+       my $rwr = eval { command_oneline(qw/config --get/, $k) };
+       if ($rwr) {
+               $rwr =~ s#/+$##;
+               if ($rwr !~ m#^[a-z\+]+://#) {
+                       die "$rwr is not a valid URL (key: $k)\n";
+               }
+       }
+       $self->{-rewrite_root} = $rwr;
+}
+
+sub rewrite_uuid {
+       my ($self) = @_;
+       return $self->{-rewrite_uuid} if exists $self->{-rewrite_uuid};
+       my $k = "svn-remote.$self->{repo_id}.rewriteUUID";
+       my $rwid = eval { command_oneline(qw/config --get/, $k) };
+       if ($rwid) {
+               $rwid =~ s#/+$##;
+               if ($rwid !~ m#^[a-f0-9]{8}-(?:[a-f0-9]{4}-){3}[a-f0-9]{12}$#) {
+                       die "$rwid is not a valid UUID (key: $k)\n";
+               }
+       }
+       $self->{-rewrite_uuid} = $rwid;
+}
+
+sub metadata_url {
+       my ($self) = @_;
+       my $url = $self->rewrite_root || $self->url;
+       return canonicalize_url( add_path_to_url( $url, $self->path ) );
+}
+
+sub full_url {
+       my ($self) = @_;
+       return canonicalize_url( add_path_to_url( $self->url, $self->path ) );
+}
+
+sub full_pushurl {
+       my ($self) = @_;
+       if ($self->{pushurl}) {
+               return canonicalize_url( add_path_to_url( $self->{pushurl}, $self->path ) );
+       } else {
+               return $self->full_url;
+       }
+}
+
+sub set_commit_header_env {
+       my ($log_entry) = @_;
+       my %env;
+       foreach my $ned (qw/NAME EMAIL DATE/) {
+               foreach my $ac (qw/AUTHOR COMMITTER/) {
+                       $env{"GIT_${ac}_${ned}"} = $ENV{"GIT_${ac}_${ned}"};
+               }
+       }
+
+       $ENV{GIT_AUTHOR_NAME} = $log_entry->{name};
+       $ENV{GIT_AUTHOR_EMAIL} = $log_entry->{email};
+       $ENV{GIT_AUTHOR_DATE} = $ENV{GIT_COMMITTER_DATE} = $log_entry->{date};
+
+       $ENV{GIT_COMMITTER_NAME} = (defined $log_entry->{commit_name})
+                                               ? $log_entry->{commit_name}
+                                               : $log_entry->{name};
+       $ENV{GIT_COMMITTER_EMAIL} = (defined $log_entry->{commit_email})
+                                               ? $log_entry->{commit_email}
+                                               : $log_entry->{email};
+       \%env;
+}
+
+sub restore_commit_header_env {
+       my ($env) = @_;
+       foreach my $ned (qw/NAME EMAIL DATE/) {
+               foreach my $ac (qw/AUTHOR COMMITTER/) {
+                       my $k = "GIT_${ac}_${ned}";
+                       if (defined $env->{$k}) {
+                               $ENV{$k} = $env->{$k};
+                       } else {
+                               delete $ENV{$k};
+                       }
+               }
+       }
+}
+
+sub gc {
+       command_noisy('gc', '--auto');
+};
+
+sub do_git_commit {
+       my ($self, $log_entry) = @_;
+       my $lr = $self->last_rev;
+       if (defined $lr && $lr >= $log_entry->{revision}) {
+               die "Last fetched revision of ", $self->refname,
+                   " was r$lr, but we are about to fetch: ",
+                   "r$log_entry->{revision}!\n";
+       }
+       if (my $c = $self->rev_map_get($log_entry->{revision})) {
+               croak "$log_entry->{revision} = $c already exists! ",
+                     "Why are we refetching it?\n";
+       }
+       my $old_env = set_commit_header_env($log_entry);
+       my $tree = $log_entry->{tree};
+       if (!defined $tree) {
+               $tree = $self->tmp_index_do(sub {
+                                           command_oneline('write-tree') });
+       }
+       die "Tree is not a valid sha1: $tree\n" if $tree !~ /^$::sha1$/o;
+
+       my @exec = ('git', 'commit-tree', $tree);
+       foreach ($self->get_commit_parents($log_entry)) {
+               push @exec, '-p', $_;
+       }
+       defined(my $pid = open3(my $msg_fh, my $out_fh, '>&STDERR', @exec))
+                                                                  or croak $!;
+       binmode $msg_fh;
+
+       # we always get UTF-8 from SVN, but we may want our commits in
+       # a different encoding.
+       if (my $enc = Git::config('i18n.commitencoding')) {
+               require Encode;
+               Encode::from_to($log_entry->{log}, 'UTF-8', $enc);
+       }
+       print $msg_fh $log_entry->{log} or croak $!;
+       restore_commit_header_env($old_env);
+       unless ($self->no_metadata) {
+               print $msg_fh "\ngit-svn-id: $log_entry->{metadata}\n"
+                             or croak $!;
+       }
+       $msg_fh->flush == 0 or croak $!;
+       close $msg_fh or croak $!;
+       chomp(my $commit = do { local $/; <$out_fh> });
+       close $out_fh or croak $!;
+       waitpid $pid, 0;
+       croak $? if $?;
+       if ($commit !~ /^$::sha1$/o) {
+               die "Failed to commit, invalid sha1: $commit\n";
+       }
+
+       $self->rev_map_set($log_entry->{revision}, $commit, 1);
+
+       $self->{last_rev} = $log_entry->{revision};
+       $self->{last_commit} = $commit;
+       print "r$log_entry->{revision}" unless $::_q > 1;
+       if (defined $log_entry->{svm_revision}) {
+                print " (\@$log_entry->{svm_revision})" unless $::_q > 1;
+                $self->rev_map_set($log_entry->{svm_revision}, $commit,
+                                  0, $self->svm_uuid);
+       }
+       print " = $commit ($self->{ref_id})\n" unless $::_q > 1;
+       if (--$_gc_nr == 0) {
+               $_gc_nr = $_gc_period;
+               gc();
+       }
+       return $commit;
+}
+
+sub match_paths {
+       my ($self, $paths, $r) = @_;
+       return 1 if $self->path eq '';
+       if (my $path = $paths->{"/".$self->path}) {
+               return ($path->{action} eq 'D') ? 0 : 1;
+       }
+       $self->{path_regex} ||= qr{^/\Q@{[$self->path]}\E/};
+       if (grep /$self->{path_regex}/, keys %$paths) {
+               return 1;
+       }
+       my $c = '';
+       foreach (split m#/#, $self->path) {
+               $c .= "/$_";
+               next unless ($paths->{$c} &&
+                            ($paths->{$c}->{action} =~ /^[AR]$/));
+               if ($self->ra->check_path($self->path, $r) ==
+                   $SVN::Node::dir) {
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+sub find_parent_branch {
+       my ($self, $paths, $rev) = @_;
+       return undef unless $self->follow_parent;
+       unless (defined $paths) {
+               my $err_handler = $SVN::Error::handler;
+               $SVN::Error::handler = \&Git::SVN::Ra::skip_unknown_revs;
+               $self->ra->get_log([$self->path], $rev, $rev, 0, 1, 1,
+                                  sub { $paths = $_[0] });
+               $SVN::Error::handler = $err_handler;
+       }
+       return undef unless defined $paths;
+
+       # look for a parent from another branch:
+       my @b_path_components = split m#/#, $self->path;
+       my @a_path_components;
+       my $i;
+       while (@b_path_components) {
+               $i = $paths->{'/'.join('/', @b_path_components)};
+               last if $i && defined $i->{copyfrom_path};
+               unshift(@a_path_components, pop(@b_path_components));
+       }
+       return undef unless defined $i && defined $i->{copyfrom_path};
+       my $branch_from = $i->{copyfrom_path};
+       if (@a_path_components) {
+               print STDERR "branch_from: $branch_from => ";
+               $branch_from .= '/'.join('/', @a_path_components);
+               print STDERR $branch_from, "\n";
+       }
+       my $r = $i->{copyfrom_rev};
+       my $repos_root = $self->ra->{repos_root};
+       my $url = $self->ra->url;
+       my $new_url = canonicalize_url( add_path_to_url( $url, $branch_from ) );
+       print STDERR  "Found possible branch point: ",
+                     "$new_url => ", $self->full_url, ", $r\n"
+                     unless $::_q > 1;
+       $branch_from =~ s#^/##;
+       my $gs = $self->other_gs($new_url, $url,
+                                $branch_from, $r, $self->{ref_id});
+       my ($r0, $parent) = $gs->find_rev_before($r, 1);
+       {
+               my ($base, $head);
+               if (!defined $r0 || !defined $parent) {
+                       ($base, $head) = parse_revision_argument(0, $r);
+               } else {
+                       if ($r0 < $r) {
+                               $gs->ra->get_log([$gs->path], $r0 + 1, $r, 1,
+                                       0, 1, sub { $base = $_[1] - 1 });
+                       }
+               }
+               if (defined $base && $base <= $r) {
+                       $gs->fetch($base, $r);
+               }
+               ($r0, $parent) = $gs->find_rev_before($r, 1);
+       }
+       if (defined $r0 && defined $parent) {
+               print STDERR "Found branch parent: ($self->{ref_id}) $parent\n"
+                            unless $::_q > 1;
+               my $ed;
+               if ($self->ra->can_do_switch) {
+                       $self->assert_index_clean($parent);
+                       print STDERR "Following parent with do_switch\n"
+                                    unless $::_q > 1;
+                       # do_switch works with svn/trunk >= r22312, but that
+                       # is not included with SVN 1.4.3 (the latest version
+                       # at the moment), so we can't rely on it
+                       $self->{last_rev} = $r0;
+                       $self->{last_commit} = $parent;
+                       $ed = Git::SVN::Fetcher->new($self, $gs->path);
+                       $gs->ra->gs_do_switch($r0, $rev, $gs,
+                                             $self->full_url, $ed)
+                         or die "SVN connection failed somewhere...\n";
+               } elsif ($self->ra->trees_match($new_url, $r0,
+                                               $self->full_url, $rev)) {
+                       print STDERR "Trees match:\n",
+                                    "  $new_url\@$r0\n",
+                                    "  ${\$self->full_url}\@$rev\n",
+                                    "Following parent with no changes\n"
+                                    unless $::_q > 1;
+                       $self->tmp_index_do(sub {
+                           command_noisy('read-tree', $parent);
+                       });
+                       $self->{last_commit} = $parent;
+               } else {
+                       print STDERR "Following parent with do_update\n"
+                                    unless $::_q > 1;
+                       $ed = Git::SVN::Fetcher->new($self);
+                       $self->ra->gs_do_update($rev, $rev, $self, $ed)
+                         or die "SVN connection failed somewhere...\n";
+               }
+               print STDERR "Successfully followed parent\n" unless $::_q > 1;
+               return $self->make_log_entry($rev, [$parent], $ed);
+       }
+       return undef;
+}
+
+sub do_fetch {
+       my ($self, $paths, $rev) = @_;
+       my $ed;
+       my ($last_rev, @parents);
+       if (my $lc = $self->last_commit) {
+               # we can have a branch that was deleted, then re-added
+               # under the same name but copied from another path, in
+               # which case we'll have multiple parents (we don't
+               # want to break the original ref, nor lose copypath info):
+               if (my $log_entry = $self->find_parent_branch($paths, $rev)) {
+                       push @{$log_entry->{parents}}, $lc;
+                       return $log_entry;
+               }
+               $ed = Git::SVN::Fetcher->new($self);
+               $last_rev = $self->{last_rev};
+               $ed->{c} = $lc;
+               @parents = ($lc);
+       } else {
+               $last_rev = $rev;
+               if (my $log_entry = $self->find_parent_branch($paths, $rev)) {
+                       return $log_entry;
+               }
+               $ed = Git::SVN::Fetcher->new($self);
+       }
+       unless ($self->ra->gs_do_update($last_rev, $rev, $self, $ed)) {
+               die "SVN connection failed somewhere...\n";
+       }
+       $self->make_log_entry($rev, \@parents, $ed);
+}
+
+sub mkemptydirs {
+       my ($self, $r) = @_;
+
+       sub scan {
+               my ($r, $empty_dirs, $line) = @_;
+               if (defined $r && $line =~ /^r(\d+)$/) {
+                       return 0 if $1 > $r;
+               } elsif ($line =~ /^  \+empty_dir: (.+)$/) {
+                       $empty_dirs->{$1} = 1;
+               } elsif ($line =~ /^  \-empty_dir: (.+)$/) {
+                       my @d = grep {m[^\Q$1\E(/|$)]} (keys %$empty_dirs);
+                       delete @$empty_dirs{@d};
+               }
+               1; # continue
+       };
+
+       my %empty_dirs = ();
+       my $gz_file = "$self->{dir}/unhandled.log.gz";
+       if (-f $gz_file) {
+               if (!can_compress()) {
+                       warn "Compress::Zlib could not be found; ",
+                            "empty directories in $gz_file will not be read\n";
+               } else {
+                       my $gz = Compress::Zlib::gzopen($gz_file, "rb") or
+                               die "Unable to open $gz_file: $!\n";
+                       my $line;
+                       while ($gz->gzreadline($line) > 0) {
+                               scan($r, \%empty_dirs, $line) or last;
+                       }
+                       $gz->gzclose;
+               }
+       }
+
+       if (open my $fh, '<', "$self->{dir}/unhandled.log") {
+               binmode $fh or croak "binmode: $!";
+               while (<$fh>) {
+                       scan($r, \%empty_dirs, $_) or last;
+               }
+               close $fh;
+       }
+
+       my $strip = qr/\A\Q@{[$self->path]}\E(?:\/|$)/;
+       foreach my $d (sort keys %empty_dirs) {
+               $d = uri_decode($d);
+               $d =~ s/$strip//;
+               next unless length($d);
+               next if -d $d;
+               if (-e $d) {
+                       warn "$d exists but is not a directory\n";
+               } else {
+                       print "creating empty directory: $d\n";
+                       mkpath([$d]);
+               }
+       }
+}
+
+sub get_untracked {
+       my ($self, $ed) = @_;
+       my @out;
+       my $h = $ed->{empty};
+       foreach (sort keys %$h) {
+               my $act = $h->{$_} ? '+empty_dir' : '-empty_dir';
+               push @out, "  $act: " . uri_encode($_);
+               warn "W: $act: $_\n";
+       }
+       foreach my $t (qw/dir_prop file_prop/) {
+               $h = $ed->{$t} or next;
+               foreach my $path (sort keys %$h) {
+                       my $ppath = $path eq '' ? '.' : $path;
+                       foreach my $prop (sort keys %{$h->{$path}}) {
+                               next if $SKIP_PROP{$prop};
+                               my $v = $h->{$path}->{$prop};
+                               my $t_ppath_prop = "$t: " .
+                                                   uri_encode($ppath) . ' ' .
+                                                   uri_encode($prop);
+                               if (defined $v) {
+                                       push @out, "  +$t_ppath_prop " .
+                                                  uri_encode($v);
+                               } else {
+                                       push @out, "  -$t_ppath_prop";
+                               }
+                       }
+               }
+       }
+       foreach my $t (qw/absent_file absent_directory/) {
+               $h = $ed->{$t} or next;
+               foreach my $parent (sort keys %$h) {
+                       foreach my $path (sort @{$h->{$parent}}) {
+                               push @out, "  $t: " .
+                                          uri_encode("$parent/$path");
+                               warn "W: $t: $parent/$path ",
+                                    "Insufficient permissions?\n";
+                       }
+               }
+       }
+       \@out;
+}
+
+sub get_tz {
+       # some systmes don't handle or mishandle %z, so be creative.
+       my $t = shift || time;
+       my $gm = timelocal(gmtime($t));
+       my $sign = qw( + + - )[ $t <=> $gm ];
+       return sprintf("%s%02d%02d", $sign, (gmtime(abs($t - $gm)))[2,1]);
+}
+
+# parse_svn_date(DATE)
+# --------------------
+# Given a date (in UTC) from Subversion, return a string in the format
+# "<TZ Offset> <local date/time>" that Git will use.
+#
+# By default the parsed date will be in UTC; if $Git::SVN::_localtime
+# is true we'll convert it to the local timezone instead.
+sub parse_svn_date {
+       my $date = shift || return '+0000 1970-01-01 00:00:00';
+       my ($Y,$m,$d,$H,$M,$S) = ($date =~ /^(\d{4})\-(\d\d)\-(\d\d)T
+                                           (\d\d)\:(\d\d)\:(\d\d)\.\d*Z$/x) or
+                                        croak "Unable to parse date: $date\n";
+       my $parsed_date;    # Set next.
+
+       if ($Git::SVN::_localtime) {
+               # Translate the Subversion datetime to an epoch time.
+               # Begin by switching ourselves to $date's timezone, UTC.
+               my $old_env_TZ = $ENV{TZ};
+               $ENV{TZ} = 'UTC';
+
+               my $epoch_in_UTC =
+                   POSIX::strftime('%s', $S, $M, $H, $d, $m - 1, $Y - 1900);
+
+               # Determine our local timezone (including DST) at the
+               # time of $epoch_in_UTC.  $Git::SVN::Log::TZ stored the
+               # value of TZ, if any, at the time we were run.
+               if (defined $Git::SVN::Log::TZ) {
+                       $ENV{TZ} = $Git::SVN::Log::TZ;
+               } else {
+                       delete $ENV{TZ};
+               }
+
+               my $our_TZ = get_tz();
+
+               # This converts $epoch_in_UTC into our local timezone.
+               my ($sec, $min, $hour, $mday, $mon, $year,
+                   $wday, $yday, $isdst) = localtime($epoch_in_UTC);
+
+               $parsed_date = sprintf('%s %04d-%02d-%02d %02d:%02d:%02d',
+                                      $our_TZ, $year + 1900, $mon + 1,
+                                      $mday, $hour, $min, $sec);
+
+               # Reset us to the timezone in effect when we entered
+               # this routine.
+               if (defined $old_env_TZ) {
+                       $ENV{TZ} = $old_env_TZ;
+               } else {
+                       delete $ENV{TZ};
+               }
+       } else {
+               $parsed_date = "+0000 $Y-$m-$d $H:$M:$S";
+       }
+
+       return $parsed_date;
+}
+
+sub other_gs {
+       my ($self, $new_url, $url,
+           $branch_from, $r, $old_ref_id) = @_;
+       my $gs = Git::SVN->find_by_url($new_url, $url, $branch_from);
+       unless ($gs) {
+               my $ref_id = $old_ref_id;
+               $ref_id =~ s/\@\d+-*$//;
+               $ref_id .= "\@$r";
+               # just grow a tail if we're not unique enough :x
+               $ref_id .= '-' while find_ref($ref_id);
+               my ($u, $p, $repo_id) = ($new_url, '', $ref_id);
+               if ($u =~ s#^\Q$url\E(/|$)##) {
+                       $p = $u;
+                       $u = $url;
+                       $repo_id = $self->{repo_id};
+               }
+               while (1) {
+                       # It is possible to tag two different subdirectories at
+                       # the same revision.  If the url for an existing ref
+                       # does not match, we must either find a ref with a
+                       # matching url or create a new ref by growing a tail.
+                       $gs = Git::SVN->init($u, $p, $repo_id, $ref_id, 1);
+                       my (undef, $max_commit) = $gs->rev_map_max(1);
+                       last if (!$max_commit);
+                       my ($url) = ::cmt_metadata($max_commit);
+                       last if ($url eq $gs->metadata_url);
+                       $ref_id .= '-';
+               }
+               print STDERR "Initializing parent: $ref_id\n" unless $::_q > 1;
+       }
+       $gs
+}
+
+sub call_authors_prog {
+       my ($orig_author) = @_;
+       $orig_author = command_oneline('rev-parse', '--sq-quote', $orig_author);
+       my $author = `$::_authors_prog $orig_author`;
+       if ($? != 0) {
+               die "$::_authors_prog failed with exit code $?\n"
+       }
+       if ($author =~ /^\s*(.+?)\s*<(.*)>\s*$/) {
+               my ($name, $email) = ($1, $2);
+               $email = undef if length $2 == 0;
+               return [$name, $email];
+       } else {
+               die "Author: $orig_author: $::_authors_prog returned "
+                       . "invalid author format: $author\n";
+       }
+}
+
+sub check_author {
+       my ($author) = @_;
+       if (!defined $author || length $author == 0) {
+               $author = '(no author)';
+       }
+       if (!defined $::users{$author}) {
+               if (defined $::_authors_prog) {
+                       $::users{$author} = call_authors_prog($author);
+               } elsif (defined $::_authors) {
+                       die "Author: $author not defined in $::_authors file\n";
+               }
+       }
+       $author;
+}
+
+sub find_extra_svk_parents {
+       my ($self, $ed, $tickets, $parents) = @_;
+       # aha!  svk:merge property changed...
+       my @tickets = split "\n", $tickets;
+       my @known_parents;
+       for my $ticket ( @tickets ) {
+               my ($uuid, $path, $rev) = split /:/, $ticket;
+               if ( $uuid eq $self->ra_uuid ) {
+                       my $repos_root = $self->url;
+                       my $branch_from = $path;
+                       $branch_from =~ s{^/}{};
+                       my $gs = $self->other_gs(add_path_to_url( $repos_root, $branch_from ),
+                                                $repos_root,
+                                                $branch_from,
+                                                $rev,
+                                                $self->{ref_id});
+                       if ( my $commit = $gs->rev_map_get($rev, $uuid) ) {
+                               # wahey!  we found it, but it might be
+                               # an old one (!)
+                               push @known_parents, [ $rev, $commit ];
+                       }
+               }
+       }
+       # Ordering matters; highest-numbered commit merge tickets
+       # first, as they may account for later merge ticket additions
+       # or changes.
+       @known_parents = map {$_->[1]} sort {$b->[0] <=> $a->[0]} @known_parents;
+       for my $parent ( @known_parents ) {
+               my @cmd = ('rev-list', $parent, map { "^$_" } @$parents );
+               my ($msg_fh, $ctx) = command_output_pipe(@cmd);
+               my $new;
+               while ( <$msg_fh> ) {
+                       $new=1;last;
+               }
+               command_close_pipe($msg_fh, $ctx);
+               if ( $new ) {
+                       print STDERR
+                           "Found merge parent (svk:merge ticket): $parent\n";
+                       push @$parents, $parent;
+               }
+       }
+}
+
+sub lookup_svn_merge {
+       my $uuid = shift;
+       my $url = shift;
+       my $merge = shift;
+
+       my ($source, $revs) = split ":", $merge;
+       my $path = $source;
+       $path =~ s{^/}{};
+       my $gs = Git::SVN->find_by_url($url.$source, $url, $path);
+       if ( !$gs ) {
+               warn "Couldn't find revmap for $url$source\n";
+               return;
+       }
+       my @ranges = split ",", $revs;
+       my ($tip, $tip_commit);
+       my @merged_commit_ranges;
+       # find the tip
+       for my $range ( @ranges ) {
+               my ($bottom, $top) = split "-", $range;
+               $top ||= $bottom;
+               my $bottom_commit = $gs->find_rev_after( $bottom, 1, $top );
+               my $top_commit = $gs->find_rev_before( $top, 1, $bottom );
+
+               unless ($top_commit and $bottom_commit) {
+                       warn "W:unknown path/rev in svn:mergeinfo "
+                               ."dirprop: $source:$range\n";
+                       next;
+               }
+
+               if (scalar(command('rev-parse', "$bottom_commit^@"))) {
+                       push @merged_commit_ranges,
+                            "$bottom_commit^..$top_commit";
+               } else {
+                       push @merged_commit_ranges, "$top_commit";
+               }
+
+               if ( !defined $tip or $top > $tip ) {
+                       $tip = $top;
+                       $tip_commit = $top_commit;
+               }
+       }
+       return ($tip_commit, @merged_commit_ranges);
+}
+
+sub _rev_list {
+       my ($msg_fh, $ctx) = command_output_pipe(
+               "rev-list", @_,
+              );
+       my @rv;
+       while ( <$msg_fh> ) {
+               chomp;
+               push @rv, $_;
+       }
+       command_close_pipe($msg_fh, $ctx);
+       @rv;
+}
+
+sub check_cherry_pick {
+       my $base = shift;
+       my $tip = shift;
+       my $parents = shift;
+       my @ranges = @_;
+       my %commits = map { $_ => 1 }
+               _rev_list("--no-merges", $tip, "--not", $base, @$parents, "--");
+       for my $range ( @ranges ) {
+               delete @commits{_rev_list($range, "--")};
+       }
+       for my $commit (keys %commits) {
+               if (has_no_changes($commit)) {
+                       delete $commits{$commit};
+               }
+       }
+       return (keys %commits);
+}
+
+sub has_no_changes {
+       my $commit = shift;
+
+       my @revs = split / /, command_oneline(
+               qw(rev-list --parents -1 -m), $commit);
+
+       # Commits with no parents, e.g. the start of a partial branch,
+       # have changes by definition.
+       return 1 if (@revs < 2);
+
+       # Commits with multiple parents, e.g a merge, have no changes
+       # by definition.
+       return 0 if (@revs > 2);
+
+       return (command_oneline("rev-parse", "$commit^{tree}") eq
+               command_oneline("rev-parse", "$commit~1^{tree}"));
+}
+
+sub tie_for_persistent_memoization {
+       my $hash = shift;
+       my $path = shift;
+
+       if ($can_use_yaml) {
+               tie %$hash => 'Git::SVN::Memoize::YAML', "$path.yaml";
+       } else {
+               tie %$hash => 'Memoize::Storable', "$path.db", 'nstore';
+       }
+}
+
+# The GIT_DIR environment variable is not always set until after the command
+# line arguments are processed, so we can't memoize in a BEGIN block.
+{
+       my $memoized = 0;
+
+       sub memoize_svn_mergeinfo_functions {
+               return if $memoized;
+               $memoized = 1;
+
+               my $cache_path = "$ENV{GIT_DIR}/svn/.caches/";
+               mkpath([$cache_path]) unless -d $cache_path;
+
+               my %lookup_svn_merge_cache;
+               my %check_cherry_pick_cache;
+               my %has_no_changes_cache;
+
+               tie_for_persistent_memoization(\%lookup_svn_merge_cache,
+                   "$cache_path/lookup_svn_merge");
+               memoize 'lookup_svn_merge',
+                       SCALAR_CACHE => 'FAULT',
+                       LIST_CACHE => ['HASH' => \%lookup_svn_merge_cache],
+               ;
+
+               tie_for_persistent_memoization(\%check_cherry_pick_cache,
+                   "$cache_path/check_cherry_pick");
+               memoize 'check_cherry_pick',
+                       SCALAR_CACHE => 'FAULT',
+                       LIST_CACHE => ['HASH' => \%check_cherry_pick_cache],
+               ;
+
+               tie_for_persistent_memoization(\%has_no_changes_cache,
+                   "$cache_path/has_no_changes");
+               memoize 'has_no_changes',
+                       SCALAR_CACHE => ['HASH' => \%has_no_changes_cache],
+                       LIST_CACHE => 'FAULT',
+               ;
+       }
+
+       sub unmemoize_svn_mergeinfo_functions {
+               return if not $memoized;
+               $memoized = 0;
+
+               Memoize::unmemoize 'lookup_svn_merge';
+               Memoize::unmemoize 'check_cherry_pick';
+               Memoize::unmemoize 'has_no_changes';
+       }
+
+       sub clear_memoized_mergeinfo_caches {
+               die "Only call this method in non-memoized context" if ($memoized);
+
+               my $cache_path = "$ENV{GIT_DIR}/svn/.caches/";
+               return unless -d $cache_path;
+
+               for my $cache_file (("$cache_path/lookup_svn_merge",
+                                    "$cache_path/check_cherry_pick",
+                                    "$cache_path/has_no_changes")) {
+                       for my $suffix (qw(yaml db)) {
+                               my $file = "$cache_file.$suffix";
+                               next unless -e $file;
+                               unlink($file) or die "unlink($file) failed: $!\n";
+                       }
+               }
+       }
+
+
+       Memoize::memoize 'Git::SVN::repos_root';
+}
+
+END {
+       # Force cache writeout explicitly instead of waiting for
+       # global destruction to avoid segfault in Storable:
+       # http://rt.cpan.org/Public/Bug/Display.html?id=36087
+       unmemoize_svn_mergeinfo_functions();
+}
+
+sub parents_exclude {
+       my $parents = shift;
+       my @commits = @_;
+       return unless @commits;
+
+       my @excluded;
+       my $excluded;
+       do {
+               my @cmd = ('rev-list', "-1", @commits, "--not", @$parents );
+               $excluded = command_oneline(@cmd);
+               if ( $excluded ) {
+                       my @new;
+                       my $found;
+                       for my $commit ( @commits ) {
+                               if ( $commit eq $excluded ) {
+                                       push @excluded, $commit;
+                                       $found++;
+                               }
+                               else {
+                                       push @new, $commit;
+                               }
+                       }
+                       die "saw commit '$excluded' in rev-list output, "
+                               ."but we didn't ask for that commit (wanted: @commits --not @$parents)"
+                                       unless $found;
+                       @commits = @new;
+               }
+       }
+               while ($excluded and @commits);
+
+       return @excluded;
+}
+
+
+# note: this function should only be called if the various dirprops
+# have actually changed
+sub find_extra_svn_parents {
+       my ($self, $ed, $mergeinfo, $parents) = @_;
+       # aha!  svk:merge property changed...
+
+       memoize_svn_mergeinfo_functions();
+
+       # We first search for merged tips which are not in our
+       # history.  Then, we figure out which git revisions are in
+       # that tip, but not this revision.  If all of those revisions
+       # are now marked as merge, we can add the tip as a parent.
+       my @merges = split "\n", $mergeinfo;
+       my @merge_tips;
+       my $url = $self->url;
+       my $uuid = $self->ra_uuid;
+       my @all_ranges;
+       for my $merge ( @merges ) {
+               my ($tip_commit, @ranges) =
+                       lookup_svn_merge( $uuid, $url, $merge );
+               unless (!$tip_commit or
+                               grep { $_ eq $tip_commit } @$parents ) {
+                       push @merge_tips, $tip_commit;
+                       push @all_ranges, @ranges;
+               } else {
+                       push @merge_tips, undef;
+               }
+       }
+
+       my %excluded = map { $_ => 1 }
+               parents_exclude($parents, grep { defined } @merge_tips);
+
+       # check merge tips for new parents
+       my @new_parents;
+       for my $merge_tip ( @merge_tips ) {
+               my $spec = shift @merges;
+               next unless $merge_tip and $excluded{$merge_tip};
+
+               # check out 'new' tips
+               my $merge_base;
+               eval {
+                       $merge_base = command_oneline(
+                               "merge-base",
+                               @$parents, $merge_tip,
+                       );
+               };
+               if ($@) {
+                       die "An error occurred during merge-base"
+                               unless $@->isa("Git::Error::Command");
+
+                       warn "W: Cannot find common ancestor between ".
+                            "@$parents and $merge_tip. Ignoring merge info.\n";
+                       next;
+               }
+
+               # double check that there are no missing non-merge commits
+               my (@incomplete) = check_cherry_pick(
+                       $merge_base, $merge_tip,
+                       $parents,
+                       @all_ranges,
+                      );
+
+               if ( @incomplete ) {
+                       warn "W:svn cherry-pick ignored ($spec) - missing "
+                               .@incomplete." commit(s) (eg $incomplete[0])\n";
+               } else {
+                       warn
+                               "Found merge parent (svn:mergeinfo prop): ",
+                                       $merge_tip, "\n";
+                       push @new_parents, $merge_tip;
+               }
+       }
+
+       # cater for merges which merge commits from multiple branches
+       if ( @new_parents > 1 ) {
+               for ( my $i = 0; $i <= $#new_parents; $i++ ) {
+                       for ( my $j = 0; $j <= $#new_parents; $j++ ) {
+                               next if $i == $j;
+                               next unless $new_parents[$i];
+                               next unless $new_parents[$j];
+                               my $revs = command_oneline(
+                                       "rev-list", "-1",
+                                       "$new_parents[$i]..$new_parents[$j]",
+                                      );
+                               if ( !$revs ) {
+                                       undef($new_parents[$j]);
+                               }
+                       }
+               }
+       }
+       push @$parents, grep { defined } @new_parents;
+}
+
+sub make_log_entry {
+       my ($self, $rev, $parents, $ed) = @_;
+       my $untracked = $self->get_untracked($ed);
+
+       my @parents = @$parents;
+       my $ps = $ed->{path_strip} || "";
+       for my $path ( grep { m/$ps/ } %{$ed->{dir_prop}} ) {
+               my $props = $ed->{dir_prop}{$path};
+               if ( $props->{"svk:merge"} ) {
+                       $self->find_extra_svk_parents
+                               ($ed, $props->{"svk:merge"}, \@parents);
+               }
+               if ( $props->{"svn:mergeinfo"} ) {
+                       $self->find_extra_svn_parents
+                               ($ed,
+                                $props->{"svn:mergeinfo"},
+                                \@parents);
+               }
+       }
+
+       open my $un, '>>', "$self->{dir}/unhandled.log" or croak $!;
+       print $un "r$rev\n" or croak $!;
+       print $un $_, "\n" foreach @$untracked;
+       my %log_entry = ( parents => \@parents, revision => $rev,
+                         log => '');
+
+       my $headrev;
+       my $logged = delete $self->{logged_rev_props};
+       if (!$logged || $self->{-want_revprops}) {
+               my $rp = $self->ra->rev_proplist($rev);
+               foreach (sort keys %$rp) {
+                       my $v = $rp->{$_};
+                       if (/^svn:(author|date|log)$/) {
+                               $log_entry{$1} = $v;
+                       } elsif ($_ eq 'svm:headrev') {
+                               $headrev = $v;
+                       } else {
+                               print $un "  rev_prop: ", uri_encode($_), ' ',
+                                         uri_encode($v), "\n";
+                       }
+               }
+       } else {
+               map { $log_entry{$_} = $logged->{$_} } keys %$logged;
+       }
+       close $un or croak $!;
+
+       $log_entry{date} = parse_svn_date($log_entry{date});
+       $log_entry{log} .= "\n";
+       my $author = $log_entry{author} = check_author($log_entry{author});
+       my ($name, $email) = defined $::users{$author} ? @{$::users{$author}}
+                                                      : ($author, undef);
+
+       my ($commit_name, $commit_email) = ($name, $email);
+       if ($_use_log_author) {
+               my $name_field;
+               if ($log_entry{log} =~ /From:\s+(.*\S)\s*\n/i) {
+                       $name_field = $1;
+               } elsif ($log_entry{log} =~ /Signed-off-by:\s+(.*\S)\s*\n/i) {
+                       $name_field = $1;
+               }
+               if (!defined $name_field) {
+                       if (!defined $email) {
+                               $email = $name;
+                       }
+               } elsif ($name_field =~ /(.*?)\s+<(.*)>/) {
+                       ($name, $email) = ($1, $2);
+               } elsif ($name_field =~ /(.*)@/) {
+                       ($name, $email) = ($1, $name_field);
+               } else {
+                       ($name, $email) = ($name_field, $name_field);
+               }
+       }
+       if (defined $headrev && $self->use_svm_props) {
+               if ($self->rewrite_root) {
+                       die "Can't have both 'useSvmProps' and 'rewriteRoot' ",
+                           "options set!\n";
+               }
+               if ($self->rewrite_uuid) {
+                       die "Can't have both 'useSvmProps' and 'rewriteUUID' ",
+                           "options set!\n";
+               }
+               my ($uuid, $r) = $headrev =~ m{^([a-f\d\-]{30,}):(\d+)$}i;
+               # we don't want "SVM: initializing mirror for junk" ...
+               return undef if $r == 0;
+               my $svm = $self->svm;
+               if ($uuid ne $svm->{uuid}) {
+                       die "UUID mismatch on SVM path:\n",
+                           "expected: $svm->{uuid}\n",
+                           "     got: $uuid\n";
+               }
+               my $full_url = $self->full_url;
+               $full_url =~ s#^\Q$svm->{replace}\E(/|$)#$svm->{source}$1# or
+                            die "Failed to replace '$svm->{replace}' with ",
+                                "'$svm->{source}' in $full_url\n";
+               # throw away username for storing in records
+               remove_username($full_url);
+               $log_entry{metadata} = "$full_url\@$r $uuid";
+               $log_entry{svm_revision} = $r;
+               $email ||= "$author\@$uuid";
+               $commit_email ||= "$author\@$uuid";
+       } elsif ($self->use_svnsync_props) {
+               my $full_url = canonicalize_url(
+                       add_path_to_url( $self->svnsync->{url}, $self->path )
+               );
+               remove_username($full_url);
+               my $uuid = $self->svnsync->{uuid};
+               $log_entry{metadata} = "$full_url\@$rev $uuid";
+               $email ||= "$author\@$uuid";
+               $commit_email ||= "$author\@$uuid";
+       } else {
+               my $url = $self->metadata_url;
+               remove_username($url);
+               my $uuid = $self->rewrite_uuid || $self->ra->get_uuid;
+               $log_entry{metadata} = "$url\@$rev " . $uuid;
+               $email ||= "$author\@" . $uuid;
+               $commit_email ||= "$author\@" . $uuid;
+       }
+       $log_entry{name} = $name;
+       $log_entry{email} = $email;
+       $log_entry{commit_name} = $commit_name;
+       $log_entry{commit_email} = $commit_email;
+       \%log_entry;
+}
+
+sub fetch {
+       my ($self, $min_rev, $max_rev, @parents) = @_;
+       my ($last_rev, $last_commit) = $self->last_rev_commit;
+       my ($base, $head) = $self->get_fetch_range($min_rev, $max_rev);
+       $self->ra->gs_fetch_loop_common($base, $head, [$self]);
+}
+
+sub set_tree_cb {
+       my ($self, $log_entry, $tree, $rev, $date, $author) = @_;
+       $self->{inject_parents} = { $rev => $tree };
+       $self->fetch(undef, undef);
+}
+
+sub set_tree {
+       my ($self, $tree) = (shift, shift);
+       my $log_entry = ::get_commit_entry($tree);
+       unless ($self->{last_rev}) {
+               fatal("Must have an existing revision to commit");
+       }
+       my %ed_opts = ( r => $self->{last_rev},
+                       log => $log_entry->{log},
+                       ra => $self->ra,
+                       tree_a => $self->{last_commit},
+                       tree_b => $tree,
+                       editor_cb => sub {
+                              $self->set_tree_cb($log_entry, $tree, @_) },
+                       svn_path => $self->path );
+       if (!Git::SVN::Editor->new(\%ed_opts)->apply_diff) {
+               print "No changes\nr$self->{last_rev} = $tree\n";
+       }
+}
+
+sub rebuild_from_rev_db {
+       my ($self, $path) = @_;
+       my $r = -1;
+       open my $fh, '<', $path or croak "open: $!";
+       binmode $fh or croak "binmode: $!";
+       while (<$fh>) {
+               length($_) == 41 or croak "inconsistent size in ($_) != 41";
+               chomp($_);
+               ++$r;
+               next if $_ eq ('0' x 40);
+               $self->rev_map_set($r, $_);
+               print "r$r = $_\n";
+       }
+       close $fh or croak "close: $!";
+       unlink $path or croak "unlink: $!";
+}
+
+sub rebuild {
+       my ($self) = @_;
+       my $map_path = $self->map_path;
+       my $partial = (-e $map_path && ! -z $map_path);
+       return unless ::verify_ref($self->refname.'^0');
+       if (!$partial && ($self->use_svm_props || $self->no_metadata)) {
+               my $rev_db = $self->rev_db_path;
+               $self->rebuild_from_rev_db($rev_db);
+               if ($self->use_svm_props) {
+                       my $svm_rev_db = $self->rev_db_path($self->svm_uuid);
+                       $self->rebuild_from_rev_db($svm_rev_db);
+               }
+               $self->unlink_rev_db_symlink;
+               return;
+       }
+       print "Rebuilding $map_path ...\n" if (!$partial);
+       my ($base_rev, $head) = ($partial ? $self->rev_map_max_norebuild(1) :
+               (undef, undef));
+       my ($log, $ctx) =
+           command_output_pipe(qw/rev-list --pretty=raw --reverse/,
+                               ($head ? "$head.." : "") . $self->refname,
+                               '--');
+       my $metadata_url = $self->metadata_url;
+       remove_username($metadata_url);
+       my $svn_uuid = $self->rewrite_uuid || $self->ra_uuid;
+       my $c;
+       while (<$log>) {
+               if ( m{^commit ($::sha1)$} ) {
+                       $c = $1;
+                       next;
+               }
+               next unless s{^\s*(git-svn-id:)}{$1};
+               my ($url, $rev, $uuid) = ::extract_metadata($_);
+               remove_username($url);
+
+               # ignore merges (from set-tree)
+               next if (!defined $rev || !$uuid);
+
+               # if we merged or otherwise started elsewhere, this is
+               # how we break out of it
+               if (($uuid ne $svn_uuid) ||
+                   ($metadata_url && $url && ($url ne $metadata_url))) {
+                       next;
+               }
+               if ($partial && $head) {
+                       print "Partial-rebuilding $map_path ...\n";
+                       print "Currently at $base_rev = $head\n";
+                       $head = undef;
+               }
+
+               $self->rev_map_set($rev, $c);
+               print "r$rev = $c\n";
+       }
+       command_close_pipe($log, $ctx);
+       print "Done rebuilding $map_path\n" if (!$partial || !$head);
+       my $rev_db_path = $self->rev_db_path;
+       if (-f $self->rev_db_path) {
+               unlink $self->rev_db_path or croak "unlink: $!";
+       }
+       $self->unlink_rev_db_symlink;
+}
+
+# rev_map:
+# Tie::File seems to be prone to offset errors if revisions get sparse,
+# it's not that fast, either.  Tie::File is also not in Perl 5.6.  So
+# one of my favorite modules is out :<  Next up would be one of the DBM
+# modules, but I'm not sure which is most portable...
+#
+# This is the replacement for the rev_db format, which was too big
+# and inefficient for large repositories with a lot of sparse history
+# (mainly tags)
+#
+# The format is this:
+#   - 24 bytes for every record,
+#     * 4 bytes for the integer representing an SVN revision number
+#     * 20 bytes representing the sha1 of a git commit
+#   - No empty padding records like the old format
+#     (except the last record, which can be overwritten)
+#   - new records are written append-only since SVN revision numbers
+#     increase monotonically
+#   - lookups on SVN revision number are done via a binary search
+#   - Piping the file to xxd -c24 is a good way of dumping it for
+#     viewing or editing (piped back through xxd -r), should the need
+#     ever arise.
+#   - The last record can be padding revision with an all-zero sha1
+#     This is used to optimize fetch performance when using multiple
+#     "fetch" directives in .git/config
+#
+# These files are disposable unless noMetadata or useSvmProps is set
+
+sub _rev_map_set {
+       my ($fh, $rev, $commit) = @_;
+
+       binmode $fh or croak "binmode: $!";
+       my $size = (stat($fh))[7];
+       ($size % 24) == 0 or croak "inconsistent size: $size";
+
+       my $wr_offset = 0;
+       if ($size > 0) {
+               sysseek($fh, -24, SEEK_END) or croak "seek: $!";
+               my $read = sysread($fh, my $buf, 24) or croak "read: $!";
+               $read == 24 or croak "read only $read bytes (!= 24)";
+               my ($last_rev, $last_commit) = unpack(rev_map_fmt, $buf);
+               if ($last_commit eq ('0' x40)) {
+                       if ($size >= 48) {
+                               sysseek($fh, -48, SEEK_END) or croak "seek: $!";
+                               $read = sysread($fh, $buf, 24) or
+                                   croak "read: $!";
+                               $read == 24 or
+                                   croak "read only $read bytes (!= 24)";
+                               ($last_rev, $last_commit) =
+                                   unpack(rev_map_fmt, $buf);
+                               if ($last_commit eq ('0' x40)) {
+                                       croak "inconsistent .rev_map\n";
+                               }
+                       }
+                       if ($last_rev >= $rev) {
+                               croak "last_rev is higher!: $last_rev >= $rev";
+                       }
+                       $wr_offset = -24;
+               }
+       }
+       sysseek($fh, $wr_offset, SEEK_END) or croak "seek: $!";
+       syswrite($fh, pack(rev_map_fmt, $rev, $commit), 24) == 24 or
+         croak "write: $!";
+}
+
+sub _rev_map_reset {
+       my ($fh, $rev, $commit) = @_;
+       my $c = _rev_map_get($fh, $rev);
+       $c eq $commit or die "_rev_map_reset(@_) commit $c does not match!\n";
+       my $offset = sysseek($fh, 0, SEEK_CUR) or croak "seek: $!";
+       truncate $fh, $offset or croak "truncate: $!";
+}
+
+sub mkfile {
+       my ($path) = @_;
+       unless (-e $path) {
+               my ($dir, $base) = ($path =~ m#^(.*?)/?([^/]+)$#);
+               mkpath([$dir]) unless -d $dir;
+               open my $fh, '>>', $path or die "Couldn't create $path: $!\n";
+               close $fh or die "Couldn't close (create) $path: $!\n";
+       }
+}
+
+sub rev_map_set {
+       my ($self, $rev, $commit, $update_ref, $uuid) = @_;
+       defined $commit or die "missing arg3\n";
+       length $commit == 40 or die "arg3 must be a full SHA1 hexsum\n";
+       my $db = $self->map_path($uuid);
+       my $db_lock = "$db.lock";
+       my $sigmask;
+       $update_ref ||= 0;
+       if ($update_ref) {
+               $sigmask = POSIX::SigSet->new();
+               my $signew = POSIX::SigSet->new(SIGINT, SIGHUP, SIGTERM,
+                       SIGALRM, SIGUSR1, SIGUSR2);
+               sigprocmask(SIG_BLOCK, $signew, $sigmask) or
+                       croak "Can't block signals: $!";
+       }
+       mkfile($db);
+
+       $LOCKFILES{$db_lock} = 1;
+       my $sync;
+       # both of these options make our .rev_db file very, very important
+       # and we can't afford to lose it because rebuild() won't work
+       if ($self->use_svm_props || $self->no_metadata) {
+               $sync = 1;
+               copy($db, $db_lock) or die "rev_map_set(@_): ",
+                                          "Failed to copy: ",
+                                          "$db => $db_lock ($!)\n";
+       } else {
+               rename $db, $db_lock or die "rev_map_set(@_): ",
+                                           "Failed to rename: ",
+                                           "$db => $db_lock ($!)\n";
+       }
+
+       sysopen(my $fh, $db_lock, O_RDWR | O_CREAT)
+            or croak "Couldn't open $db_lock: $!\n";
+       if ($update_ref eq 'reset') {
+               clear_memoized_mergeinfo_caches();
+               _rev_map_reset($fh, $rev, $commit);
+       } else {
+               _rev_map_set($fh, $rev, $commit);
+       }
+
+       if ($sync) {
+               $fh->flush or die "Couldn't flush $db_lock: $!\n";
+               $fh->sync or die "Couldn't sync $db_lock: $!\n";
+       }
+       close $fh or croak $!;
+       if ($update_ref) {
+               $_head = $self;
+               my $note = "";
+               $note = " ($update_ref)" if ($update_ref !~ /^\d*$/);
+               command_noisy('update-ref', '-m', "r$rev$note",
+                             $self->refname, $commit);
+       }
+       rename $db_lock, $db or die "rev_map_set(@_): ", "Failed to rename: ",
+                                   "$db_lock => $db ($!)\n";
+       delete $LOCKFILES{$db_lock};
+       if ($update_ref) {
+               sigprocmask(SIG_SETMASK, $sigmask) or
+                       croak "Can't restore signal mask: $!";
+       }
+}
+
+# If want_commit, this will return an array of (rev, commit) where
+# commit _must_ be a valid commit in the archive.
+# Otherwise, it'll return the max revision (whether or not the
+# commit is valid or just a 0x40 placeholder).
+sub rev_map_max {
+       my ($self, $want_commit) = @_;
+       $self->rebuild;
+       my ($r, $c) = $self->rev_map_max_norebuild($want_commit);
+       $want_commit ? ($r, $c) : $r;
+}
+
+sub rev_map_max_norebuild {
+       my ($self, $want_commit) = @_;
+       my $map_path = $self->map_path;
+       stat $map_path or return $want_commit ? (0, undef) : 0;
+       sysopen(my $fh, $map_path, O_RDONLY) or croak "open: $!";
+       binmode $fh or croak "binmode: $!";
+       my $size = (stat($fh))[7];
+       ($size % 24) == 0 or croak "inconsistent size: $size";
+
+       if ($size == 0) {
+               close $fh or croak "close: $!";
+               return $want_commit ? (0, undef) : 0;
+       }
+
+       sysseek($fh, -24, SEEK_END) or croak "seek: $!";
+       sysread($fh, my $buf, 24) == 24 or croak "read: $!";
+       my ($r, $c) = unpack(rev_map_fmt, $buf);
+       if ($want_commit && $c eq ('0' x40)) {
+               if ($size < 48) {
+                       return $want_commit ? (0, undef) : 0;
+               }
+               sysseek($fh, -48, SEEK_END) or croak "seek: $!";
+               sysread($fh, $buf, 24) == 24 or croak "read: $!";
+               ($r, $c) = unpack(rev_map_fmt, $buf);
+               if ($c eq ('0'x40)) {
+                       croak "Penultimate record is all-zeroes in $map_path";
+               }
+       }
+       close $fh or croak "close: $!";
+       $want_commit ? ($r, $c) : $r;
+}
+
+sub rev_map_get {
+       my ($self, $rev, $uuid) = @_;
+       my $map_path = $self->map_path($uuid);
+       return undef unless -e $map_path;
+
+       sysopen(my $fh, $map_path, O_RDONLY) or croak "open: $!";
+       my $c = _rev_map_get($fh, $rev);
+       close($fh) or croak "close: $!";
+       $c
+}
+
+sub _rev_map_get {
+       my ($fh, $rev) = @_;
+
+       binmode $fh or croak "binmode: $!";
+       my $size = (stat($fh))[7];
+       ($size % 24) == 0 or croak "inconsistent size: $size";
+
+       if ($size == 0) {
+               return undef;
+       }
+
+       my ($l, $u) = (0, $size - 24);
+       my ($r, $c, $buf);
+
+       while ($l <= $u) {
+               my $i = int(($l/24 + $u/24) / 2) * 24;
+               sysseek($fh, $i, SEEK_SET) or croak "seek: $!";
+               sysread($fh, my $buf, 24) == 24 or croak "read: $!";
+               my ($r, $c) = unpack(rev_map_fmt, $buf);
+
+               if ($r < $rev) {
+                       $l = $i + 24;
+               } elsif ($r > $rev) {
+                       $u = $i - 24;
+               } else { # $r == $rev
+                       return $c eq ('0' x 40) ? undef : $c;
+               }
+       }
+       undef;
+}
+
+# Finds the first svn revision that exists on (if $eq_ok is true) or
+# before $rev for the current branch.  It will not search any lower
+# than $min_rev.  Returns the git commit hash and svn revision number
+# if found, else (undef, undef).
+sub find_rev_before {
+       my ($self, $rev, $eq_ok, $min_rev) = @_;
+       --$rev unless $eq_ok;
+       $min_rev ||= 1;
+       my $max_rev = $self->rev_map_max;
+       $rev = $max_rev if ($rev > $max_rev);
+       while ($rev >= $min_rev) {
+               if (my $c = $self->rev_map_get($rev)) {
+                       return ($rev, $c);
+               }
+               --$rev;
+       }
+       return (undef, undef);
+}
+
+# Finds the first svn revision that exists on (if $eq_ok is true) or
+# after $rev for the current branch.  It will not search any higher
+# than $max_rev.  Returns the git commit hash and svn revision number
+# if found, else (undef, undef).
+sub find_rev_after {
+       my ($self, $rev, $eq_ok, $max_rev) = @_;
+       ++$rev unless $eq_ok;
+       $max_rev ||= $self->rev_map_max;
+       while ($rev <= $max_rev) {
+               if (my $c = $self->rev_map_get($rev)) {
+                       return ($rev, $c);
+               }
+               ++$rev;
+       }
+       return (undef, undef);
+}
+
+sub _new {
+       my ($class, $repo_id, $ref_id, $path) = @_;
+       unless (defined $repo_id && length $repo_id) {
+               $repo_id = $default_repo_id;
+       }
+       unless (defined $ref_id && length $ref_id) {
+               # Access the prefix option from the git-svn main program if it's loaded.
+               my $prefix = defined &::opt_prefix ? ::opt_prefix() : "";
+               $_[2] = $ref_id =
+                            "refs/remotes/$prefix$default_ref_id";
+       }
+       $_[1] = $repo_id;
+       my $dir = "$ENV{GIT_DIR}/svn/$ref_id";
+
+       # Older repos imported by us used $GIT_DIR/svn/foo instead of
+       # $GIT_DIR/svn/refs/remotes/foo when tracking refs/remotes/foo
+       if ($ref_id =~ m{^refs/remotes/(.*)}) {
+               my $old_dir = "$ENV{GIT_DIR}/svn/$1";
+               if (-d $old_dir && ! -d $dir) {
+                       $dir = $old_dir;
+               }
+       }
+
+       $_[3] = $path = '' unless (defined $path);
+       mkpath([$dir]);
+       my $obj = bless {
+               ref_id => $ref_id, dir => $dir, index => "$dir/index",
+               config => "$ENV{GIT_DIR}/svn/config",
+               map_root => "$dir/.rev_map", repo_id => $repo_id }, $class;
+
+       # Ensure it gets canonicalized
+       $obj->path($path);
+
+       return $obj;
+}
+
+sub path {
+       my $self = shift;
+
+       if (@_) {
+               my $path = shift;
+               $self->{_path} = canonicalize_path($path);
+               return;
+       }
+
+       return $self->{_path};
+}
+
+sub url {
+       my $self = shift;
+
+       if (@_) {
+               my $url = shift;
+               $self->{url} = canonicalize_url($url);
+               return;
+       }
+
+       return $self->{url};
+}
+
+# for read-only access of old .rev_db formats
+sub unlink_rev_db_symlink {
+       my ($self) = @_;
+       my $link = $self->rev_db_path;
+       $link =~ s/\.[\w-]+$// or croak "missing UUID at the end of $link";
+       if (-l $link) {
+               unlink $link or croak "unlink: $link failed!";
+       }
+}
+
+sub rev_db_path {
+       my ($self, $uuid) = @_;
+       my $db_path = $self->map_path($uuid);
+       $db_path =~ s{/\.rev_map\.}{/\.rev_db\.}
+           or croak "map_path: $db_path does not contain '/.rev_map.' !";
+       $db_path;
+}
+
+# the new replacement for .rev_db
+sub map_path {
+       my ($self, $uuid) = @_;
+       $uuid ||= $self->ra_uuid;
+       "$self->{map_root}.$uuid";
+}
+
+sub uri_encode {
+       my ($f) = @_;
+       $f =~ s#([^a-zA-Z0-9\*!\:_\./\-])#uc sprintf("%%%02x",ord($1))#eg;
+       $f
+}
+
+sub uri_decode {
+       my ($f) = @_;
+       $f =~ s#%([0-9a-fA-F]{2})#chr(hex($1))#eg;
+       $f
+}
+
+sub remove_username {
+       $_[0] =~ s{^([^:]*://)[^@]+@}{$1};
+}
+
+1;
index 755092fdffce322b88959a97b08d796460b41ffe..3bbc20a054576b75e77a15faffd82c46e553fef8 100644 (file)
@@ -345,7 +345,30 @@ sub M {
        $self->close_file($fbat,undef,$self->{pool});
 }
 
-sub T { shift->M(@_) }
+sub T {
+       my ($self, $m, $deletions) = @_;
+
+       # Work around subversion issue 4091: toggling the "is a
+       # symlink" property requires removing and re-adding a
+       # file or else "svn up" on affected clients trips an
+       # assertion and aborts.
+       if (($m->{mode_b} =~ /^120/ && $m->{mode_a} !~ /^120/) ||
+           ($m->{mode_b} !~ /^120/ && $m->{mode_a} =~ /^120/)) {
+               $self->D({
+                       mode_a => $m->{mode_a}, mode_b => '000000',
+                       sha1_a => $m->{sha1_a}, sha1_b => '0' x 40,
+                       chg => 'D', file_b => $m->{file_b}
+               });
+               $self->A({
+                       mode_a => '000000', mode_b => $m->{mode_b},
+                       sha1_a => '0' x 40, sha1_b => $m->{sha1_b},
+                       chg => 'A', file_b => $m->{file_b}
+               });
+               return;
+       }
+
+       $self->M($m, $deletions);
+}
 
 sub change_file_prop {
        my ($self, $fbat, $pname, $pval) = @_;
index ef8e9ed2a5bf52ba5c14cdfba722bf252ecde6dd..046a7a2f31cf923f634bd8b516b3da38ff989a46 100644 (file)
@@ -57,6 +57,7 @@ sub new {
        $self->{file_prop} = {};
        $self->{absent_dir} = {};
        $self->{absent_file} = {};
+       require Git::IndexInfo;
        $self->{gii} = $git_svn->tmp_index_do(sub { Git::IndexInfo->new });
        $self->{pathnameencoding} = Git::config('svn.pathnameencoding');
        $self;
@@ -82,7 +83,7 @@ sub _mark_empty_symlinks {
        chomp(my $empty_blob = `git hash-object -t blob --stdin < /dev/null`);
        my ($ls, $ctx) = command_output_pipe(qw/ls-tree -r -z/, $cmt);
        local $/ = "\0";
-       my $pfx = defined($switch_path) ? $switch_path : $git_svn->{path};
+       my $pfx = defined($switch_path) ? $switch_path : $git_svn->path;
        $pfx .= '/' if length($pfx);
        while (<$ls>) {
                chomp;
diff --git a/perl/Git/SVN/GlobSpec.pm b/perl/Git/SVN/GlobSpec.pm
new file mode 100644 (file)
index 0000000..c95f5d7
--- /dev/null
@@ -0,0 +1,61 @@
+package Git::SVN::GlobSpec;
+use strict;
+use warnings;
+
+sub new {
+       my ($class, $glob, $pattern_ok) = @_;
+       my $re = $glob;
+       $re =~ s!/+$!!g; # no need for trailing slashes
+       my (@left, @right, @patterns);
+       my $state = "left";
+       my $die_msg = "Only one set of wildcard directories " .
+                               "(e.g. '*' or '*/*/*') is supported: '$glob'\n";
+       for my $part (split(m|/|, $glob)) {
+               if ($part =~ /\*/ && $part ne "*") {
+                       die "Invalid pattern in '$glob': $part\n";
+               } elsif ($pattern_ok && $part =~ /[{}]/ &&
+                        $part !~ /^\{[^{}]+\}/) {
+                       die "Invalid pattern in '$glob': $part\n";
+               }
+               if ($part eq "*") {
+                       die $die_msg if $state eq "right";
+                       $state = "pattern";
+                       push(@patterns, "[^/]*");
+               } elsif ($pattern_ok && $part =~ /^\{(.*)\}$/) {
+                       die $die_msg if $state eq "right";
+                       $state = "pattern";
+                       my $p = quotemeta($1);
+                       $p =~ s/\\,/|/g;
+                       push(@patterns, "(?:$p)");
+               } else {
+                       if ($state eq "left") {
+                               push(@left, $part);
+                       } else {
+                               push(@right, $part);
+                               $state = "right";
+                       }
+               }
+       }
+       my $depth = @patterns;
+       if ($depth == 0) {
+               die "One '*' is needed in glob: '$glob'\n";
+       }
+       my $left = join('/', @left);
+       my $right = join('/', @right);
+       $re = join('/', @patterns);
+       $re = join('\/',
+                  grep(length, quotemeta($left),
+                                "($re)(?=/|\$)",
+                                quotemeta($right)));
+       my $left_re = qr/^\/\Q$left\E(\/|$)/;
+       bless { left => $left, right => $right, left_regex => $left_re,
+               regex => qr/$re/, glob => $glob, depth => $depth }, $class;
+}
+
+sub full_path {
+       my ($self, $path) = @_;
+       return (length $self->{left} ? "$self->{left}/" : '') .
+              $path . (length $self->{right} ? "/$self->{right}" : '');
+}
+
+1;
diff --git a/perl/Git/SVN/Log.pm b/perl/Git/SVN/Log.pm
new file mode 100644 (file)
index 0000000..3cc1c6f
--- /dev/null
@@ -0,0 +1,395 @@
+package Git::SVN::Log;
+use strict;
+use warnings;
+use Git::SVN::Utils qw(fatal);
+use Git qw(command command_oneline command_output_pipe command_close_pipe);
+use POSIX qw/strftime/;
+use constant commit_log_separator => ('-' x 72) . "\n";
+use vars qw/$TZ $limit $color $pager $non_recursive $verbose $oneline
+            %rusers $show_commit $incremental/;
+
+# Option set in git-svn
+our $_git_format;
+
+sub cmt_showable {
+       my ($c) = @_;
+       return 1 if defined $c->{r};
+
+       # big commit message got truncated by the 16k pretty buffer in rev-list
+       if ($c->{l} && $c->{l}->[-1] eq "...\n" &&
+                               $c->{a_raw} =~ /\@([a-f\d\-]+)>$/) {
+               @{$c->{l}} = ();
+               my @log = command(qw/cat-file commit/, $c->{c});
+
+               # shift off the headers
+               shift @log while ($log[0] ne '');
+               shift @log;
+
+               # TODO: make $c->{l} not have a trailing newline in the future
+               @{$c->{l}} = map { "$_\n" } grep !/^git-svn-id: /, @log;
+
+               (undef, $c->{r}, undef) = ::extract_metadata(
+                               (grep(/^git-svn-id: /, @log))[-1]);
+       }
+       return defined $c->{r};
+}
+
+sub log_use_color {
+       return $color || Git->repository->get_colorbool('color.diff');
+}
+
+sub git_svn_log_cmd {
+       my ($r_min, $r_max, @args) = @_;
+       my $head = 'HEAD';
+       my (@files, @log_opts);
+       foreach my $x (@args) {
+               if ($x eq '--' || @files) {
+                       push @files, $x;
+               } else {
+                       if (::verify_ref("$x^0")) {
+                               $head = $x;
+                       } else {
+                               push @log_opts, $x;
+                       }
+               }
+       }
+
+       my ($url, $rev, $uuid, $gs) = ::working_head_info($head);
+
+       require Git::SVN;
+       $gs ||= Git::SVN->_new;
+       my @cmd = (qw/log --abbrev-commit --pretty=raw --default/,
+                  $gs->refname);
+       push @cmd, '-r' unless $non_recursive;
+       push @cmd, qw/--raw --name-status/ if $verbose;
+       push @cmd, '--color' if log_use_color();
+       push @cmd, @log_opts;
+       if (defined $r_max && $r_max == $r_min) {
+               push @cmd, '--max-count=1';
+               if (my $c = $gs->rev_map_get($r_max)) {
+                       push @cmd, $c;
+               }
+       } elsif (defined $r_max) {
+               if ($r_max < $r_min) {
+                       ($r_min, $r_max) = ($r_max, $r_min);
+               }
+               my (undef, $c_max) = $gs->find_rev_before($r_max, 1, $r_min);
+               my (undef, $c_min) = $gs->find_rev_after($r_min, 1, $r_max);
+               # If there are no commits in the range, both $c_max and $c_min
+               # will be undefined.  If there is at least 1 commit in the
+               # range, both will be defined.
+               return () if !defined $c_min || !defined $c_max;
+               if ($c_min eq $c_max) {
+                       push @cmd, '--max-count=1', $c_min;
+               } else {
+                       push @cmd, '--boundary', "$c_min..$c_max";
+               }
+       }
+       return (@cmd, @files);
+}
+
+# adapted from pager.c
+sub config_pager {
+       if (! -t *STDOUT) {
+               $ENV{GIT_PAGER_IN_USE} = 'false';
+               $pager = undef;
+               return;
+       }
+       chomp($pager = command_oneline(qw(var GIT_PAGER)));
+       if ($pager eq 'cat') {
+               $pager = undef;
+       }
+       $ENV{GIT_PAGER_IN_USE} = defined($pager);
+}
+
+sub run_pager {
+       return unless defined $pager;
+       pipe my ($rfd, $wfd) or return;
+       defined(my $pid = fork) or fatal "Can't fork: $!";
+       if (!$pid) {
+               open STDOUT, '>&', $wfd or
+                                    fatal "Can't redirect to stdout: $!";
+               return;
+       }
+       open STDIN, '<&', $rfd or fatal "Can't redirect stdin: $!";
+       $ENV{LESS} ||= 'FRSX';
+       exec $pager or fatal "Can't run pager: $! ($pager)";
+}
+
+sub format_svn_date {
+       my $t = shift || time;
+       require Git::SVN;
+       my $gmoff = Git::SVN::get_tz($t);
+       return strftime("%Y-%m-%d %H:%M:%S $gmoff (%a, %d %b %Y)", localtime($t));
+}
+
+sub parse_git_date {
+       my ($t, $tz) = @_;
+       # Date::Parse isn't in the standard Perl distro :(
+       if ($tz =~ s/^\+//) {
+               $t += tz_to_s_offset($tz);
+       } elsif ($tz =~ s/^\-//) {
+               $t -= tz_to_s_offset($tz);
+       }
+       return $t;
+}
+
+sub set_local_timezone {
+       if (defined $TZ) {
+               $ENV{TZ} = $TZ;
+       } else {
+               delete $ENV{TZ};
+       }
+}
+
+sub tz_to_s_offset {
+       my ($tz) = @_;
+       $tz =~ s/(\d\d)$//;
+       return ($1 * 60) + ($tz * 3600);
+}
+
+sub get_author_info {
+       my ($dest, $author, $t, $tz) = @_;
+       $author =~ s/(?:^\s*|\s*$)//g;
+       $dest->{a_raw} = $author;
+       my $au;
+       if ($::_authors) {
+               $au = $rusers{$author} || undef;
+       }
+       if (!$au) {
+               ($au) = ($author =~ /<([^>]+)\@[^>]+>$/);
+       }
+       $dest->{t} = $t;
+       $dest->{tz} = $tz;
+       $dest->{a} = $au;
+       $dest->{t_utc} = parse_git_date($t, $tz);
+}
+
+sub process_commit {
+       my ($c, $r_min, $r_max, $defer) = @_;
+       if (defined $r_min && defined $r_max) {
+               if ($r_min == $c->{r} && $r_min == $r_max) {
+                       show_commit($c);
+                       return 0;
+               }
+               return 1 if $r_min == $r_max;
+               if ($r_min < $r_max) {
+                       # we need to reverse the print order
+                       return 0 if (defined $limit && --$limit < 0);
+                       push @$defer, $c;
+                       return 1;
+               }
+               if ($r_min != $r_max) {
+                       return 1 if ($r_min < $c->{r});
+                       return 1 if ($r_max > $c->{r});
+               }
+       }
+       return 0 if (defined $limit && --$limit < 0);
+       show_commit($c);
+       return 1;
+}
+
+my $l_fmt;
+sub show_commit {
+       my $c = shift;
+       if ($oneline) {
+               my $x = "\n";
+               if (my $l = $c->{l}) {
+                       while ($l->[0] =~ /^\s*$/) { shift @$l }
+                       $x = $l->[0];
+               }
+               $l_fmt ||= 'A' . length($c->{r});
+               print 'r',pack($l_fmt, $c->{r}),' | ';
+               print "$c->{c} | " if $show_commit;
+               print $x;
+       } else {
+               show_commit_normal($c);
+       }
+}
+
+sub show_commit_changed_paths {
+       my ($c) = @_;
+       return unless $c->{changed};
+       print "Changed paths:\n", @{$c->{changed}};
+}
+
+sub show_commit_normal {
+       my ($c) = @_;
+       print commit_log_separator, "r$c->{r} | ";
+       print "$c->{c} | " if $show_commit;
+       print "$c->{a} | ", format_svn_date($c->{t_utc}), ' | ';
+       my $nr_line = 0;
+
+       if (my $l = $c->{l}) {
+               while ($l->[$#$l] eq "\n" && $#$l > 0
+                                         && $l->[($#$l - 1)] eq "\n") {
+                       pop @$l;
+               }
+               $nr_line = scalar @$l;
+               if (!$nr_line) {
+                       print "1 line\n\n\n";
+               } else {
+                       if ($nr_line == 1) {
+                               $nr_line = '1 line';
+                       } else {
+                               $nr_line .= ' lines';
+                       }
+                       print $nr_line, "\n";
+                       show_commit_changed_paths($c);
+                       print "\n";
+                       print $_ foreach @$l;
+               }
+       } else {
+               print "1 line\n";
+               show_commit_changed_paths($c);
+               print "\n";
+
+       }
+       foreach my $x (qw/raw stat diff/) {
+               if ($c->{$x}) {
+                       print "\n";
+                       print $_ foreach @{$c->{$x}}
+               }
+       }
+}
+
+sub cmd_show_log {
+       my (@args) = @_;
+       my ($r_min, $r_max);
+       my $r_last = -1; # prevent dupes
+       set_local_timezone();
+       if (defined $::_revision) {
+               if ($::_revision =~ /^(\d+):(\d+)$/) {
+                       ($r_min, $r_max) = ($1, $2);
+               } elsif ($::_revision =~ /^\d+$/) {
+                       $r_min = $r_max = $::_revision;
+               } else {
+                       fatal "-r$::_revision is not supported, use ",
+                               "standard 'git log' arguments instead";
+               }
+       }
+
+       config_pager();
+       @args = git_svn_log_cmd($r_min, $r_max, @args);
+       if (!@args) {
+               print commit_log_separator unless $incremental || $oneline;
+               return;
+       }
+       my $log = command_output_pipe(@args);
+       run_pager();
+       my (@k, $c, $d, $stat);
+       my $esc_color = qr/(?:\033\[(?:(?:\d+;)*\d*)?m)*/;
+       while (<$log>) {
+               if (/^${esc_color}commit (?:- )?($::sha1_short)/o) {
+                       my $cmt = $1;
+                       if ($c && cmt_showable($c) && $c->{r} != $r_last) {
+                               $r_last = $c->{r};
+                               process_commit($c, $r_min, $r_max, \@k) or
+                                                               goto out;
+                       }
+                       $d = undef;
+                       $c = { c => $cmt };
+               } elsif (/^${esc_color}author (.+) (\d+) ([\-\+]?\d+)$/o) {
+                       get_author_info($c, $1, $2, $3);
+               } elsif (/^${esc_color}(?:tree|parent|committer) /o) {
+                       # ignore
+               } elsif (/^${esc_color}:\d{6} \d{6} $::sha1_short/o) {
+                       push @{$c->{raw}}, $_;
+               } elsif (/^${esc_color}[ACRMDT]\t/) {
+                       # we could add $SVN->{svn_path} here, but that requires
+                       # remote access at the moment (repo_path_split)...
+                       s#^(${esc_color})([ACRMDT])\t#$1   $2 #o;
+                       push @{$c->{changed}}, $_;
+               } elsif (/^${esc_color}diff /o) {
+                       $d = 1;
+                       push @{$c->{diff}}, $_;
+               } elsif ($d) {
+                       push @{$c->{diff}}, $_;
+               } elsif (/^\ .+\ \|\s*\d+\ $esc_color[\+\-]*
+                         $esc_color*[\+\-]*$esc_color$/x) {
+                       $stat = 1;
+                       push @{$c->{stat}}, $_;
+               } elsif ($stat && /^ \d+ files changed, \d+ insertions/) {
+                       push @{$c->{stat}}, $_;
+                       $stat = undef;
+               } elsif (/^${esc_color}    (git-svn-id:.+)$/o) {
+                       ($c->{url}, $c->{r}, undef) = ::extract_metadata($1);
+               } elsif (s/^${esc_color}    //o) {
+                       push @{$c->{l}}, $_;
+               }
+       }
+       if ($c && defined $c->{r} && $c->{r} != $r_last) {
+               $r_last = $c->{r};
+               process_commit($c, $r_min, $r_max, \@k);
+       }
+       if (@k) {
+               ($r_min, $r_max) = ($r_max, $r_min);
+               process_commit($_, $r_min, $r_max) foreach reverse @k;
+       }
+out:
+       close $log;
+       print commit_log_separator unless $incremental || $oneline;
+}
+
+sub cmd_blame {
+       my $path = pop;
+
+       config_pager();
+       run_pager();
+
+       my ($fh, $ctx, $rev);
+
+       if ($_git_format) {
+               ($fh, $ctx) = command_output_pipe('blame', @_, $path);
+               while (my $line = <$fh>) {
+                       if ($line =~ /^\^?([[:xdigit:]]+)\s/) {
+                               # Uncommitted edits show up as a rev ID of
+                               # all zeros, which we can't look up with
+                               # cmt_metadata
+                               if ($1 !~ /^0+$/) {
+                                       (undef, $rev, undef) =
+                                               ::cmt_metadata($1);
+                                       $rev = '0' if (!$rev);
+                               } else {
+                                       $rev = '0';
+                               }
+                               $rev = sprintf('%-10s', $rev);
+                               $line =~ s/^\^?[[:xdigit:]]+(\s)/$rev$1/;
+                       }
+                       print $line;
+               }
+       } else {
+               ($fh, $ctx) = command_output_pipe('blame', '-p', @_, 'HEAD',
+                                                 '--', $path);
+               my ($sha1);
+               my %authors;
+               my @buffer;
+               my %dsha; #distinct sha keys
+
+               while (my $line = <$fh>) {
+                       push @buffer, $line;
+                       if ($line =~ /^([[:xdigit:]]{40})\s\d+\s\d+/) {
+                               $dsha{$1} = 1;
+                       }
+               }
+
+               my $s2r = ::cmt_sha2rev_batch([keys %dsha]);
+
+               foreach my $line (@buffer) {
+                       if ($line =~ /^([[:xdigit:]]{40})\s\d+\s\d+/) {
+                               $rev = $s2r->{$1};
+                               $rev = '0' if (!$rev)
+                       }
+                       elsif ($line =~ /^author (.*)/) {
+                               $authors{$rev} = $1;
+                               $authors{$rev} =~ s/\s/_/g;
+                       }
+                       elsif ($line =~ /^\t(.*)$/) {
+                               printf("%6s %10s %s\n", $rev, $authors{$rev}, $1);
+                       }
+               }
+       }
+       command_close_pipe($fh, $ctx);
+}
+
+1;
diff --git a/perl/Git/SVN/Migration.pm b/perl/Git/SVN/Migration.pm
new file mode 100644 (file)
index 0000000..30daf35
--- /dev/null
@@ -0,0 +1,258 @@
+package Git::SVN::Migration;
+# these version numbers do NOT correspond to actual version numbers
+# of git nor git-svn.  They are just relative.
+#
+# v0 layout: .git/$id/info/url, refs/heads/$id-HEAD
+#
+# v1 layout: .git/$id/info/url, refs/remotes/$id
+#
+# v2 layout: .git/svn/$id/info/url, refs/remotes/$id
+#
+# v3 layout: .git/svn/$id, refs/remotes/$id
+#            - info/url may remain for backwards compatibility
+#            - this is what we migrate up to this layout automatically,
+#            - this will be used by git svn init on single branches
+# v3.1 layout (auto migrated):
+#            - .rev_db => .rev_db.$UUID, .rev_db will remain as a symlink
+#              for backwards compatibility
+#
+# v4 layout: .git/svn/$repo_id/$id, refs/remotes/$repo_id/$id
+#            - this is only created for newly multi-init-ed
+#              repositories.  Similar in spirit to the
+#              --use-separate-remotes option in git-clone (now default)
+#            - we do not automatically migrate to this (following
+#              the example set by core git)
+#
+# v5 layout: .rev_db.$UUID => .rev_map.$UUID
+#            - newer, more-efficient format that uses 24-bytes per record
+#              with no filler space.
+#            - use xxd -c24 < .rev_map.$UUID to view and debug
+#            - This is a one-way migration, repositories updated to the
+#              new format will not be able to use old git-svn without
+#              rebuilding the .rev_db.  Rebuilding the rev_db is not
+#              possible if noMetadata or useSvmProps are set; but should
+#              be no problem for users that use the (sensible) defaults.
+use strict;
+use warnings;
+use Carp qw/croak/;
+use File::Path qw/mkpath/;
+use File::Basename qw/dirname basename/;
+
+our $_minimize;
+use Git qw(
+       command
+       command_noisy
+       command_output_pipe
+       command_close_pipe
+);
+
+sub migrate_from_v0 {
+       my $git_dir = $ENV{GIT_DIR};
+       return undef unless -d $git_dir;
+       my ($fh, $ctx) = command_output_pipe(qw/rev-parse --symbolic --all/);
+       my $migrated = 0;
+       while (<$fh>) {
+               chomp;
+               my ($id, $orig_ref) = ($_, $_);
+               next unless $id =~ s#^refs/heads/(.+)-HEAD$#$1#;
+               next unless -f "$git_dir/$id/info/url";
+               my $new_ref = "refs/remotes/$id";
+               if (::verify_ref("$new_ref^0")) {
+                       print STDERR "W: $orig_ref is probably an old ",
+                                    "branch used by an ancient version of ",
+                                    "git-svn.\n",
+                                    "However, $new_ref also exists.\n",
+                                    "We will not be able ",
+                                    "to use this branch until this ",
+                                    "ambiguity is resolved.\n";
+                       next;
+               }
+               print STDERR "Migrating from v0 layout...\n" if !$migrated;
+               print STDERR "Renaming ref: $orig_ref => $new_ref\n";
+               command_noisy('update-ref', $new_ref, $orig_ref);
+               command_noisy('update-ref', '-d', $orig_ref, $orig_ref);
+               $migrated++;
+       }
+       command_close_pipe($fh, $ctx);
+       print STDERR "Done migrating from v0 layout...\n" if $migrated;
+       $migrated;
+}
+
+sub migrate_from_v1 {
+       my $git_dir = $ENV{GIT_DIR};
+       my $migrated = 0;
+       return $migrated unless -d $git_dir;
+       my $svn_dir = "$git_dir/svn";
+
+       # just in case somebody used 'svn' as their $id at some point...
+       return $migrated if -d $svn_dir && ! -f "$svn_dir/info/url";
+
+       print STDERR "Migrating from a git-svn v1 layout...\n";
+       mkpath([$svn_dir]);
+       print STDERR "Data from a previous version of git-svn exists, but\n\t",
+                    "$svn_dir\n\t(required for this version ",
+                    "($::VERSION) of git-svn) does not exist.\n";
+       my ($fh, $ctx) = command_output_pipe(qw/rev-parse --symbolic --all/);
+       while (<$fh>) {
+               my $x = $_;
+               next unless $x =~ s#^refs/remotes/##;
+               chomp $x;
+               next unless -f "$git_dir/$x/info/url";
+               my $u = eval { ::file_to_s("$git_dir/$x/info/url") };
+               next unless $u;
+               my $dn = dirname("$git_dir/svn/$x");
+               mkpath([$dn]) unless -d $dn;
+               if ($x eq 'svn') { # they used 'svn' as GIT_SVN_ID:
+                       mkpath(["$git_dir/svn/svn"]);
+                       print STDERR " - $git_dir/$x/info => ",
+                                       "$git_dir/svn/$x/info\n";
+                       rename "$git_dir/$x/info", "$git_dir/svn/$x/info" or
+                              croak "$!: $x";
+                       # don't worry too much about these, they probably
+                       # don't exist with repos this old (save for index,
+                       # and we can easily regenerate that)
+                       foreach my $f (qw/unhandled.log index .rev_db/) {
+                               rename "$git_dir/$x/$f", "$git_dir/svn/$x/$f";
+                       }
+               } else {
+                       print STDERR " - $git_dir/$x => $git_dir/svn/$x\n";
+                       rename "$git_dir/$x", "$git_dir/svn/$x" or
+                              croak "$!: $x";
+               }
+               $migrated++;
+       }
+       command_close_pipe($fh, $ctx);
+       print STDERR "Done migrating from a git-svn v1 layout\n";
+       $migrated;
+}
+
+sub read_old_urls {
+       my ($l_map, $pfx, $path) = @_;
+       my @dir;
+       foreach (<$path/*>) {
+               if (-r "$_/info/url") {
+                       $pfx .= '/' if $pfx && $pfx !~ m!/$!;
+                       my $ref_id = $pfx . basename $_;
+                       my $url = ::file_to_s("$_/info/url");
+                       $l_map->{$ref_id} = $url;
+               } elsif (-d $_) {
+                       push @dir, $_;
+               }
+       }
+       foreach (@dir) {
+               my $x = $_;
+               $x =~ s!^\Q$ENV{GIT_DIR}\E/svn/!!o;
+               read_old_urls($l_map, $x, $_);
+       }
+}
+
+sub migrate_from_v2 {
+       my @cfg = command(qw/config -l/);
+       return if grep /^svn-remote\..+\.url=/, @cfg;
+       my %l_map;
+       read_old_urls(\%l_map, '', "$ENV{GIT_DIR}/svn");
+       my $migrated = 0;
+
+       require Git::SVN;
+       foreach my $ref_id (sort keys %l_map) {
+               eval { Git::SVN->init($l_map{$ref_id}, '', undef, $ref_id) };
+               if ($@) {
+                       Git::SVN->init($l_map{$ref_id}, '', $ref_id, $ref_id);
+               }
+               $migrated++;
+       }
+       $migrated;
+}
+
+sub minimize_connections {
+       require Git::SVN;
+       require Git::SVN::Ra;
+
+       my $r = Git::SVN::read_all_remotes();
+       my $new_urls = {};
+       my $root_repos = {};
+       foreach my $repo_id (keys %$r) {
+               my $url = $r->{$repo_id}->{url} or next;
+               my $fetch = $r->{$repo_id}->{fetch} or next;
+               my $ra = Git::SVN::Ra->new($url);
+
+               # skip existing cases where we already connect to the root
+               if (($ra->url eq $ra->{repos_root}) ||
+                   ($ra->{repos_root} eq $repo_id)) {
+                       $root_repos->{$ra->url} = $repo_id;
+                       next;
+               }
+
+               my $root_ra = Git::SVN::Ra->new($ra->{repos_root});
+               my $root_path = $ra->url;
+               $root_path =~ s#^\Q$ra->{repos_root}\E(/|$)##;
+               foreach my $path (keys %$fetch) {
+                       my $ref_id = $fetch->{$path};
+                       my $gs = Git::SVN->new($ref_id, $repo_id, $path);
+
+                       # make sure we can read when connecting to
+                       # a higher level of a repository
+                       my ($last_rev, undef) = $gs->last_rev_commit;
+                       if (!defined $last_rev) {
+                               $last_rev = eval {
+                                       $root_ra->get_latest_revnum;
+                               };
+                               next if $@;
+                       }
+                       my $new = $root_path;
+                       $new .= length $path ? "/$path" : '';
+                       eval {
+                               $root_ra->get_log([$new], $last_rev, $last_rev,
+                                                 0, 0, 1, sub { });
+                       };
+                       next if $@;
+                       $new_urls->{$ra->{repos_root}}->{$new} =
+                               { ref_id => $ref_id,
+                                 old_repo_id => $repo_id,
+                                 old_path => $path };
+               }
+       }
+
+       my @emptied;
+       foreach my $url (keys %$new_urls) {
+               # see if we can re-use an existing [svn-remote "repo_id"]
+               # instead of creating a(n ugly) new section:
+               my $repo_id = $root_repos->{$url} || $url;
+
+               my $fetch = $new_urls->{$url};
+               foreach my $path (keys %$fetch) {
+                       my $x = $fetch->{$path};
+                       Git::SVN->init($url, $path, $repo_id, $x->{ref_id});
+                       my $pfx = "svn-remote.$x->{old_repo_id}";
+
+                       my $old_fetch = quotemeta("$x->{old_path}:".
+                                                 "$x->{ref_id}");
+                       command_noisy(qw/config --unset/,
+                                     "$pfx.fetch", '^'. $old_fetch . '$');
+                       delete $r->{$x->{old_repo_id}}->
+                              {fetch}->{$x->{old_path}};
+                       if (!keys %{$r->{$x->{old_repo_id}}->{fetch}}) {
+                               command_noisy(qw/config --unset/,
+                                             "$pfx.url");
+                               push @emptied, $x->{old_repo_id}
+                       }
+               }
+       }
+       if (@emptied) {
+               my $file = $ENV{GIT_CONFIG} || "$ENV{GIT_DIR}/config";
+               print STDERR <<EOF;
+The following [svn-remote] sections in your config file ($file) are empty
+and can be safely removed:
+EOF
+               print STDERR "[svn-remote \"$_\"]\n" foreach @emptied;
+       }
+}
+
+sub migration_check {
+       migrate_from_v0();
+       migrate_from_v1();
+       migrate_from_v2();
+       minimize_connections() if $_minimize;
+}
+
+1;
index 23ff43e86b4f08fb38b8d9ca90a6c77319ae8f63..049c97bfafac143e552f2e8ddb988292a6328df2 100644 (file)
@@ -3,6 +3,12 @@ use vars qw/@ISA $config_dir $_ignore_refs_regex $_log_window_size/;
 use strict;
 use warnings;
 use SVN::Client;
+use Git::SVN::Utils qw(
+       canonicalize_url
+       canonicalize_path
+       add_path_to_url
+);
+
 use SVN::Ra;
 BEGIN {
        @ISA = qw(SVN::Ra);
@@ -62,29 +68,11 @@ sub _auth_providers () {
        \@rv;
 }
 
-sub escape_uri_only {
-       my ($uri) = @_;
-       my @tmp;
-       foreach (split m{/}, $uri) {
-               s/([^~\w.%+-]|%(?![a-fA-F0-9]{2}))/sprintf("%%%02X",ord($1))/eg;
-               push @tmp, $_;
-       }
-       join('/', @tmp);
-}
-
-sub escape_url {
-       my ($url) = @_;
-       if ($url =~ m#^(https?)://([^/]+)(.*)$#) {
-               my ($scheme, $domain, $uri) = ($1, $2, escape_uri_only($3));
-               $url = "$scheme://$domain$uri";
-       }
-       $url;
-}
 
 sub new {
        my ($class, $url) = @_;
-       $url =~ s!/+$!!;
-       return $RA if ($RA && $RA->{url} eq $url);
+       $url = canonicalize_url($url);
+       return $RA if ($RA && $RA->url eq $url);
 
        ::_req_svn();
 
@@ -115,17 +103,34 @@ sub new {
                        $Git::SVN::Prompt::_no_auth_cache = 1;
                }
        } # no warnings 'once'
-       my $self = SVN::Ra->new(url => escape_url($url), auth => $baton,
+
+       my $self = SVN::Ra->new(url => $url, auth => $baton,
                              config => $config,
                              pool => SVN::Pool->new,
                              auth_provider_callbacks => $callbacks);
-       $self->{url} = $url;
+       $RA = bless $self, $class;
+
+       # Make sure its canonicalized
+       $self->url($url);
        $self->{svn_path} = $url;
        $self->{repos_root} = $self->get_repos_root;
        $self->{svn_path} =~ s#^\Q$self->{repos_root}\E(/|$)##;
        $self->{cache} = { check_path => { r => 0, data => {} },
                           get_dir => { r => 0, data => {} } };
-       $RA = bless $self, $class;
+
+       return $RA;
+}
+
+sub url {
+       my $self = shift;
+
+       if (@_) {
+               my $url = shift;
+               $self->{url} = canonicalize_url($url);
+               return;
+       }
+
+       return $self->{url};
 }
 
 sub check_path {
@@ -195,6 +200,7 @@ sub get_log {
                                qw/copyfrom_path copyfrom_rev action/;
                        if ($s{'copyfrom_path'}) {
                                $s{'copyfrom_path'} =~ s/$prefix_regex//;
+                               $s{'copyfrom_path'} = canonicalize_path($s{'copyfrom_path'});
                        }
                        $_[0]{$p} = \%s;
                }
@@ -246,7 +252,7 @@ sub get_commit_editor {
 sub gs_do_update {
        my ($self, $rev_a, $rev_b, $gs, $editor) = @_;
        my $new = ($rev_a == $rev_b);
-       my $path = $gs->{path};
+       my $path = $gs->path;
 
        if ($new && -e $gs->{index}) {
                unlink $gs->{index} or die
@@ -282,30 +288,33 @@ sub gs_do_update {
 # svn_ra_reparent didn't work before 1.4)
 sub gs_do_switch {
        my ($self, $rev_a, $rev_b, $gs, $url_b, $editor) = @_;
-       my $path = $gs->{path};
+       my $path = $gs->path;
        my $pool = SVN::Pool->new;
 
-       my $full_url = $self->{url};
-       my $old_url = $full_url;
-       $full_url .= '/' . $path if length $path;
+       my $old_url = $self->url;
+       my $full_url = add_path_to_url( $self->url, $path );
        my ($ra, $reparented);
 
        if ($old_url =~ m#^svn(\+ssh)?://# ||
            ($full_url =~ m#^https?://# &&
-            escape_url($full_url) ne $full_url)) {
+            canonicalize_url($full_url) ne $full_url)) {
                $_[0] = undef;
                $self = undef;
                $RA = undef;
                $ra = Git::SVN::Ra->new($full_url);
                $ra_invalid = 1;
        } elsif ($old_url ne $full_url) {
-               SVN::_Ra::svn_ra_reparent($self->{session}, $full_url, $pool);
-               $self->{url} = $full_url;
+               SVN::_Ra::svn_ra_reparent(
+                       $self->{session},
+                       canonicalize_url($full_url),
+                       $pool
+               );
+               $self->url($full_url);
                $reparented = 1;
        }
 
        $ra ||= $self;
-       $url_b = escape_url($url_b);
+       $url_b = canonicalize_url($url_b);
        my $reporter = $ra->do_switch($rev_b, '', 1, $url_b, $editor, $pool);
        my @lock = (::compare_svn_version('1.2.0') >= 0) ? (undef) : ();
        $reporter->set_path('', $rev_a, 0, @lock, $pool);
@@ -313,7 +322,7 @@ sub gs_do_switch {
 
        if ($reparented) {
                SVN::_Ra::svn_ra_reparent($self->{session}, $old_url, $pool);
-               $self->{url} = $old_url;
+               $self->url($old_url);
        }
 
        $pool->clear;
@@ -326,7 +335,7 @@ sub longest_common_path {
        my $common_max = scalar @$gsv;
 
        foreach my $gs (@$gsv) {
-               my @tmp = split m#/#, $gs->{path};
+               my @tmp = split m#/#, $gs->path;
                my $p = '';
                foreach (@tmp) {
                        $p .= length($p) ? "/$_" : $_;
@@ -362,7 +371,7 @@ sub gs_fetch_loop_common {
        my $inc = $_log_window_size;
        my ($min, $max) = ($base, $head < $base + $inc ? $head : $base + $inc);
        my $longest_path = longest_common_path($gsv, $globs);
-       my $ra_url = $self->{url};
+       my $ra_url = $self->url;
        my $find_trailing_edge;
        while (1) {
                my %revs;
@@ -407,7 +416,7 @@ sub gs_fetch_loop_common {
                }
                $SVN::Error::handler = $err_handler;
 
-               my %exists = map { $_->{path} => $_ } @$gsv;
+               my %exists = map { $_->path => $_ } @$gsv;
                foreach my $r (sort {$a <=> $b} keys %revs) {
                        my ($paths, $logged) = @{$revs{$r}};
 
@@ -508,7 +517,7 @@ sub match_globs {
                                 ($self->check_path($p, $r) !=
                                  $SVN::Node::dir));
                        next unless $p =~ /$g->{path}->{regex}/;
-                       $exists->{$p} = Git::SVN->init($self->{url}, $p, undef,
+                       $exists->{$p} = Git::SVN->init($self->url, $p, undef,
                                         $g->{ref}->full_path($de), 1);
                }
        }
@@ -532,7 +541,7 @@ sub match_globs {
                        next if ($self->check_path($pathname, $r) !=
                                 $SVN::Node::dir);
                        $exists->{$pathname} = Git::SVN->init(
-                                             $self->{url}, $pathname, undef,
+                                             $self->url, $pathname, undef,
                                              $g->{ref}->full_path($p), 1);
                }
                my $c = '';
@@ -548,19 +557,20 @@ sub match_globs {
 
 sub minimize_url {
        my ($self) = @_;
-       return $self->{url} if ($self->{url} eq $self->{repos_root});
+       return $self->url if ($self->url eq $self->{repos_root});
        my $url = $self->{repos_root};
        my @components = split(m!/!, $self->{svn_path});
        my $c = '';
        do {
-               $url .= "/$c" if length $c;
+               $url = add_path_to_url($url, $c);
                eval {
                        my $ra = (ref $self)->new($url);
                        my $latest = $ra->get_latest_revnum;
                        $ra->get_log("", $latest, 0, 1, 0, 1, sub {});
                };
        } while ($@ && ($c = shift @components));
-       $url;
+
+       return canonicalize_url($url);
 }
 
 sub can_do_switch {
@@ -568,7 +578,7 @@ sub can_do_switch {
        unless (defined $can_do_switch) {
                my $pool = SVN::Pool->new;
                my $rep = eval {
-                       $self->do_switch(1, '', 0, $self->{url},
+                       $self->do_switch(1, '', 0, $self->url,
                                         SVN::Delta::Editor->new, $pool);
                };
                if ($@) {
diff --git a/perl/Git/SVN/Utils.pm b/perl/Git/SVN/Utils.pm
new file mode 100644 (file)
index 0000000..8b8cf37
--- /dev/null
@@ -0,0 +1,232 @@
+package Git::SVN::Utils;
+
+use strict;
+use warnings;
+
+use SVN::Core;
+
+use base qw(Exporter);
+
+our @EXPORT_OK = qw(
+       fatal
+       can_compress
+       canonicalize_path
+       canonicalize_url
+       join_paths
+       add_path_to_url
+);
+
+
+=head1 NAME
+
+Git::SVN::Utils - utility functions used across Git::SVN
+
+=head1 SYNOPSIS
+
+    use Git::SVN::Utils qw(functions to import);
+
+=head1 DESCRIPTION
+
+This module contains functions which are useful across many different
+parts of Git::SVN.  Mostly it's a place to put utility functions
+rather than duplicate the code or have classes grabbing at other
+classes.
+
+=head1 FUNCTIONS
+
+All functions can be imported only on request.
+
+=head3 fatal
+
+    fatal(@message);
+
+Display a message and exit with a fatal error code.
+
+=cut
+
+# Note: not certain why this is in use instead of die.  Probably because
+# the exit code of die is 255?  Doesn't appear to be used consistently.
+sub fatal (@) { print STDERR "@_\n"; exit 1 }
+
+
+=head3 can_compress
+
+    my $can_compress = can_compress;
+
+Returns true if Compress::Zlib is available, false otherwise.
+
+=cut
+
+my $can_compress;
+sub can_compress {
+       return $can_compress if defined $can_compress;
+
+       return $can_compress = eval { require Compress::Zlib; };
+}
+
+
+=head3 canonicalize_path
+
+    my $canoncalized_path = canonicalize_path($path);
+
+Converts $path into a canonical form which is safe to pass to the SVN
+API as a file path.
+
+=cut
+
+# Turn foo/../bar into bar
+sub _collapse_dotdot {
+       my $path = shift;
+
+       1 while $path =~ s{/[^/]+/+\.\.}{};
+       1 while $path =~ s{[^/]+/+\.\./}{};
+       1 while $path =~ s{[^/]+/+\.\.}{};
+
+       return $path;
+}
+
+
+sub canonicalize_path {
+       my $path = shift;
+       my $rv;
+
+       # The 1.7 way to do it
+       if ( defined &SVN::_Core::svn_dirent_canonicalize ) {
+               $path = _collapse_dotdot($path);
+               $rv = SVN::_Core::svn_dirent_canonicalize($path);
+       }
+       # The 1.6 way to do it
+       # This can return undef on subversion-perl-1.4.2-2.el5 (CentOS 5.2)
+       elsif ( defined &SVN::_Core::svn_path_canonicalize ) {
+               $path = _collapse_dotdot($path);
+               $rv = SVN::_Core::svn_path_canonicalize($path);
+       }
+
+       return $rv if defined $rv;
+
+       # No SVN API canonicalization is available, or the SVN API
+       # didn't return a successful result, do it ourselves
+       return _canonicalize_path_ourselves($path);
+}
+
+
+sub _canonicalize_path_ourselves {
+       my ($path) = @_;
+       my $dot_slash_added = 0;
+       if (substr($path, 0, 1) ne "/") {
+               $path = "./" . $path;
+               $dot_slash_added = 1;
+       }
+       $path =~ s#/+#/#g;
+       $path =~ s#/\.(?:/|$)#/#g;
+       $path = _collapse_dotdot($path);
+       $path =~ s#/$##g;
+       $path =~ s#^\./## if $dot_slash_added;
+       $path =~ s#^\.$##;
+       return $path;
+}
+
+
+=head3 canonicalize_url
+
+    my $canonicalized_url = canonicalize_url($url);
+
+Converts $url into a canonical form which is safe to pass to the SVN
+API as a URL.
+
+=cut
+
+sub canonicalize_url {
+       my $url = shift;
+
+       # The 1.7 way to do it
+       if ( defined &SVN::_Core::svn_uri_canonicalize ) {
+               return SVN::_Core::svn_uri_canonicalize($url);
+       }
+       # There wasn't a 1.6 way to do it, so we do it ourself.
+       else {
+               return _canonicalize_url_ourselves($url);
+       }
+}
+
+
+sub _canonicalize_url_path {
+       my ($uri_path) = @_;
+
+       my @parts;
+       foreach my $part (split m{/+}, $uri_path) {
+               $part =~ s/([^~\w.%+-]|%(?![a-fA-F0-9]{2}))/sprintf("%%%02X",ord($1))/eg;
+               push @parts, $part;
+       }
+
+       return join('/', @parts);
+}
+
+sub _canonicalize_url_ourselves {
+       my ($url) = @_;
+       if ($url =~ m#^([^:]+)://([^/]*)(.*)$#) {
+               my ($scheme, $domain, $uri) = ($1, $2, _canonicalize_url_path(canonicalize_path($3)));
+               $url = "$scheme://$domain$uri";
+       }
+       $url;
+}
+
+
+=head3 join_paths
+
+    my $new_path = join_paths(@paths);
+
+Appends @paths together into a single path.  Any empty paths are ignored.
+
+=cut
+
+sub join_paths {
+       my @paths = @_;
+
+       @paths = grep { defined $_ && length $_ } @paths;
+
+       return '' unless @paths;
+       return $paths[0] if @paths == 1;
+
+       my $new_path = shift @paths;
+       $new_path =~ s{/+$}{};
+
+       my $last_path = pop @paths;
+       $last_path =~ s{^/+}{};
+
+       for my $path (@paths) {
+               $path =~ s{^/+}{};
+               $path =~ s{/+$}{};
+               $new_path .= "/$path";
+       }
+
+       return $new_path .= "/$last_path";
+}
+
+
+=head3 add_path_to_url
+
+    my $new_url = add_path_to_url($url, $path);
+
+Appends $path onto the $url.  If $path is empty, $url is returned unchanged.
+
+=cut
+
+sub add_path_to_url {
+       my($url, $path) = @_;
+
+       return $url if !defined $path or !length $path;
+
+       # Strip trailing and leading slashes so we don't
+       # wind up with http://x.com///path
+       $url  =~ s{/+$}{};
+       $path =~ s{^/+}{};
+
+       # If a path has a % in it, URI escape it so it's not
+       # mistaken for a URI escape later.
+       $path =~ s{%}{%25}g;
+
+       return join '/', $url, $path;
+}
+
+1;
index fe7a48646412b872d8db09bdef70de751399cad6..15d96fcc7a5a81ae0304bc51a603fe54bcbb95c6 100644 (file)
@@ -20,36 +20,57 @@ clean:
        $(RM) ppport.h
        $(RM) $(makfile)
        $(RM) $(makfile).old
+       $(RM) PM.stamp
+
+$(makfile): PM.stamp
 
 ifdef NO_PERL_MAKEMAKER
 instdir_SQ = $(subst ','\'',$(prefix)/lib)
 
 modules += Git
 modules += Git/I18N
+modules += Git/IndexInfo
+modules += Git/SVN
 modules += Git/SVN/Memoize/YAML
 modules += Git/SVN/Fetcher
 modules += Git/SVN/Editor
+modules += Git/SVN/GlobSpec
+modules += Git/SVN/Log
+modules += Git/SVN/Migration
 modules += Git/SVN/Prompt
 modules += Git/SVN/Ra
+modules += Git/SVN/Utils
 
 $(makfile): ../GIT-CFLAGS Makefile
        echo all: private-Error.pm Git.pm Git/I18N.pm > $@
-       echo '  mkdir -p blib/lib/Git/SVN/Memoize' >> $@
        set -e; \
        for i in $(modules); \
        do \
+               if test $$i = $${i%/*}; \
+               then \
+                       subdir=; \
+               else \
+                       subdir=/$${i%/*}; \
+               fi; \
                echo '  $(RM) blib/lib/'$$i'.pm' >> $@; \
+               echo '  mkdir -p blib/lib'$$subdir >> $@; \
                echo '  cp '$$i'.pm blib/lib/'$$i'.pm' >> $@; \
        done
        echo '  $(RM) blib/lib/Error.pm' >> $@
        '$(PERL_PATH_SQ)' -MError -e 'exit($$Error::VERSION < 0.15009)' || \
        echo '  cp private-Error.pm blib/lib/Error.pm' >> $@
        echo install: >> $@
-       echo '  mkdir -p "$$(DESTDIR)$(instdir_SQ)/Git/SVN/Memoize"' >> $@
        set -e; \
        for i in $(modules); \
        do \
+               if test $$i = $${i%/*}; \
+               then \
+                       subdir=; \
+               else \
+                       subdir=/$${i%/*}; \
+               fi; \
                echo '  $(RM) "$$(DESTDIR)$(instdir_SQ)/'$$i'.pm"' >> $@; \
+               echo '  mkdir -p "$$(DESTDIR)$(instdir_SQ)'$$subdir'"' >> $@; \
                echo '  cp '$$i'.pm "$$(DESTDIR)$(instdir_SQ)/'$$i'.pm"' >> $@; \
        done
        echo '  $(RM) "$$(DESTDIR)$(instdir_SQ)/Error.pm"' >> $@
index b54b04a619b0aa338cae37ade9350bb52f2edd05..3f29ba98a6fcaa6ad023123b68cd6f6b5b9250dd 100644 (file)
@@ -2,11 +2,16 @@ use strict;
 use warnings;
 use ExtUtils::MakeMaker;
 use Getopt::Long;
+use File::Find;
+
+# Don't forget to update the perl/Makefile, too.
+# Don't forget to test with NO_PERL_MAKEMAKER=YesPlease
 
 # Sanity: die at first unknown option
 Getopt::Long::Configure qw/ pass_through /;
 
-GetOptions("localedir=s" => \my $localedir);
+my $localedir = '';
+GetOptions("localedir=s" => \$localedir);
 
 sub MY::postamble {
        return <<'MAKE_FRAG';
@@ -24,24 +29,22 @@ endif
 MAKE_FRAG
 }
 
-# XXX. When editing this list:
-#
-# * Please update perl/Makefile, too.
-# * Don't forget to test with NO_PERL_MAKEMAKER=YesPlease
-my %pm = (
-       'Git.pm' => '$(INST_LIBDIR)/Git.pm',
-       'Git/I18N.pm' => '$(INST_LIBDIR)/Git/I18N.pm',
-       'Git/SVN/Memoize/YAML.pm' => '$(INST_LIBDIR)/Git/SVN/Memoize/YAML.pm',
-       'Git/SVN/Fetcher.pm' => '$(INST_LIBDIR)/Git/SVN/Fetcher.pm',
-       'Git/SVN/Editor.pm' => '$(INST_LIBDIR)/Git/SVN/Editor.pm',
-       'Git/SVN/Prompt.pm' => '$(INST_LIBDIR)/Git/SVN/Prompt.pm',
-       'Git/SVN/Ra.pm' => '$(INST_LIBDIR)/Git/SVN/Ra.pm',
-);
+# Find all the .pm files in "Git/" and Git.pm
+my %pm;
+find sub {
+       return unless /\.pm$/;
+
+       # sometimes File::Find prepends a ./  Strip it.
+       my $pm_path = $File::Find::name;
+       $pm_path =~ s{^\./}{};
+
+       $pm{$pm_path} = '$(INST_LIBDIR)/'.$pm_path;
+}, "Git", "Git.pm";
+
 
 # We come with our own bundled Error.pm. It's not in the set of default
 # Perl modules so install it if it's not available on the system yet.
-eval { require Error };
-if ($@ || $Error::VERSION < 0.15009) {
+if ( !eval { require Error } || $Error::VERSION < 0.15009) {
        $pm{'private-Error.pm'} = '$(INST_LIBDIR)/Error.pm';
 }
 
index 5a04984ea31744528de30269add2754ed2dcd105..eaba15f124b5d8247d39bd0844967cb5a9101ba8 100644 (file)
@@ -135,13 +135,19 @@ void packet_buf_write(struct strbuf *buf, const char *fmt, ...)
        strbuf_add(buf, buffer, n);
 }
 
-static void safe_read(int fd, void *buffer, unsigned size)
+static int safe_read(int fd, void *buffer, unsigned size, int return_line_fail)
 {
        ssize_t ret = read_in_full(fd, buffer, size);
        if (ret < 0)
                die_errno("read error");
-       else if (ret < size)
+       else if (ret < size) {
+               if (return_line_fail)
+                       return -1;
+
                die("The remote end hung up unexpectedly");
+       }
+
+       return ret;
 }
 
 static int packet_length(const char *linelen)
@@ -169,12 +175,14 @@ static int packet_length(const char *linelen)
        return len;
 }
 
-int packet_read_line(int fd, char *buffer, unsigned size)
+static int packet_read_internal(int fd, char *buffer, unsigned size, int return_line_fail)
 {
-       int len;
+       int len, ret;
        char linelen[4];
 
-       safe_read(fd, linelen, 4);
+       ret = safe_read(fd, linelen, 4, return_line_fail);
+       if (return_line_fail && ret < 0)
+               return ret;
        len = packet_length(linelen);
        if (len < 0)
                die("protocol error: bad line length character: %.4s", linelen);
@@ -185,12 +193,24 @@ int packet_read_line(int fd, char *buffer, unsigned size)
        len -= 4;
        if (len >= size)
                die("protocol error: bad line length %d", len);
-       safe_read(fd, buffer, len);
+       ret = safe_read(fd, buffer, len, return_line_fail);
+       if (return_line_fail && ret < 0)
+               return ret;
        buffer[len] = 0;
        packet_trace(buffer, len, 0);
        return len;
 }
 
+int packet_read(int fd, char *buffer, unsigned size)
+{
+       return packet_read_internal(fd, buffer, size, 1);
+}
+
+int packet_read_line(int fd, char *buffer, unsigned size)
+{
+       return packet_read_internal(fd, buffer, size, 0);
+}
+
 int packet_get_line(struct strbuf *out,
        char **src_buf, size_t *src_len)
 {
index 1e5dcfe87c568eaa7746091b1eb059834f4913bb..8cfeb0c31c8661bf11ce78d3679a21cd030ffb75 100644 (file)
@@ -13,6 +13,7 @@ void packet_buf_flush(struct strbuf *buf);
 void packet_buf_write(struct strbuf *buf, const char *fmt, ...) __attribute__((format (printf, 2, 3)));
 
 int packet_read_line(int fd, char *buffer, unsigned size);
+int packet_read(int fd, char *buffer, unsigned size);
 int packet_get_line(struct strbuf *out, char **src_buf, size_t *src_len);
 ssize_t safe_write(int, const void *, ssize_t);
 
index e9ebc8cce5fea0de2abc0552243f6fe93fae20f1..1b9e9940ebc2f0de541a0576adb83754cb2186a1 100644 (file)
--- a/po/TEAMS
+++ b/po/TEAMS
@@ -33,8 +33,9 @@ Repository:   https://github.com/nafmo/git-l10n-sv/
 Leader:                Peter Krefting <peter@softwolves.pp.se>
 
 Language:      vi (Vietnamese)
-Repository:    https://github.com/vnwildman/git.git
+Repository:    https://github.com/vnwildman/git/
 Leader:                Trần Ngọc Quân <vnwildman AT gmail.com>
+Members:       Nguyễn Thái Ngọc Duy <pclouds AT gmail.com>
 
 Language:      zh_CN (Simplified Chinese)
 Repository:    https://github.com/gotgit/git-po-zh_CN/
index 70d8418f73485ebeb3ea692f67f05f0ad2338d16..0db9a9b2abd708815f6d77520aadc71aa0f4c999 100644 (file)
--- a/po/de.po
+++ b/po/de.po
@@ -5,9 +5,9 @@
 #
 msgid ""
 msgstr ""
-"Project-Id-Version: git 1.7.11\n"
+"Project-Id-Version: git 1.7.12\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2012-06-08 10:20+0800\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"
@@ -48,17 +48,17 @@ 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:696
+#: bundle.c:89 builtin/commit.c:699
 #, c-format
 msgid "could not open '%s'"
 msgstr "Konnte '%s' nicht öffnen"
 
 #: bundle.c:140
 msgid "Repository lacks these prerequisite commits:"
-msgstr "Dem Projektarchiv fehlen folgende vorrausgesetzte Versionen:"
+msgstr "Dem Projektarchiv fehlen folgende vorausgesetzte Versionen:"
 
-#: bundle.c:164 sequencer.c:550 sequencer.c:982 builtin/log.c:289
-#: builtin/log.c:720 builtin/log.c:1309 builtin/log.c:1528 builtin/merge.c:347
+#: 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
 #: builtin/shortlog.c:181
 msgid "revision walk setup failed"
 msgstr "Einrichtung des Revisionsgangs fehlgeschlagen"
@@ -71,44 +71,48 @@ msgstr[0] "Das Paket enthält %d Referenz"
 msgstr[1] "Das Paket enthält %d Referenzen"
 
 #: bundle.c:192
+msgid "The bundle records a complete history."
+msgstr "Das Paket speichert eine komplette Historie."
+
+#: bundle.c:195
 #, c-format
 msgid "The bundle requires this ref"
 msgid_plural "The bundle requires these %d refs"
 msgstr[0] "Das Paket benötigt diese Referenz"
 msgstr[1] "Das Paket benötigt diese %d Referenzen"
 
-#: bundle.c:290
+#: bundle.c:294
 msgid "rev-list died"
 msgstr "\"rev-list\" abgebrochen"
 
-#: bundle.c:296 builtin/log.c:1205 builtin/shortlog.c:284
+#: bundle.c:300 builtin/log.c:1209 builtin/shortlog.c:284
 #, c-format
 msgid "unrecognized argument: %s"
 msgstr "nicht erkanntes Argument: %s"
 
-#: bundle.c:331
+#: bundle.c:335
 #, c-format
 msgid "ref '%s' is excluded by the rev-list options"
 msgstr "Referenz '%s' wird durch \"rev-list\" Optionen ausgeschlossen"
 
-#: bundle.c:376
+#: bundle.c:380
 msgid "Refusing to create empty bundle."
 msgstr "Erstellung eines leeren Pakets zurückgewiesen."
 
-#: bundle.c:394
+#: bundle.c:398
 msgid "Could not spawn pack-objects"
 msgstr "Konnte Paketobjekte nicht erstellen"
 
-#: bundle.c:412
+#: bundle.c:416
 msgid "pack-objects died"
 msgstr "Erstellung der Paketobjekte abgebrochen"
 
-#: bundle.c:415
+#: bundle.c:419
 #, c-format
 msgid "cannot create '%s'"
 msgstr "kann '%s' nicht erstellen"
 
-#: bundle.c:437
+#: bundle.c:441
 msgid "index-pack died"
 msgstr "Erstellung der Paketindexdatei abgebrochen"
 
@@ -227,32 +231,32 @@ msgstr ""
 "Fehler in 'diff.dirstat' Konfigurationsvariable gefunden:\n"
 "%s"
 
-#: diff.c:1400
-msgid " 0 files changed\n"
-msgstr " 0 Dateien geändert\n"
+#: diff.c:1401
+msgid " 0 files changed"
+msgstr " 0 Dateien geändert"
 
-#: diff.c:1404
+#: 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:1421
+#: 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:1432
+#: diff.c:1433
 #, c-format
 msgid ", %d deletion(-)"
 msgid_plural ", %d deletions(-)"
 msgstr[0] ", %d Zeile entfernt(-)"
 msgstr[1] ", %d Zeilen entfernt(-)"
 
-#: diff.c:3478
+#: diff.c:3460
 #, c-format
 msgid ""
 "Failed to parse --dirstat/-X option parameter:\n"
@@ -288,16 +292,16 @@ msgstr "'%s': %s"
 msgid "'%s': short read %s"
 msgstr "'%s': read() zu kurz %s"
 
-#: help.c:207
+#: help.c:212
 #, c-format
 msgid "available git commands in '%s'"
 msgstr "Vorhandene Git-Kommandos in '%s'"
 
-#: help.c:214
+#: help.c:219
 msgid "git commands available from elsewhere on your $PATH"
 msgstr "Vorhandene Git-Kommandos irgendwo in deinem $PATH"
 
-#: help.c:270
+#: help.c:275
 #, c-format
 msgid ""
 "'%s' appears to be a git command, but we were not\n"
@@ -306,11 +310,11 @@ msgstr ""
 "'%s' scheint ein git-Kommando zu sein, konnte aber\n"
 "nicht ausgeführt werden. Vielleicht ist git-%s fehlerhaft?"
 
-#: help.c:327
+#: help.c:332
 msgid "Uh oh. Your system reports no Git commands at all."
 msgstr "Uh oh. Keine Git-Kommandos auf deinem System vorhanden."
 
-#: help.c:349
+#: help.c:354
 #, c-format
 msgid ""
 "WARNING: You called a Git command named '%s', which does not exist.\n"
@@ -319,17 +323,17 @@ msgstr ""
 "Warnung: Du hast das nicht existierende Git-Kommando '%s' ausgeführt.\n"
 "Setze fort unter der Annahme das du '%s' gemeint hast"
 
-#: help.c:354
+#: help.c:359
 #, c-format
 msgid "in %0.1f seconds automatically..."
 msgstr "automatisch in %0.1f Sekunden..."
 
-#: help.c:361
+#: help.c:366
 #, c-format
 msgid "git: '%s' is not a git command. See 'git --help'."
 msgstr "git: '%s' ist kein Git-Kommando. Siehe 'git --help'."
 
-#: help.c:365
+#: help.c:370
 msgid ""
 "\n"
 "Did you mean this?"
@@ -343,35 +347,293 @@ msgstr[1] ""
 "\n"
 "Hast du eines von diesen gemeint?"
 
-#: parse-options.c:493
+#: merge-recursive.c:190
+#, c-format
+msgid "(bad commit)\n"
+msgstr "(ungültige Version)\n"
+
+#: merge-recursive.c:206
+#, c-format
+msgid "addinfo_cache failed for path '%s'"
+msgstr "addinfo_cache für Pfad '%s' fehlgeschlagen"
+
+#: merge-recursive.c:268
+msgid "error building trees"
+msgstr "Fehler beim Erstellen der Bäume"
+
+#: merge-recursive.c:672
+#, c-format
+msgid "failed to create path '%s'%s"
+msgstr "Fehler beim Erstellen des Pfades '%s'%s"
+
+#: merge-recursive.c:683
+#, c-format
+msgid "Removing %s to make room for subdirectory\n"
+msgstr "Entferne %s um Platz für Unterverzeichnis zu schaffen\n"
+
+#. something else exists
+#. .. but not some other error (who really cares what?)
+#: merge-recursive.c:697 merge-recursive.c:718
+msgid ": perhaps a D/F conflict?"
+msgstr ": vielleicht ein Verzeichnis/Datei-Konflikt?"
+
+#: merge-recursive.c:708
+#, c-format
+msgid "refusing to lose untracked file at '%s'"
+msgstr "verweigere, da unbeobachtete Dateien in '%s' verloren gehen würden"
+
+#: merge-recursive.c:748
+#, c-format
+msgid "cannot read object %s '%s'"
+msgstr "kann Objekt %s '%s' nicht lesen"
+
+#: merge-recursive.c:750
+#, c-format
+msgid "blob expected for %s '%s'"
+msgstr "Blob erwartet für %s '%s'"
+
+#: merge-recursive.c:773 builtin/clone.c:302
+#, c-format
+msgid "failed to open '%s'"
+msgstr "Fehler beim Öffnen von '%s'"
+
+#: merge-recursive.c:781
+#, c-format
+msgid "failed to symlink '%s'"
+msgstr "Fehler beim Erstellen einer symbolischen Verknüpfung für '%s'"
+
+#: merge-recursive.c:784
+#, c-format
+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
+msgid "Failed to execute internal merge"
+msgstr "Fehler bei Ausführung der internen Zusammenführung"
+
+#: merge-recursive.c:925
+#, c-format
+msgid "Unable to add %s to database"
+msgstr "Konnte %s nicht zur Datenbank hinzufügen"
+
+#: merge-recursive.c:941
+msgid "unsupported object type in the tree"
+msgstr "nicht unterstützter Objekttyp im Baum"
+
+#: merge-recursive.c:1020 merge-recursive.c:1034
+#, c-format
+msgid ""
+"CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left "
+"in tree."
+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
+#, c-format
+msgid ""
+"CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left "
+"in tree at %s."
+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
+msgid "rename"
+msgstr "umbenennen"
+
+#: merge-recursive.c:1080
+msgid "renamed"
+msgstr "umbenannt"
+
+#: merge-recursive.c:1136
+#, 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
+#, c-format
+msgid ""
+"CONFLICT (rename/rename): Rename \"%s\"->\"%s\" in branch \"%s\" rename \"%s"
+"\"->\"%s\" in \"%s\"%s"
+msgstr ""
+"KONFLIKT (umbenennen/umbenennen): Benenne um \"%s\"->\"%s\" in Zweig \"%s\" "
+"und \"%s\"->\"%s\" in Zweig \"%s\"%s"
+
+#: merge-recursive.c:1163
+msgid " (left unresolved)"
+msgstr " (bleibt unaufgelöst)"
+
+#: merge-recursive.c:1217
+#, 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
+#, 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
+#, 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
+#, c-format
+msgid "Adding merged %s"
+msgstr "Füge zusammengeführte Datei %s hinzu"
+
+#: merge-recursive.c:1461 merge-recursive.c:1659
+#, c-format
+msgid "Adding as %s instead"
+msgstr "Füge stattdessen als %s hinzu"
+
+#: merge-recursive.c:1512
+#, c-format
+msgid "cannot read object %s"
+msgstr "kann Objekt %s nicht lesen"
+
+#: merge-recursive.c:1515
+#, c-format
+msgid "object %s is not a blob"
+msgstr "Objekt %s ist kein Blob"
+
+#: merge-recursive.c:1563
+msgid "modify"
+msgstr "ändern"
+
+#: merge-recursive.c:1563
+msgid "modified"
+msgstr "geändert"
+
+#: merge-recursive.c:1573
+msgid "content"
+msgstr "Inhalt"
+
+#: merge-recursive.c:1580
+msgid "add/add"
+msgstr "hinzufügen/hinzufügen"
+
+#: merge-recursive.c:1614
+#, c-format
+msgid "Skipped %s (merged same as existing)"
+msgstr "%s ausgelassen (Ergebnis der Zusammenführung existiert bereits)"
+
+#: merge-recursive.c:1628
+#, c-format
+msgid "Auto-merging %s"
+msgstr "automatische Zusammenführung von %s"
+
+#: merge-recursive.c:1632 git-submodule.sh:869
+msgid "submodule"
+msgstr "Unterprojekt"
+
+#: merge-recursive.c:1633
+#, c-format
+msgid "CONFLICT (%s): Merge conflict in %s"
+msgstr "KONFLIKT (%s): Zusammenführungskonflikt in %s"
+
+#: merge-recursive.c:1723
+#, c-format
+msgid "Removing %s"
+msgstr "Entferne %s"
+
+#: merge-recursive.c:1748
+msgid "file/directory"
+msgstr "Datei/Verzeichnis"
+
+#: merge-recursive.c:1754
+msgid "directory/file"
+msgstr "Verzeichnis/Datei"
+
+#: merge-recursive.c:1759
+#, 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
+#, c-format
+msgid "Adding %s"
+msgstr "Füge %s hinzu"
+
+#: merge-recursive.c:1786
+msgid "Fatal merge failure, shouldn't happen."
+msgstr "Fataler Fehler bei der Zusammenführung. Sollte nicht passieren."
+
+#: merge-recursive.c:1805
+msgid "Already up-to-date!"
+msgstr "Bereits aktuell!"
+
+#: merge-recursive.c:1814
+#, c-format
+msgid "merging of trees %s and %s failed"
+msgstr "Zusammenführen der Bäume %s und %s fehlgeschlagen"
+
+#: merge-recursive.c:1844
+#, c-format
+msgid "Unprocessed path??? %s"
+msgstr "unverarbeiteter Pfad??? %s"
+
+#: merge-recursive.c:1889
+msgid "Merging:"
+msgstr "Zusammenführung:"
+
+#: merge-recursive.c:1902
+#, 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
+msgid "merge returned no commit"
+msgstr "Zusammenführung hat keine Version zurückgegeben"
+
+#: merge-recursive.c:1996
+#, c-format
+msgid "Could not parse object '%s'"
+msgstr "Konnte Objekt '%s' nicht parsen."
+
+#: merge-recursive.c:2008 builtin/merge.c:696
+msgid "Unable to write index."
+msgstr "Konnte Bereitstellung nicht schreiben."
+
+#: parse-options.c:494
 msgid "..."
 msgstr "..."
 
-#: parse-options.c:511
+#: parse-options.c:512
 #, c-format
 msgid "usage: %s"
 msgstr "Verwendung: %s"
 
 #. TRANSLATORS: the colon here should align with the
 #. one in "usage: %s" translation
-#: parse-options.c:515
+#: parse-options.c:516
 #, c-format
 msgid "   or: %s"
 msgstr "      oder: %s"
 
-#: parse-options.c:518
+#: parse-options.c:519
 #, c-format
 msgid "    %s"
 msgstr "    %s"
 
-#: remote.c:1629
+#: remote.c:1632
 #, 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] "Dein Zweig ist vor '%s' um %d Version.\n"
 msgstr[1] "Dein Zweig ist vor '%s' um %d Versionen.\n"
 
-#: remote.c:1635
+#: remote.c:1638
 #, c-format
 msgid "Your branch is behind '%s' by %d commit, and can be fast-forwarded.\n"
 msgid_plural ""
@@ -382,7 +644,7 @@ msgstr[1] ""
 "Dein Zweig ist zu '%s' um %d Versionen hinterher, und kann vorgespult "
 "werden.\n"
 
-#: remote.c:1643
+#: remote.c:1646
 #, c-format
 msgid ""
 "Your branch and '%s' have diverged,\n"
@@ -397,14 +659,14 @@ msgstr[1] ""
 "Dein Zweig und '%s' sind divergiert,\n"
 "und haben jeweils %d und %d unterschiedliche Versionen.\n"
 
-#: sequencer.c:121 builtin/merge.c:865 builtin/merge.c:978
-#: builtin/merge.c:1088 builtin/merge.c:1098
+#: sequencer.c:121 builtin/merge.c:864 builtin/merge.c:977
+#: builtin/merge.c:1087 builtin/merge.c:1097
 #, 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:868
-#: builtin/merge.c:1090 builtin/merge.c:1103
+#: sequencer.c:123 builtin/merge.c:333 builtin/merge.c:867
+#: builtin/merge.c:1089 builtin/merge.c:1102
 #, c-format
 msgid "Could not write to '%s'"
 msgstr "Konnte nicht nach '%s' schreiben."
@@ -610,7 +872,7 @@ msgstr "kann Zweigspitze (HEAD) nicht auflösen"
 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:3697
+#: sequencer.c:805 builtin/apply.c:3987
 #, c-format
 msgid "cannot open %s: %s"
 msgstr "Kann %s nicht öffnen: %s"
@@ -644,21 +906,21 @@ msgstr "Kann nicht zu initialer Version zurücksetzen."
 msgid "Can't cherry-pick into empty head"
 msgstr "Kann \"cherry-pick\" nicht in einem leerem Kopf ausführen."
 
-#: sha1_name.c:864
+#: sha1_name.c:1044
 msgid "HEAD does not point to a branch"
 msgstr "Zweigspitze (HEAD) zeigt auf keinen Zweig"
 
-#: sha1_name.c:867
+#: sha1_name.c:1047
 #, c-format
 msgid "No such branch: '%s'"
 msgstr "Kein solcher Zweig '%s'"
 
-#: sha1_name.c:869
+#: sha1_name.c:1049
 #, c-format
 msgid "No upstream configured for branch '%s'"
 msgstr "Kein entferntes Projektarchiv für Zweig '%s' konfiguriert."
 
-#: sha1_name.c:872
+#: sha1_name.c:1052
 #, c-format
 msgid "Upstream branch '%s' not stored as a remote-tracking branch"
 msgstr ""
@@ -673,252 +935,367 @@ msgstr "konnte aktuellen Benutzer nicht in Passwort-Datei finden: %s"
 msgid "no such user"
 msgstr "kein solcher Benutzer"
 
-#: wt-status.c:135
+#: wt-status.c:140
 msgid "Unmerged paths:"
 msgstr "Nicht zusammengeführte Pfade:"
 
-#: wt-status.c:141 wt-status.c:158
+#: wt-status.c:167 wt-status.c:194
 #, c-format
 msgid "  (use \"git reset %s <file>...\" to unstage)"
 msgstr ""
 "  (benutze \"git reset %s <Datei>...\" zum Herausnehmen aus der "
 "Bereitstellung)"
 
-#: wt-status.c:143 wt-status.c:160
+#: wt-status.c:169 wt-status.c:196
 msgid "  (use \"git rm --cached <file>...\" to unstage)"
 msgstr ""
 "  (benutze \"git rm --cached <Datei>...\" zum Herausnehmen aus der "
 "Bereitstellung)"
 
-#: wt-status.c:144
+#: wt-status.c:173
+msgid "  (use \"git add <file>...\" to mark resolution)"
+msgstr "  (benutze \"git add/rm <Datei>...\" um die Auflösung zu markieren)"
+
+#: wt-status.c:175 wt-status.c:179
 msgid "  (use \"git add/rm <file>...\" as appropriate to mark resolution)"
 msgstr ""
 "  (benutze \"git add/rm <Datei>...\" um die Auflösung entsprechend zu "
 "markieren)"
 
-#: wt-status.c:152
+#: wt-status.c:177
+msgid "  (use \"git rm <file>...\" to mark resolution)"
+msgstr "  (benutze \"git add/rm <Datei>...\" um die Auflösung zu markieren)"
+
+#: wt-status.c:188
 msgid "Changes to be committed:"
 msgstr "zum Eintragen bereitgestellte Änderungen:"
 
-#: wt-status.c:170
+#: wt-status.c:206
 msgid "Changes not staged for commit:"
 msgstr "Änderungen, die nicht zum Eintragen bereitgestellt sind:"
 
-#: wt-status.c:174
+#: wt-status.c:210
 msgid "  (use \"git add <file>...\" to update what will be committed)"
 msgstr "  (benutze \"git add <Datei>...\" zum Bereitstellen)"
 
-#: wt-status.c:176
+#: wt-status.c:212
 msgid "  (use \"git add/rm <file>...\" to update what will be committed)"
 msgstr "  (benutze \"git add/rm <Datei>...\" zum Bereitstellen)"
 
-#: wt-status.c:177
+#: wt-status.c:213
 msgid ""
 "  (use \"git checkout -- <file>...\" to discard changes in working directory)"
 msgstr ""
 "  (benutze \"git checkout -- <Datei>...\" um die Änderungen im "
 "Arbeitsverzeichnis zu verwerfen)"
 
-#: wt-status.c:179
+#: wt-status.c:215
 msgid "  (commit or discard the untracked or modified content in submodules)"
 msgstr ""
 "  (trage ein oder verwerfe den unbeobachteten oder geänderten Inhalt in den "
 "Unterprojekten)"
 
-#: wt-status.c:188
+#: wt-status.c:224
 #, c-format
 msgid "%s files:"
 msgstr "%s Dateien:"
 
-#: wt-status.c:191
+#: wt-status.c:227
 #, c-format
 msgid "  (use \"git %s <file>...\" to include in what will be committed)"
 msgstr "  (benutze \"git %s <Datei>...\" zum Einfügen in die Eintragung)"
 
-#: wt-status.c:208
+#: wt-status.c:244
 msgid "bug"
 msgstr "Fehler"
 
-#: wt-status.c:213
+#: wt-status.c:249
 msgid "both deleted:"
 msgstr "beide gelöscht:"
 
-#: wt-status.c:214
+#: wt-status.c:250
 msgid "added by us:"
 msgstr "von uns hinzugefügt:"
 
-#: wt-status.c:215
+#: wt-status.c:251
 msgid "deleted by them:"
 msgstr "von denen gelöscht:"
 
-#: wt-status.c:216
+#: wt-status.c:252
 msgid "added by them:"
 msgstr "von denen hinzugefügt:"
 
-#: wt-status.c:217
+#: wt-status.c:253
 msgid "deleted by us:"
 msgstr "von uns gelöscht:"
 
-#: wt-status.c:218
+#: wt-status.c:254
 msgid "both added:"
 msgstr "von beiden hinzugefügt:"
 
-#: wt-status.c:219
+#: wt-status.c:255
 msgid "both modified:"
 msgstr "von beiden geändert:"
 
-#: wt-status.c:249
+#: wt-status.c:285
 msgid "new commits, "
 msgstr "neue Versionen, "
 
-#: wt-status.c:251
+#: wt-status.c:287
 msgid "modified content, "
 msgstr "geänderter Inhalt, "
 
-#: wt-status.c:253
+#: wt-status.c:289
 msgid "untracked content, "
 msgstr "unbeobachteter Inhalt, "
 
-#: wt-status.c:267
+#: wt-status.c:303
 #, c-format
 msgid "new file:   %s"
 msgstr "neue Datei:   %s"
 
-#: wt-status.c:270
+#: wt-status.c:306
 #, c-format
 msgid "copied:     %s -> %s"
 msgstr "kopiert:     %s -> %s"
 
-#: wt-status.c:273
+#: wt-status.c:309
 #, c-format
 msgid "deleted:    %s"
 msgstr "gelöscht:    %s"
 
-#: wt-status.c:276
+#: wt-status.c:312
 #, c-format
 msgid "modified:   %s"
 msgstr "geändert:   %s"
 
-#: wt-status.c:279
+#: wt-status.c:315
 #, c-format
 msgid "renamed:    %s -> %s"
 msgstr "umbenannt:    %s -> %s"
 
-#: wt-status.c:282
+#: wt-status.c:318
 #, c-format
 msgid "typechange: %s"
 msgstr "Typänderung: %s"
 
-#: wt-status.c:285
+#: wt-status.c:321
 #, c-format
 msgid "unknown:    %s"
 msgstr "unbekannt:    %s"
 
-#: wt-status.c:288
+#: wt-status.c:324
 #, c-format
 msgid "unmerged:   %s"
 msgstr "nicht zusammengeführt:   %s"
 
-#: wt-status.c:291
+#: wt-status.c:327
 #, c-format
 msgid "bug: unhandled diff status %c"
 msgstr "Fehler: unbehandelter Differenz-Status %c"
 
-#: wt-status.c:737
+#: wt-status.c:785
+msgid "You have unmerged paths."
+msgstr "Du hast nicht zusammengeführte Pfade."
+
+#: wt-status.c:788 wt-status.c:912
+msgid "  (fix conflicts and run \"git commit\")"
+msgstr " (behebe die Konflikte und führe \"git commit\" aus)"
+
+#: wt-status.c:791
+msgid "All conflicts fixed but you are still merging."
+msgstr ""
+"Alle Konflikte sind behoben, aber du bist immer noch beim Zusammenführen."
+
+#: wt-status.c:794
+msgid "  (use \"git commit\" to conclude merge)"
+msgstr "  (benutze \"git commit\" um die Zusammenführung abzuschließen)"
+
+#: wt-status.c:804
+msgid "You are in the middle of an am session."
+msgstr "Eine \"am\"-Sitzung ist im Gange."
+
+#: wt-status.c:807
+msgid "The current patch is empty."
+msgstr "Der aktuelle Patch ist leer."
+
+#: wt-status.c:811
+msgid "  (fix conflicts and then run \"git am --resolved\")"
+msgstr "  (behebe die Konflikte und führe dann \"git am --resolved\" aus)"
+
+#: wt-status.c:813
+msgid "  (use \"git am --skip\" to skip this patch)"
+msgstr " (benutze \"git am --skip\" um diesen Patch auszulassen)"
+
+#: wt-status.c:815
+msgid "  (use \"git am --abort\" to restore the original branch)"
+msgstr ""
+"  (benutze \"git am --abort\" um den ursprünglichen Zweig wiederherzustellen)"
+
+#: wt-status.c:873 wt-status.c:883
+msgid "You are currently rebasing."
+msgstr "Du bist gerade beim Neuaufbau."
+
+#: wt-status.c:876
+msgid "  (fix conflicts and then run \"git rebase --continue\")"
+msgstr "  (behebe die Konflikte und führe dann \"git rebase --continue\" aus)"
+
+#: wt-status.c:878
+msgid "  (use \"git rebase --skip\" to skip this patch)"
+msgstr "  (benutze \"git rebase --skip\" um diesen Patch auszulassen)"
+
+#: wt-status.c:880
+msgid "  (use \"git rebase --abort\" to check out the original branch)"
+msgstr ""
+"  (benutze \"git rebase --abort\" um den ursprünglichen Zweig auszuchecken)"
+
+#: wt-status.c:886
+msgid "  (all conflicts fixed: run \"git rebase --continue\")"
+msgstr "  (alle Konflikte behoben: führe \"git rebase --continue\" aus)"
+
+#: wt-status.c:888
+msgid "You are currently splitting a commit during a rebase."
+msgstr "Du teilst gerade eine Version während eines Neuaufbaus auf."
+
+#: wt-status.c:891
+msgid "  (Once your working directory is clean, run \"git rebase --continue\")"
+msgstr ""
+"  (Sobald dein Arbeitsverzeichnis sauber ist, führe \"git rebase --continue"
+"\" aus)"
+
+#: wt-status.c:893
+msgid "You are currently editing a commit during a rebase."
+msgstr "Du editierst gerade eine Version während eines Neuaufbaus."
+
+#: wt-status.c:896
+msgid "  (use \"git commit --amend\" to amend the current commit)"
+msgstr ""
+"  (benutze \"git commit --amend\" um die aktuelle Version nachzubessern)"
+
+#: wt-status.c:898
+msgid ""
+"  (use \"git rebase --continue\" once you are satisfied with your changes)"
+msgstr ""
+"  (benutze \"git rebase --continue\" sobald deine Änderungen abgeschlossen "
+"sind)"
+
+#: wt-status.c:908
+msgid "You are currently cherry-picking."
+msgstr "Du führst gerade \"cherry-pick\" aus."
+
+#: wt-status.c:915
+msgid "  (all conflicts fixed: run \"git commit\")"
+msgstr "  (alle Konflikte behoben: führe \"git commit\" aus)"
+
+#: wt-status.c:924
+msgid "You are currently bisecting."
+msgstr "Du bist gerade beim Halbieren."
+
+#: wt-status.c:927
+msgid "  (use \"git bisect reset\" to get back to the original branch)"
+msgstr ""
+"  (benutze \"git bisect reset\" um zum ursprünglichen Zweig zurückzukehren)"
+
+#: wt-status.c:978
 msgid "On branch "
 msgstr "Auf Zweig "
 
-#: wt-status.c:744
+#: wt-status.c:985
 msgid "Not currently on any branch."
 msgstr "Im Moment auf keinem Zweig."
 
-#: wt-status.c:755
+#: wt-status.c:997
 msgid "Initial commit"
 msgstr "Initiale Version"
 
-#: wt-status.c:769
+#: wt-status.c:1011
 msgid "Untracked"
 msgstr "Unbeobachtete"
 
-#: wt-status.c:771
+#: wt-status.c:1013
 msgid "Ignored"
 msgstr "Ignorierte"
 
-#: wt-status.c:773
+#: wt-status.c:1015
 #, c-format
 msgid "Untracked files not listed%s"
 msgstr "Unbeobachtete Dateien nicht aufgelistet%s"
 
-#: wt-status.c:775
+#: wt-status.c:1017
 msgid " (use -u option to show untracked files)"
 msgstr " (benutze die Option -u um unbeobachteten Dateien anzuzeigen)"
 
-#: wt-status.c:781
+#: wt-status.c:1023
 msgid "No changes"
 msgstr "Keine Änderungen"
 
-#: wt-status.c:785
+#: wt-status.c:1027
 #, c-format
 msgid "no changes added to commit%s\n"
 msgstr "keine Änderungen zum Eintragen hinzugefügt%s\n"
 
-#: wt-status.c:787
+#: wt-status.c:1029
 msgid " (use \"git add\" and/or \"git commit -a\")"
 msgstr " (benutze \"git add\" und/oder \"git commit -a\")"
 
-#: wt-status.c:789
+#: wt-status.c:1031
 #, c-format
 msgid "nothing added to commit but untracked files present%s\n"
 msgstr ""
 "nichts zum Eintragen hinzugefügt, aber es gibt unbeobachtete Dateien%s\n"
 
-#: wt-status.c:791
+#: wt-status.c:1033
 msgid " (use \"git add\" to track)"
 msgstr " (benutze \"git add\" zum Beobachten)"
 
-#: wt-status.c:793 wt-status.c:796 wt-status.c:799
+#: wt-status.c:1035 wt-status.c:1038 wt-status.c:1041
 #, c-format
 msgid "nothing to commit%s\n"
 msgstr "nichts zum Eintragen%s\n"
 
-#: wt-status.c:794
+#: 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:797
+#: wt-status.c:1039
 msgid " (use -u to show untracked files)"
 msgstr " (benutze die Option -u um unbeobachtete Dateien anzuzeigen)"
 
-#: wt-status.c:800
+#: wt-status.c:1042
 msgid " (working directory clean)"
 msgstr " (Arbeitsverzeichnis sauber)"
 
-#: wt-status.c:908
+#: wt-status.c:1150
 msgid "HEAD (no branch)"
 msgstr "HEAD (kein Zweig)"
 
-#: wt-status.c:914
+#: wt-status.c:1156
 msgid "Initial commit on "
 msgstr "Initiale Version auf "
 
-#: wt-status.c:929
+#: wt-status.c:1171
 msgid "behind "
 msgstr "hinterher "
 
-#: wt-status.c:932 wt-status.c:935
+#: wt-status.c:1174 wt-status.c:1177
 msgid "ahead "
 msgstr "voraus "
 
-#: wt-status.c:937
+#: wt-status.c:1179
 msgid ", behind "
 msgstr ", hinterher "
 
+#: compat/precompose_utf8.c:58 builtin/clone.c:341
+#, c-format
+msgid "failed to unlink '%s'"
+msgstr "Konnte '%s' nicht entfernen"
+
 #: builtin/add.c:62
 #, c-format
 msgid "unexpected diff status %c"
 msgstr "unerwarteter Differenz-Status %c"
 
-#: builtin/add.c:67 builtin/commit.c:226
+#: builtin/add.c:67 builtin/commit.c:229
 msgid "updating files failed"
 msgstr "Aktualisierung der Dateien fehlgeschlagen"
 
@@ -937,7 +1314,7 @@ msgid "Unstaged changes after refreshing the index:"
 msgstr ""
 "Nicht bereitgestellte Änderungen nach Aktualisierung der Bereitstellung:"
 
-#: builtin/add.c:195 builtin/add.c:456 builtin/rm.c:186
+#: builtin/add.c:195 builtin/add.c:459 builtin/rm.c:186
 #, c-format
 msgid "pathspec '%s' did not match any files"
 msgstr "Pfadspezifikation '%s' stimmt mit keinen Dateien überein"
@@ -1012,79 +1389,79 @@ msgstr "Nichts spezifiziert, nichts hinzugefügt.\n"
 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:286 builtin/mv.c:82
+#: builtin/add.c:420 builtin/clean.c:95 builtin/commit.c:289 builtin/mv.c:82
 #: builtin/rm.c:162
 msgid "index file corrupt"
 msgstr "Bereitstellungsdatei beschädigt"
 
-#: builtin/add.c:476 builtin/apply.c:4108 builtin/mv.c:229 builtin/rm.c:260
+#: builtin/add.c:480 builtin/apply.c:4432 builtin/mv.c:229 builtin/rm.c:260
 msgid "Unable to write new index file"
 msgstr "Konnte neue Bereitstellungsdatei nicht schreiben."
 
-#: builtin/apply.c:53
+#: builtin/apply.c:57
 msgid "git apply [options] [<patch>...]"
 msgstr "git apply [Optionen] [<Patch>...]"
 
-#: builtin/apply.c:106
+#: builtin/apply.c:110
 #, c-format
 msgid "unrecognized whitespace option '%s'"
 msgstr "nicht erkannte Option für Leerzeichen: '%s'"
 
-#: builtin/apply.c:121
+#: builtin/apply.c:125
 #, c-format
 msgid "unrecognized whitespace ignore option '%s'"
 msgstr "nicht erkannte Option zum Ignorieren von Leerzeichen: '%s'"
 
-#: builtin/apply.c:815
+#: builtin/apply.c:823
 #, c-format
 msgid "Cannot prepare timestamp regexp %s"
 msgstr "Kann regulären Ausdruck für Zeitstempel %s nicht verarbeiten"
 
-#: builtin/apply.c:824
+#: builtin/apply.c:832
 #, c-format
 msgid "regexec returned %d for input: %s"
 msgstr "Ausführung des regulären Ausdrucks gab %d zurück. Eingabe: %s"
 
-#: builtin/apply.c:905
+#: builtin/apply.c:913
 #, c-format
 msgid "unable to find filename in patch at line %d"
 msgstr "Konnte keinen Dateinamen in Zeile %d des Patches finden."
 
-#: builtin/apply.c:937
+#: builtin/apply.c:945
 #, c-format
 msgid "git apply: bad git-diff - expected /dev/null, got %s on line %d"
 msgstr ""
 "git apply: ungültiges 'git-diff' - erwartete /dev/null, erhielt %s in Zeile "
 "%d"
 
-#: builtin/apply.c:941
+#: builtin/apply.c:949
 #, c-format
 msgid "git apply: bad git-diff - inconsistent new filename on line %d"
 msgstr ""
 "git apply: ungültiges 'git-diff' - Inkonsistenter neuer Dateiname in Zeile %d"
 
-#: builtin/apply.c:942
+#: builtin/apply.c:950
 #, c-format
 msgid "git apply: bad git-diff - inconsistent old filename on line %d"
 msgstr ""
 "git apply: ungültiges 'git-diff' - Inkonsistenter alter Dateiname in Zeile %d"
 
-#: builtin/apply.c:949
+#: builtin/apply.c:957
 #, c-format
 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:1394
+#: builtin/apply.c:1402
 #, c-format
 msgid "recount: unexpected line: %.*s"
 msgstr "recount: unerwartete Zeile: %.*s"
 
-#: builtin/apply.c:1451
+#: builtin/apply.c:1459
 #, c-format
 msgid "patch fragment without header at line %d: %.*s"
 msgstr "Patch-Fragment ohne Kopfbereich bei Zeile %d: %.*s"
 
-#: builtin/apply.c:1468
+#: builtin/apply.c:1476
 #, c-format
 msgid ""
 "git diff header lacks filename information when removing %d leading pathname "
@@ -1099,70 +1476,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:1628
+#: builtin/apply.c:1636
 msgid "new file depends on old contents"
 msgstr "neue Datei hängt von alten Inhalten ab"
 
-#: builtin/apply.c:1630
+#: builtin/apply.c:1638
 msgid "deleted file still has contents"
 msgstr "entfernte Datei hat noch Inhalte"
 
-#: builtin/apply.c:1656
+#: builtin/apply.c:1664
 #, c-format
 msgid "corrupt patch at line %d"
 msgstr "fehlerhafter Patch bei Zeile %d"
 
-#: builtin/apply.c:1692
+#: builtin/apply.c:1700
 #, c-format
 msgid "new file %s depends on old contents"
 msgstr "neue Datei %s hängt von alten Inhalten ab"
 
-#: builtin/apply.c:1694
+#: builtin/apply.c:1702
 #, c-format
 msgid "deleted file %s still has contents"
 msgstr "entfernte Datei %s hat noch Inhalte"
 
-#: builtin/apply.c:1697
+#: builtin/apply.c:1705
 #, c-format
 msgid "** warning: file %s becomes empty but is not deleted"
 msgstr "** Warnung: Datei %s wird leer, aber nicht entfernt."
 
-#: builtin/apply.c:1843
+#: builtin/apply.c:1851
 #, 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:1872
+#: builtin/apply.c:1880
 #, c-format
 msgid "unrecognized binary patch at line %d"
 msgstr "nicht erkannter Binär-Patch bei Zeile %d"
 
-#: builtin/apply.c:1958
+#: builtin/apply.c:1966
 #, c-format
 msgid "patch with only garbage at line %d"
 msgstr "Patch mit nutzlosen Informationen bei Zeile %d"
 
-#: builtin/apply.c:2048
+#: builtin/apply.c:2056
 #, c-format
 msgid "unable to read symlink %s"
 msgstr "konnte symbolische Verknüpfung %s nicht lesen"
 
-#: builtin/apply.c:2052
+#: builtin/apply.c:2060
 #, c-format
 msgid "unable to open or read %s"
 msgstr "konnte %s nicht öffnen oder lesen"
 
-#: builtin/apply.c:2123
+#: builtin/apply.c:2131
 msgid "oops"
 msgstr "Ups"
 
-#: builtin/apply.c:2645
+#: builtin/apply.c:2653
 #, c-format
 msgid "invalid start of line: '%c'"
 msgstr "Ungültiger Zeilenanfang: '%c'"
 
-#: builtin/apply.c:2763
+#: builtin/apply.c:2771
 #, c-format
 msgid "Hunk #%d succeeded at %d (offset %d line)."
 msgid_plural "Hunk #%d succeeded at %d (offset %d lines)."
@@ -1170,12 +1547,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:2775
+#: builtin/apply.c:2783
 #, 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:2781
+#: builtin/apply.c:2789
 #, c-format
 msgid ""
 "while searching for:\n"
@@ -1184,329 +1561,339 @@ msgstr ""
 "bei der Suche nach:\n"
 "%.*s"
 
-#: builtin/apply.c:2800
+#: builtin/apply.c:2808
 #, c-format
 msgid "missing binary patch data for '%s'"
 msgstr "keine Daten in Binär-Patch für '%s'"
 
-#: builtin/apply.c:2903
+#: builtin/apply.c:2911
 #, c-format
 msgid "binary patch does not apply to '%s'"
 msgstr "Konnte Binär-Patch nicht auf '%s' anwenden"
 
-#: builtin/apply.c:2909
+#: builtin/apply.c:2917
 #, 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:2930
+#: builtin/apply.c:2938
 #, c-format
 msgid "patch failed: %s:%ld"
 msgstr "Anwendung des Patches fehlgeschlagen: %s:%ld"
 
-#: builtin/apply.c:3045
+#: builtin/apply.c:3060
 #, c-format
-msgid "patch %s has been renamed/deleted"
-msgstr "Patch %s wurde umbenannt/gelöscht"
+msgid "cannot checkout %s"
+msgstr "kann %s nicht auschecken"
 
-#: builtin/apply.c:3052 builtin/apply.c:3069
+#: builtin/apply.c:3105 builtin/apply.c:3114 builtin/apply.c:3158
 #, c-format
 msgid "read of %s failed"
 msgstr "Konnte %s nicht lesen"
 
-#: builtin/apply.c:3084
-msgid "removal patch leaves file contents"
-msgstr "Lösch-Patch hinterlässt Dateiinhalte"
-
-#: builtin/apply.c:3105
+#: builtin/apply.c:3138 builtin/apply.c:3360
 #, c-format
-msgid "%s: already exists in working directory"
-msgstr "%s existiert bereits im Arbeitsverzeichnis"
+msgid "path %s has been renamed/deleted"
+msgstr "Pfad %s wurde umbenannt/gelöscht"
 
-#: builtin/apply.c:3143
+#: builtin/apply.c:3219 builtin/apply.c:3374
 #, c-format
-msgid "%s: has been deleted/renamed"
-msgstr "%s wurde gelöscht/umbenannt"
+msgid "%s: does not exist in index"
+msgstr "%s ist nicht bereitgestellt"
 
-#: builtin/apply.c:3148 builtin/apply.c:3179
+#: builtin/apply.c:3223 builtin/apply.c:3366 builtin/apply.c:3388
 #, c-format
 msgid "%s: %s"
 msgstr "%s: %s"
 
-#: builtin/apply.c:3159
-#, c-format
-msgid "%s: does not exist in index"
-msgstr "%s ist nicht bereitgestellt"
-
-#: builtin/apply.c:3173
+#: builtin/apply.c:3228 builtin/apply.c:3382
 #, c-format
 msgid "%s: does not match index"
 msgstr "%s entspricht nicht der Bereitstellung"
 
-#: builtin/apply.c:3190
+#: builtin/apply.c:3330
+msgid "removal patch leaves file contents"
+msgstr "Lösch-Patch hinterlässt Dateiinhalte"
+
+#: builtin/apply.c:3399
 #, c-format
 msgid "%s: wrong type"
 msgstr "%s: falscher Typ"
 
-#: builtin/apply.c:3192
+#: builtin/apply.c:3401
 #, c-format
 msgid "%s has type %o, expected %o"
 msgstr "%s ist vom Typ %o, erwartete %o"
 
-#: builtin/apply.c:3247
+#: builtin/apply.c:3502
 #, c-format
 msgid "%s: already exists in index"
 msgstr "%s ist bereits bereitgestellt"
 
-#: builtin/apply.c:3267
+#: builtin/apply.c:3505
+#, c-format
+msgid "%s: already exists in working directory"
+msgstr "%s existiert bereits im Arbeitsverzeichnis"
+
+#: builtin/apply.c:3525
 #, 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:3272
+#: builtin/apply.c:3530
 #, 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:3280
+#: builtin/apply.c:3538
 #, c-format
 msgid "%s: patch does not apply"
 msgstr "%s: Patch konnte nicht angewendet werden"
 
-#: builtin/apply.c:3293
+#: builtin/apply.c:3551
 #, c-format
 msgid "Checking patch %s..."
 msgstr "Prüfe Patch %s..."
 
-#: builtin/apply.c:3348 builtin/checkout.c:212 builtin/reset.c:158
+#: builtin/apply.c:3606 builtin/checkout.c:213 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:3491
+#: builtin/apply.c:3749
 #, c-format
 msgid "unable to remove %s from index"
 msgstr "konnte %s nicht aus der Bereitstellung entfernen"
 
-#: builtin/apply.c:3518
+#: builtin/apply.c:3777
 #, c-format
 msgid "corrupt patch for subproject %s"
 msgstr "fehlerhafter Patch für Unterprojekt %s"
 
-#: builtin/apply.c:3522
+#: builtin/apply.c:3781
 #, c-format
 msgid "unable to stat newly created file '%s'"
 msgstr "konnte neu erstellte Datei '%s' nicht lesen"
 
-#: builtin/apply.c:3527
+#: builtin/apply.c:3786
 #, 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:3530
+#: builtin/apply.c:3789 builtin/apply.c:3897
 #, 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:3563
+#: builtin/apply.c:3822
 #, c-format
 msgid "closing file '%s'"
 msgstr "schließe Datei '%s'"
 
-#: builtin/apply.c:3612
+#: builtin/apply.c:3871
 #, c-format
 msgid "unable to write file '%s' mode %o"
 msgstr "konnte Datei '%s' mit Modus %o nicht schreiben"
 
-#: builtin/apply.c:3668
+#: builtin/apply.c:3958
 #, c-format
 msgid "Applied patch %s cleanly."
 msgstr "Patch %s sauber angewendet"
 
-#: builtin/apply.c:3676
+#: builtin/apply.c:3966
 msgid "internal error"
 msgstr "interner Fehler"
 
 #. Say this even without --verbose
-#: builtin/apply.c:3679
+#: builtin/apply.c:3969
 #, 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:3689
+#: builtin/apply.c:3979
 #, c-format
 msgid "truncating .rej filename to %.*s.rej"
 msgstr "Verkürze Name von .rej Datei zu %.*s.rej"
 
-#: builtin/apply.c:3710
+#: builtin/apply.c:4000
 #, c-format
 msgid "Hunk #%d applied cleanly."
 msgstr "Patch-Bereich #%d sauber angewendet."
 
-#: builtin/apply.c:3713
+#: builtin/apply.c:4003
 #, c-format
 msgid "Rejected hunk #%d."
 msgstr "Patch-Bereich #%d zurückgewiesen."
 
-#: builtin/apply.c:3844
+#: builtin/apply.c:4153
 msgid "unrecognized input"
 msgstr "nicht erkannte Eingabe"
 
-#: builtin/apply.c:3855
+#: builtin/apply.c:4164
 msgid "unable to read index file"
 msgstr "Konnte Bereitstellungsdatei nicht lesen"
 
-#: builtin/apply.c:3970 builtin/apply.c:3973
+#: builtin/apply.c:4283 builtin/apply.c:4286
 msgid "path"
 msgstr "Pfad"
 
-#: builtin/apply.c:3971
+#: builtin/apply.c:4284
 msgid "don't apply changes matching the given path"
 msgstr "wendet keine Änderungen im angegebenen Pfad an"
 
-#: builtin/apply.c:3974
+#: builtin/apply.c:4287
 msgid "apply changes matching the given path"
 msgstr "wendet Änderungen nur im angegebenen Pfad an"
 
-#: builtin/apply.c:3976
+#: builtin/apply.c:4289
 msgid "num"
 msgstr "Anzahl"
 
-#: builtin/apply.c:3977
+#: builtin/apply.c:4290
 msgid "remove <num> leading slashes from traditional diff paths"
 msgstr ""
-"entfernt <Anzahl> vorrangestellte Schrägstriche von herkömmlichen "
+"entfernt <Anzahl> vorangestellte Schrägstriche von herkömmlichen "
 "Differenzpfaden"
 
-#: builtin/apply.c:3980
+#: builtin/apply.c:4293
 msgid "ignore additions made by the patch"
 msgstr "ignoriert hinzugefügte Zeilen des Patches"
 
-#: builtin/apply.c:3982
+#: builtin/apply.c:4295
 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:3986
+#: builtin/apply.c:4299
 msgid "shows number of added and deleted lines in decimal notation"
 msgstr ""
 "zeigt die Anzahl von hinzugefügten/entfernten Zeilen in Dezimalnotation"
 
-#: builtin/apply.c:3988
+#: builtin/apply.c:4301
 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:3990
+#: builtin/apply.c:4303
 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:3992
+#: builtin/apply.c:4305
 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:3994
+#: builtin/apply.c:4307
 msgid "apply a patch without touching the working tree"
 msgstr "wendet einen Patch an, ohne Änderungen im Arbeitszweig vorzunehmen"
 
-#: builtin/apply.c:3996
+#: builtin/apply.c:4309
 msgid "also apply the patch (use with --stat/--summary/--check)"
 msgstr "wendet den Patch an (Benutzung mit --stat/--summary/--check)"
 
-#: builtin/apply.c:3998
+#: builtin/apply.c:4311
+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
 msgid "build a temporary index based on embedded index information"
 msgstr ""
 "erstellt eine temporäre Bereitstellung basierend auf den integrierten "
 "Bereitstellungsinformationen"
 
-#: builtin/apply.c:4000
+#: builtin/apply.c:4315
 msgid "paths are separated with NUL character"
 msgstr "Pfade sind getrennt durch NUL Zeichen"
 
-#: builtin/apply.c:4003
+#: builtin/apply.c:4318
 msgid "ensure at least <n> lines of context match"
 msgstr ""
 "stellt sicher, dass mindestens <Anzahl> Zeilen des Kontextes übereinstimmen"
 
-#: builtin/apply.c:4004
+#: builtin/apply.c:4319
 msgid "action"
 msgstr "Aktion"
 
-#: builtin/apply.c:4005
+#: builtin/apply.c:4320
 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:4008 builtin/apply.c:4011
+#: builtin/apply.c:4323 builtin/apply.c:4326
 msgid "ignore changes in whitespace when finding context"
 msgstr "ignoriert Änderungen in Leerzeichen bei der Suche des Kontextes"
 
-#: builtin/apply.c:4014
+#: builtin/apply.c:4329
 msgid "apply the patch in reverse"
 msgstr "wendet den Patch in umgekehrter Reihenfolge an"
 
-#: builtin/apply.c:4016
+#: builtin/apply.c:4331
 msgid "don't expect at least one line of context"
 msgstr "erwartet keinen Kontext"
 
-#: builtin/apply.c:4018
+#: builtin/apply.c:4333
 msgid "leave the rejected hunks in corresponding *.rej files"
 msgstr ""
 "hinterlässt zurückgewiesene Patch-Bereiche in den entsprechenden *.rej "
 "Dateien"
 
-#: builtin/apply.c:4020
+#: builtin/apply.c:4335
 msgid "allow overlapping hunks"
 msgstr "erlaubt sich überlappende Patch-Bereiche"
 
-#: builtin/apply.c:4021
+#: builtin/apply.c:4336
 msgid "be verbose"
 msgstr "erweiterte Ausgaben"
 
-#: builtin/apply.c:4023
+#: builtin/apply.c:4338
 msgid "tolerate incorrectly detected missing new-line at the end of file"
 msgstr "toleriert fehlerhaft erkannten fehlenden Zeilenumbruch am Dateiende"
 
-#: builtin/apply.c:4026
+#: builtin/apply.c:4341
 msgid "do not trust the line counts in the hunk headers"
 msgstr "vertraut nicht den Zeilennummern im Kopf des Patch-Bereiches"
 
-#: builtin/apply.c:4028
+#: builtin/apply.c:4343
 msgid "root"
 msgstr "Wurzelverzeichnis"
 
-#: builtin/apply.c:4029
+#: builtin/apply.c:4344
 msgid "prepend <root> to all filenames"
 msgstr "stellt <Wurzelverzeichnis> vor alle Dateinamen"
 
-#: builtin/apply.c:4050
+#: builtin/apply.c:4366
+msgid "--3way outside a repository"
+msgstr "--3way außerhalb eines Projektarchivs"
+
+#: builtin/apply.c:4374
 msgid "--index outside a repository"
 msgstr "--index außerhalb eines Projektarchivs"
 
-#: builtin/apply.c:4053
+#: builtin/apply.c:4377
 msgid "--cached outside a repository"
 msgstr "--cached außerhalb eines Projektarchivs"
 
-#: builtin/apply.c:4069
+#: builtin/apply.c:4393
 #, c-format
 msgid "can't open patch '%s'"
 msgstr "kann Patch '%s' nicht öffnen"
 
-#: builtin/apply.c:4083
+#: builtin/apply.c:4407
 #, 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:4089 builtin/apply.c:4099
+#: builtin/apply.c:4413 builtin/apply.c:4423
 #, c-format
 msgid "%d line adds whitespace errors."
 msgid_plural "%d lines add whitespace errors."
@@ -1675,7 +2062,7 @@ msgstr "Konnte einige Referenzen nicht lesen"
 #: builtin/branch.c:613
 msgid "cannot rename the current branch while not on any."
 msgstr ""
-"Kann aktuellen Zweig nicht umbennen, solange du dich auf keinem befindest."
+"Kann aktuellen Zweig nicht umbenennen, solange du dich auf keinem befindest."
 
 #: builtin/branch.c:623
 #, c-format
@@ -1716,7 +2103,7 @@ msgstr "Konnte Beschreibungsvorlage für Zweig nicht schreiben: %s"
 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:558
+#: builtin/branch.c:788 builtin/clone.c:561
 msgid "HEAD not found below refs/heads!"
 msgstr "Zweigspitze (HEAD) wurde nicht unter \"refs/heads\" gefunden!"
 
@@ -1743,54 +2130,50 @@ 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:113 builtin/checkout.c:146
+#: 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/checkout.c:115 builtin/checkout.c:148
+#: 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/checkout.c:131
+#: builtin/checkout.c:132
 #, c-format
 msgid "path '%s' does not have all necessary versions"
 msgstr "Pfad '%s' hat nicht alle notwendigen Versionen."
 
-#: builtin/checkout.c:175
+#: builtin/checkout.c:176
 #, c-format
 msgid "path '%s' does not have necessary versions"
 msgstr "Pfad '%s' hat nicht die notwendigen Versionen."
 
-#: builtin/checkout.c:192
+#: builtin/checkout.c:193
 #, c-format
 msgid "path '%s': cannot merge"
 msgstr "Pfad '%s': kann nicht zusammenführen"
 
-#: builtin/checkout.c:209
+#: 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/checkout.c:234 builtin/checkout.c:392
+#: builtin/checkout.c:235 builtin/checkout.c:392
 msgid "corrupt index file"
 msgstr "beschädigte Bereitstellungsdatei"
 
-#: builtin/checkout.c:264 builtin/checkout.c:271
+#: builtin/checkout.c:265 builtin/checkout.c:272
 #, c-format
 msgid "path '%s' is unmerged"
 msgstr "Pfad '%s' ist nicht zusammengeführt."
 
-#: builtin/checkout.c:302 builtin/checkout.c:498 builtin/clone.c:583
-#: builtin/merge.c:812
+#: 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/checkout.c:319 builtin/diff.c:302 builtin/merge.c:408
-msgid "diff_setup_done failed"
-msgstr "diff_setup_done fehlgeschlagen"
-
 #: builtin/checkout.c:414
 msgid "you need to resolve your current index first"
 msgstr "Du musst zuerst deine aktuelle Bereitstellung auflösen."
@@ -1881,7 +2264,7 @@ msgstr "interner Fehler im Revisionsgang"
 msgid "Previous HEAD position was"
 msgstr "Vorherige Position der Zweigspitze (HEAD) war"
 
-#: builtin/checkout.c:724
+#: builtin/checkout.c:724 builtin/checkout.c:919
 msgid "You are on a branch yet to be born"
 msgstr "du bist auf einem Zweig, der noch geboren wird"
 
@@ -1897,47 +2280,47 @@ msgstr "Ungültige Referenz: %s"
 msgid "reference is not a tree: %s"
 msgstr "Referenz ist kein Baum: %s"
 
-#: builtin/checkout.c:974
+#: builtin/checkout.c:976
 msgid "-B cannot be used with -b"
 msgstr "-B kann nicht mit -b benutzt werden"
 
-#: builtin/checkout.c:983
+#: builtin/checkout.c:985
 msgid "--patch is incompatible with all other options"
 msgstr "--patch ist inkompatibel mit allen anderen Optionen"
 
-#: builtin/checkout.c:986
+#: 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:988
+#: builtin/checkout.c:990
 msgid "--detach cannot be used with -t"
 msgstr "--detach kann nicht mit -t benutzt werden"
 
-#: builtin/checkout.c:994
+#: builtin/checkout.c:996
 msgid "--track needs a branch name"
 msgstr "--track benötigt einen Zweignamen"
 
-#: builtin/checkout.c:1001
+#: builtin/checkout.c:1003
 msgid "Missing branch name; try -b"
 msgstr "Vermisse Zweignamen; versuche -b"
 
-#: builtin/checkout.c:1007
+#: builtin/checkout.c:1009
 msgid "--orphan and -b|-B are mutually exclusive"
 msgstr "--orphan und -b|-B sind gegenseitig exklusiv"
 
-#: builtin/checkout.c:1009
+#: builtin/checkout.c:1011
 msgid "--orphan cannot be used with -t"
 msgstr "--orphan kann nicht mit -t benutzt werden"
 
-#: builtin/checkout.c:1019
+#: builtin/checkout.c:1021
 msgid "git checkout: -f and -m are incompatible"
 msgstr "git checkout: -f und -m sind inkompatibel"
 
-#: builtin/checkout.c:1053
+#: builtin/checkout.c:1055
 msgid "invalid path specification"
 msgstr "ungültige Pfadspezifikation"
 
-#: builtin/checkout.c:1061
+#: builtin/checkout.c:1063
 #, c-format
 msgid ""
 "git checkout: updating paths is incompatible with switching branches.\n"
@@ -1948,29 +2331,29 @@ msgstr ""
 "Hast du beabsichtigt '%s' auszuchecken, welcher nicht als Version aufgelöst "
 "werden kann?"
 
-#: builtin/checkout.c:1063
+#: 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:1068
+#: 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:1071
+#: builtin/checkout.c:1073
 msgid ""
 "git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
 "checking out of the index."
 msgstr ""
-"git checkout: --ours/--theirs, --force and --merge sind inkompatibel wenn\n"
+"git checkout: --ours/--theirs, --force und --merge sind inkompatibel wenn\n"
 "du aus der Bereitstellung auscheckst."
 
-#: builtin/checkout.c:1090
+#: builtin/checkout.c:1092
 msgid "Cannot switch branch to a non-commit."
 msgstr "Kann Zweig nur zu einer Version wechseln."
 
-#: builtin/checkout.c:1093
+#: builtin/checkout.c:1095
 msgid "--ours/--theirs is incompatible with switching branches."
 msgstr "--ours/--theirs ist inkompatibel mit den Wechseln von Zweigen."
 
@@ -2023,17 +2406,12 @@ msgstr "Entferne nicht %s\n"
 msgid "reference repository '%s' is not a local directory."
 msgstr "Referenziertes Projektarchiv '%s' ist kein lokales Verzeichnis."
 
-#: builtin/clone.c:302
-#, c-format
-msgid "failed to open '%s'"
-msgstr "Fehler beim Öffnen von '%s'"
-
 #: builtin/clone.c:306
 #, c-format
 msgid "failed to create directory '%s'"
 msgstr "Fehler beim Erstellen von Verzeichnis '%s'"
 
-#: builtin/clone.c:308 builtin/diff.c:75
+#: builtin/clone.c:308 builtin/diff.c:77
 #, c-format
 msgid "failed to stat '%s'"
 msgstr "Konnte '%s' nicht lesen"
@@ -2048,11 +2426,6 @@ msgstr "%s existiert und ist kein Verzeichnis"
 msgid "failed to stat %s\n"
 msgstr "Konnte %s nicht lesen\n"
 
-#: builtin/clone.c:341
-#, c-format
-msgid "failed to unlink '%s'"
-msgstr "Konnte '%s' nicht entfernen"
-
 #: builtin/clone.c:346
 #, c-format
 msgid "failed to create link '%s'"
@@ -2068,80 +2441,80 @@ msgstr "Konnte Datei nicht nach '%s' kopieren"
 msgid "done.\n"
 msgstr "Fertig.\n"
 
-#: builtin/clone.c:440
+#: builtin/clone.c:443
 #, c-format
 msgid "Could not find remote branch %s to clone."
 msgstr "Konnte zu klonenden externer Zweig %s nicht finden."
 
-#: builtin/clone.c:549
+#: builtin/clone.c:552
 msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n"
 msgstr ""
 "Externe Zweigspitze (HEAD) bezieht sich auf eine nicht existierende Referenz "
 "und kann nicht ausgecheckt werden.\n"
 
-#: builtin/clone.c:639
+#: builtin/clone.c:642
 msgid "Too many arguments."
 msgstr "Zu viele Argumente."
 
-#: builtin/clone.c:643
+#: builtin/clone.c:646
 msgid "You must specify a repository to clone."
 msgstr "Du musst ein Projektarchiv zum Klonen angeben."
 
-#: builtin/clone.c:654
+#: builtin/clone.c:657
 #, c-format
 msgid "--bare and --origin %s options are incompatible."
 msgstr "--bare und --origin %s Optionen sind inkompatibel."
 
-#: builtin/clone.c:668
+#: builtin/clone.c:671
 #, c-format
 msgid "repository '%s' does not exist"
 msgstr "Projektarchiv '%s' existiert nicht."
 
-#: builtin/clone.c:673
+#: builtin/clone.c:676
 msgid "--depth is ignored in local clones; use file:// instead."
 msgstr "--depth wird in lokalen Klonen ignoriert; benutze stattdessen file://."
 
-#: builtin/clone.c:683
+#: builtin/clone.c:686
 #, 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:693
+#: builtin/clone.c:696
 #, c-format
 msgid "working tree '%s' already exists."
 msgstr "Arbeitsbaum '%s' existiert bereits."
 
-#: builtin/clone.c:706 builtin/clone.c:720
+#: builtin/clone.c:709 builtin/clone.c:723
 #, c-format
 msgid "could not create leading directories of '%s'"
 msgstr "Konnte führende Verzeichnisse von '%s' nicht erstellen."
 
-#: builtin/clone.c:709
+#: builtin/clone.c:712
 #, c-format
 msgid "could not create work tree dir '%s'."
 msgstr "Konnte Arbeitsverzeichnis '%s' nicht erstellen."
 
-#: builtin/clone.c:728
+#: builtin/clone.c:731
 #, c-format
 msgid "Cloning into bare repository '%s'...\n"
 msgstr "Klone in bloßes Projektarchiv '%s'...\n"
 
-#: builtin/clone.c:730
+#: builtin/clone.c:733
 #, c-format
 msgid "Cloning into '%s'...\n"
 msgstr "Klone nach '%s'...\n"
 
-#: builtin/clone.c:786
+#: builtin/clone.c:789
 #, c-format
 msgid "Don't know how to clone %s"
 msgstr "Weiß nicht wie %s zu klonen ist."
 
-#: builtin/clone.c:835
+#: builtin/clone.c:838
 #, c-format
 msgid "Remote branch %s not found in upstream %s"
 msgstr "externer Zweig %s nicht im anderen Projektarchiv %s gefunden"
 
-#: builtin/clone.c:842
+#: builtin/clone.c:845
 msgid "You appear to have cloned an empty repository."
 msgstr "Du scheinst ein leeres Projektarchiv geklont zu haben."
 
@@ -2202,97 +2575,97 @@ msgstr ""
 "\n"
 "Andernfalls benutze bitte 'git reset'\n"
 
-#: builtin/commit.c:253
+#: builtin/commit.c:256
 msgid "failed to unpack HEAD tree object"
 msgstr "Fehler beim Entpacken des Baum-Objektes der Zweigspitze (HEAD)."
 
-#: builtin/commit.c:295
+#: builtin/commit.c:298
 msgid "unable to create temporary index"
 msgstr "Konnte temporäre Bereitstellung nicht erstellen."
 
-#: builtin/commit.c:301
+#: builtin/commit.c:304
 msgid "interactive add failed"
 msgstr "interaktives Hinzufügen fehlgeschlagen"
 
-#: builtin/commit.c:334 builtin/commit.c:355 builtin/commit.c:405
+#: builtin/commit.c:337 builtin/commit.c:358 builtin/commit.c:408
 msgid "unable to write new_index file"
 msgstr "Konnte new_index Datei nicht schreiben"
 
-#: builtin/commit.c:386
+#: builtin/commit.c:389
 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:388
+#: builtin/commit.c:391
 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:398
+#: builtin/commit.c:401
 msgid "cannot read the index"
 msgstr "Kann Bereitstellung nicht lesen"
 
-#: builtin/commit.c:418
+#: builtin/commit.c:421
 msgid "unable to write temporary index file"
 msgstr "Konnte temporäre Bereitstellungsdatei nicht schreiben."
 
-#: builtin/commit.c:493 builtin/commit.c:499
+#: builtin/commit.c:496 builtin/commit.c:502
 #, c-format
 msgid "invalid commit: %s"
 msgstr "Ungültige Version: %s"
 
-#: builtin/commit.c:522
+#: builtin/commit.c:525
 msgid "malformed --author parameter"
 msgstr "Fehlerhafter --author Parameter"
 
-#: builtin/commit.c:582
+#: builtin/commit.c:585
 #, c-format
 msgid "Malformed ident string: '%s'"
 msgstr "Fehlerhafte Identifikations-String: '%s'"
 
-#: builtin/commit.c:620 builtin/commit.c:653 builtin/commit.c:967
+#: builtin/commit.c:623 builtin/commit.c:656 builtin/commit.c:970
 #, c-format
 msgid "could not lookup commit %s"
 msgstr "Konnte Version %s nicht nachschlagen"
 
-#: builtin/commit.c:632 builtin/shortlog.c:296
+#: builtin/commit.c:635 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:634
+#: builtin/commit.c:637
 msgid "could not read log from standard input"
 msgstr "Konnte Log nicht von Standard-Eingabe lesen."
 
-#: builtin/commit.c:638
+#: builtin/commit.c:641
 #, c-format
 msgid "could not read log file '%s'"
 msgstr "Konnte Log-Datei '%s' nicht lesen"
 
-#: builtin/commit.c:644
+#: builtin/commit.c:647
 msgid "commit has empty message"
 msgstr "Version hat eine leere Beschreibung"
 
-#: builtin/commit.c:660
+#: builtin/commit.c:663
 msgid "could not read MERGE_MSG"
 msgstr "Konnte MERGE_MSG nicht lesen"
 
-#: builtin/commit.c:664
+#: builtin/commit.c:667
 msgid "could not read SQUASH_MSG"
 msgstr "Konnte SQUASH_MSG nicht lesen"
 
-#: builtin/commit.c:668
+#: builtin/commit.c:671
 #, c-format
 msgid "could not read '%s'"
 msgstr "Konnte '%s' nicht lesen"
 
-#: builtin/commit.c:720
+#: builtin/commit.c:723
 msgid "could not write commit template"
 msgstr "Konnte Versionsvorlage nicht schreiben"
 
-#: builtin/commit.c:731
+#: builtin/commit.c:734
 #, c-format
 msgid ""
 "\n"
@@ -2307,7 +2680,7 @@ msgstr ""
 "\t%s\n"
 "und versuche es erneut.\n"
 
-#: builtin/commit.c:736
+#: builtin/commit.c:739
 #, c-format
 msgid ""
 "\n"
@@ -2322,7 +2695,7 @@ msgstr ""
 "\t%s\n"
 "und versuche es erneut.\n"
 
-#: builtin/commit.c:748
+#: builtin/commit.c:751
 msgid ""
 "Please enter the commit message for your changes. Lines starting\n"
 "with '#' will be ignored, and an empty message aborts the commit.\n"
@@ -2331,7 +2704,7 @@ msgstr ""
 "die mit '#' beginnen, werden ignoriert, und eine leere Versionsbeschreibung\n"
 "bricht die Eintragung ab.\n"
 
-#: builtin/commit.c:753
+#: builtin/commit.c:756
 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"
@@ -2342,171 +2715,171 @@ msgstr ""
 "entfernen.\n"
 "Eine leere Versionsbeschreibung bricht die Eintragung ab.\n"
 
-#: builtin/commit.c:766
+#: builtin/commit.c:769
 #, c-format
 msgid "%sAuthor:    %s"
 msgstr "%sAutor:    %s"
 
-#: builtin/commit.c:773
+#: builtin/commit.c:776
 #, c-format
 msgid "%sCommitter: %s"
 msgstr "%sEintragender: %s"
 
-#: builtin/commit.c:793
+#: builtin/commit.c:796
 msgid "Cannot read index"
 msgstr "Kann Bereitstellung nicht lesen"
 
-#: builtin/commit.c:830
+#: builtin/commit.c:833
 msgid "Error building trees"
 msgstr "Fehler beim Erzeugen der Zweige"
 
-#: builtin/commit.c:845 builtin/tag.c:361
+#: builtin/commit.c:848 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:942
+#: builtin/commit.c:945
 #, c-format
 msgid "No existing author found with '%s'"
 msgstr "Kein existierender Autor mit '%s' gefunden."
 
-#: builtin/commit.c:957 builtin/commit.c:1157
+#: builtin/commit.c:960 builtin/commit.c:1160
 #, c-format
 msgid "Invalid untracked files mode '%s'"
 msgstr "Ungültiger Modus '%s' für unbeobachtete Dateien"
 
-#: builtin/commit.c:997
+#: builtin/commit.c:1000
 msgid "Using both --reset-author and --author does not make sense"
 msgstr "Verwendung von --reset-author und --author macht keinen Sinn."
 
-#: builtin/commit.c:1008
+#: builtin/commit.c:1011
 msgid "You have nothing to amend."
 msgstr "Du hast nichts zum nachbessern."
 
-#: builtin/commit.c:1011
+#: builtin/commit.c:1014
 msgid "You are in the middle of a merge -- cannot amend."
 msgstr "Eine Zusammenführung ist im Gange -- kann nicht nachbessern."
 
-#: builtin/commit.c:1013
+#: builtin/commit.c:1016
 msgid "You are in the middle of a cherry-pick -- cannot amend."
 msgstr "\"cherry-pick\" ist im Gange -- kann nicht nachbessern."
 
-#: builtin/commit.c:1016
+#: builtin/commit.c:1019
 msgid "Options --squash and --fixup cannot be used together"
 msgstr ""
 "Die Optionen --squash und --fixup können nicht gemeinsam benutzt werden."
 
-#: builtin/commit.c:1026
+#: builtin/commit.c:1029
 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:1028
+#: builtin/commit.c:1031
 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:1036
+#: builtin/commit.c:1039
 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:1053
+#: builtin/commit.c:1056
 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:1055
+#: builtin/commit.c:1058
 msgid "No paths with --include/--only does not make sense."
 msgstr "--include/--only machen ohne Pfade keinen Sinn."
 
-#: builtin/commit.c:1057
+#: builtin/commit.c:1060
 msgid "Clever... amending the last one with dirty index."
 msgstr ""
 "Klug... die letzte Version mit einer unsauberen Bereitstellung nachbessern."
 
-#: builtin/commit.c:1059
+#: builtin/commit.c:1062
 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:1069 builtin/tag.c:577
+#: builtin/commit.c:1072 builtin/tag.c:577
 #, c-format
 msgid "Invalid cleanup mode %s"
 msgstr "Ungültiger \"cleanup\" Modus %s"
 
-#: builtin/commit.c:1074
+#: builtin/commit.c:1077
 msgid "Paths with -a does not make sense."
 msgstr "Pfade mit -a machen keinen Sinn."
 
-#: builtin/commit.c:1257
+#: builtin/commit.c:1260
 msgid "couldn't look up newly created commit"
 msgstr "Konnte neu erstellte Version nicht nachschlagen."
 
-#: builtin/commit.c:1259
+#: builtin/commit.c:1262
 msgid "could not parse newly created commit"
 msgstr "Konnte neulich erstellte Version nicht analysieren."
 
-#: builtin/commit.c:1300
+#: builtin/commit.c:1303
 msgid "detached HEAD"
 msgstr "losgelöste Zweigspitze (HEAD)"
 
-#: builtin/commit.c:1302
+#: builtin/commit.c:1305
 msgid " (root-commit)"
 msgstr " (Basis-Version)"
 
-#: builtin/commit.c:1446
+#: builtin/commit.c:1449
 msgid "could not parse HEAD commit"
 msgstr "Konnte Version der Zweigspitze (HEAD) nicht analysieren."
 
-#: builtin/commit.c:1484 builtin/merge.c:509
+#: builtin/commit.c:1487 builtin/merge.c:508
 #, c-format
 msgid "could not open '%s' for reading"
 msgstr "Konnte '%s' nicht zum Lesen öffnen."
 
-#: builtin/commit.c:1491
+#: builtin/commit.c:1494
 #, c-format
 msgid "Corrupt MERGE_HEAD file (%s)"
 msgstr "Beschädigte MERGE_HEAD-Datei (%s)"
 
-#: builtin/commit.c:1498
+#: builtin/commit.c:1501
 msgid "could not read MERGE_MODE"
 msgstr "Konnte MERGE_MODE nicht lesen"
 
-#: builtin/commit.c:1517
+#: builtin/commit.c:1520
 #, c-format
 msgid "could not read commit message: %s"
 msgstr "Konnte Versionsbeschreibung nicht lesen: %s"
 
-#: builtin/commit.c:1531
+#: builtin/commit.c:1534
 #, c-format
 msgid "Aborting commit; you did not edit the message.\n"
 msgstr "Eintragung abgebrochen; du hast die Beschreibung nicht editiert.\n"
 
-#: builtin/commit.c:1536
+#: builtin/commit.c:1539
 #, c-format
 msgid "Aborting commit due to empty commit message.\n"
 msgstr "Eintragung aufgrund leerer Versionsbeschreibung abgebrochen.\n"
 
-#: builtin/commit.c:1551 builtin/merge.c:936 builtin/merge.c:961
+#: builtin/commit.c:1554 builtin/merge.c:935 builtin/merge.c:960
 msgid "failed to write commit object"
 msgstr "Fehler beim Schreiben des Versionsobjektes."
 
-#: builtin/commit.c:1572
+#: builtin/commit.c:1575
 msgid "cannot lock HEAD ref"
 msgstr "Kann Referenz der Zweigspitze (HEAD) nicht sperren."
 
-#: builtin/commit.c:1576
+#: builtin/commit.c:1579
 msgid "cannot update HEAD ref"
 msgstr "Kann Referenz der Zweigspitze (HEAD) nicht aktualisieren."
 
-#: builtin/commit.c:1587
+#: 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"
 "not exceeded, and then \"git reset HEAD\" to recover."
 msgstr ""
 "Das Projektarchiv wurde aktualisiert, aber die \"new_index\"-Datei\n"
-"konnte nicht geschrieben werden. Prüfe, dass dein Speicher nicht\n"
+"konnte nicht geschrieben werden. Prüfe, dass deine Festplatte nicht\n"
 "voll und Dein Kontingent nicht aufgebraucht ist und führe\n"
 "anschließend \"git reset HEAD\" zu Wiederherstellung aus."
 
@@ -2594,36 +2967,36 @@ msgstr "Keine Namen gefunden, kann nichts beschreiben."
 msgid "--dirty is incompatible with committishes"
 msgstr "--dirty ist inkompatibel mit Versionen"
 
-#: builtin/diff.c:77
+#: builtin/diff.c:79
 #, c-format
 msgid "'%s': not a regular file or symlink"
 msgstr "'%s': keine reguläre Datei oder symbolischer Link"
 
-#: builtin/diff.c:220
+#: builtin/diff.c:224
 #, c-format
 msgid "invalid option: %s"
 msgstr "Ungültige Option: %s"
 
-#: builtin/diff.c:297
+#: builtin/diff.c:301
 msgid "Not a git repository"
 msgstr "Kein Git-Projektarchiv"
 
-#: builtin/diff.c:347
+#: builtin/diff.c:344
 #, c-format
 msgid "invalid object '%s' given."
 msgstr "Objekt '%s' ist ungültig."
 
-#: builtin/diff.c:352
+#: builtin/diff.c:349
 #, c-format
 msgid "more than %d trees given: '%s'"
 msgstr "Mehr als %d Zweige angegeben: '%s'"
 
-#: builtin/diff.c:362
+#: builtin/diff.c:359
 #, c-format
 msgid "more than two blobs given: '%s'"
 msgstr "Mehr als zwei Blobs angegeben: '%s'"
 
-#: builtin/diff.c:370
+#: builtin/diff.c:367
 #, c-format
 msgid "unhandled object '%s' given."
 msgstr "unbehandeltes Objekt '%s' angegeben"
@@ -2827,85 +3200,85 @@ msgstr ""
 msgid "grep: failed to create thread: %s"
 msgstr "grep: Fehler beim Erzeugen eines Thread: %s"
 
-#: builtin/grep.c:402
+#: builtin/grep.c:454
 #, c-format
 msgid "Failed to chdir: %s"
 msgstr "Fehler beim Verzeichniswechsel: %s"
 
-#: builtin/grep.c:478 builtin/grep.c:512
+#: builtin/grep.c:530 builtin/grep.c:564
 #, c-format
 msgid "unable to read tree (%s)"
 msgstr "konnte Zweig (%s) nicht lesen"
 
-#: builtin/grep.c:526
+#: builtin/grep.c:578
 #, 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:584
+#: builtin/grep.c:636
 #, c-format
 msgid "switch `%c' expects a numerical value"
 msgstr "Schalter '%c' erwartet einen numerischen Wert"
 
-#: builtin/grep.c:601
+#: builtin/grep.c:653
 #, c-format
 msgid "cannot open '%s'"
 msgstr "kann '%s' nicht öffnen"
 
-#: builtin/grep.c:885
+#: builtin/grep.c:917
 msgid "no pattern given."
 msgstr "keine Muster angegeben"
 
-#: builtin/grep.c:899
+#: builtin/grep.c:931
 #, c-format
 msgid "bad object %s"
 msgstr "ungültiges Objekt %s"
 
-#: builtin/grep.c:940
+#: builtin/grep.c:972
 msgid "--open-files-in-pager only works on the worktree"
 msgstr "--open-files-in-pager arbeitet nur innerhalb des Arbeitsbaums"
 
-#: builtin/grep.c:963
+#: builtin/grep.c:995
 msgid "--cached or --untracked cannot be used with --no-index."
 msgstr "--cached oder --untracked kann nicht mit --no-index benutzt werden"
 
-#: builtin/grep.c:968
+#: builtin/grep.c:1000
 msgid "--no-index or --untracked cannot be used with revs."
 msgstr "--no-index oder --untracked kann nicht mit Versionen benutzt werden"
 
-#: builtin/grep.c:971
+#: builtin/grep.c:1003
 msgid "--[no-]exclude-standard cannot be used for tracked contents."
 msgstr ""
 "--[no-]exlude-standard kann nicht mit beobachteten Inhalten benutzt werden"
 
-#: builtin/grep.c:979
+#: builtin/grep.c:1011
 msgid "both --cached and trees are given."
 msgstr "sowohl --cached als auch Zweige gegeben"
 
-#: builtin/help.c:59
+#: builtin/help.c:65
 #, c-format
 msgid "unrecognized help format '%s'"
 msgstr "nicht erkanntes Hilfeformat: %s"
 
-#: builtin/help.c:87
+#: builtin/help.c:93
 msgid "Failed to start emacsclient."
 msgstr "Konnte emacsclient nicht starten."
 
-#: builtin/help.c:100
+#: builtin/help.c:106
 msgid "Failed to parse emacsclient version."
 msgstr "Konnte Version des emacsclient nicht parsen."
 
-#: builtin/help.c:108
+#: builtin/help.c:114
 #, c-format
 msgid "emacsclient version '%d' too old (< 22)."
 msgstr "Version des emacsclient '%d' ist zu alt (< 22)."
 
-#: builtin/help.c:126 builtin/help.c:154 builtin/help.c:163 builtin/help.c:171
+#: 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 "Fehler beim Ausführen von '%s': %s"
 
-#: builtin/help.c:211
+#: builtin/help.c:217
 #, c-format
 msgid ""
 "'%s': path for unsupported man viewer.\n"
@@ -2914,7 +3287,7 @@ msgstr ""
 "'%s': Pfad für nicht unterstützten Handbuchbetrachter.\n"
 "Du könntest stattdessen 'man.<Werkzeug>.cmd' benutzen."
 
-#: builtin/help.c:223
+#: builtin/help.c:229
 #, c-format
 msgid ""
 "'%s': cmd for supported man viewer.\n"
@@ -2923,267 +3296,273 @@ msgstr ""
 "'%s': Kommando für unterstützten Handbuchbetrachter.\n"
 "Du könntest stattdessen 'man.<Werkzeug>.path' benutzen."
 
-#: builtin/help.c:287
+#: builtin/help.c:299
 msgid "The most commonly used git commands are:"
 msgstr "Die allgemein verwendeten Git-Kommandos sind:"
 
-#: builtin/help.c:355
+#: builtin/help.c:367
 #, c-format
 msgid "'%s': unknown man viewer."
 msgstr "'%s': unbekannter Handbuch-Betrachter."
 
-#: builtin/help.c:372
+#: builtin/help.c:384
 msgid "no man viewer handled the request"
 msgstr "kein Handbuch-Betrachter konnte mit dieser Anfrage umgehen"
 
-#: builtin/help.c:380
+#: builtin/help.c:392
 msgid "no info viewer handled the request"
 msgstr "kein Informations-Betrachter konnte mit dieser Anfrage umgehen"
 
-#: builtin/help.c:391
-#, c-format
-msgid "'%s': not a documentation directory."
-msgstr "'%s' ist kein Dokumentationsverzeichnis"
-
-#: builtin/help.c:432 builtin/help.c:439
+#: builtin/help.c:447 builtin/help.c:454
 #, c-format
 msgid "usage: %s%s"
 msgstr "Verwendung: %s%s"
 
-#: builtin/help.c:453
+#: builtin/help.c:470
 #, c-format
 msgid "`git %s' is aliased to `%s'"
 msgstr "für `git %s' wurde der Alias `%s' angelegt"
 
-#: builtin/index-pack.c:169
+#: builtin/index-pack.c:170
 #, c-format
 msgid "object type mismatch at %s"
 msgstr "Objekt-Typen passen bei %s nicht zusammen"
 
-#: builtin/index-pack.c:189
+#: builtin/index-pack.c:190
 msgid "object of unexpected type"
 msgstr "Objekt hat unerwarteten Typ"
 
-#: builtin/index-pack.c:226
+#: builtin/index-pack.c:227
 #, c-format
 msgid "cannot fill %d byte"
 msgid_plural "cannot fill %d bytes"
 msgstr[0] "kann %d Byte nicht lesen"
 msgstr[1] "kann %d Bytes nicht lesen"
 
-#: builtin/index-pack.c:236
+#: builtin/index-pack.c:237
 msgid "early EOF"
 msgstr "zu frühes Dateiende"
 
-#: builtin/index-pack.c:237
+#: builtin/index-pack.c:238
 msgid "read error on input"
 msgstr "Fehler beim Lesen der Eingabe"
 
-#: builtin/index-pack.c:249
+#: builtin/index-pack.c:250
 msgid "used more bytes than were available"
 msgstr "verwendete mehr Bytes als verfügbar waren"
 
-#: builtin/index-pack.c:256
+#: builtin/index-pack.c:257
 msgid "pack too large for current definition of off_t"
 msgstr "Paket ist zu groß für die aktuelle Definition von off_t"
 
-#: builtin/index-pack.c:272
+#: builtin/index-pack.c:273
 #, c-format
 msgid "unable to create '%s'"
 msgstr "konnte '%s' nicht erstellen"
 
-#: builtin/index-pack.c:277
+#: builtin/index-pack.c:278
 #, c-format
 msgid "cannot open packfile '%s'"
 msgstr "Kann Paketdatei '%s' nicht öffnen"
 
-#: builtin/index-pack.c:291
+#: builtin/index-pack.c:292
 msgid "pack signature mismatch"
 msgstr "Paketsignatur stimmt nicht überein"
 
-#: builtin/index-pack.c:311
+#: builtin/index-pack.c:312
 #, c-format
 msgid "pack has bad object at offset %lu: %s"
 msgstr "Paket hat ein ungültiges Objekt bei Versatz %lu: %s"
 
-#: builtin/index-pack.c:405
+#: builtin/index-pack.c:434
 #, c-format
 msgid "inflate returned %d"
 msgstr "Dekomprimierung gab %d zurück"
 
-#: builtin/index-pack.c:450
+#: builtin/index-pack.c:483
 msgid "offset value overflow for delta base object"
 msgstr "Wert für Versatz bei Differenzobjekt übergelaufen"
 
-#: builtin/index-pack.c:458
+#: builtin/index-pack.c:491
 msgid "delta base offset is out of bound"
 msgstr ""
 "Wert für Versatz bei Differenzobjekt liegt außerhalb des gültigen Bereichs"
 
-#: builtin/index-pack.c:466
+#: builtin/index-pack.c:499
 #, c-format
 msgid "unknown object type %d"
 msgstr "Unbekannter Objekt-Typ %d"
 
-#: builtin/index-pack.c:495
+#: builtin/index-pack.c:530
 msgid "cannot pread pack file"
 msgstr "Kann Paketdatei %s nicht lesen"
 
-#: builtin/index-pack.c:497
+#: builtin/index-pack.c:532
 #, c-format
 msgid "premature end of pack file, %lu byte missing"
 msgid_plural "premature end of pack file, %lu bytes missing"
 msgstr[0] "frühzeitiges Ende der Paketdatei, vermisse %lu Byte"
 msgstr[1] "frühzeitiges Ende der Paketdatei, vermisse %lu Bytes"
 
-#: builtin/index-pack.c:510
+#: builtin/index-pack.c:558
 msgid "serious inflate inconsistency"
 msgstr "ernsthafte Inkonsistenz nach Dekomprimierung"
 
-#: builtin/index-pack.c:583
-#, c-format
-msgid "cannot read existing object %s"
-msgstr "Kann existierendes Objekt %s nicht lesen."
-
-#: builtin/index-pack.c:586
+#: builtin/index-pack.c:649 builtin/index-pack.c:655 builtin/index-pack.c:678
+#: builtin/index-pack.c:712 builtin/index-pack.c:721
 #, c-format
 msgid "SHA1 COLLISION FOUND WITH %s !"
 msgstr "SHA1 KOLLISION MIT %s GEFUNDEN !"
 
-#: builtin/index-pack.c:598
+#: builtin/index-pack.c:652 builtin/pack-objects.c:170
+#: builtin/pack-objects.c:262
+#, c-format
+msgid "unable to read %s"
+msgstr "kann %s nicht lesen"
+
+#: builtin/index-pack.c:718
+#, c-format
+msgid "cannot read existing object %s"
+msgstr "Kann existierendes Objekt %s nicht lesen."
+
+#: builtin/index-pack.c:732
 #, c-format
 msgid "invalid blob object %s"
 msgstr "ungültiges Blob-Objekt %s"
 
-#: builtin/index-pack.c:610
+#: builtin/index-pack.c:747
 #, c-format
 msgid "invalid %s"
 msgstr "Ungültiger Objekt-Typ %s"
 
-#: builtin/index-pack.c:612
+#: builtin/index-pack.c:749
 msgid "Error in object"
 msgstr "Fehler in Objekt"
 
-#: builtin/index-pack.c:614
+#: builtin/index-pack.c:751
 #, c-format
 msgid "Not all child objects of %s are reachable"
 msgstr "Nicht alle Kind-Objekte von %s sind erreichbar"
 
-#: builtin/index-pack.c:687 builtin/index-pack.c:713
+#: builtin/index-pack.c:821 builtin/index-pack.c:847
 msgid "failed to apply delta"
 msgstr "Konnte Dateiunterschied nicht anwenden"
 
-#: builtin/index-pack.c:850
+#: builtin/index-pack.c:986
 msgid "Receiving objects"
 msgstr "Empfange Objekte"
 
-#: builtin/index-pack.c:850
+#: builtin/index-pack.c:986
 msgid "Indexing objects"
 msgstr "Indiziere Objekte"
 
-#: builtin/index-pack.c:872
+#: builtin/index-pack.c:1012
 msgid "pack is corrupted (SHA1 mismatch)"
 msgstr "Paket ist beschädigt (SHA1 unterschiedlich)"
 
-#: builtin/index-pack.c:877
+#: builtin/index-pack.c:1017
 msgid "cannot fstat packfile"
 msgstr "kann Paketdatei nicht lesen"
 
-#: builtin/index-pack.c:880
+#: builtin/index-pack.c:1020
 msgid "pack has junk at the end"
 msgstr "Paketende enthält nicht verwendbaren Inhalt"
 
-#: builtin/index-pack.c:903
+#: builtin/index-pack.c:1031
+msgid "confusion beyond insanity in parse_pack_objects()"
+msgstr "Fehler beim Ausführen von \"parse_pack_objects()\""
+
+#: builtin/index-pack.c:1054
 msgid "Resolving deltas"
 msgstr "Löse Unterschiede auf"
 
-#: builtin/index-pack.c:954
+#: builtin/index-pack.c:1105
 msgid "confusion beyond insanity"
 msgstr "Fehler beim Auflösen der Unterschiede"
 
-#: builtin/index-pack.c:973
+#: builtin/index-pack.c:1124
 #, 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:998
+#: builtin/index-pack.c:1149
 #, c-format
 msgid "unable to deflate appended object (%d)"
 msgstr "Konnte angehängtes Objekt (%d) nicht komprimieren"
 
-#: builtin/index-pack.c:1077
+#: builtin/index-pack.c:1228
 #, c-format
 msgid "local object %s is corrupt"
 msgstr "lokales Objekt %s ist beschädigt"
 
-#: builtin/index-pack.c:1101
+#: builtin/index-pack.c:1252
 msgid "error while closing pack file"
 msgstr "Fehler beim Schließen der Paketdatei"
 
-#: builtin/index-pack.c:1114
+#: builtin/index-pack.c:1265
 #, c-format
 msgid "cannot write keep file '%s'"
 msgstr "Kann Paketbeschreibungsdatei '%s' nicht schreiben"
 
-#: builtin/index-pack.c:1122
+#: builtin/index-pack.c:1273
 #, c-format
 msgid "cannot close written keep file '%s'"
 msgstr "Kann eben erstellte Paketbeschreibungsdatei '%s' nicht schließen"
 
-#: builtin/index-pack.c:1135
+#: builtin/index-pack.c:1286
 msgid "cannot store pack file"
 msgstr "Kann Paketdatei nicht speichern"
 
-#: builtin/index-pack.c:1146
+#: builtin/index-pack.c:1297
 msgid "cannot store index file"
 msgstr "Kann Indexdatei nicht speichern"
 
-#: builtin/index-pack.c:1247
+#: builtin/index-pack.c:1398
 #, c-format
 msgid "Cannot open existing pack file '%s'"
 msgstr "Kann existierende Paketdatei '%s' nicht öffnen"
 
-#: builtin/index-pack.c:1249
+#: builtin/index-pack.c:1400
 #, 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:1296
+#: builtin/index-pack.c:1447
 #, 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:1303
+#: builtin/index-pack.c:1454
 #, 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:1330
+#: builtin/index-pack.c:1481
 msgid "Cannot come back to cwd"
 msgstr "Kann nicht zurück zu Arbeitsverzeichnis wechseln"
 
-#: builtin/index-pack.c:1374 builtin/index-pack.c:1377
-#: builtin/index-pack.c:1389 builtin/index-pack.c:1393
+#: builtin/index-pack.c:1525 builtin/index-pack.c:1528
+#: builtin/index-pack.c:1540 builtin/index-pack.c:1544
 #, c-format
 msgid "bad %s"
 msgstr "%s ist ungültig"
 
-#: builtin/index-pack.c:1407
+#: builtin/index-pack.c:1558
 msgid "--fix-thin cannot be used without --stdin"
 msgstr "--fix-thin kann nicht ohne --stdin benutzt werden"
 
-#: builtin/index-pack.c:1411 builtin/index-pack.c:1421
+#: builtin/index-pack.c:1562 builtin/index-pack.c:1572
 #, c-format
 msgid "packfile name '%s' does not end with '.pack'"
 msgstr "Name der Paketdatei '%s' endet nicht mit '.pack'"
 
-#: builtin/index-pack.c:1430
+#: builtin/index-pack.c:1581
 msgid "--verify with no packfile name given"
 msgstr "--verify ohne Name der Paketdatei angegeben"
 
@@ -3257,63 +3636,63 @@ msgstr "kopiere keine Vorlagen mit einer falschen Formatversion %d von '%s'"
 msgid "insane git directory %s"
 msgstr "ungültiges Git-Verzeichnis %s"
 
-#: builtin/init-db.c:322 builtin/init-db.c:325
+#: builtin/init-db.c:323 builtin/init-db.c:326
 #, c-format
 msgid "%s already exists"
 msgstr "%s existiert bereits"
 
-#: builtin/init-db.c:354
+#: builtin/init-db.c:355
 #, c-format
 msgid "unable to handle file type %d"
 msgstr "kann nicht mit Dateityp %d umgehen"
 
-#: builtin/init-db.c:357
+#: builtin/init-db.c:358
 #, c-format
 msgid "unable to move %s to %s"
 msgstr "Konnte %s nicht nach %s verschieben"
 
-#: builtin/init-db.c:362
+#: builtin/init-db.c:363
 #, c-format
 msgid "Could not create git link %s"
-msgstr "Konnte git-Verknüfung %s nicht erstellen"
+msgstr "Konnte git-Verknüpfung %s nicht erstellen"
 
 #.
 #. * TRANSLATORS: The first '%s' is either "Reinitialized
 #. * existing" or "Initialized empty", the second " shared" or
 #. * "", and the last '%s%s' is the verbatim directory name.
 #.
-#: builtin/init-db.c:419
+#: builtin/init-db.c:420
 #, c-format
 msgid "%s%s Git repository in %s%s\n"
 msgstr "%s%s Git-Projektarchiv in %s%s\n"
 
-#: builtin/init-db.c:420
+#: builtin/init-db.c:421
 msgid "Reinitialized existing"
 msgstr "Reinitialisierte existierendes"
 
-#: builtin/init-db.c:420
+#: builtin/init-db.c:421
 msgid "Initialized empty"
 msgstr "Initialisierte leeres"
 
-#: builtin/init-db.c:421
+#: builtin/init-db.c:422
 msgid " shared"
 msgstr " gemeinsames"
 
-#: builtin/init-db.c:440
+#: builtin/init-db.c:441
 msgid "cannot tell cwd"
 msgstr "kann aktuelles Arbeitsverzeichnis nicht ermitteln"
 
-#: builtin/init-db.c:521 builtin/init-db.c:528
+#: builtin/init-db.c:522 builtin/init-db.c:529
 #, c-format
 msgid "cannot mkdir %s"
 msgstr "kann Verzeichnis %s nicht erstellen"
 
-#: builtin/init-db.c:532
+#: builtin/init-db.c:533
 #, c-format
 msgid "cannot chdir to %s"
 msgstr "kann nicht in Verzeichnis %s wechseln"
 
-#: builtin/init-db.c:554
+#: builtin/init-db.c:555
 #, c-format
 msgid ""
 "%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-"
@@ -3322,103 +3701,103 @@ msgstr ""
 "%s (oder --work-tree=<Verzeichnis>) nicht erlaubt ohne Spezifizierung von %s "
 "(oder --git-dir=<Verzeichnis>)"
 
-#: builtin/init-db.c:578
+#: builtin/init-db.c:579
 msgid "Cannot access current working directory"
 msgstr "Kann nicht auf aktuelles Arbeitsverzeichnis zugreifen."
 
-#: builtin/init-db.c:585
+#: builtin/init-db.c:586
 #, c-format
 msgid "Cannot access work tree '%s'"
 msgstr "Kann nicht auf Arbeitsbaum '%s' zugreifen."
 
-#: builtin/log.c:188
+#: builtin/log.c:189
 #, c-format
 msgid "Final output: %d %s\n"
 msgstr "letzte Ausgabe: %d %s\n"
 
-#: builtin/log.c:401 builtin/log.c:489
+#: builtin/log.c:403 builtin/log.c:494
 #, c-format
 msgid "Could not read object %s"
 msgstr "Kann Objekt %s nicht lesen."
 
-#: builtin/log.c:513
+#: builtin/log.c:518
 #, c-format
 msgid "Unknown type: %d"
 msgstr "Unbekannter Typ: %d"
 
-#: builtin/log.c:602
+#: builtin/log.c:608
 msgid "format.headers without value"
 msgstr "format.headers ohne Wert"
 
-#: builtin/log.c:676
+#: builtin/log.c:682
 msgid "name of output directory is too long"
 msgstr "Name des Ausgabeverzeichnisses ist zu lang."
 
-#: builtin/log.c:687
+#: builtin/log.c:693
 #, c-format
 msgid "Cannot open patch file %s"
 msgstr "Kann Patch-Datei %s nicht öffnen"
 
-#: builtin/log.c:701
+#: builtin/log.c:707
 msgid "Need exactly one range."
 msgstr "Brauche genau einen Versionsbereich."
 
-#: builtin/log.c:709
+#: builtin/log.c:715
 msgid "Not a range."
 msgstr "Kein Versionsbereich."
 
-#: builtin/log.c:786
+#: builtin/log.c:789
 msgid "Cover letter needs email format"
 msgstr "Anschreiben benötigt E-Mail-Format"
 
-#: builtin/log.c:859
+#: builtin/log.c:862
 #, c-format
 msgid "insane in-reply-to: %s"
 msgstr "ungültiges in-reply-to: %s"
 
-#: builtin/log.c:932
+#: builtin/log.c:935
 msgid "Two output directories?"
 msgstr "Zwei Ausgabeverzeichnisse?"
 
-#: builtin/log.c:1153
+#: builtin/log.c:1157
 #, c-format
 msgid "bogus committer info %s"
 msgstr "unechte Einreicher-Informationen %s"
 
-#: builtin/log.c:1198
+#: builtin/log.c:1202
 msgid "-n and -k are mutually exclusive."
-msgstr "-n und -k schliessen sich gegenseitig aus"
+msgstr "-n und -k schließen sich gegenseitig aus"
 
-#: builtin/log.c:1200
+#: builtin/log.c:1204
 msgid "--subject-prefix and -k are mutually exclusive."
-msgstr "--subject-prefix und -k schliessen sich gegenseitig aus"
+msgstr "--subject-prefix und -k schließen sich gegenseitig aus"
 
-#: builtin/log.c:1208
+#: builtin/log.c:1212
 msgid "--name-only does not make sense"
 msgstr "--name-only macht keinen Sinn"
 
-#: builtin/log.c:1210
+#: builtin/log.c:1214
 msgid "--name-status does not make sense"
 msgstr "--name-status macht keinen Sinn"
 
-#: builtin/log.c:1212
+#: builtin/log.c:1216
 msgid "--check does not make sense"
 msgstr "--check macht keinen Sinn"
 
-#: builtin/log.c:1235
+#: builtin/log.c:1239
 msgid "standard output, or directory, which one?"
 msgstr "Standard-Ausgabe oder Verzeichnis, welches von beidem?"
 
-#: builtin/log.c:1237
+#: builtin/log.c:1241
 #, c-format
 msgid "Could not create directory '%s'"
 msgstr "Konnte Verzeichnis '%s' nicht erstellen."
 
-#: builtin/log.c:1390
+#: builtin/log.c:1394
 msgid "Failed to create output files"
 msgstr "Fehler beim Erstellen der Ausgabedateien."
 
-#: builtin/log.c:1494
+#: builtin/log.c:1498
 #, c-format
 msgid ""
 "Could not find a tracked remote branch, please specify <upstream> manually.\n"
@@ -3426,7 +3805,7 @@ msgstr ""
 "Konnte gefolgten, externen Zweig nicht finden, bitte gebe <upstream> manuell "
 "an.\n"
 
-#: builtin/log.c:1510 builtin/log.c:1512 builtin/log.c:1524
+#: builtin/log.c:1511 builtin/log.c:1513 builtin/log.c:1525
 #, c-format
 msgid "Unknown commit %s"
 msgstr "Unbekannte Version %s"
@@ -3491,55 +3870,51 @@ msgstr ""
 "Keine Zusammenführungsbeschreibung -- Zweigspitze (HEAD) wird nicht "
 "aktualisiert\n"
 
-#: builtin/merge.c:437
+#: builtin/merge.c:436
 #, c-format
 msgid "'%s' does not point to a commit"
 msgstr "'%s' zeigt auf keine Version"
 
-#: builtin/merge.c:536
+#: builtin/merge.c:535
 #, c-format
 msgid "Bad branch.%s.mergeoptions string: %s"
 msgstr "Ungültiger branch.%s.mergeoptions String: %s"
 
-#: builtin/merge.c:629
+#: builtin/merge.c:628
 msgid "git write-tree failed to write a tree"
 msgstr "\"git write-tree\" schlug beim Schreiben eines Baumes fehl"
 
-#: builtin/merge.c:679
+#: builtin/merge.c:678
 msgid "failed to read the cache"
 msgstr "Lesen des Zwischenspeichers fehlgeschlagen"
 
-#: builtin/merge.c:697
-msgid "Unable to write index."
-msgstr "Konnte Bereitstellung nicht schreiben."
-
-#: builtin/merge.c:710
+#: builtin/merge.c:709
 msgid "Not handling anything other than two heads merge."
 msgstr "Es wird nur die Zusammenführung von zwei Zweigen behandelt."
 
-#: builtin/merge.c:724
+#: builtin/merge.c:723
 #, c-format
 msgid "Unknown option for merge-recursive: -X%s"
 msgstr "Unbekannte Option für merge-recursive: -X%s"
 
-#: builtin/merge.c:738
+#: builtin/merge.c:737
 #, c-format
 msgid "unable to write %s"
 msgstr "konnte %s nicht schreiben"
 
-#: builtin/merge.c:877
+#: builtin/merge.c:876
 #, c-format
 msgid "Could not read from '%s'"
 msgstr "konnte nicht von '%s' lesen"
 
-#: builtin/merge.c:886
+#: builtin/merge.c:885
 #, 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:892
+#: builtin/merge.c:891
 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"
@@ -3555,56 +3930,56 @@ msgstr ""
 "Zeilen beginnend mit '#' werden ignoriert, und eine leere Beschreibung "
 "bricht die Eintragung ab.\n"
 
-#: builtin/merge.c:916
+#: builtin/merge.c:915
 msgid "Empty commit message."
 msgstr "Leere Versionsbeschreibung"
 
-#: builtin/merge.c:928
+#: builtin/merge.c:927
 #, c-format
 msgid "Wonderful.\n"
 msgstr "Wunderbar.\n"
 
-#: builtin/merge.c:993
+#: builtin/merge.c:992
 #, 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:1009
+#: builtin/merge.c:1008
 #, c-format
 msgid "'%s' is not a commit"
 msgstr "'%s' ist keine Version"
 
-#: builtin/merge.c:1050
+#: builtin/merge.c:1049
 msgid "No current branch."
 msgstr "Du befindest dich auf keinem Zweig."
 
-#: builtin/merge.c:1052
+#: builtin/merge.c:1051
 msgid "No remote for the current branch."
 msgstr "Kein externes Archiv für den aktuellen Zweig."
 
-#: builtin/merge.c:1054
+#: builtin/merge.c:1053
 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:1059
+#: builtin/merge.c:1058
 #, c-format
 msgid "No remote tracking branch for %s from %s"
 msgstr "Kein externer Übernahmezweig für %s von %s"
 
-#: builtin/merge.c:1146 builtin/merge.c:1303
+#: builtin/merge.c:1145 builtin/merge.c:1302
 #, c-format
 msgid "%s - not something we can merge"
 msgstr "%s - nichts was wir zusammenführen können"
 
-#: builtin/merge.c:1214
+#: builtin/merge.c:1213
 msgid "There is no merge to abort (MERGE_HEAD missing)."
 msgstr "Es gibt keine Zusammenführung zum Abbrechen (vermisse MERGE_HEAD)"
 
-#: builtin/merge.c:1230 git-pull.sh:31
+#: builtin/merge.c:1229 git-pull.sh:31
 msgid ""
 "You have not concluded your merge (MERGE_HEAD exists).\n"
 "Please, commit your changes before you can merge."
@@ -3612,12 +3987,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:1233 git-pull.sh:34
+#: builtin/merge.c:1232 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:1237
+#: builtin/merge.c:1236
 msgid ""
 "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
 "Please, commit your changes before you can merge."
@@ -3625,80 +4000,80 @@ 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:1240
+#: builtin/merge.c:1239
 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:1249
+#: builtin/merge.c:1248
 msgid "You cannot combine --squash with --no-ff."
 msgstr "Du kannst --squash nicht mit --no-ff kombinieren."
 
-#: builtin/merge.c:1254
+#: builtin/merge.c:1253
 msgid "You cannot combine --no-ff with --ff-only."
 msgstr "Du kannst --no-ff nicht mit --ff--only kombinieren."
 
-#: builtin/merge.c:1261
+#: builtin/merge.c:1260
 msgid "No commit specified and merge.defaultToUpstream not set."
 msgstr "Keine Version angegeben und merge.defaultToUpstream ist nicht gesetzt."
 
-#: builtin/merge.c:1293
+#: builtin/merge.c:1292
 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:1296
+#: builtin/merge.c:1295
 msgid "Squash commit into empty head not supported yet"
 msgstr "Bin auf einem Zweig, der noch geboren wird; kann nicht quetschen."
 
-#: builtin/merge.c:1298
+#: builtin/merge.c:1297
 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:1413
+#: builtin/merge.c:1412
 #, c-format
 msgid "Updating %s..%s\n"
 msgstr "Aktualisiere %s..%s\n"
 
-#: builtin/merge.c:1451
+#: builtin/merge.c:1450
 #, c-format
 msgid "Trying really trivial in-index merge...\n"
 msgstr "Probiere wirklich triviale \"in-index\"-Zusammenführung...\n"
 
-#: builtin/merge.c:1458
+#: builtin/merge.c:1457
 #, c-format
 msgid "Nope.\n"
 msgstr "Nein.\n"
 
-#: builtin/merge.c:1490
+#: builtin/merge.c:1489
 msgid "Not possible to fast-forward, aborting."
 msgstr "Vorspulen nicht möglich, breche ab."
 
-#: builtin/merge.c:1513 builtin/merge.c:1592
+#: builtin/merge.c:1512 builtin/merge.c:1591
 #, c-format
 msgid "Rewinding the tree to pristine...\n"
 msgstr "Rücklauf des Zweiges bis zum Ursprung...\n"
 
-#: builtin/merge.c:1517
+#: builtin/merge.c:1516
 #, c-format
 msgid "Trying merge strategy %s...\n"
 msgstr "Probiere Zusammenführungsstrategie %s...\n"
 
-#: builtin/merge.c:1583
+#: builtin/merge.c:1582
 #, c-format
 msgid "No merge strategy handled the merge.\n"
 msgstr "Keine Zusammenführungsstrategie behandelt diese Zusammenführung.\n"
 
-#: builtin/merge.c:1585
+#: builtin/merge.c:1584
 #, c-format
 msgid "Merge with strategy %s failed.\n"
 msgstr "Zusammenführung mit Strategie %s fehlgeschlagen.\n"
 
-#: builtin/merge.c:1594
+#: builtin/merge.c:1593
 #, 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:1606
+#: builtin/merge.c:1605
 #, c-format
 msgid "Automatic merge went well; stopped before committing as requested\n"
 msgstr ""
@@ -3926,22 +4301,27 @@ msgstr "Objekt %s hat keine Notiz\n"
 msgid "Unknown subcommand: %s"
 msgstr "Unbekanntes Unterkommando: %s"
 
-#: builtin/pack-objects.c:2337
+#: 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
 #, c-format
 msgid "unsupported index version %s"
 msgstr "Nicht unterstützte Bereitstellungsversion %s"
 
-#: builtin/pack-objects.c:2341
+#: builtin/pack-objects.c:2402
 #, c-format
 msgid "bad index version '%s'"
 msgstr "Ungültige Bereitstellungsversion '%s'"
 
-#: builtin/pack-objects.c:2364
+#: builtin/pack-objects.c:2425
 #, c-format
 msgid "option %s does not accept negative form"
 msgstr "Option %s akzeptiert keine negative Form"
 
-#: builtin/pack-objects.c:2368
+#: builtin/pack-objects.c:2429
 #, c-format
 msgid "unable to parse value '%s' for option %s"
 msgstr "konnte Wert '%s' für Option %s nicht parsen"
@@ -4034,14 +4414,49 @@ msgstr ""
 "aktuellen Zweiges '%s' ist, ohne mir mitzuteilen, was ich versenden\n"
 "soll, um welchen externen Zweig zu aktualisieren."
 
-#: builtin/push.c:174
+#: builtin/push.c:151
+msgid ""
+"push.default is unset; its implicit value is changing in\n"
+"Git 2.0 from 'matching' to 'simple'. To squelch this message\n"
+"and maintain the current behavior after the default changes, use:\n"
+"\n"
+"  git config --global push.default matching\n"
+"\n"
+"To squelch this message and adopt the new behavior now, use:\n"
+"\n"
+"  git config --global push.default simple\n"
+"\n"
+"See 'git help config' and search for 'push.default' for further "
+"information.\n"
+"(the 'simple' mode was introduced in Git 1.7.11. Use the similar mode\n"
+"'current' instead of 'simple' if you sometimes use older versions of Git)"
+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"
+"  git config --global push.default matching\n"
+"\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.)"
+
+#: builtin/push.c:199
 msgid ""
 "You didn't specify any refspecs to push, and push.default is \"nothing\"."
 msgstr ""
 "Du hast keine Referenzspezifikationen zum Versenden angegeben, und push."
 "default ist \"nothing\"."
 
-#: builtin/push.c:181
+#: builtin/push.c:206
 msgid ""
 "Updates were rejected because the tip of your current branch is behind\n"
 "its remote counterpart. Merge the remote changes (e.g. 'git pull')\n"
@@ -4054,22 +4469,22 @@ msgstr ""
 "Siehe auch die Sektion 'Note about fast-forwards' in 'git push --help'\n"
 "für weitere Details."
 
-#: builtin/push.c:187
+#: builtin/push.c:212
 msgid ""
 "Updates were rejected because a pushed branch tip is behind its remote\n"
 "counterpart. If you did not intend to push that branch, you may want to\n"
-"specify branches to push or set the 'push.default' configuration\n"
-"variable to 'current' or 'upstream' to push only the current branch."
+"specify branches to push or set the 'push.default' configuration variable\n"
+"to 'simple', 'current' or 'upstream' to push only the current branch."
 msgstr ""
 "Aktualisierungen wurden zurückgewiesen, weil die Spitze eines versendeten\n"
 "Zweiges hinter seinem externen Gegenstück zurückgefallen ist. Wenn du nicht\n"
 "beabsichtigt hast, diesen Zweig zu versenden, kannst du auch den zu "
 "versendenden\n"
 "Zweig spezifizieren oder die Konfigurationsvariable 'push.default' zu "
-"'current'\n"
+"'simple', 'current'\n"
 "oder 'upstream' setzen, um nur den aktuellen Zweig zu versenden."
 
-#: builtin/push.c:193
+#: builtin/push.c:218
 msgid ""
 "Updates were rejected because a pushed branch tip is behind its remote\n"
 "counterpart. Check out this branch and merge the remote changes\n"
@@ -4083,22 +4498,22 @@ msgstr ""
 "Siehe auch die Sektion 'Note about fast-forwards' in 'git push --help'\n"
 "für weitere Details."
 
-#: builtin/push.c:233
+#: builtin/push.c:258
 #, c-format
 msgid "Pushing to %s\n"
 msgstr "Versende nach %s\n"
 
-#: builtin/push.c:237
+#: builtin/push.c:262
 #, c-format
 msgid "failed to push some refs to '%s'"
 msgstr "Fehler beim Versenden einiger Referenzen nach '%s'"
 
-#: builtin/push.c:269
+#: builtin/push.c:294
 #, c-format
 msgid "bad repository '%s'"
 msgstr "ungültiges Projektarchiv '%s'"
 
-#: builtin/push.c:270
+#: builtin/push.c:295
 msgid ""
 "No configured push destination.\n"
 "Either specify the URL from the command-line or configure a remote "
@@ -4120,31 +4535,31 @@ msgstr ""
 "\n"
 "    git push <Name>\n"
 
-#: builtin/push.c:285
+#: builtin/push.c:310
 msgid "--all and --tags are incompatible"
 msgstr "--all und --tags sind inkompatibel"
 
-#: builtin/push.c:286
+#: builtin/push.c:311
 msgid "--all can't be combined with refspecs"
 msgstr "--all kann nicht mit Referenzspezifikationen kombiniert werden"
 
-#: builtin/push.c:291
+#: builtin/push.c:316
 msgid "--mirror and --tags are incompatible"
 msgstr "--mirror und --tags sind inkompatibel"
 
-#: builtin/push.c:292
+#: builtin/push.c:317
 msgid "--mirror can't be combined with refspecs"
 msgstr "--mirror kann nicht mit Referenzspezifikationen kombiniert werden"
 
-#: builtin/push.c:297
+#: builtin/push.c:322
 msgid "--all and --mirror are incompatible"
 msgstr "--all und --mirror sind inkompatibel"
 
-#: builtin/push.c:385
+#: builtin/push.c:410
 msgid "--delete is incompatible with --all, --mirror and --tags"
 msgstr "--delete ist inkompatibel mit --all, --mirror und --tags"
 
-#: builtin/push.c:387
+#: builtin/push.c:412
 msgid "--delete doesn't make sense without any refs"
 msgstr "--delete macht ohne irgendeine Referenz keinen Sinn"
 
@@ -4566,31 +4981,31 @@ msgstr ""
 "Kann keine '%s' Zurücksetzung durchführen, während eine Zusammenführung im "
 "Gange ist."
 
-#: builtin/reset.c:297
+#: builtin/reset.c:303
 #, c-format
 msgid "Could not parse object '%s'."
 msgstr "Konnte Objekt '%s' nicht parsen."
 
-#: builtin/reset.c:302
+#: builtin/reset.c:308
 msgid "--patch is incompatible with --{hard,mixed,soft}"
 msgstr "--patch ist inkompatibel mit --{hard,mixed,soft}"
 
-#: builtin/reset.c:311
+#: builtin/reset.c:317
 msgid "--mixed with paths is deprecated; use 'git reset -- <paths>' instead."
 msgstr ""
 "--mixed mit Pfaden ist veraltet; benutze stattdessen 'git reset -- <Pfade>'."
 
-#: builtin/reset.c:313
+#: builtin/reset.c:319
 #, c-format
 msgid "Cannot do %s reset with paths."
 msgstr "Eine '%s' Zurücksetzung mit Pfaden ist nicht möglich."
 
-#: builtin/reset.c:325
+#: builtin/reset.c:331
 #, c-format
 msgid "%s reset is not allowed in a bare repository"
 msgstr "'%s' Zurücksetzung ist in einem bloßen Projektarchiv nicht erlaubt"
 
-#: builtin/reset.c:341
+#: builtin/reset.c:347
 #, c-format
 msgid "Could not reset index file to revision '%s'."
 msgstr "Konnte Bereitstellungsdatei nicht zu Version '%s' zurücksetzen."
@@ -4941,14 +5356,15 @@ msgstr ""
 #: git-am.sh:105
 #, sh-format
 msgid ""
-"When you have resolved this problem run \"$cmdline --resolved\".\n"
-"If you would prefer to skip this patch, instead run \"$cmdline --skip\".\n"
-"To restore the original branch and stop patching run \"$cmdline --abort\"."
-msgstr ""
-"Wenn du das Problem aufgelöst hast, führe \"$cmdline --resolved\" aus.\n"
-"Falls du diesen Patch auslassen möchtest, führe stattdessen "
-"\"$cmdline --skip\" aus.\n"
-"Um den ursprünglichen Zweig wiederherzustellen und die Anwendung der Patches\n"
+"When you have resolved this problem, run \"$cmdline --resolved\".\n"
+"If you prefer to skip this patch, run \"$cmdline --skip\" instead.\n"
+"To restore the original branch and stop patching, run \"$cmdline --abort\"."
+msgstr ""
+"Wenn du das Problem gelöst hast, führe \"$cmdline --resolved\" aus.\n"
+"Falls du diesen Patch auslassen möchtest, führe stattdessen \"$cmdline --skip"
+"\" aus.\n"
+"Um den ursprünglichen Zweig wiederherzustellen und die Anwendung der "
+"Patches\n"
 "abzubrechen, führe \"$cmdline --abort\" aus."
 
 #: git-am.sh:121
@@ -4961,6 +5377,12 @@ msgstr ""
 "Dem Projektarchiv fehlen notwendige Blobs um auf eine 3-Wege-Zusammenführung "
 "zurückzufallen."
 
+#: git-am.sh:139
+msgid "Using index info to reconstruct a base tree..."
+msgstr ""
+"Verwende Informationen aus der Bereitstellung um einen Basisbaum "
+"nachzustellen"
+
 #: git-am.sh:154
 msgid ""
 "Did you hand edit your patch?\n"
@@ -4973,45 +5395,53 @@ msgstr ""
 msgid "Falling back to patching base and 3-way merge..."
 msgstr "Falle zurück zum Patchen der Basis und der 3-Wege-Zusammenführung..."
 
-#: git-am.sh:275
+#: git-am.sh:179
+msgid "Failed to merge in the changes."
+msgstr "Zusammenführung der Änderungen fehlgeschlagen"
+
+#: git-am.sh:274
 msgid "Only one StGIT patch series can be applied at once"
 msgstr "Es kann nur eine StGIT Patch-Serie auf einmal angewendet werden."
 
-#: git-am.sh:362
+#: git-am.sh:361
 #, sh-format
 msgid "Patch format $patch_format is not supported."
 msgstr "Patch-Format $patch_format wird nicht unterstützt."
 
-#: git-am.sh:364
+#: git-am.sh:363
 msgid "Patch format detection failed."
 msgstr "Patch-Formaterkennung fehlgeschlagen."
 
-#: git-am.sh:418
-msgid "-d option is no longer supported.  Do not use."
-msgstr "-d Option wird nicht länger unterstützt. Nicht benutzen."
+#: git-am.sh:389
+msgid ""
+"The -b/--binary option has been a no-op for long time, and\n"
+"it will be removed. Please do not use it anymore."
+msgstr ""
+"Die -b/--binary Option hat seit Langem keinen Effekt und wird\n"
+"entfernt. Bitte nicht mehr verwenden."
 
-#: git-am.sh:481
+#: git-am.sh:477
 #, sh-format
 msgid "previous rebase directory $dotest still exists but mbox given."
 msgstr ""
 "Vorheriges Verzeichnis des Neuaufbaus $dotest existiert noch, aber mbox "
 "gegeben."
 
-#: git-am.sh:486
+#: git-am.sh:482
 msgid "Please make up your mind. --skip or --abort?"
 msgstr "Bitte werde dir klar. --skip oder --abort?"
 
-#: git-am.sh:513
+#: git-am.sh:509
 msgid "Resolve operation not in progress, we are not resuming."
 msgstr "Es ist keine Auflösung im Gange, es wird nicht fortgesetzt."
 
-#: git-am.sh:579
+#: git-am.sh:575
 #, sh-format
 msgid "Dirty index: cannot apply patches (dirty: $files)"
 msgstr ""
 "Unsaubere Bereitstellung: kann Patches nicht anwenden (unsauber: $files)"
 
-#: git-am.sh:671
+#: git-am.sh:679
 #, sh-format
 msgid ""
 "Patch is empty.  Was it split wrong?\n"
@@ -5019,38 +5449,39 @@ msgid ""
 "To restore the original branch and stop patching run \"$cmdline --abort\"."
 msgstr ""
 "Patch ist leer. Wurde er falsch aufgeteilt?\n"
-"Wenn du diesen Patch auslassen möchtest, führe stattdessen "
-"\"$cmdline --skip\" aus.\n"
-"Um den ursprünglichen Zweig wiederherzustellen und die Anwendung der Patches\n"
+"Wenn du diesen Patch auslassen möchtest, führe stattdessen \"$cmdline --skip"
+"\" aus.\n"
+"Um den ursprünglichen Zweig wiederherzustellen und die Anwendung der "
+"Patches\n"
 "abzubrechen, führe \"$cmdline --abort\" aus."
 
-#: git-am.sh:708
+#: git-am.sh:706
 msgid "Patch does not have a valid e-mail address."
 msgstr "Patch enthält keine gültige eMail-Adresse."
 
-#: git-am.sh:755
+#: git-am.sh:753
 msgid "cannot be interactive without stdin connected to a terminal."
 msgstr ""
 "Kann nicht interaktiv sein, ohne dass die Standard-Eingabe mit einem "
 "Terminal verbunden ist."
 
-#: git-am.sh:759
+#: git-am.sh:757
 msgid "Commit Body is:"
 msgstr "Beschreibung der Eintragung ist:"
 
 #. TRANSLATORS: Make sure to include [y], [n], [e], [v] and [a]
 #. in your translation. The program will only accept English
 #. input at this point.
-#: git-am.sh:766
+#: git-am.sh:764
 msgid "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all "
 msgstr "Anwenden? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all "
 
-#: git-am.sh:802
+#: git-am.sh:800
 #, sh-format
 msgid "Applying: $FIRSTLINE"
 msgstr "Wende an: $FIRSTLINE"
 
-#: git-am.sh:823
+#: git-am.sh:821
 msgid ""
 "No changes - did you forget to use 'git add'?\n"
 "If there is nothing left to stage, chances are that something else\n"
@@ -5061,7 +5492,7 @@ msgstr ""
 "diese bereits anderweitig eingefügt worden sein; du könntest diesen Patch\n"
 "auslassen."
 
-#: git-am.sh:831
+#: git-am.sh:829
 msgid ""
 "You still have unmerged paths in your index\n"
 "did you forget to use 'git add'?"
@@ -5069,16 +5500,16 @@ msgstr ""
 "Du hast immer noch nicht zusammengeführte Pfade in der Bereitstellung.\n"
 "Hast du vergessen 'git add' zu benutzen?"
 
-#: git-am.sh:847
+#: git-am.sh:845
 msgid "No changes -- Patch already applied."
 msgstr "Keine Änderungen -- Patches bereits angewendet."
 
-#: git-am.sh:857
+#: git-am.sh:855
 #, sh-format
 msgid "Patch failed at $msgnum $FIRSTLINE"
 msgstr "Anwendung des Patches fehlgeschlagen bei $msgnum $FIRSTLINE"
 
-#: git-am.sh:873
+#: git-am.sh:876
 msgid "applying to an empty history"
 msgstr "wende zu leerer Historie an"
 
@@ -5283,6 +5714,131 @@ msgstr "Kann nicht mehrere Zweige in einen ungeborenen Zweig zusammenführen"
 msgid "Cannot rebase onto multiple branches"
 msgstr "kann nicht auf mehrere Zweige neu aufbauen"
 
+#: git-rebase.sh:52
+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"
+"To check out the original branch and stop rebasing, run \"git rebase --abort"
+"\"."
+msgstr ""
+"Wenn du das Problem aufgelöst hast, führe \"git rebase --continue\" aus.\n"
+"Falls du diesen Patch auslassen möchtest, führe stattdessen \"git rebase --"
+"skip\" aus.\n"
+"Um den ursprünglichen Zweig wiederherzustellen und den Neuaufbau "
+"abzubrechen,\n"
+"führe \"git rebase --abort\" aus."
+
+#: git-rebase.sh:159
+msgid "The pre-rebase hook refused to rebase."
+msgstr "Der \"pre-rebase hook\" hat den Neuaufbau zurückgewiesen."
+
+#: git-rebase.sh:164
+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
+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
+msgid "No rebase in progress?"
+msgstr "Kein Neuaufbau im Gange?"
+
+#: git-rebase.sh:313
+msgid "Cannot read HEAD"
+msgstr "Kann Zweigspitze (HEAD) nicht lesen"
+
+#: git-rebase.sh:316
+msgid ""
+"You must edit all merge conflicts and then\n"
+"mark them as resolved using git add"
+msgstr ""
+"Du musst alle Zusammenführungskonflikte editieren und diese dann\n"
+"mittels \"git add\" als aufgelöst markieren"
+
+#: git-rebase.sh:334
+#, sh-format
+msgid "Could not move back to $head_name"
+msgstr "Konnte nicht zu $head_name zurückgehen"
+
+#: git-rebase.sh:350
+#, sh-format
+msgid ""
+"It seems that there is already a $state_dir_base directory, and\n"
+"I wonder if you are in the middle of another rebase.  If that is the\n"
+"case, please try\n"
+"\t$cmd_live_rebase\n"
+"If that is not the case, please\n"
+"\t$cmd_clear_stale_rebase\n"
+"and run me again.  I am stopping in case you still have something\n"
+"valuable there."
+msgstr ""
+"Es sieht so aus, als ob es das Verzeichnis $state_dir_base bereits gibt\n"
+"und es könnte ein anderer Neuaufbau im Gange sein. Wenn das der Fall ist,\n"
+"probiere bitte\n"
+"\t$cmd_live_rebase\n"
+"Wenn das nicht der Fall ist, probiere bitte\n"
+"\t$cmd_clear_stale_rebase\n"
+"und führe dieses Kommando nochmal aus. Es wird angehalten, falls noch\n"
+"etwas Schützenswertes vorhanden ist."
+
+#: git-rebase.sh:395
+#, sh-format
+msgid "invalid upstream $upstream_name"
+msgstr "ungültiger Übernahmezweig $upstream_name"
+
+#: git-rebase.sh:419
+#, 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
+#, sh-format
+msgid "$onto_name: there is no merge base"
+msgstr "$onto_name: es gibt keine Zusammenführungsbasis"
+
+#: git-rebase.sh:431
+#, 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
+#, sh-format
+msgid "fatal: no such branch: $branch_name"
+msgstr "fatal: Zweig $branch_name nicht gefunden"
+
+#: git-rebase.sh:474
+msgid "Please commit or stash them."
+msgstr "Bitte trage die Änderungen ein oder benutze \"stash\"."
+
+#: git-rebase.sh:492
+#, 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
+#, 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
+#, sh-format
+msgid "Changes from $mb to $onto:"
+msgstr "Änderungen von $mb zu $onto:"
+
+#. Detach HEAD and reset the tree
+#: git-rebase.sh:515
+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
+#, sh-format
+msgid "Fast-forwarded $branch_name to $onto_name."
+msgstr "$branch_name zu $onto_name vorgespult."
+
 #: git-stash.sh:51
 msgid "git stash clear with parameters is unimplemented"
 msgstr "git stash clear mit Parametern ist nicht implementiert"
@@ -5414,109 +5970,108 @@ msgstr "Kein Zweigname spezifiziert"
 msgid "(To restore them type \"git stash apply\")"
 msgstr "(Zur Wiederherstellung gebe \"git stash apply\" ein)"
 
-#: git-submodule.sh:56
+#: git-submodule.sh:88
 #, sh-format
 msgid "cannot strip one component off url '$remoteurl'"
 msgstr "Kann eine Komponente von URL '$remoteurl' nicht extrahieren"
 
-#: git-submodule.sh:109
+#: git-submodule.sh:167
 #, sh-format
 msgid "No submodule mapping found in .gitmodules for path '$sm_path'"
 msgstr ""
 "Keine Unterprojekt-Zuordnung in .gitmodules für Pfad '$sm_path' gefunden"
 
-#: git-submodule.sh:150
+#: git-submodule.sh:211
 #, sh-format
 msgid "Clone of '$url' into submodule path '$sm_path' failed"
 msgstr "Klonen von '$url' in Unterprojekt-Pfad '$sm_path' fehlgeschlagen"
 
-#: git-submodule.sh:160
+#: git-submodule.sh:223
 #, sh-format
 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:249
+#: git-submodule.sh:312
 #, 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:266
+#: git-submodule.sh:329
 #, sh-format
 msgid "'$sm_path' already exists in the index"
 msgstr "'$sm_path' existiert bereits in der Bereitstellung"
 
-#: git-submodule.sh:270
+#: git-submodule.sh:333
 #, sh-format
 msgid ""
 "The following path is ignored by one of your .gitignore files:\n"
 "$sm_path\n"
 "Use -f if you really want to add it."
 msgstr ""
-"Der folgende Pfad wird durch eine deiner \".gitignore\" Dateien "
-"ignoriert:\n"
+"Der folgende Pfad wird durch eine deiner \".gitignore\" Dateien ignoriert:\n"
 "$sm_path\n"
 "Benutze -f wenn du diesen wirklich hinzufügen möchtest."
 
-#: git-submodule.sh:281
+#: git-submodule.sh:344
 #, sh-format
 msgid "Adding existing repo at '$sm_path' to the index"
-msgstr "Füge existierendes Projektarchiv in '$sm_path' der Bereitstellung "
-"hinzu."
+msgstr ""
+"Füge existierendes Projektarchiv in '$sm_path' der Bereitstellung hinzu."
 
-#: git-submodule.sh:283
+#: git-submodule.sh:346
 #, 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:297
+#: git-submodule.sh:360
 #, sh-format
 msgid "Unable to checkout submodule '$sm_path'"
 msgstr "Unfähig Unterprojekt '$sm_path' auszuchecken"
 
-#: git-submodule.sh:302
+#: git-submodule.sh:365
 #, sh-format
 msgid "Failed to add submodule '$sm_path'"
 msgstr "Hinzufügen von Unterprojekt '$sm_path' fehlgeschlagen"
 
-#: git-submodule.sh:307
+#: git-submodule.sh:370
 #, sh-format
 msgid "Failed to register submodule '$sm_path'"
 msgstr "Registierung von Unterprojekt '$sm_path' fehlgeschlagen"
 
-#: git-submodule.sh:349
+#: git-submodule.sh:413
 #, sh-format
 msgid "Entering '$prefix$sm_path'"
 msgstr "Betrete '$prefix$sm_path'"
 
-#: git-submodule.sh:363
+#: git-submodule.sh:427
 #, 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:406
+#: git-submodule.sh:471
 #, 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:415
+#: git-submodule.sh:480
 #, 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:417
+#: git-submodule.sh:482
 #, 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:425
+#: git-submodule.sh:490
 #, 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:524
+#: git-submodule.sh:590
 #, sh-format
 msgid ""
 "Submodule path '$sm_path' not initialized\n"
@@ -5525,99 +6080,113 @@ msgstr ""
 "Unterprojekt-Pfad '$sm_path' ist nicht initialisiert\n"
 "Vielleicht möchtest du 'update --init' benutzen?"
 
-#: git-submodule.sh:537
+#: git-submodule.sh:603
 #, 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:556
+#: git-submodule.sh:622
 #, sh-format
 msgid "Unable to fetch in submodule path '$sm_path'"
 msgstr "Konnte in Unterprojekt-Pfad '$sm_path' nicht anfordern"
 
-#: git-submodule.sh:570
+#: git-submodule.sh:636
 #, 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:571
+#: git-submodule.sh:637
 #, sh-format
 msgid "Submodule path '$sm_path': rebased into '$sha1'"
 msgstr "Unterprojekt-Pfad '$sm_path': neu aufgebaut in '$sha1'"
 
-#: git-submodule.sh:576
+#: git-submodule.sh:642
 #, 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:577
+#: git-submodule.sh:643
 #, sh-format
 msgid "Submodule path '$sm_path': merged in '$sha1'"
 msgstr "Unterprojekt-Pfad '$sm_path': zusammengeführt in '$sha1'"
 
-#: git-submodule.sh:582
+#: git-submodule.sh:648
 #, 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:583
+#: git-submodule.sh:649
 #, sh-format
 msgid "Submodule path '$sm_path': checked out '$sha1'"
 msgstr "Unterprojekt-Pfad: '$sm_path': '$sha1' ausgecheckt"
 
-#: git-submodule.sh:605 git-submodule.sh:928
+#: git-submodule.sh:671 git-submodule.sh:995
 #, sh-format
 msgid "Failed to recurse into submodule path '$sm_path'"
 msgstr "Fehler bei Rekursion in Unterprojekt-Pfad '$sm_path'"
 
-#: git-submodule.sh:713
-msgid "--cached cannot be used with --files"
-msgstr "--cached kann nicht mit --files benutzt werden"
+#: git-submodule.sh:779
+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:753
+#: git-submodule.sh:819
 #, sh-format
 msgid "unexpected mode $mod_dst"
 msgstr "unerwarteter Modus $mod_dst"
 
-#: git-submodule.sh:771
+#: git-submodule.sh:837
 #, sh-format
 msgid "  Warn: $name doesn't contain commit $sha1_src"
 msgstr "  Warnung: $name beinhaltet nicht Version $sha1_src"
 
-#: git-submodule.sh:774
+#: git-submodule.sh:840
 #, sh-format
 msgid "  Warn: $name doesn't contain commit $sha1_dst"
 msgstr "  Warnung: $name beinhaltet nicht Version $sha1_dst"
 
-#: git-submodule.sh:777
+#: git-submodule.sh:843
 #, 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:802
+#: git-submodule.sh:868
 msgid "blob"
 msgstr "Blob"
 
-#: git-submodule.sh:803
-msgid "submodule"
-msgstr "Unterprojekt"
-
-#: git-submodule.sh:840
+#: git-submodule.sh:906
 msgid "# Submodules changed but not updated:"
 msgstr "# Unterprojekte geändert, aber nicht aktualisiert:"
 
-#: git-submodule.sh:842
+#: git-submodule.sh:908
 msgid "# Submodule changes to be committed:"
 msgstr "# Änderungen in Unterprojekt zum Eintragen:"
 
-#: git-submodule.sh:974
+#: git-submodule.sh:1054
 #, sh-format
 msgid "Synchronizing submodule url for '$name'"
 msgstr "Synchronisiere Unterprojekt-URL für '$name'"
 
+#~ msgid "diff setup failed"
+#~ msgstr "diff_setup_done fehlgeschlagen"
+
+#~ msgid "merge-recursive: disk full?"
+#~ msgstr "merge-recursive: Festplatte voll?"
+
+#~ msgid "diff_setup_done failed"
+#~ msgstr "diff_setup_done fehlgeschlagen"
+
+#~ msgid "-d option is no longer supported.  Do not use."
+#~ msgstr "-d Option wird nicht länger unterstützt. Nicht benutzen."
+
+#~ msgid "%s: has been deleted/renamed"
+#~ msgstr "%s wurde gelöscht/umbenannt"
+
+#~ msgid "'%s': not a documentation directory."
+#~ msgstr "'%s' ist kein Dokumentationsverzeichnis"
+
 #~ msgid "--"
 #~ msgstr "--"
 
index b6665060de23353efecb6307830d4ae11689dcca..e5611581e65c561cfd90de0a0fec5f22043f21f0 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-06-08 10:20+0800\n"
+"POT-Creation-Date: 2012-10-16 08:38+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"
@@ -35,6 +35,91 @@ msgid ""
 "or use 'git commit -a'."
 msgstr ""
 
+#: archive.c:10
+msgid "git archive [options] <tree-ish> [<path>...]"
+msgstr ""
+
+#: archive.c:11
+msgid "git archive --list"
+msgstr ""
+
+#: archive.c:12
+msgid ""
+"git archive --remote <repo> [--exec <cmd>] [options] <tree-ish> [<path>...]"
+msgstr ""
+
+#: archive.c:13
+msgid "git archive --remote <repo> [--exec <cmd>] --list"
+msgstr ""
+
+#: archive.c:322
+msgid "fmt"
+msgstr ""
+
+#: archive.c:322
+msgid "archive format"
+msgstr ""
+
+#: archive.c:323 builtin/log.c:1079
+msgid "prefix"
+msgstr ""
+
+#: archive.c:324
+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
+#: 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 ""
+
+#: archive.c:326 builtin/archive.c:92
+msgid "write the archive to this file"
+msgstr ""
+
+#: archive.c:328
+msgid "read .gitattributes in working directory"
+msgstr ""
+
+#: archive.c:329
+msgid "report archived files on stderr"
+msgstr ""
+
+#: archive.c:330
+msgid "store only"
+msgstr ""
+
+#: archive.c:331
+msgid "compress faster"
+msgstr ""
+
+#: archive.c:339
+msgid "compress better"
+msgstr ""
+
+#: archive.c:342
+msgid "list supported archive formats"
+msgstr ""
+
+#: archive.c:344 builtin/archive.c:93 builtin/clone.c:85
+msgid "repo"
+msgstr ""
+
+#: archive.c:345 builtin/archive.c:94
+msgid "retrieve the archive from remote repository <repo>"
+msgstr ""
+
+#: archive.c:346 builtin/archive.c:95 builtin/notes.c:619
+msgid "command"
+msgstr ""
+
+#: archive.c:347 builtin/archive.c:96
+msgid "path to the remote git-upload-archive command"
+msgstr ""
+
 #: bundle.c:36
 #, c-format
 msgid "'%s' does not look like a v2 bundle file"
@@ -45,7 +130,7 @@ msgstr ""
 msgid "unrecognized header: %s%s (%d)"
 msgstr ""
 
-#: bundle.c:89 builtin/commit.c:696
+#: bundle.c:89 builtin/commit.c:672
 #, c-format
 msgid "could not open '%s'"
 msgstr ""
@@ -54,8 +139,8 @@ msgstr ""
 msgid "Repository lacks these prerequisite commits:"
 msgstr ""
 
-#: bundle.c:164 sequencer.c:550 sequencer.c:982 builtin/log.c:289
-#: builtin/log.c:720 builtin/log.c:1309 builtin/log.c:1528 builtin/merge.c:347
+#: 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/shortlog.c:181
 msgid "revision walk setup failed"
 msgstr ""
@@ -68,53 +153,57 @@ msgstr[0] ""
 msgstr[1] ""
 
 #: bundle.c:192
+msgid "The bundle records a complete history."
+msgstr ""
+
+#: bundle.c:195
 #, c-format
 msgid "The bundle requires this ref"
 msgid_plural "The bundle requires these %d refs"
 msgstr[0] ""
 msgstr[1] ""
 
-#: bundle.c:290
+#: bundle.c:294
 msgid "rev-list died"
 msgstr ""
 
-#: bundle.c:296 builtin/log.c:1205 builtin/shortlog.c:284
+#: bundle.c:300 builtin/log.c:1209 builtin/shortlog.c:284
 #, c-format
 msgid "unrecognized argument: %s"
 msgstr ""
 
-#: bundle.c:331
+#: bundle.c:335
 #, c-format
 msgid "ref '%s' is excluded by the rev-list options"
 msgstr ""
 
-#: bundle.c:376
+#: bundle.c:380
 msgid "Refusing to create empty bundle."
 msgstr ""
 
-#: bundle.c:394
+#: bundle.c:398
 msgid "Could not spawn pack-objects"
 msgstr ""
 
-#: bundle.c:412
+#: bundle.c:416
 msgid "pack-objects died"
 msgstr ""
 
-#: bundle.c:415
+#: bundle.c:419
 #, c-format
 msgid "cannot create '%s'"
 msgstr ""
 
-#: bundle.c:437
+#: bundle.c:441
 msgid "index-pack died"
 msgstr ""
 
-#: commit.c:48
+#: commit.c:50
 #, c-format
 msgid "could not parse %s"
 msgstr ""
 
-#: commit.c:50
+#: commit.c:52
 #, c-format
 msgid "%s %s is not a commit!"
 msgstr ""
@@ -221,32 +310,7 @@ msgid ""
 "%s"
 msgstr ""
 
-#: diff.c:1400
-msgid " 0 files changed\n"
-msgstr ""
-
-#: diff.c:1404
-#, c-format
-msgid " %d file changed"
-msgid_plural " %d files changed"
-msgstr[0] ""
-msgstr[1] ""
-
-#: diff.c:1421
-#, c-format
-msgid ", %d insertion(+)"
-msgid_plural ", %d insertions(+)"
-msgstr[0] ""
-msgstr[1] ""
-
-#: diff.c:1432
-#, c-format
-msgid ", %d deletion(-)"
-msgid_plural ", %d deletions(-)"
-msgstr[0] ""
-msgstr[1] ""
-
-#: diff.c:3478
+#: diff.c:3458
 #, c-format
 msgid ""
 "Failed to parse --dirstat/-X option parameter:\n"
@@ -265,59 +329,59 @@ msgstr ""
 msgid "gpg failed to sign the data"
 msgstr ""
 
-#: grep.c:1320
+#: grep.c:1441
 #, c-format
 msgid "'%s': unable to read %s"
 msgstr ""
 
-#: grep.c:1337
+#: grep.c:1458
 #, c-format
 msgid "'%s': %s"
 msgstr ""
 
-#: grep.c:1348
+#: grep.c:1469
 #, c-format
 msgid "'%s': short read %s"
 msgstr ""
 
-#: help.c:207
+#: help.c:212
 #, c-format
 msgid "available git commands in '%s'"
 msgstr ""
 
-#: help.c:214
+#: help.c:219
 msgid "git commands available from elsewhere on your $PATH"
 msgstr ""
 
-#: help.c:270
+#: help.c:275
 #, c-format
 msgid ""
 "'%s' appears to be a git command, but we were not\n"
 "able to execute it. Maybe git-%s is broken?"
 msgstr ""
 
-#: help.c:327
+#: help.c:332
 msgid "Uh oh. Your system reports no Git commands at all."
 msgstr ""
 
-#: help.c:349
+#: help.c:354
 #, c-format
 msgid ""
 "WARNING: You called a Git command named '%s', which does not exist.\n"
 "Continuing under the assumption that you meant '%s'"
 msgstr ""
 
-#: help.c:354
+#: help.c:359
 #, c-format
 msgid "in %0.1f seconds automatically..."
 msgstr ""
 
-#: help.c:361
+#: help.c:366
 #, c-format
 msgid "git: '%s' is not a git command. See 'git --help'."
 msgstr ""
 
-#: help.c:365
+#: help.c:370
 msgid ""
 "\n"
 "Did you mean this?"
@@ -327,35 +391,281 @@ msgid_plural ""
 msgstr[0] ""
 msgstr[1] ""
 
-#: parse-options.c:493
+#: merge-recursive.c:190
+#, c-format
+msgid "(bad commit)\n"
+msgstr ""
+
+#: merge-recursive.c:206
+#, c-format
+msgid "addinfo_cache failed for path '%s'"
+msgstr ""
+
+#: merge-recursive.c:268
+msgid "error building trees"
+msgstr ""
+
+#: merge-recursive.c:672
+#, c-format
+msgid "failed to create path '%s'%s"
+msgstr ""
+
+#: merge-recursive.c:683
+#, c-format
+msgid "Removing %s to make room for subdirectory\n"
+msgstr ""
+
+#. something else exists
+#. .. but not some other error (who really cares what?)
+#: merge-recursive.c:697 merge-recursive.c:718
+msgid ": perhaps a D/F conflict?"
+msgstr ""
+
+#: merge-recursive.c:708
+#, c-format
+msgid "refusing to lose untracked file at '%s'"
+msgstr ""
+
+#: merge-recursive.c:748
+#, c-format
+msgid "cannot read object %s '%s'"
+msgstr ""
+
+#: merge-recursive.c:750
+#, c-format
+msgid "blob expected for %s '%s'"
+msgstr ""
+
+#: merge-recursive.c:773 builtin/clone.c:302
+#, c-format
+msgid "failed to open '%s'"
+msgstr ""
+
+#: merge-recursive.c:781
+#, c-format
+msgid "failed to symlink '%s'"
+msgstr ""
+
+#: merge-recursive.c:784
+#, c-format
+msgid "do not know what to do with %06o %s '%s'"
+msgstr ""
+
+#: merge-recursive.c:922
+msgid "Failed to execute internal merge"
+msgstr ""
+
+#: merge-recursive.c:926
+#, c-format
+msgid "Unable to add %s to database"
+msgstr ""
+
+#: merge-recursive.c:942
+msgid "unsupported object type in the tree"
+msgstr ""
+
+#: 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 "
+"in tree."
+msgstr ""
+
+#: 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 "
+"in tree at %s."
+msgstr ""
+
+#: merge-recursive.c:1081
+msgid "rename"
+msgstr ""
+
+#: merge-recursive.c:1081
+msgid "renamed"
+msgstr ""
+
+#: merge-recursive.c:1137
+#, c-format
+msgid "%s is a directory in %s adding as %s instead"
+msgstr ""
+
+#: merge-recursive.c:1159
+#, c-format
+msgid ""
+"CONFLICT (rename/rename): Rename \"%s\"->\"%s\" in branch \"%s\" rename \"%s"
+"\"->\"%s\" in \"%s\"%s"
+msgstr ""
+
+#: merge-recursive.c:1164
+msgid " (left unresolved)"
+msgstr ""
+
+#: merge-recursive.c:1218
+#, c-format
+msgid "CONFLICT (rename/rename): Rename %s->%s in %s. Rename %s->%s in %s"
+msgstr ""
+
+#: merge-recursive.c:1248
+#, c-format
+msgid "Renaming %s to %s and %s to %s instead"
+msgstr ""
+
+#: merge-recursive.c:1447
+#, c-format
+msgid "CONFLICT (rename/add): Rename %s->%s in %s. %s added in %s"
+msgstr ""
+
+#: merge-recursive.c:1457
+#, c-format
+msgid "Adding merged %s"
+msgstr ""
+
+#: merge-recursive.c:1462 merge-recursive.c:1660
+#, c-format
+msgid "Adding as %s instead"
+msgstr ""
+
+#: merge-recursive.c:1513
+#, c-format
+msgid "cannot read object %s"
+msgstr ""
+
+#: merge-recursive.c:1516
+#, c-format
+msgid "object %s is not a blob"
+msgstr ""
+
+#: merge-recursive.c:1564
+msgid "modify"
+msgstr ""
+
+#: merge-recursive.c:1564
+msgid "modified"
+msgstr ""
+
+#: merge-recursive.c:1574
+msgid "content"
+msgstr ""
+
+#: merge-recursive.c:1581
+msgid "add/add"
+msgstr ""
+
+#: merge-recursive.c:1615
+#, c-format
+msgid "Skipped %s (merged same as existing)"
+msgstr ""
+
+#: merge-recursive.c:1629
+#, c-format
+msgid "Auto-merging %s"
+msgstr ""
+
+#: merge-recursive.c:1633 git-submodule.sh:869
+msgid "submodule"
+msgstr ""
+
+#: merge-recursive.c:1634
+#, c-format
+msgid "CONFLICT (%s): Merge conflict in %s"
+msgstr ""
+
+#: merge-recursive.c:1724
+#, c-format
+msgid "Removing %s"
+msgstr ""
+
+#: merge-recursive.c:1749
+msgid "file/directory"
+msgstr ""
+
+#: merge-recursive.c:1755
+msgid "directory/file"
+msgstr ""
+
+#: merge-recursive.c:1760
+#, c-format
+msgid "CONFLICT (%s): There is a directory with name %s in %s. Adding %s as %s"
+msgstr ""
+
+#: merge-recursive.c:1770
+#, c-format
+msgid "Adding %s"
+msgstr ""
+
+#: merge-recursive.c:1787
+msgid "Fatal merge failure, shouldn't happen."
+msgstr ""
+
+#: merge-recursive.c:1806
+msgid "Already up-to-date!"
+msgstr ""
+
+#: merge-recursive.c:1815
+#, c-format
+msgid "merging of trees %s and %s failed"
+msgstr ""
+
+#: merge-recursive.c:1845
+#, c-format
+msgid "Unprocessed path??? %s"
+msgstr ""
+
+#: merge-recursive.c:1890
+msgid "Merging:"
+msgstr ""
+
+#: merge-recursive.c:1903
+#, c-format
+msgid "found %u common ancestor:"
+msgid_plural "found %u common ancestors:"
+msgstr[0] ""
+msgstr[1] ""
+
+#: merge-recursive.c:1940
+msgid "merge returned no commit"
+msgstr ""
+
+#: merge-recursive.c:1997
+#, c-format
+msgid "Could not parse object '%s'"
+msgstr ""
+
+#: merge-recursive.c:2009 builtin/merge.c:696
+msgid "Unable to write index."
+msgstr ""
+
+#: parse-options.c:494
 msgid "..."
 msgstr ""
 
-#: parse-options.c:511
+#: parse-options.c:512
 #, c-format
 msgid "usage: %s"
 msgstr ""
 
 #. TRANSLATORS: the colon here should align with the
 #. one in "usage: %s" translation
-#: parse-options.c:515
+#: parse-options.c:516
 #, c-format
 msgid "   or: %s"
 msgstr ""
 
-#: parse-options.c:518
+#: parse-options.c:519
 #, c-format
 msgid "    %s"
 msgstr ""
 
-#: remote.c:1629
+#: remote.c:1632
 #, 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] ""
 msgstr[1] ""
 
-#: remote.c:1635
+#: remote.c:1638
 #, c-format
 msgid "Your branch is behind '%s' by %d commit, and can be fast-forwarded.\n"
 msgid_plural ""
@@ -363,7 +673,7 @@ msgid_plural ""
 msgstr[0] ""
 msgstr[1] ""
 
-#: remote.c:1643
+#: remote.c:1646
 #, c-format
 msgid ""
 "Your branch and '%s' have diverged,\n"
@@ -374,505 +684,622 @@ msgid_plural ""
 msgstr[0] ""
 msgstr[1] ""
 
-#: sequencer.c:121 builtin/merge.c:865 builtin/merge.c:978
-#: builtin/merge.c:1088 builtin/merge.c:1098
+#: sequencer.c:123 builtin/merge.c:864 builtin/merge.c:977
+#: builtin/merge.c:1087 builtin/merge.c:1097
 #, c-format
 msgid "Could not open '%s' for writing"
 msgstr ""
 
-#: sequencer.c:123 builtin/merge.c:333 builtin/merge.c:868
-#: builtin/merge.c:1090 builtin/merge.c:1103
+#: sequencer.c:125 builtin/merge.c:333 builtin/merge.c:867
+#: builtin/merge.c:1089 builtin/merge.c:1102
 #, c-format
 msgid "Could not write to '%s'"
 msgstr ""
 
-#: sequencer.c:144
+#: sequencer.c:146
 msgid ""
 "after resolving the conflicts, mark the corrected paths\n"
 "with 'git add <paths>' or 'git rm <paths>'"
 msgstr ""
 
-#: 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"
 "and commit the result with 'git commit'"
 msgstr ""
 
-#: 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 ""
 
-#: sequencer.c:163
+#: sequencer.c:165
 #, c-format
 msgid "Error wrapping up %s"
 msgstr ""
 
-#: sequencer.c:178
+#: sequencer.c:180
 msgid "Your local changes would be overwritten by cherry-pick."
 msgstr ""
 
-#: sequencer.c:180
+#: sequencer.c:182
 msgid "Your local changes would be overwritten by revert."
 msgstr ""
 
-#: sequencer.c:183
+#: sequencer.c:185
 msgid "Commit your changes or stash them to proceed."
 msgstr ""
 
 #. 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 ""
 
-#: sequencer.c:261
+#: sequencer.c:266
 msgid "Could not resolve HEAD commit\n"
 msgstr ""
 
-#: sequencer.c:282
+#: sequencer.c:287
 msgid "Unable to update cache tree\n"
 msgstr ""
 
-#: sequencer.c:324
+#: sequencer.c:332
 #, c-format
 msgid "Could not parse commit %s\n"
 msgstr ""
 
-#: sequencer.c:329
+#: sequencer.c:337
 #, c-format
 msgid "Could not parse parent commit %s\n"
 msgstr ""
 
-#: sequencer.c:395
+#: sequencer.c:403
 msgid "Your index file is unmerged."
 msgstr ""
 
-#: sequencer.c:398
+#: sequencer.c:406
 msgid "You do not have a valid HEAD"
 msgstr ""
 
-#: sequencer.c:413
+#: sequencer.c:421
 #, c-format
 msgid "Commit %s is a merge but no -m option was given."
 msgstr ""
 
-#: sequencer.c:421
+#: sequencer.c:429
 #, c-format
 msgid "Commit %s does not have parent %d"
 msgstr ""
 
-#: sequencer.c:425
+#: sequencer.c:433
 #, c-format
 msgid "Mainline was specified but commit %s is not a merge."
 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 ""
 
-#: sequencer.c:440
+#: sequencer.c:448
 #, c-format
 msgid "Cannot get commit message for %s"
 msgstr ""
 
-#: sequencer.c:524
+#: sequencer.c:532
 #, c-format
 msgid "could not revert %s... %s"
 msgstr ""
 
-#: sequencer.c:525
+#: sequencer.c:533
 #, c-format
 msgid "could not apply %s... %s"
 msgstr ""
 
-#: sequencer.c:553
+#: sequencer.c:565
 msgid "empty commit set passed"
 msgstr ""
 
-#: sequencer.c:561
+#: sequencer.c:573
 #, c-format
 msgid "git %s: failed to read the index"
 msgstr ""
 
-#: sequencer.c:566
+#: sequencer.c:578
 #, c-format
 msgid "git %s: failed to refresh the index"
 msgstr ""
 
-#: sequencer.c:624
+#: sequencer.c:636
 #, c-format
 msgid "Cannot %s during a %s"
 msgstr ""
 
-#: sequencer.c:646
+#: sequencer.c:658
 #, c-format
 msgid "Could not parse line %d."
 msgstr ""
 
-#: sequencer.c:651
+#: sequencer.c:663
 msgid "No commits parsed."
 msgstr ""
 
-#: sequencer.c:664
+#: sequencer.c:676
 #, c-format
 msgid "Could not open %s"
 msgstr ""
 
-#: sequencer.c:668
+#: sequencer.c:680
 #, c-format
 msgid "Could not read %s."
 msgstr ""
 
-#: sequencer.c:675
+#: sequencer.c:687
 #, c-format
 msgid "Unusable instruction sheet: %s"
 msgstr ""
 
-#: sequencer.c:703
+#: sequencer.c:715
 #, c-format
 msgid "Invalid key: %s"
 msgstr ""
 
-#: sequencer.c:706
+#: sequencer.c:718
 #, c-format
 msgid "Invalid value for %s: %s"
 msgstr ""
 
-#: sequencer.c:718
+#: sequencer.c:730
 #, c-format
 msgid "Malformed options sheet: %s"
 msgstr ""
 
-#: sequencer.c:739
+#: sequencer.c:751
 msgid "a cherry-pick or revert is already in progress"
 msgstr ""
 
-#: sequencer.c:740
+#: sequencer.c:752
 msgid "try \"git cherry-pick (--continue | --quit | --abort)\""
 msgstr ""
 
-#: sequencer.c:744
+#: sequencer.c:756
 #, c-format
 msgid "Could not create sequencer directory %s"
 msgstr ""
 
-#: sequencer.c:760 sequencer.c:845
+#: sequencer.c:772 sequencer.c:857
 #, c-format
 msgid "Error wrapping up %s."
 msgstr ""
 
-#: sequencer.c:779 sequencer.c:913
+#: sequencer.c:791 sequencer.c:925
 msgid "no cherry-pick or revert in progress"
 msgstr ""
 
-#: sequencer.c:781
+#: sequencer.c:793
 msgid "cannot resolve HEAD"
 msgstr ""
 
-#: sequencer.c:783
+#: sequencer.c:795
 msgid "cannot abort from a branch yet to be born"
 msgstr ""
 
-#: sequencer.c:805 builtin/apply.c:3697
+#: sequencer.c:817 builtin/apply.c:4005
 #, c-format
 msgid "cannot open %s: %s"
 msgstr ""
 
-#: sequencer.c:808
+#: sequencer.c:820
 #, c-format
 msgid "cannot read %s: %s"
 msgstr ""
 
-#: sequencer.c:809
+#: sequencer.c:821
 msgid "unexpected end of file"
 msgstr ""
 
-#: sequencer.c:815
+#: sequencer.c:827
 #, c-format
 msgid "stored pre-cherry-pick HEAD file '%s' is corrupt"
 msgstr ""
 
-#: sequencer.c:838
+#: sequencer.c:850
 #, c-format
 msgid "Could not format %s."
 msgstr ""
 
-#: sequencer.c:1000
+#: sequencer.c:1012
 msgid "Can't revert as initial commit"
 msgstr ""
 
-#: sequencer.c:1001
+#: sequencer.c:1013
 msgid "Can't cherry-pick into empty head"
 msgstr ""
 
-#: sha1_name.c:864
+#: sha1_name.c:1044
 msgid "HEAD does not point to a branch"
 msgstr ""
 
-#: sha1_name.c:867
+#: sha1_name.c:1047
 #, c-format
 msgid "No such branch: '%s'"
 msgstr ""
 
-#: sha1_name.c:869
+#: sha1_name.c:1049
 #, c-format
 msgid "No upstream configured for branch '%s'"
 msgstr ""
 
-#: sha1_name.c:872
+#: sha1_name.c:1052
 #, c-format
 msgid "Upstream branch '%s' not stored as a remote-tracking branch"
 msgstr ""
 
-#: wrapper.c:413
+#: wrapper.c:408
+#, c-format
+msgid "unable to access '%s': %s"
+msgstr ""
+
+#: wrapper.c:426
 #, c-format
 msgid "unable to look up current user in the passwd file: %s"
 msgstr ""
 
-#: wrapper.c:414
+#: wrapper.c:427
 msgid "no such user"
 msgstr ""
 
-#: wt-status.c:135
+#: wt-status.c:140
 msgid "Unmerged paths:"
 msgstr ""
 
-#: wt-status.c:141 wt-status.c:158
+#: wt-status.c:167 wt-status.c:194
 #, c-format
 msgid "  (use \"git reset %s <file>...\" to unstage)"
 msgstr ""
 
-#: wt-status.c:143 wt-status.c:160
+#: wt-status.c:169 wt-status.c:196
 msgid "  (use \"git rm --cached <file>...\" to unstage)"
 msgstr ""
 
-#: wt-status.c:144
+#: wt-status.c:173
+msgid "  (use \"git add <file>...\" to mark resolution)"
+msgstr ""
+
+#: wt-status.c:175 wt-status.c:179
 msgid "  (use \"git add/rm <file>...\" as appropriate to mark resolution)"
 msgstr ""
 
-#: wt-status.c:152
+#: wt-status.c:177
+msgid "  (use \"git rm <file>...\" to mark resolution)"
+msgstr ""
+
+#: wt-status.c:188
 msgid "Changes to be committed:"
 msgstr ""
 
-#: wt-status.c:170
+#: wt-status.c:206
 msgid "Changes not staged for commit:"
 msgstr ""
 
-#: wt-status.c:174
+#: wt-status.c:210
 msgid "  (use \"git add <file>...\" to update what will be committed)"
 msgstr ""
 
-#: wt-status.c:176
+#: wt-status.c:212
 msgid "  (use \"git add/rm <file>...\" to update what will be committed)"
 msgstr ""
 
-#: wt-status.c:177
+#: wt-status.c:213
 msgid ""
 "  (use \"git checkout -- <file>...\" to discard changes in working directory)"
 msgstr ""
 
-#: wt-status.c:179
+#: wt-status.c:215
 msgid "  (commit or discard the untracked or modified content in submodules)"
 msgstr ""
 
-#: wt-status.c:188
-#, c-format
-msgid "%s files:"
-msgstr ""
-
-#: wt-status.c:191
+#: wt-status.c:227
 #, c-format
 msgid "  (use \"git %s <file>...\" to include in what will be committed)"
 msgstr ""
 
-#: wt-status.c:208
+#: wt-status.c:244
 msgid "bug"
 msgstr ""
 
-#: wt-status.c:213
+#: wt-status.c:249
 msgid "both deleted:"
 msgstr ""
 
-#: wt-status.c:214
+#: wt-status.c:250
 msgid "added by us:"
 msgstr ""
 
-#: wt-status.c:215
+#: wt-status.c:251
 msgid "deleted by them:"
 msgstr ""
 
-#: wt-status.c:216
+#: wt-status.c:252
 msgid "added by them:"
 msgstr ""
 
-#: wt-status.c:217
+#: wt-status.c:253
 msgid "deleted by us:"
 msgstr ""
 
-#: wt-status.c:218
+#: wt-status.c:254
 msgid "both added:"
 msgstr ""
 
-#: wt-status.c:219
+#: wt-status.c:255
 msgid "both modified:"
 msgstr ""
 
-#: wt-status.c:249
+#: wt-status.c:285
 msgid "new commits, "
 msgstr ""
 
-#: wt-status.c:251
+#: wt-status.c:287
 msgid "modified content, "
 msgstr ""
 
-#: wt-status.c:253
+#: wt-status.c:289
 msgid "untracked content, "
 msgstr ""
 
-#: wt-status.c:267
+#: wt-status.c:303
 #, c-format
 msgid "new file:   %s"
 msgstr ""
 
-#: wt-status.c:270
+#: wt-status.c:306
 #, c-format
 msgid "copied:     %s -> %s"
 msgstr ""
 
-#: wt-status.c:273
+#: wt-status.c:309
 #, c-format
 msgid "deleted:    %s"
 msgstr ""
 
-#: wt-status.c:276
+#: wt-status.c:312
 #, c-format
 msgid "modified:   %s"
 msgstr ""
 
-#: wt-status.c:279
+#: wt-status.c:315
 #, c-format
 msgid "renamed:    %s -> %s"
 msgstr ""
 
-#: wt-status.c:282
+#: wt-status.c:318
 #, c-format
 msgid "typechange: %s"
 msgstr ""
 
-#: wt-status.c:285
+#: wt-status.c:321
 #, c-format
 msgid "unknown:    %s"
 msgstr ""
 
-#: wt-status.c:288
+#: wt-status.c:324
 #, c-format
 msgid "unmerged:   %s"
 msgstr ""
 
-#: wt-status.c:291
+#: wt-status.c:327
 #, c-format
 msgid "bug: unhandled diff status %c"
 msgstr ""
 
-#: wt-status.c:737
-msgid "On branch "
+#: wt-status.c:785
+msgid "You have unmerged paths."
 msgstr ""
 
-#: wt-status.c:744
-msgid "Not currently on any branch."
+#: wt-status.c:788 wt-status.c:912
+msgid "  (fix conflicts and run \"git commit\")"
 msgstr ""
 
-#: wt-status.c:755
-msgid "Initial commit"
+#: wt-status.c:791
+msgid "All conflicts fixed but you are still merging."
 msgstr ""
 
-#: wt-status.c:769
-msgid "Untracked"
+#: wt-status.c:794
+msgid "  (use \"git commit\" to conclude merge)"
 msgstr ""
 
-#: wt-status.c:771
-msgid "Ignored"
+#: wt-status.c:804
+msgid "You are in the middle of an am session."
 msgstr ""
 
-#: wt-status.c:773
-#, c-format
-msgid "Untracked files not listed%s"
+#: wt-status.c:807
+msgid "The current patch is empty."
 msgstr ""
 
-#: wt-status.c:775
-msgid " (use -u option to show untracked files)"
+#: wt-status.c:811
+msgid "  (fix conflicts and then run \"git am --resolved\")"
 msgstr ""
 
-#: wt-status.c:781
-msgid "No changes"
+#: wt-status.c:813
+msgid "  (use \"git am --skip\" to skip this patch)"
 msgstr ""
 
-#: wt-status.c:785
-#, c-format
-msgid "no changes added to commit%s\n"
+#: wt-status.c:815
+msgid "  (use \"git am --abort\" to restore the original branch)"
 msgstr ""
 
-#: wt-status.c:787
-msgid " (use \"git add\" and/or \"git commit -a\")"
+#: wt-status.c:873 wt-status.c:883
+msgid "You are currently rebasing."
 msgstr ""
 
-#: wt-status.c:789
-#, c-format
-msgid "nothing added to commit but untracked files present%s\n"
+#: wt-status.c:876
+msgid "  (fix conflicts and then run \"git rebase --continue\")"
 msgstr ""
 
-#: wt-status.c:791
-msgid " (use \"git add\" to track)"
+#: wt-status.c:878
+msgid "  (use \"git rebase --skip\" to skip this patch)"
 msgstr ""
 
-#: wt-status.c:793 wt-status.c:796 wt-status.c:799
-#, c-format
-msgid "nothing to commit%s\n"
+#: wt-status.c:880
+msgid "  (use \"git rebase --abort\" to check out the original branch)"
 msgstr ""
 
-#: wt-status.c:794
-msgid " (create/copy files and use \"git add\" to track)"
+#: wt-status.c:886
+msgid "  (all conflicts fixed: run \"git rebase --continue\")"
 msgstr ""
 
-#: wt-status.c:797
-msgid " (use -u to show untracked files)"
+#: wt-status.c:888
+msgid "You are currently splitting a commit during a rebase."
 msgstr ""
 
-#: wt-status.c:800
-msgid " (working directory clean)"
+#: wt-status.c:891
+msgid "  (Once your working directory is clean, run \"git rebase --continue\")"
 msgstr ""
 
-#: wt-status.c:908
-msgid "HEAD (no branch)"
+#: wt-status.c:893
+msgid "You are currently editing a commit during a rebase."
 msgstr ""
 
-#: wt-status.c:914
-msgid "Initial commit on "
+#: wt-status.c:896
+msgid "  (use \"git commit --amend\" to amend the current commit)"
 msgstr ""
 
-#: wt-status.c:929
-msgid "behind "
+#: wt-status.c:898
+msgid ""
+"  (use \"git rebase --continue\" once you are satisfied with your changes)"
 msgstr ""
 
-#: wt-status.c:932 wt-status.c:935
+#: wt-status.c:908
+msgid "You are currently cherry-picking."
+msgstr ""
+
+#: wt-status.c:915
+msgid "  (all conflicts fixed: run \"git commit\")"
+msgstr ""
+
+#: wt-status.c:924
+msgid "You are currently bisecting."
+msgstr ""
+
+#: wt-status.c:927
+msgid "  (use \"git bisect reset\" to get back to the original branch)"
+msgstr ""
+
+#: wt-status.c:978
+msgid "On branch "
+msgstr ""
+
+#: wt-status.c:985
+msgid "Not currently on any branch."
+msgstr ""
+
+#: wt-status.c:997
+msgid "Initial commit"
+msgstr ""
+
+#: wt-status.c:1011
+msgid "Untracked files"
+msgstr ""
+
+#: wt-status.c:1013
+msgid "Ignored files"
+msgstr ""
+
+#: wt-status.c:1015
+#, c-format
+msgid "Untracked files not listed%s"
+msgstr ""
+
+#: wt-status.c:1017
+msgid " (use -u option to show untracked files)"
+msgstr ""
+
+#: wt-status.c:1023
+msgid "No changes"
+msgstr ""
+
+#: wt-status.c:1028
+#, c-format
+msgid "no changes added to commit (use \"git add\" and/or \"git commit -a\")\n"
+msgstr ""
+
+#: wt-status.c:1031
+#, c-format
+msgid "no changes added to commit\n"
+msgstr ""
+
+#: wt-status.c:1034
+#, c-format
+msgid ""
+"nothing added to commit but untracked files present (use \"git add\" to "
+"track)\n"
+msgstr ""
+
+#: wt-status.c:1037
+#, c-format
+msgid "nothing added to commit but untracked files present\n"
+msgstr ""
+
+#: wt-status.c:1040
+#, c-format
+msgid "nothing to commit (create/copy files and use \"git add\" to track)\n"
+msgstr ""
+
+#: wt-status.c:1043 wt-status.c:1048
+#, c-format
+msgid "nothing to commit\n"
+msgstr ""
+
+#: wt-status.c:1046
+#, c-format
+msgid "nothing to commit (use -u to show untracked files)\n"
+msgstr ""
+
+#: wt-status.c:1050
+#, c-format
+msgid "nothing to commit, working directory clean\n"
+msgstr ""
+
+#: wt-status.c:1158
+msgid "HEAD (no branch)"
+msgstr ""
+
+#: wt-status.c:1164
+msgid "Initial commit on "
+msgstr ""
+
+#: wt-status.c:1179
+msgid "behind "
+msgstr ""
+
+#: wt-status.c:1182 wt-status.c:1185
 msgid "ahead "
 msgstr ""
 
-#: wt-status.c:937
+#: wt-status.c:1187
 msgid ", behind "
 msgstr ""
 
+#: compat/precompose_utf8.c:58 builtin/clone.c:341
+#, c-format
+msgid "failed to unlink '%s'"
+msgstr ""
+
+#: builtin/add.c:19
+msgid "git add [options] [--] <filepattern>..."
+msgstr ""
+
 #: builtin/add.c:62
 #, c-format
 msgid "unexpected diff status %c"
 msgstr ""
 
-#: builtin/add.c:67 builtin/commit.c:226
+#: builtin/add.c:67 builtin/commit.c:230
 msgid "updating files failed"
 msgstr ""
 
@@ -890,7 +1317,7 @@ msgstr ""
 msgid "Unstaged changes after refreshing the index:"
 msgstr ""
 
-#: builtin/add.c:195 builtin/add.c:456 builtin/rm.c:186
+#: builtin/add.c:195 builtin/add.c:460 builtin/rm.c:186
 #, c-format
 msgid "pathspec '%s' did not match any files"
 msgstr ""
@@ -927,110 +1354,162 @@ msgstr ""
 msgid "Could not apply '%s'"
 msgstr ""
 
-#: builtin/add.c:312
+#: builtin/add.c:313
 msgid "The following paths are ignored by one of your .gitignore files:\n"
 msgstr ""
 
-#: 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:133
+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/mv.c:62 builtin/read-tree.c:112
+msgid "be verbose"
+msgstr ""
+
+#: builtin/add.c:322
+msgid "interactive picking"
+msgstr ""
+
+#: builtin/add.c:323 builtin/checkout.c:1028 builtin/reset.c:248
+msgid "select hunks interactively"
+msgstr ""
+
+#: builtin/add.c:324
+msgid "edit current diff and apply"
+msgstr ""
+
+#: builtin/add.c:325
+msgid "allow adding otherwise ignored files"
+msgstr ""
+
+#: builtin/add.c:326
+msgid "update tracked files"
+msgstr ""
+
+#: builtin/add.c:327
+msgid "record only the fact that the path will be added later"
+msgstr ""
+
+#: builtin/add.c:328
+msgid "add changes from all tracked and untracked files"
+msgstr ""
+
+#: builtin/add.c:329
+msgid "don't add, only refresh the index"
+msgstr ""
+
+#: builtin/add.c:330
+msgid "just skip files which cannot be added because of errors"
+msgstr ""
+
+#: builtin/add.c:331
+msgid "check if - even missing - files are ignored in dry run"
+msgstr ""
+
+#: builtin/add.c:353
 #, c-format
 msgid "Use -f if you really want to add them.\n"
 msgstr ""
 
-#: builtin/add.c:353
+#: builtin/add.c:354
 msgid "no files added"
 msgstr ""
 
-#: builtin/add.c:359
+#: builtin/add.c:360
 msgid "adding files failed"
 msgstr ""
 
-#: builtin/add.c:391
+#: builtin/add.c:392
 msgid "-A and -u are mutually incompatible"
 msgstr ""
 
-#: builtin/add.c:393
+#: builtin/add.c:394
 msgid "Option --ignore-missing can only be used together with --dry-run"
 msgstr ""
 
-#: builtin/add.c:413
+#: builtin/add.c:414
 #, c-format
 msgid "Nothing specified, nothing added.\n"
 msgstr ""
 
-#: builtin/add.c:414
+#: builtin/add.c:415
 #, c-format
 msgid "Maybe you wanted to say 'git add .'?\n"
 msgstr ""
 
-#: builtin/add.c:420 builtin/clean.c:95 builtin/commit.c:286 builtin/mv.c:82
+#: builtin/add.c:421 builtin/clean.c:95 builtin/commit.c:290 builtin/mv.c:82
 #: builtin/rm.c:162
 msgid "index file corrupt"
 msgstr ""
 
-#: builtin/add.c:476 builtin/apply.c:4108 builtin/mv.c:229 builtin/rm.c:260
+#: builtin/add.c:481 builtin/apply.c:4450 builtin/mv.c:229 builtin/rm.c:260
 msgid "Unable to write new index file"
 msgstr ""
 
-#: builtin/apply.c:53
+#: builtin/apply.c:57
 msgid "git apply [options] [<patch>...]"
 msgstr ""
 
-#: builtin/apply.c:106
+#: builtin/apply.c:110
 #, c-format
 msgid "unrecognized whitespace option '%s'"
 msgstr ""
 
-#: builtin/apply.c:121
+#: builtin/apply.c:125
 #, c-format
 msgid "unrecognized whitespace ignore option '%s'"
 msgstr ""
 
-#: builtin/apply.c:815
+#: builtin/apply.c:823
 #, c-format
 msgid "Cannot prepare timestamp regexp %s"
 msgstr ""
 
-#: builtin/apply.c:824
+#: builtin/apply.c:832
 #, c-format
 msgid "regexec returned %d for input: %s"
 msgstr ""
 
-#: builtin/apply.c:905
+#: builtin/apply.c:913
 #, c-format
 msgid "unable to find filename in patch at line %d"
 msgstr ""
 
-#: builtin/apply.c:937
+#: builtin/apply.c:945
 #, c-format
 msgid "git apply: bad git-diff - expected /dev/null, got %s on line %d"
 msgstr ""
 
-#: builtin/apply.c:941
+#: builtin/apply.c:949
 #, c-format
 msgid "git apply: bad git-diff - inconsistent new filename on line %d"
 msgstr ""
 
-#: builtin/apply.c:942
+#: builtin/apply.c:950
 #, c-format
 msgid "git apply: bad git-diff - inconsistent old filename on line %d"
 msgstr ""
 
-#: builtin/apply.c:949
+#: builtin/apply.c:957
 #, c-format
 msgid "git apply: bad git-diff - expected /dev/null on line %d"
 msgstr ""
 
-#: builtin/apply.c:1394
+#: builtin/apply.c:1420
 #, c-format
 msgid "recount: unexpected line: %.*s"
 msgstr ""
 
-#: builtin/apply.c:1451
+#: builtin/apply.c:1477
 #, c-format
 msgid "patch fragment without header at line %d: %.*s"
 msgstr ""
 
-#: builtin/apply.c:1468
+#: builtin/apply.c:1494
 #, c-format
 msgid ""
 "git diff header lacks filename information when removing %d leading pathname "
@@ -1041,395 +1520,400 @@ msgid_plural ""
 msgstr[0] ""
 msgstr[1] ""
 
-#: builtin/apply.c:1628
+#: builtin/apply.c:1654
 msgid "new file depends on old contents"
 msgstr ""
 
-#: builtin/apply.c:1630
+#: builtin/apply.c:1656
 msgid "deleted file still has contents"
 msgstr ""
 
-#: builtin/apply.c:1656
+#: builtin/apply.c:1682
 #, c-format
 msgid "corrupt patch at line %d"
 msgstr ""
 
-#: builtin/apply.c:1692
+#: builtin/apply.c:1718
 #, c-format
 msgid "new file %s depends on old contents"
 msgstr ""
 
-#: builtin/apply.c:1694
+#: builtin/apply.c:1720
 #, c-format
 msgid "deleted file %s still has contents"
 msgstr ""
 
-#: builtin/apply.c:1697
+#: builtin/apply.c:1723
 #, c-format
 msgid "** warning: file %s becomes empty but is not deleted"
 msgstr ""
 
-#: builtin/apply.c:1843
+#: builtin/apply.c:1869
 #, c-format
 msgid "corrupt binary patch at line %d: %.*s"
 msgstr ""
 
 #. there has to be one hunk (forward hunk)
-#: builtin/apply.c:1872
+#: builtin/apply.c:1898
 #, c-format
 msgid "unrecognized binary patch at line %d"
 msgstr ""
 
-#: builtin/apply.c:1958
+#: builtin/apply.c:1984
 #, c-format
 msgid "patch with only garbage at line %d"
 msgstr ""
 
-#: builtin/apply.c:2048
+#: builtin/apply.c:2074
 #, c-format
 msgid "unable to read symlink %s"
 msgstr ""
 
-#: builtin/apply.c:2052
+#: builtin/apply.c:2078
 #, c-format
 msgid "unable to open or read %s"
 msgstr ""
 
-#: builtin/apply.c:2123
+#: builtin/apply.c:2149
 msgid "oops"
 msgstr ""
 
-#: builtin/apply.c:2645
+#: builtin/apply.c:2671
 #, c-format
 msgid "invalid start of line: '%c'"
 msgstr ""
 
-#: builtin/apply.c:2763
+#: 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)."
 msgstr[0] ""
 msgstr[1] ""
 
-#: builtin/apply.c:2775
+#: builtin/apply.c:2801
 #, c-format
 msgid "Context reduced to (%ld/%ld) to apply fragment at %d"
 msgstr ""
 
-#: builtin/apply.c:2781
+#: builtin/apply.c:2807
 #, c-format
 msgid ""
 "while searching for:\n"
 "%.*s"
 msgstr ""
 
-#: builtin/apply.c:2800
+#: builtin/apply.c:2826
 #, c-format
 msgid "missing binary patch data for '%s'"
 msgstr ""
 
-#: builtin/apply.c:2903
+#: builtin/apply.c:2929
 #, c-format
 msgid "binary patch does not apply to '%s'"
 msgstr ""
 
-#: builtin/apply.c:2909
+#: builtin/apply.c:2935
 #, c-format
 msgid "binary patch to '%s' creates incorrect result (expecting %s, got %s)"
 msgstr ""
 
-#: builtin/apply.c:2930
+#: builtin/apply.c:2956
 #, c-format
 msgid "patch failed: %s:%ld"
 msgstr ""
 
-#: builtin/apply.c:3045
+#: builtin/apply.c:3078
 #, c-format
-msgid "patch %s has been renamed/deleted"
+msgid "cannot checkout %s"
 msgstr ""
 
-#: builtin/apply.c:3052 builtin/apply.c:3069
+#: builtin/apply.c:3123 builtin/apply.c:3132 builtin/apply.c:3176
 #, c-format
 msgid "read of %s failed"
 msgstr ""
 
-#: builtin/apply.c:3084
-msgid "removal patch leaves file contents"
-msgstr ""
-
-#: builtin/apply.c:3105
+#: builtin/apply.c:3156 builtin/apply.c:3378
 #, c-format
-msgid "%s: already exists in working directory"
+msgid "path %s has been renamed/deleted"
 msgstr ""
 
-#: builtin/apply.c:3143
+#: builtin/apply.c:3237 builtin/apply.c:3392
 #, c-format
-msgid "%s: has been deleted/renamed"
+msgid "%s: does not exist in index"
 msgstr ""
 
-#: builtin/apply.c:3148 builtin/apply.c:3179
+#: builtin/apply.c:3241 builtin/apply.c:3384 builtin/apply.c:3406
 #, c-format
 msgid "%s: %s"
 msgstr ""
 
-#: builtin/apply.c:3159
+#: builtin/apply.c:3246 builtin/apply.c:3400
 #, c-format
-msgid "%s: does not exist in index"
+msgid "%s: does not match index"
 msgstr ""
 
-#: builtin/apply.c:3173
-#, c-format
-msgid "%s: does not match index"
+#: builtin/apply.c:3348
+msgid "removal patch leaves file contents"
 msgstr ""
 
-#: builtin/apply.c:3190
+#: builtin/apply.c:3417
 #, c-format
 msgid "%s: wrong type"
 msgstr ""
 
-#: builtin/apply.c:3192
+#: builtin/apply.c:3419
 #, c-format
 msgid "%s has type %o, expected %o"
 msgstr ""
 
-#: builtin/apply.c:3247
+#: builtin/apply.c:3520
 #, c-format
 msgid "%s: already exists in index"
 msgstr ""
 
-#: builtin/apply.c:3267
+#: builtin/apply.c:3523
+#, c-format
+msgid "%s: already exists in working directory"
+msgstr ""
+
+#: builtin/apply.c:3543
 #, c-format
 msgid "new mode (%o) of %s does not match old mode (%o)"
 msgstr ""
 
-#: builtin/apply.c:3272
+#: builtin/apply.c:3548
 #, c-format
 msgid "new mode (%o) of %s does not match old mode (%o) of %s"
 msgstr ""
 
-#: builtin/apply.c:3280
+#: builtin/apply.c:3556
 #, c-format
 msgid "%s: patch does not apply"
 msgstr ""
 
-#: builtin/apply.c:3293
+#: builtin/apply.c:3569
 #, c-format
 msgid "Checking patch %s..."
 msgstr ""
 
-#: builtin/apply.c:3348 builtin/checkout.c:212 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 ""
 
-#: builtin/apply.c:3491
+#: builtin/apply.c:3767
 #, c-format
 msgid "unable to remove %s from index"
 msgstr ""
 
-#: builtin/apply.c:3518
+#: builtin/apply.c:3795
 #, c-format
 msgid "corrupt patch for subproject %s"
 msgstr ""
 
-#: builtin/apply.c:3522
+#: builtin/apply.c:3799
 #, c-format
 msgid "unable to stat newly created file '%s'"
 msgstr ""
 
-#: builtin/apply.c:3527
+#: builtin/apply.c:3804
 #, c-format
 msgid "unable to create backing store for newly created file %s"
 msgstr ""
 
-#: builtin/apply.c:3530
+#: builtin/apply.c:3807 builtin/apply.c:3915
 #, c-format
 msgid "unable to add cache entry for %s"
 msgstr ""
 
-#: builtin/apply.c:3563
+#: builtin/apply.c:3840
 #, c-format
 msgid "closing file '%s'"
 msgstr ""
 
-#: builtin/apply.c:3612
+#: builtin/apply.c:3889
 #, c-format
 msgid "unable to write file '%s' mode %o"
 msgstr ""
 
-#: builtin/apply.c:3668
+#: builtin/apply.c:3976
 #, c-format
 msgid "Applied patch %s cleanly."
 msgstr ""
 
-#: builtin/apply.c:3676
+#: builtin/apply.c:3984
 msgid "internal error"
 msgstr ""
 
 #. Say this even without --verbose
-#: builtin/apply.c:3679
+#: builtin/apply.c:3987
 #, c-format
 msgid "Applying patch %%s with %d reject..."
 msgid_plural "Applying patch %%s with %d rejects..."
 msgstr[0] ""
 msgstr[1] ""
 
-#: builtin/apply.c:3689
+#: builtin/apply.c:3997
 #, c-format
 msgid "truncating .rej filename to %.*s.rej"
 msgstr ""
 
-#: builtin/apply.c:3710
+#: builtin/apply.c:4018
 #, c-format
 msgid "Hunk #%d applied cleanly."
 msgstr ""
 
-#: builtin/apply.c:3713
+#: builtin/apply.c:4021
 #, c-format
 msgid "Rejected hunk #%d."
 msgstr ""
 
-#: builtin/apply.c:3844
+#: builtin/apply.c:4171
 msgid "unrecognized input"
 msgstr ""
 
-#: builtin/apply.c:3855
+#: builtin/apply.c:4182
 msgid "unable to read index file"
 msgstr ""
 
-#: builtin/apply.c:3970 builtin/apply.c:3973
+#: builtin/apply.c:4301 builtin/apply.c:4304 builtin/clone.c:91
+#: builtin/fetch.c:63
 msgid "path"
 msgstr ""
 
-#: builtin/apply.c:3971
+#: builtin/apply.c:4302
 msgid "don't apply changes matching the given path"
 msgstr ""
 
-#: builtin/apply.c:3974
+#: builtin/apply.c:4305
 msgid "apply changes matching the given path"
 msgstr ""
 
-#: builtin/apply.c:3976
+#: builtin/apply.c:4307
 msgid "num"
 msgstr ""
 
-#: builtin/apply.c:3977
+#: builtin/apply.c:4308
 msgid "remove <num> leading slashes from traditional diff paths"
 msgstr ""
 
-#: builtin/apply.c:3980
+#: builtin/apply.c:4311
 msgid "ignore additions made by the patch"
 msgstr ""
 
-#: builtin/apply.c:3982
+#: builtin/apply.c:4313
 msgid "instead of applying the patch, output diffstat for the input"
 msgstr ""
 
-#: builtin/apply.c:3986
-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 ""
 
-#: builtin/apply.c:3988
+#: builtin/apply.c:4319
 msgid "instead of applying the patch, output a summary for the input"
 msgstr ""
 
-#: builtin/apply.c:3990
+#: builtin/apply.c:4321
 msgid "instead of applying the patch, see if the patch is applicable"
 msgstr ""
 
-#: builtin/apply.c:3992
+#: builtin/apply.c:4323
 msgid "make sure the patch is applicable to the current index"
 msgstr ""
 
-#: builtin/apply.c:3994
+#: builtin/apply.c:4325
 msgid "apply a patch without touching the working tree"
 msgstr ""
 
-#: builtin/apply.c:3996
+#: builtin/apply.c:4327
 msgid "also apply the patch (use with --stat/--summary/--check)"
 msgstr ""
 
-#: builtin/apply.c:3998
+#: builtin/apply.c:4329
+msgid "attempt three-way merge if a patch does not apply"
+msgstr ""
+
+#: builtin/apply.c:4331
 msgid "build a temporary index based on embedded index information"
 msgstr ""
 
-#: builtin/apply.c:4000
+#: builtin/apply.c:4333 builtin/checkout-index.c:197 builtin/ls-files.c:460
 msgid "paths are separated with NUL character"
 msgstr ""
 
-#: builtin/apply.c:4003
+#: builtin/apply.c:4336
 msgid "ensure at least <n> lines of context match"
 msgstr ""
 
-#: builtin/apply.c:4004
+#: builtin/apply.c:4337
 msgid "action"
 msgstr ""
 
-#: builtin/apply.c:4005
+#: builtin/apply.c:4338
 msgid "detect new or modified lines that have whitespace errors"
 msgstr ""
 
-#: builtin/apply.c:4008 builtin/apply.c:4011
+#: builtin/apply.c:4341 builtin/apply.c:4344
 msgid "ignore changes in whitespace when finding context"
 msgstr ""
 
-#: builtin/apply.c:4014
+#: builtin/apply.c:4347
 msgid "apply the patch in reverse"
 msgstr ""
 
-#: builtin/apply.c:4016
+#: builtin/apply.c:4349
 msgid "don't expect at least one line of context"
 msgstr ""
 
-#: builtin/apply.c:4018
+#: builtin/apply.c:4351
 msgid "leave the rejected hunks in corresponding *.rej files"
 msgstr ""
 
-#: builtin/apply.c:4020
+#: builtin/apply.c:4353
 msgid "allow overlapping hunks"
 msgstr ""
 
-#: builtin/apply.c:4021
-msgid "be verbose"
-msgstr ""
-
-#: builtin/apply.c:4023
+#: builtin/apply.c:4356
 msgid "tolerate incorrectly detected missing new-line at the end of file"
 msgstr ""
 
-#: builtin/apply.c:4026
+#: builtin/apply.c:4359
 msgid "do not trust the line counts in the hunk headers"
 msgstr ""
 
-#: builtin/apply.c:4028
+#: builtin/apply.c:4361
 msgid "root"
 msgstr ""
 
-#: builtin/apply.c:4029
+#: builtin/apply.c:4362
 msgid "prepend <root> to all filenames"
 msgstr ""
 
-#: builtin/apply.c:4050
+#: builtin/apply.c:4384
+msgid "--3way outside a repository"
+msgstr ""
+
+#: builtin/apply.c:4392
 msgid "--index outside a repository"
 msgstr ""
 
-#: builtin/apply.c:4053
+#: builtin/apply.c:4395
 msgid "--cached outside a repository"
 msgstr ""
 
-#: builtin/apply.c:4069
+#: builtin/apply.c:4411
 #, c-format
 msgid "can't open patch '%s'"
 msgstr ""
 
-#: builtin/apply.c:4083
+#: builtin/apply.c:4425
 #, c-format
 msgid "squelched %d whitespace error"
 msgid_plural "squelched %d whitespace errors"
 msgstr[0] ""
 msgstr[1] ""
 
-#: builtin/apply.c:4089 builtin/apply.c:4099
+#: builtin/apply.c:4431 builtin/apply.c:4441
 #, c-format
 msgid "%d line adds whitespace errors."
 msgid_plural "%d lines add whitespace errors."
@@ -1471,2872 +1955,5816 @@ msgstr ""
 msgid "git archive: expected a flush"
 msgstr ""
 
-#: builtin/branch.c:144
+#: builtin/bisect--helper.c:7
+msgid "git bisect--helper --next-all [--no-checkout]"
+msgstr ""
+
+#: builtin/bisect--helper.c:17
+msgid "perform 'git bisect next'"
+msgstr ""
+
+#: builtin/bisect--helper.c:19
+msgid "update BISECT_HEAD instead of checking out the current commit"
+msgstr ""
+
+#: builtin/blame.c:25
+msgid "git blame [options] [rev-opts] [rev] [--] file"
+msgstr ""
+
+#: builtin/blame.c:30 builtin/shortlog.c:15
+msgid "[rev-opts] are documented in git-rev-list(1)"
+msgstr ""
+
+#: builtin/blame.c:2373
+msgid "Show blame entries as we find them, incrementally"
+msgstr ""
+
+#: builtin/blame.c:2374
+msgid "Show blank SHA-1 for boundary commits (Default: off)"
+msgstr ""
+
+#: builtin/blame.c:2375
+msgid "Do not treat root commits as boundaries (Default: off)"
+msgstr ""
+
+#: builtin/blame.c:2376
+msgid "Show work cost statistics"
+msgstr ""
+
+#: builtin/blame.c:2377
+msgid "Show output score for blame entries"
+msgstr ""
+
+#: builtin/blame.c:2378
+msgid "Show original filename (Default: auto)"
+msgstr ""
+
+#: builtin/blame.c:2379
+msgid "Show original linenumber (Default: off)"
+msgstr ""
+
+#: builtin/blame.c:2380
+msgid "Show in a format designed for machine consumption"
+msgstr ""
+
+#: builtin/blame.c:2381
+msgid "Show porcelain format with per-line commit information"
+msgstr ""
+
+#: builtin/blame.c:2382
+msgid "Use the same output mode as git-annotate (Default: off)"
+msgstr ""
+
+#: builtin/blame.c:2383
+msgid "Show raw timestamp (Default: off)"
+msgstr ""
+
+#: builtin/blame.c:2384
+msgid "Show long commit SHA1 (Default: off)"
+msgstr ""
+
+#: builtin/blame.c:2385
+msgid "Suppress author name and timestamp (Default: off)"
+msgstr ""
+
+#: builtin/blame.c:2386
+msgid "Show author email instead of name (Default: off)"
+msgstr ""
+
+#: builtin/blame.c:2387
+msgid "Ignore whitespace differences"
+msgstr ""
+
+#: builtin/blame.c:2388
+msgid "Spend extra cycles to find better match"
+msgstr ""
+
+#: builtin/blame.c:2389
+msgid "Use revisions from <file> instead of calling git-rev-list"
+msgstr ""
+
+#: builtin/blame.c:2390
+msgid "Use <file>'s contents as the final image"
+msgstr ""
+
+#: builtin/blame.c:2391 builtin/blame.c:2392
+msgid "score"
+msgstr ""
+
+#: builtin/blame.c:2391
+msgid "Find line copies within and across files"
+msgstr ""
+
+#: builtin/blame.c:2392
+msgid "Find line movements within and across files"
+msgstr ""
+
+#: builtin/blame.c:2393
+msgid "n,m"
+msgstr ""
+
+#: builtin/blame.c:2393
+msgid "Process only line range n,m, counting from 1"
+msgstr ""
+
+#: builtin/branch.c:23
+msgid "git branch [options] [-r | -a] [--merged | --no-merged]"
+msgstr ""
+
+#: builtin/branch.c:24
+msgid "git branch [options] [-l] [-f] <branchname> [<start-point>]"
+msgstr ""
+
+#: builtin/branch.c:25
+msgid "git branch [options] [-r] (-d | -D) <branchname>..."
+msgstr ""
+
+#: builtin/branch.c:26
+msgid "git branch [options] (-m | -M) [<oldbranch>] <newbranch>"
+msgstr ""
+
+#: builtin/branch.c:145
 #, c-format
 msgid ""
 "deleting branch '%s' that has been merged to\n"
 "         '%s', but not yet merged to HEAD."
 msgstr ""
 
-#: builtin/branch.c:148
+#: builtin/branch.c:149
 #, c-format
 msgid ""
 "not deleting branch '%s' that is not yet merged to\n"
 "         '%s', even though it is merged to HEAD."
 msgstr ""
 
-#: builtin/branch.c:180
+#: builtin/branch.c:181
 msgid "cannot use -a with -d"
 msgstr ""
 
-#: builtin/branch.c:186
+#: builtin/branch.c:187
 msgid "Couldn't look up commit object for HEAD"
 msgstr ""
 
-#: builtin/branch.c:191
+#: builtin/branch.c:192
 #, c-format
 msgid "Cannot delete the branch '%s' which you are currently on."
 msgstr ""
 
-#: builtin/branch.c:202
+#: builtin/branch.c:203
 #, c-format
 msgid "remote branch '%s' not found."
 msgstr ""
 
-#: builtin/branch.c:203
+#: builtin/branch.c:204
 #, c-format
 msgid "branch '%s' not found."
 msgstr ""
 
-#: builtin/branch.c:210
+#: builtin/branch.c:211
 #, c-format
 msgid "Couldn't look up commit object for '%s'"
 msgstr ""
 
-#: builtin/branch.c:216
+#: 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:225
+#: builtin/branch.c:226
 #, c-format
 msgid "Error deleting remote branch '%s'"
 msgstr ""
 
-#: builtin/branch.c:226
+#: builtin/branch.c:227
 #, c-format
 msgid "Error deleting branch '%s'"
 msgstr ""
 
-#: builtin/branch.c:233
+#: builtin/branch.c:234
 #, c-format
 msgid "Deleted remote branch %s (was %s).\n"
 msgstr ""
 
-#: builtin/branch.c:234
+#: builtin/branch.c:235
 #, c-format
 msgid "Deleted branch %s (was %s).\n"
 msgstr ""
 
-#: builtin/branch.c:239
+#: builtin/branch.c:240
 msgid "Update of config-file failed"
 msgstr ""
 
-#: builtin/branch.c:337
+#: builtin/branch.c:338
 #, c-format
 msgid "branch '%s' does not point at a commit"
 msgstr ""
 
-#: builtin/branch.c:409
+#: builtin/branch.c:410
 #, c-format
 msgid "[%s: behind %d]"
 msgstr ""
 
-#: builtin/branch.c:411
+#: builtin/branch.c:412
 #, c-format
 msgid "[behind %d]"
 msgstr ""
 
-#: builtin/branch.c:415
+#: builtin/branch.c:416
 #, c-format
 msgid "[%s: ahead %d]"
 msgstr ""
 
-#: builtin/branch.c:417
+#: builtin/branch.c:418
 #, c-format
 msgid "[ahead %d]"
 msgstr ""
 
-#: builtin/branch.c:420
+#: builtin/branch.c:421
 #, c-format
 msgid "[%s: ahead %d, behind %d]"
 msgstr ""
 
-#: builtin/branch.c:423
+#: builtin/branch.c:424
 #, c-format
 msgid "[ahead %d, behind %d]"
 msgstr ""
 
-#: builtin/branch.c:535
+#: builtin/branch.c:537
 msgid "(no branch)"
 msgstr ""
 
-#: builtin/branch.c:600
+#: builtin/branch.c:602
 msgid "some refs could not be read"
 msgstr ""
 
-#: builtin/branch.c:613
+#: builtin/branch.c:615
 msgid "cannot rename the current branch while not on any."
 msgstr ""
 
-#: builtin/branch.c:623
+#: builtin/branch.c:625
 #, c-format
 msgid "Invalid branch name: '%s'"
 msgstr ""
 
-#: builtin/branch.c:638
+#: builtin/branch.c:640
 msgid "Branch rename failed"
 msgstr ""
 
-#: builtin/branch.c:642
+#: builtin/branch.c:644
 #, c-format
 msgid "Renamed a misnamed branch '%s' away"
 msgstr ""
 
-#: builtin/branch.c:646
+#: builtin/branch.c:648
 #, c-format
 msgid "Branch renamed to %s, but HEAD is not updated!"
 msgstr ""
 
-#: builtin/branch.c:653
+#: builtin/branch.c:655
 msgid "Branch is renamed, but update of config-file failed"
 msgstr ""
 
-#: builtin/branch.c:668
+#: builtin/branch.c:670
 #, c-format
 msgid "malformed object name %s"
 msgstr ""
 
-#: builtin/branch.c:692
+#: builtin/branch.c:694
 #, c-format
 msgid "could not write branch description template: %s"
 msgstr ""
 
-#: builtin/branch.c:783
-msgid "Failed to resolve HEAD as a valid ref."
+#: builtin/branch.c:724
+msgid "Generic options"
 msgstr ""
 
-#: builtin/branch.c:788 builtin/clone.c:558
-msgid "HEAD not found below refs/heads!"
+#: builtin/branch.c:726
+msgid "show hash and subject, give twice for upstream branch"
 msgstr ""
 
-#: builtin/branch.c:808
-msgid "--column and --verbose are incompatible"
+#: builtin/branch.c:727
+msgid "suppress informational messages"
 msgstr ""
 
-#: builtin/branch.c:857
-msgid "-a and -r options to 'git branch' do not make sense with a branch name"
+#: builtin/branch.c:728
+msgid "set up tracking mode (see git-pull(1))"
 msgstr ""
 
-#: builtin/bundle.c:47
-#, c-format
-msgid "%s is okay\n"
+#: builtin/branch.c:730
+msgid "change upstream info"
 msgstr ""
 
-#: builtin/bundle.c:56
-msgid "Need a repository to create a bundle."
+#: builtin/branch.c:734
+msgid "use colored output"
 msgstr ""
 
-#: builtin/bundle.c:60
-msgid "Need a repository to unbundle."
+#: builtin/branch.c:735
+msgid "act on remote-tracking branches"
 msgstr ""
 
-#: builtin/checkout.c:113 builtin/checkout.c:146
-#, c-format
-msgid "path '%s' does not have our version"
+#: 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
+msgid "commit"
 msgstr ""
 
-#: builtin/checkout.c:115 builtin/checkout.c:148
-#, c-format
-msgid "path '%s' does not have their version"
+#: builtin/branch.c:739 builtin/branch.c:745
+msgid "print only branches that contain the commit"
 msgstr ""
 
-#: builtin/checkout.c:131
-#, c-format
-msgid "path '%s' does not have all necessary versions"
+#: builtin/branch.c:751
+msgid "Specific git-branch actions:"
 msgstr ""
 
-#: builtin/checkout.c:175
-#, c-format
-msgid "path '%s' does not have necessary versions"
+#: builtin/branch.c:752
+msgid "list both remote-tracking and local branches"
 msgstr ""
 
-#: builtin/checkout.c:192
-#, c-format
-msgid "path '%s': cannot merge"
+#: builtin/branch.c:754
+msgid "delete fully merged branch"
 msgstr ""
 
-#: builtin/checkout.c:209
-#, c-format
-msgid "Unable to add merge result for '%s'"
+#: builtin/branch.c:755
+msgid "delete branch (even if not merged)"
 msgstr ""
 
-#: builtin/checkout.c:234 builtin/checkout.c:392
-msgid "corrupt index file"
+#: builtin/branch.c:756
+msgid "move/rename a branch and its reflog"
 msgstr ""
 
-#: builtin/checkout.c:264 builtin/checkout.c:271
-#, c-format
-msgid "path '%s' is unmerged"
+#: builtin/branch.c:757
+msgid "move/rename a branch, even if target exists"
 msgstr ""
 
-#: builtin/checkout.c:302 builtin/checkout.c:498 builtin/clone.c:583
-#: builtin/merge.c:812
-msgid "unable to write new index file"
+#: builtin/branch.c:758
+msgid "list branch names"
 msgstr ""
 
-#: builtin/checkout.c:319 builtin/diff.c:302 builtin/merge.c:408
-msgid "diff_setup_done failed"
+#: builtin/branch.c:759
+msgid "create the branch's reflog"
 msgstr ""
 
-#: builtin/checkout.c:414
-msgid "you need to resolve your current index first"
+#: builtin/branch.c:761
+msgid "edit the description for the branch"
 msgstr ""
 
-#: builtin/checkout.c:533
-#, c-format
-msgid "Can not do reflog for '%s'\n"
+#: builtin/branch.c:762
+msgid "force creation (when already exists)"
 msgstr ""
 
-#: builtin/checkout.c:566
-msgid "HEAD is now at"
+#: builtin/branch.c:765
+msgid "print only not merged branches"
 msgstr ""
 
-#: builtin/checkout.c:573
-#, c-format
-msgid "Reset branch '%s'\n"
+#: builtin/branch.c:771
+msgid "print only merged branches"
 msgstr ""
 
-#: builtin/checkout.c:576
-#, c-format
-msgid "Already on '%s'\n"
+#: builtin/branch.c:775
+msgid "list branches in columns"
 msgstr ""
 
-#: builtin/checkout.c:580
-#, c-format
-msgid "Switched to and reset branch '%s'\n"
+#: builtin/branch.c:788
+msgid "Failed to resolve HEAD as a valid ref."
 msgstr ""
 
-#: builtin/checkout.c:582
+#: builtin/branch.c:793 builtin/clone.c:561
+msgid "HEAD not found below refs/heads!"
+msgstr ""
+
+#: builtin/branch.c:813
+msgid "--column and --verbose are incompatible"
+msgstr ""
+
+#: builtin/branch.c:864
 #, c-format
-msgid "Switched to a new branch '%s'\n"
+msgid "branch '%s' does not exist"
 msgstr ""
 
-#: builtin/checkout.c:584
+#: builtin/branch.c:876
 #, c-format
-msgid "Switched to branch '%s'\n"
+msgid "Branch '%s' has no upstream information"
 msgstr ""
 
-#: builtin/checkout.c:640
+#: builtin/branch.c:891
+msgid "-a and -r options to 'git branch' do not make sense with a branch name"
+msgstr ""
+
+#: builtin/branch.c:894
 #, c-format
-msgid " ... and %d more.\n"
+msgid ""
+"The --set-upstream flag is deprecated and will be removed. Consider using --"
+"track or --set-upstream-to\n"
 msgstr ""
 
-#. The singular version
-#: builtin/checkout.c:646
+#: builtin/branch.c:911
 #, c-format
 msgid ""
-"Warning: you are leaving %d commit behind, not connected to\n"
-"any of your branches:\n"
 "\n"
-"%s\n"
-msgid_plural ""
-"Warning: you are leaving %d commits behind, not connected to\n"
-"any of your branches:\n"
+"If you wanted to make '%s' track '%s', do this:\n"
 "\n"
-"%s\n"
-msgstr[0] ""
-msgstr[1] ""
+msgstr ""
 
-#: builtin/checkout.c:664
+#: builtin/branch.c:912
 #, c-format
-msgid ""
-"If you want to keep them by creating a new branch, this may be a good time\n"
-"to do so with:\n"
-"\n"
-" git branch new_branch_name %s\n"
-"\n"
+msgid "    git branch -d %s\n"
 msgstr ""
 
-#: builtin/checkout.c:694
-msgid "internal error in revision walk"
+#: builtin/branch.c:913
+#, c-format
+msgid "    git branch --set-upstream-to %s\n"
 msgstr ""
 
-#: builtin/checkout.c:698
-msgid "Previous HEAD position was"
+#: builtin/bundle.c:47
+#, c-format
+msgid "%s is okay\n"
 msgstr ""
 
-#: builtin/checkout.c:724
-msgid "You are on a branch yet to be born"
+#: builtin/bundle.c:56
+msgid "Need a repository to create a bundle."
 msgstr ""
 
-#. case (1)
-#: builtin/checkout.c:855
-#, c-format
-msgid "invalid reference: %s"
+#: builtin/bundle.c:60
+msgid "Need a repository to unbundle."
 msgstr ""
 
-#. case (1): want a tree
-#: builtin/checkout.c:894
-#, c-format
-msgid "reference is not a tree: %s"
+#: builtin/cat-file.c:247
+msgid "git cat-file (-t|-s|-e|-p|<type>|--textconv) <object>"
 msgstr ""
 
-#: builtin/checkout.c:974
-msgid "-B cannot be used with -b"
+#: builtin/cat-file.c:248
+msgid "git cat-file (--batch|--batch-check) < <list_of_objects>"
 msgstr ""
 
-#: builtin/checkout.c:983
-msgid "--patch is incompatible with all other options"
+#: builtin/cat-file.c:266
+msgid "<type> can be one of: blob, tree, commit, tag"
 msgstr ""
 
-#: builtin/checkout.c:986
-msgid "--detach cannot be used with -b/-B/--orphan"
+#: builtin/cat-file.c:267
+msgid "show object type"
 msgstr ""
 
-#: builtin/checkout.c:988
-msgid "--detach cannot be used with -t"
+#: builtin/cat-file.c:268
+msgid "show object size"
 msgstr ""
 
-#: builtin/checkout.c:994
-msgid "--track needs a branch name"
+#: builtin/cat-file.c:270
+msgid "exit with zero when there's no error"
 msgstr ""
 
-#: builtin/checkout.c:1001
-msgid "Missing branch name; try -b"
+#: builtin/cat-file.c:271
+msgid "pretty-print object's content"
 msgstr ""
 
-#: builtin/checkout.c:1007
-msgid "--orphan and -b|-B are mutually exclusive"
+#: builtin/cat-file.c:273
+msgid "for blob objects, run textconv on object's content"
 msgstr ""
 
-#: builtin/checkout.c:1009
-msgid "--orphan cannot be used with -t"
+#: builtin/cat-file.c:275
+msgid "show info and content of objects fed from the standard input"
 msgstr ""
 
-#: builtin/checkout.c:1019
-msgid "git checkout: -f and -m are incompatible"
+#: builtin/cat-file.c:278
+msgid "show info about objects fed from the standard input"
 msgstr ""
 
-#: builtin/checkout.c:1053
-msgid "invalid path specification"
+#: builtin/check-attr.c:11
+msgid "git check-attr [-a | --all | attr...] [--] pathname..."
 msgstr ""
 
-#: builtin/checkout.c:1061
-#, c-format
-msgid ""
-"git checkout: updating paths is incompatible with switching branches.\n"
-"Did you intend to checkout '%s' which can not be resolved as commit?"
+#: builtin/check-attr.c:12
+msgid "git check-attr --stdin [-z] [-a | --all | attr...] < <list-of-paths>"
 msgstr ""
 
-#: builtin/checkout.c:1063
-msgid "git checkout: updating paths is incompatible with switching branches."
+#: builtin/check-attr.c:19
+msgid "report all attributes set on file"
 msgstr ""
 
-#: builtin/checkout.c:1068
-msgid "git checkout: --detach does not take a path argument"
+#: builtin/check-attr.c:20
+msgid "use .gitattributes only from the index"
 msgstr ""
 
-#: builtin/checkout.c:1071
-msgid ""
-"git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
-"checking out of the index."
+#: builtin/check-attr.c:21 builtin/hash-object.c:75
+msgid "read file names from stdin"
 msgstr ""
 
-#: builtin/checkout.c:1090
-msgid "Cannot switch branch to a non-commit."
+#: builtin/check-attr.c:23
+msgid "input paths are terminated by a null character"
 msgstr ""
 
-#: builtin/checkout.c:1093
-msgid "--ours/--theirs is incompatible with switching branches."
+#: builtin/checkout-index.c:126
+msgid "git checkout-index [options] [--] [<file>...]"
 msgstr ""
 
-#: builtin/clean.c:78
-msgid "-x and -X cannot be used together"
+#: builtin/checkout-index.c:187
+msgid "check out all files in the index"
 msgstr ""
 
-#: builtin/clean.c:82
-msgid ""
-"clean.requireForce set to true and neither -n nor -f given; refusing to clean"
+#: builtin/checkout-index.c:188
+msgid "force overwrite of existing files"
 msgstr ""
 
-#: builtin/clean.c:85
-msgid ""
-"clean.requireForce defaults to true and neither -n nor -f given; refusing to "
-"clean"
+#: builtin/checkout-index.c:190
+msgid "no warning for existing files and files not in index"
 msgstr ""
 
-#: builtin/clean.c:155 builtin/clean.c:176
-#, c-format
-msgid "Would remove %s\n"
+#: builtin/checkout-index.c:192
+msgid "don't checkout new files"
 msgstr ""
 
-#: builtin/clean.c:159 builtin/clean.c:179
-#, c-format
-msgid "Removing %s\n"
+#: builtin/checkout-index.c:194
+msgid "update stat information in the index file"
 msgstr ""
 
-#: builtin/clean.c:162 builtin/clean.c:182
-#, c-format
-msgid "failed to remove %s"
+#: builtin/checkout-index.c:200
+msgid "read list of paths from the standard input"
 msgstr ""
 
-#: builtin/clean.c:166
-#, c-format
-msgid "Would not remove %s\n"
+#: builtin/checkout-index.c:202
+msgid "write the content to temporary files"
 msgstr ""
 
-#: builtin/clean.c:168
-#, c-format
-msgid "Not removing %s\n"
+#: builtin/checkout-index.c:203 builtin/column.c:30
+msgid "string"
 msgstr ""
 
-#: builtin/clone.c:243
-#, c-format
-msgid "reference repository '%s' is not a local directory."
+#: builtin/checkout-index.c:204
+msgid "when creating files, prepend <string>"
 msgstr ""
 
-#: builtin/clone.c:302
-#, c-format
-msgid "failed to open '%s'"
+#: builtin/checkout-index.c:207
+msgid "copy out the files from named stage"
 msgstr ""
 
-#: builtin/clone.c:306
-#, c-format
-msgid "failed to create directory '%s'"
+#: builtin/checkout.c:25
+msgid "git checkout [options] <branch>"
 msgstr ""
 
-#: builtin/clone.c:308 builtin/diff.c:75
-#, c-format
-msgid "failed to stat '%s'"
+#: builtin/checkout.c:26
+msgid "git checkout [options] [<branch>] -- <file>..."
 msgstr ""
 
-#: builtin/clone.c:310
+#: builtin/checkout.c:116 builtin/checkout.c:149
 #, c-format
-msgid "%s exists and is not a directory"
+msgid "path '%s' does not have our version"
 msgstr ""
 
-#: builtin/clone.c:324
+#: builtin/checkout.c:118 builtin/checkout.c:151
 #, c-format
-msgid "failed to stat %s\n"
+msgid "path '%s' does not have their version"
 msgstr ""
 
-#: builtin/clone.c:341
+#: builtin/checkout.c:134
 #, c-format
-msgid "failed to unlink '%s'"
+msgid "path '%s' does not have all necessary versions"
 msgstr ""
 
-#: builtin/clone.c:346
+#: builtin/checkout.c:178
 #, c-format
-msgid "failed to create link '%s'"
+msgid "path '%s' does not have necessary versions"
 msgstr ""
 
-#: builtin/clone.c:350
+#: builtin/checkout.c:195
 #, c-format
-msgid "failed to copy file to '%s'"
+msgid "path '%s': cannot merge"
 msgstr ""
 
-#: builtin/clone.c:373
+#: builtin/checkout.c:212
 #, c-format
-msgid "done.\n"
+msgid "Unable to add merge result for '%s'"
 msgstr ""
 
-#: builtin/clone.c:440
+#: builtin/checkout.c:236 builtin/checkout.c:239 builtin/checkout.c:242
+#: builtin/checkout.c:245
 #, c-format
-msgid "Could not find remote branch %s to clone."
+msgid "'%s' cannot be used with updating paths"
 msgstr ""
 
-#: builtin/clone.c:549
-msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n"
+#: builtin/checkout.c:248 builtin/checkout.c:251
+#, c-format
+msgid "'%s' cannot be used with %s"
 msgstr ""
 
-#: builtin/clone.c:639
-msgid "Too many arguments."
+#: builtin/checkout.c:254
+#, c-format
+msgid "Cannot update paths and switch to branch '%s' at the same time."
 msgstr ""
 
-#: builtin/clone.c:643
-msgid "You must specify a repository to clone."
+#: builtin/checkout.c:265 builtin/checkout.c:426
+msgid "corrupt index file"
 msgstr ""
 
-#: builtin/clone.c:654
+#: builtin/checkout.c:295 builtin/checkout.c:302
 #, c-format
-msgid "--bare and --origin %s options are incompatible."
+msgid "path '%s' is unmerged"
 msgstr ""
 
-#: builtin/clone.c:668
-#, c-format
-msgid "repository '%s' does not exist"
+#: 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/clone.c:673
-msgid "--depth is ignored in local clones; use file:// instead."
+#: builtin/checkout.c:448
+msgid "you need to resolve your current index first"
 msgstr ""
 
-#: builtin/clone.c:683
+#: builtin/checkout.c:569
 #, c-format
-msgid "destination path '%s' already exists and is not an empty directory."
+msgid "Can not do reflog for '%s'\n"
 msgstr ""
 
-#: builtin/clone.c:693
-#, c-format
-msgid "working tree '%s' already exists."
+#: builtin/checkout.c:602
+msgid "HEAD is now at"
 msgstr ""
 
-#: builtin/clone.c:706 builtin/clone.c:720
+#: builtin/checkout.c:609
 #, c-format
-msgid "could not create leading directories of '%s'"
+msgid "Reset branch '%s'\n"
 msgstr ""
 
-#: builtin/clone.c:709
+#: builtin/checkout.c:612
 #, c-format
-msgid "could not create work tree dir '%s'."
+msgid "Already on '%s'\n"
 msgstr ""
 
-#: builtin/clone.c:728
+#: builtin/checkout.c:616
 #, c-format
-msgid "Cloning into bare repository '%s'...\n"
+msgid "Switched to and reset branch '%s'\n"
 msgstr ""
 
-#: builtin/clone.c:730
+#: builtin/checkout.c:618
 #, c-format
-msgid "Cloning into '%s'...\n"
+msgid "Switched to a new branch '%s'\n"
 msgstr ""
 
-#: builtin/clone.c:786
+#: builtin/checkout.c:620
 #, c-format
-msgid "Don't know how to clone %s"
+msgid "Switched to branch '%s'\n"
 msgstr ""
 
-#: builtin/clone.c:835
+#: builtin/checkout.c:676
 #, c-format
-msgid "Remote branch %s not found in upstream %s"
-msgstr ""
-
-#: builtin/clone.c:842
-msgid "You appear to have cloned an empty repository."
-msgstr ""
-
-#: builtin/column.c:51
-msgid "--command must be the first argument"
+msgid " ... and %d more.\n"
 msgstr ""
 
-#: builtin/commit.c:43
+#. The singular version
+#: builtin/checkout.c:682
+#, c-format
 msgid ""
-"Your name and email address were configured automatically based\n"
-"on your username and hostname. Please check that they are accurate.\n"
-"You can suppress this message by setting them explicitly:\n"
-"\n"
-"    git config --global user.name \"Your Name\"\n"
-"    git config --global user.email you@example.com\n"
+"Warning: you are leaving %d commit behind, not connected to\n"
+"any of your branches:\n"
 "\n"
-"After doing this, you may fix the identity used for this commit with:\n"
+"%s\n"
+msgid_plural ""
+"Warning: you are leaving %d commits behind, not connected to\n"
+"any of your branches:\n"
 "\n"
-"    git commit --amend --reset-author\n"
-msgstr ""
-
-#: builtin/commit.c:55
-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"
-"remove the commit entirely with \"git reset HEAD^\".\n"
-msgstr ""
+"%s\n"
+msgstr[0] ""
+msgstr[1] ""
 
-#: builtin/commit.c:60
+#: builtin/checkout.c:700
+#, c-format
 msgid ""
-"The previous cherry-pick is now empty, possibly due to conflict resolution.\n"
-"If you wish to commit it anyway, use:\n"
+"If you want to keep them by creating a new branch, this may be a good time\n"
+"to do so with:\n"
 "\n"
-"    git commit --allow-empty\n"
+" git branch new_branch_name %s\n"
 "\n"
-"Otherwise, please use 'git reset'\n"
 msgstr ""
 
-#: builtin/commit.c:253
-msgid "failed to unpack HEAD tree object"
+#: builtin/checkout.c:730
+msgid "internal error in revision walk"
 msgstr ""
 
-#: builtin/commit.c:295
-msgid "unable to create temporary index"
+#: builtin/checkout.c:734
+msgid "Previous HEAD position was"
 msgstr ""
 
-#: builtin/commit.c:301
-msgid "interactive add failed"
+#: builtin/checkout.c:761 builtin/checkout.c:950
+msgid "You are on a branch yet to be born"
 msgstr ""
 
-#: builtin/commit.c:334 builtin/commit.c:355 builtin/commit.c:405
-msgid "unable to write new_index file"
+#. case (1)
+#: builtin/checkout.c:886
+#, c-format
+msgid "invalid reference: %s"
 msgstr ""
 
-#: builtin/commit.c:386
-msgid "cannot do a partial commit during a merge."
+#. case (1): want a tree
+#: builtin/checkout.c:925
+#, c-format
+msgid "reference is not a tree: %s"
 msgstr ""
 
-#: builtin/commit.c:388
-msgid "cannot do a partial commit during a cherry-pick."
+#: builtin/checkout.c:961
+msgid "paths cannot be used with switching branches"
 msgstr ""
 
-#: builtin/commit.c:398
-msgid "cannot read the index"
+#: builtin/checkout.c:964 builtin/checkout.c:968
+#, c-format
+msgid "'%s' cannot be used with switching branches"
 msgstr ""
 
-#: builtin/commit.c:418
-msgid "unable to write temporary index file"
+#: builtin/checkout.c:972 builtin/checkout.c:975 builtin/checkout.c:980
+#: builtin/checkout.c:983
+#, c-format
+msgid "'%s' cannot be used with '%s'"
 msgstr ""
 
-#: builtin/commit.c:493 builtin/commit.c:499
+#: builtin/checkout.c:988
 #, c-format
-msgid "invalid commit: %s"
+msgid "Cannot switch branch to a non-commit '%s'"
 msgstr ""
 
-#: builtin/commit.c:522
-msgid "malformed --author parameter"
+#: builtin/checkout.c:1009 builtin/gc.c:177
+msgid "suppress progress reporting"
 msgstr ""
 
-#: builtin/commit.c:582
-#, c-format
-msgid "Malformed ident string: '%s'"
+#: builtin/checkout.c:1010 builtin/checkout.c:1012 builtin/clone.c:89
+#: builtin/remote.c:169 builtin/remote.c:171
+msgid "branch"
 msgstr ""
 
-#: builtin/commit.c:620 builtin/commit.c:653 builtin/commit.c:967
-#, c-format
-msgid "could not lookup commit %s"
+#: builtin/checkout.c:1011
+msgid "create and checkout a new branch"
 msgstr ""
 
-#: builtin/commit.c:632 builtin/shortlog.c:296
-#, c-format
-msgid "(reading log message from standard input)\n"
+#: builtin/checkout.c:1013
+msgid "create/reset and checkout a branch"
 msgstr ""
 
-#: builtin/commit.c:634
-msgid "could not read log from standard input"
+#: builtin/checkout.c:1014
+msgid "create reflog for new branch"
 msgstr ""
 
-#: builtin/commit.c:638
-#, c-format
-msgid "could not read log file '%s'"
+#: builtin/checkout.c:1015
+msgid "detach the HEAD at named commit"
 msgstr ""
 
-#: builtin/commit.c:644
-msgid "commit has empty message"
+#: builtin/checkout.c:1016
+msgid "set upstream info for new branch"
 msgstr ""
 
-#: builtin/commit.c:660
-msgid "could not read MERGE_MSG"
+#: builtin/checkout.c:1018
+msgid "new branch"
 msgstr ""
 
-#: builtin/commit.c:664
-msgid "could not read SQUASH_MSG"
+#: builtin/checkout.c:1018
+msgid "new unparented branch"
 msgstr ""
 
-#: builtin/commit.c:668
-#, c-format
-msgid "could not read '%s'"
+#: builtin/checkout.c:1019
+msgid "checkout our version for unmerged files"
 msgstr ""
 
-#: builtin/commit.c:720
-msgid "could not write commit template"
+#: builtin/checkout.c:1021
+msgid "checkout their version for unmerged files"
 msgstr ""
 
-#: builtin/commit.c:731
-#, c-format
-msgid ""
-"\n"
-"It looks like you may be committing a merge.\n"
-"If this is not correct, please remove the file\n"
-"\t%s\n"
-"and try again.\n"
+#: builtin/checkout.c:1023
+msgid "force checkout (throw away local modifications)"
 msgstr ""
 
-#: builtin/commit.c:736
-#, c-format
-msgid ""
-"\n"
-"It looks like you may be committing a cherry-pick.\n"
-"If this is not correct, please remove the file\n"
-"\t%s\n"
-"and try again.\n"
+#: builtin/checkout.c:1024
+msgid "perform a 3-way merge with the new branch"
 msgstr ""
 
-#: builtin/commit.c:748
-msgid ""
-"Please enter the commit message for your changes. Lines starting\n"
-"with '#' will be ignored, and an empty message aborts the commit.\n"
+#: builtin/checkout.c:1025 builtin/merge.c:215
+msgid "update ignored files (default)"
 msgstr ""
 
-#: builtin/commit.c:753
-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"
+#: builtin/checkout.c:1026 builtin/log.c:1111 parse-options.h:241
+msgid "style"
 msgstr ""
 
-#: builtin/commit.c:766
-#, c-format
-msgid "%sAuthor:    %s"
+#: builtin/checkout.c:1027
+msgid "conflict style (merge or diff3)"
 msgstr ""
 
-#: builtin/commit.c:773
-#, c-format
-msgid "%sCommitter: %s"
+#: builtin/checkout.c:1030
+msgid "second guess 'git checkout no-such-branch'"
 msgstr ""
 
-#: builtin/commit.c:793
-msgid "Cannot read index"
+#: builtin/checkout.c:1054
+msgid "-b, -B and --orphan are mutually exclusive"
 msgstr ""
 
-#: builtin/commit.c:830
-msgid "Error building trees"
+#: builtin/checkout.c:1071
+msgid "--track needs a branch name"
 msgstr ""
 
-#: builtin/commit.c:845 builtin/tag.c:361
-#, c-format
-msgid "Please supply the message using either -m or -F option.\n"
+#: builtin/checkout.c:1078
+msgid "Missing branch name; try -b"
+msgstr ""
+
+#: builtin/checkout.c:1113
+msgid "invalid path specification"
 msgstr ""
 
-#: builtin/commit.c:942
+#: builtin/checkout.c:1120
 #, c-format
-msgid "No existing author found with '%s'"
+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/commit.c:957 builtin/commit.c:1157
+#: builtin/checkout.c:1125
 #, c-format
-msgid "Invalid untracked files mode '%s'"
+msgid "git checkout: --detach does not take a path argument '%s'"
 msgstr ""
 
-#: builtin/commit.c:997
-msgid "Using both --reset-author and --author does not make sense"
+#: builtin/checkout.c:1129
+msgid ""
+"git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
+"checking out of the index."
 msgstr ""
 
-#: builtin/commit.c:1008
-msgid "You have nothing to amend."
+#: builtin/clean.c:19
+msgid "git clean [-d] [-f] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>..."
 msgstr ""
 
-#: builtin/commit.c:1011
-msgid "You are in the middle of a merge -- cannot amend."
+#: builtin/clean.c:51
+msgid "do not print names of files removed"
 msgstr ""
 
-#: builtin/commit.c:1013
-msgid "You are in the middle of a cherry-pick -- cannot amend."
+#: builtin/clean.c:53
+msgid "force"
 msgstr ""
 
-#: builtin/commit.c:1016
-msgid "Options --squash and --fixup cannot be used together"
+#: builtin/clean.c:55
+msgid "remove whole directories"
 msgstr ""
 
-#: builtin/commit.c:1026
-msgid "Only one of -c/-C/-F/--fixup can be used."
+#: 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
+msgid "pattern"
 msgstr ""
 
-#: builtin/commit.c:1028
-msgid "Option -m cannot be combined with -c/-C/-F/--fixup."
+#: builtin/clean.c:57
+msgid "add <pattern> to ignore rules"
 msgstr ""
 
-#: builtin/commit.c:1036
-msgid "--reset-author can be used only with -C, -c or --amend."
+#: builtin/clean.c:58
+msgid "remove ignored files, too"
 msgstr ""
 
-#: builtin/commit.c:1053
-msgid "Only one of --include/--only/--all/--interactive/--patch can be used."
+#: builtin/clean.c:60
+msgid "remove only ignored files"
 msgstr ""
 
-#: builtin/commit.c:1055
-msgid "No paths with --include/--only does not make sense."
+#: builtin/clean.c:78
+msgid "-x and -X cannot be used together"
 msgstr ""
 
-#: builtin/commit.c:1057
-msgid "Clever... amending the last one with dirty index."
+#: builtin/clean.c:82
+msgid ""
+"clean.requireForce set to true and neither -n nor -f given; refusing to clean"
 msgstr ""
 
-#: builtin/commit.c:1059
-msgid "Explicit paths specified without -i nor -o; assuming --only paths..."
+#: builtin/clean.c:85
+msgid ""
+"clean.requireForce defaults to true and neither -n nor -f given; refusing to "
+"clean"
 msgstr ""
 
-#: builtin/commit.c:1069 builtin/tag.c:577
+#: builtin/clean.c:155 builtin/clean.c:176
 #, c-format
-msgid "Invalid cleanup mode %s"
+msgid "Would remove %s\n"
 msgstr ""
 
-#: builtin/commit.c:1074
-msgid "Paths with -a does not make sense."
+#: builtin/clean.c:159 builtin/clean.c:179
+#, c-format
+msgid "Removing %s\n"
 msgstr ""
 
-#: builtin/commit.c:1257
-msgid "couldn't look up newly created commit"
+#: builtin/clean.c:162 builtin/clean.c:182
+#, c-format
+msgid "failed to remove %s"
 msgstr ""
 
-#: builtin/commit.c:1259
-msgid "could not parse newly created commit"
+#: builtin/clean.c:166
+#, c-format
+msgid "Would not remove %s\n"
 msgstr ""
 
-#: builtin/commit.c:1300
-msgid "detached HEAD"
+#: builtin/clean.c:168
+#, c-format
+msgid "Not removing %s\n"
 msgstr ""
 
-#: builtin/commit.c:1302
-msgid " (root-commit)"
+#: builtin/clone.c:36
+msgid "git clone [options] [--] <repo> [<dir>]"
 msgstr ""
 
-#: builtin/commit.c:1446
-msgid "could not parse HEAD commit"
+#: builtin/clone.c:64 builtin/fetch.c:82 builtin/merge.c:212
+#: builtin/push.c:399
+msgid "force progress reporting"
 msgstr ""
 
-#: builtin/commit.c:1484 builtin/merge.c:509
-#, c-format
-msgid "could not open '%s' for reading"
+#: builtin/clone.c:66
+msgid "don't create a checkout"
 msgstr ""
 
-#: builtin/commit.c:1491
-#, c-format
-msgid "Corrupt MERGE_HEAD file (%s)"
+#: builtin/clone.c:67 builtin/clone.c:69 builtin/init-db.c:488
+msgid "create a bare repository"
 msgstr ""
 
-#: builtin/commit.c:1498
-msgid "could not read MERGE_MODE"
+#: builtin/clone.c:72
+msgid "create a mirror repository (implies bare)"
 msgstr ""
 
-#: builtin/commit.c:1517
-#, c-format
-msgid "could not read commit message: %s"
+#: builtin/clone.c:74
+msgid "to clone from a local repository"
 msgstr ""
 
-#: builtin/commit.c:1531
-#, c-format
-msgid "Aborting commit; you did not edit the message.\n"
+#: builtin/clone.c:76
+msgid "don't use local hardlinks, always copy"
 msgstr ""
 
-#: builtin/commit.c:1536
-#, c-format
-msgid "Aborting commit due to empty commit message.\n"
+#: builtin/clone.c:78
+msgid "setup as shared repository"
 msgstr ""
 
-#: builtin/commit.c:1551 builtin/merge.c:936 builtin/merge.c:961
-msgid "failed to write commit object"
+#: builtin/clone.c:80 builtin/clone.c:82
+msgid "initialize submodules in the clone"
 msgstr ""
 
-#: builtin/commit.c:1572
-msgid "cannot lock HEAD ref"
+#: builtin/clone.c:83 builtin/init-db.c:485
+msgid "template-directory"
 msgstr ""
 
-#: builtin/commit.c:1576
-msgid "cannot update HEAD ref"
+#: builtin/clone.c:84 builtin/init-db.c:486
+msgid "directory from which templates will be used"
 msgstr ""
 
-#: builtin/commit.c:1587
-msgid ""
-"Repository has been updated, but unable to write\n"
-"new_index file. Check that disk is not full or quota is\n"
-"not exceeded, and then \"git reset HEAD\" to recover."
+#: builtin/clone.c:86
+msgid "reference repository"
 msgstr ""
 
-#: builtin/describe.c:234
-#, c-format
-msgid "annotated tag %s not available"
+#: builtin/clone.c:87 builtin/column.c:26 builtin/merge-file.c:44
+msgid "name"
 msgstr ""
 
-#: builtin/describe.c:238
-#, c-format
-msgid "annotated tag %s has no embedded name"
+#: builtin/clone.c:88
+msgid "use <name> instead of 'origin' to track upstream"
 msgstr ""
 
-#: builtin/describe.c:240
-#, c-format
-msgid "tag '%s' is really '%s' here"
+#: builtin/clone.c:90
+msgid "checkout <branch> instead of the remote's HEAD"
 msgstr ""
 
-#: builtin/describe.c:267
+#: builtin/clone.c:92
+msgid "path to git-upload-pack on the remote"
+msgstr ""
+
+#: builtin/clone.c:93 builtin/fetch.c:83 builtin/grep.c:748
+msgid "depth"
+msgstr ""
+
+#: builtin/clone.c:94
+msgid "create a shallow clone of that depth"
+msgstr ""
+
+#: builtin/clone.c:96
+msgid "clone only one branch, HEAD or --branch"
+msgstr ""
+
+#: builtin/clone.c:97 builtin/init-db.c:494
+msgid "gitdir"
+msgstr ""
+
+#: builtin/clone.c:98 builtin/init-db.c:495
+msgid "separate git dir from working tree"
+msgstr ""
+
+#: builtin/clone.c:99
+msgid "key=value"
+msgstr ""
+
+#: builtin/clone.c:100
+msgid "set config inside the new repository"
+msgstr ""
+
+#: builtin/clone.c:243
 #, c-format
-msgid "Not a valid object name %s"
+msgid "reference repository '%s' is not a local directory."
 msgstr ""
 
-#: builtin/describe.c:270
+#: builtin/clone.c:306
 #, c-format
-msgid "%s is not a valid '%s' object"
+msgid "failed to create directory '%s'"
 msgstr ""
 
-#: builtin/describe.c:287
+#: builtin/clone.c:308 builtin/diff.c:77
 #, c-format
-msgid "no tag exactly matches '%s'"
+msgid "failed to stat '%s'"
 msgstr ""
 
-#: builtin/describe.c:289
+#: builtin/clone.c:310
 #, c-format
-msgid "searching to describe %s\n"
+msgid "%s exists and is not a directory"
 msgstr ""
 
-#: builtin/describe.c:329
+#: builtin/clone.c:324
 #, c-format
-msgid "finished search at %s\n"
+msgid "failed to stat %s\n"
 msgstr ""
 
-#: builtin/describe.c:353
+#: builtin/clone.c:346
 #, c-format
-msgid ""
-"No annotated tags can describe '%s'.\n"
-"However, there were unannotated tags: try --tags."
+msgid "failed to create link '%s'"
 msgstr ""
 
-#: builtin/describe.c:357
+#: builtin/clone.c:350
 #, c-format
-msgid ""
-"No tags can describe '%s'.\n"
-"Try --always, or create some tags."
+msgid "failed to copy file to '%s'"
 msgstr ""
 
-#: builtin/describe.c:378
+#: builtin/clone.c:373
 #, c-format
-msgid "traversed %lu commits\n"
+msgid "done.\n"
 msgstr ""
 
-#: builtin/describe.c:381
+#: builtin/clone.c:443
 #, c-format
-msgid ""
-"more than %i tags found; listed %i most recent\n"
-"gave up search at %s\n"
+msgid "Could not find remote branch %s to clone."
 msgstr ""
 
-#: builtin/describe.c:436
-msgid "--long is incompatible with --abbrev=0"
+#: builtin/clone.c:552
+msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n"
 msgstr ""
 
-#: builtin/describe.c:462
-msgid "No names found, cannot describe anything."
+#: builtin/clone.c:690
+msgid "Too many arguments."
 msgstr ""
 
-#: builtin/describe.c:482
-msgid "--dirty is incompatible with committishes"
+#: builtin/clone.c:694
+msgid "You must specify a repository to clone."
 msgstr ""
 
-#: builtin/diff.c:77
+#: builtin/clone.c:705
 #, c-format
-msgid "'%s': not a regular file or symlink"
+msgid "--bare and --origin %s options are incompatible."
 msgstr ""
 
-#: builtin/diff.c:220
+#: builtin/clone.c:719
 #, c-format
-msgid "invalid option: %s"
+msgid "repository '%s' does not exist"
 msgstr ""
 
-#: builtin/diff.c:297
-msgid "Not a git repository"
+#: builtin/clone.c:724
+msgid "--depth is ignored in local clones; use file:// instead."
 msgstr ""
 
-#: builtin/diff.c:347
+#: builtin/clone.c:734
 #, c-format
-msgid "invalid object '%s' given."
+msgid "destination path '%s' already exists and is not an empty directory."
 msgstr ""
 
-#: builtin/diff.c:352
+#: builtin/clone.c:744
 #, c-format
-msgid "more than %d trees given: '%s'"
+msgid "working tree '%s' already exists."
 msgstr ""
 
-#: builtin/diff.c:362
+#: builtin/clone.c:757 builtin/clone.c:771
 #, c-format
-msgid "more than two blobs given: '%s'"
+msgid "could not create leading directories of '%s'"
 msgstr ""
 
-#: builtin/diff.c:370
+#: builtin/clone.c:760
 #, c-format
-msgid "unhandled object '%s' given."
+msgid "could not create work tree dir '%s'."
 msgstr ""
 
-#: builtin/fetch.c:200
-msgid "Couldn't find remote ref HEAD"
+#: builtin/clone.c:779
+#, c-format
+msgid "Cloning into bare repository '%s'...\n"
 msgstr ""
 
-#: builtin/fetch.c:253
+#: builtin/clone.c:781
 #, c-format
-msgid "object %s not found"
+msgid "Cloning into '%s'...\n"
 msgstr ""
 
-#: builtin/fetch.c:259
-msgid "[up to date]"
+#: builtin/clone.c:823
+#, c-format
+msgid "Don't know how to clone %s"
 msgstr ""
 
-#: builtin/fetch.c:273
+#: builtin/clone.c:872
 #, c-format
-msgid "! %-*s %-*s -> %s  (can't fetch in current branch)"
+msgid "Remote branch %s not found in upstream %s"
 msgstr ""
 
-#: builtin/fetch.c:274 builtin/fetch.c:360
-msgid "[rejected]"
+#: builtin/clone.c:879
+msgid "You appear to have cloned an empty repository."
 msgstr ""
 
-#: builtin/fetch.c:285
-msgid "[tag update]"
+#: builtin/column.c:9
+msgid "git column [options]"
 msgstr ""
 
-#: builtin/fetch.c:287 builtin/fetch.c:322 builtin/fetch.c:340
-msgid "  (unable to update local ref)"
+#: builtin/column.c:26
+msgid "lookup config vars"
 msgstr ""
 
-#: builtin/fetch.c:305
-msgid "[new tag]"
+#: builtin/column.c:27 builtin/column.c:28
+msgid "layout to use"
 msgstr ""
 
-#: builtin/fetch.c:308
-msgid "[new branch]"
+#: builtin/column.c:29
+msgid "Maximum width"
 msgstr ""
 
-#: builtin/fetch.c:311
-msgid "[new ref]"
+#: builtin/column.c:30
+msgid "Padding space on left border"
 msgstr ""
 
-#: builtin/fetch.c:356
-msgid "unable to update local ref"
+#: builtin/column.c:31
+msgid "Padding space on right border"
 msgstr ""
 
-#: builtin/fetch.c:356
-msgid "forced update"
+#: builtin/column.c:32
+msgid "Padding space between columns"
 msgstr ""
 
-#: builtin/fetch.c:362
-msgid "(non-fast-forward)"
+#: builtin/column.c:51
+msgid "--command must be the first argument"
 msgstr ""
 
-#: builtin/fetch.c:393 builtin/fetch.c:685
-#, c-format
-msgid "cannot open %s: %s\n"
+#: builtin/commit.c:34
+msgid "git commit [options] [--] <filepattern>..."
 msgstr ""
 
-#: builtin/fetch.c:402
-#, c-format
-msgid "%s did not send all necessary objects\n"
+#: builtin/commit.c:39
+msgid "git status [options] [--] <filepattern>..."
 msgstr ""
 
-#: builtin/fetch.c:488
-#, c-format
-msgid "From %.*s\n"
+#: 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"
+"You can suppress this message by setting them explicitly:\n"
+"\n"
+"    git config --global user.name \"Your Name\"\n"
+"    git config --global user.email you@example.com\n"
+"\n"
+"After doing this, you may fix the identity used for this commit with:\n"
+"\n"
+"    git commit --amend --reset-author\n"
 msgstr ""
 
-#: builtin/fetch.c:499
-#, c-format
+#: builtin/commit.c:56
 msgid ""
-"some local refs could not be updated; try running\n"
-" 'git remote prune %s' to remove any old, conflicting branches"
+"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"
+"remove the commit entirely with \"git reset HEAD^\".\n"
 msgstr ""
 
-#: builtin/fetch.c:549
-#, c-format
-msgid "   (%s will become dangling)"
+#: 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"
+"\n"
+"    git commit --allow-empty\n"
+"\n"
+"Otherwise, please use 'git reset'\n"
 msgstr ""
 
-#: builtin/fetch.c:550
-#, c-format
-msgid "   (%s has become dangling)"
+#: builtin/commit.c:257
+msgid "failed to unpack HEAD tree object"
 msgstr ""
 
-#: builtin/fetch.c:557
-msgid "[deleted]"
+#: builtin/commit.c:299
+msgid "unable to create temporary index"
 msgstr ""
 
-#: builtin/fetch.c:558 builtin/remote.c:1055
-msgid "(none)"
+#: builtin/commit.c:305
+msgid "interactive add failed"
 msgstr ""
 
-#: builtin/fetch.c:675
-#, c-format
-msgid "Refusing to fetch into current branch %s of non-bare repository"
+#: builtin/commit.c:338 builtin/commit.c:359 builtin/commit.c:409
+msgid "unable to write new_index file"
 msgstr ""
 
-#: builtin/fetch.c:709
-#, c-format
-msgid "Don't know how to fetch from %s"
+#: builtin/commit.c:390
+msgid "cannot do a partial commit during a merge."
 msgstr ""
 
-#: builtin/fetch.c:786
-#, c-format
-msgid "Option \"%s\" value \"%s\" is not valid for %s"
+#: builtin/commit.c:392
+msgid "cannot do a partial commit during a cherry-pick."
 msgstr ""
 
-#: builtin/fetch.c:789
-#, c-format
-msgid "Option \"%s\" is ignored for %s\n"
+#: builtin/commit.c:402
+msgid "cannot read the index"
 msgstr ""
 
-#: builtin/fetch.c:888
-#, c-format
-msgid "Fetching %s\n"
+#: builtin/commit.c:422
+msgid "unable to write temporary index file"
 msgstr ""
 
-#: builtin/fetch.c:890 builtin/remote.c:100
+#: builtin/commit.c:509 builtin/commit.c:515
 #, c-format
-msgid "Could not fetch %s"
+msgid "invalid commit: %s"
 msgstr ""
 
-#: builtin/fetch.c:907
-msgid ""
-"No remote repository specified.  Please, specify either a URL or a\n"
-"remote name from which new revisions should be fetched."
+#: builtin/commit.c:538
+msgid "malformed --author parameter"
 msgstr ""
 
-#: builtin/fetch.c:927
-msgid "You need to specify a tag name."
+#: builtin/commit.c:558
+#, c-format
+msgid "Malformed ident string: '%s'"
 msgstr ""
 
-#: builtin/fetch.c:979
-msgid "fetch --all does not take a repository argument"
+#: builtin/commit.c:596 builtin/commit.c:629 builtin/commit.c:952
+#, c-format
+msgid "could not lookup commit %s"
 msgstr ""
 
-#: builtin/fetch.c:981
-msgid "fetch --all does not make sense with refspecs"
+#: builtin/commit.c:608 builtin/shortlog.c:296
+#, c-format
+msgid "(reading log message from standard input)\n"
+msgstr ""
+
+#: builtin/commit.c:610
+msgid "could not read log from standard input"
 msgstr ""
 
-#: builtin/fetch.c:992
+#: builtin/commit.c:614
 #, c-format
-msgid "No such remote or remote group: %s"
+msgid "could not read log file '%s'"
 msgstr ""
 
-#: builtin/fetch.c:1000
-msgid "Fetching a group and specifying refspecs does not make sense"
+#: builtin/commit.c:620
+msgid "commit has empty message"
 msgstr ""
 
-#: builtin/gc.c:63
-#, c-format
-msgid "Invalid %s: '%s'"
+#: builtin/commit.c:636
+msgid "could not read MERGE_MSG"
 msgstr ""
 
-#: builtin/gc.c:90
+#: builtin/commit.c:640
+msgid "could not read SQUASH_MSG"
+msgstr ""
+
+#: builtin/commit.c:644
 #, c-format
-msgid "insanely long object directory %.*s"
+msgid "could not read '%s'"
+msgstr ""
+
+#: builtin/commit.c:705
+msgid "could not write commit template"
 msgstr ""
 
-#: builtin/gc.c:221
+#: builtin/commit.c:716
 #, c-format
-msgid "Auto packing the repository for optimum performance.\n"
+msgid ""
+"\n"
+"It looks like you may be committing a merge.\n"
+"If this is not correct, please remove the file\n"
+"\t%s\n"
+"and try again.\n"
 msgstr ""
 
-#: builtin/gc.c:224
+#: builtin/commit.c:721
 #, c-format
 msgid ""
-"Auto packing the repository for optimum performance. You may also\n"
-"run \"git gc\" manually. See \"git help gc\" for more information.\n"
+"\n"
+"It looks like you may be committing a cherry-pick.\n"
+"If this is not correct, please remove the file\n"
+"\t%s\n"
+"and try again.\n"
 msgstr ""
 
-#: builtin/gc.c:251
+#: builtin/commit.c:733
 msgid ""
-"There are too many unreachable loose objects; run 'git prune' to remove them."
+"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/grep.c:216
-#, c-format
-msgid "grep: failed to create thread: %s"
+#: builtin/commit.c:738
+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/grep.c:402
+#: builtin/commit.c:751
 #, c-format
-msgid "Failed to chdir: %s"
+msgid "%sAuthor:    %s"
 msgstr ""
 
-#: builtin/grep.c:478 builtin/grep.c:512
+#: builtin/commit.c:758
 #, c-format
-msgid "unable to read tree (%s)"
+msgid "%sCommitter: %s"
+msgstr ""
+
+#: builtin/commit.c:778
+msgid "Cannot read index"
+msgstr ""
+
+#: builtin/commit.c:815
+msgid "Error building trees"
 msgstr ""
 
-#: builtin/grep.c:526
+#: builtin/commit.c:830 builtin/tag.c:361
 #, c-format
-msgid "unable to grep from object of type %s"
+msgid "Please supply the message using either -m or -F option.\n"
 msgstr ""
 
-#: builtin/grep.c:584
+#: builtin/commit.c:927
 #, c-format
-msgid "switch `%c' expects a numerical value"
+msgid "No existing author found with '%s'"
 msgstr ""
 
-#: builtin/grep.c:601
+#: builtin/commit.c:942 builtin/commit.c:1142
 #, c-format
-msgid "cannot open '%s'"
+msgid "Invalid untracked files mode '%s'"
 msgstr ""
 
-#: builtin/grep.c:885
-msgid "no pattern given."
+#: builtin/commit.c:982
+msgid "Using both --reset-author and --author does not make sense"
 msgstr ""
 
-#: builtin/grep.c:899
-#, c-format
-msgid "bad object %s"
+#: builtin/commit.c:993
+msgid "You have nothing to amend."
 msgstr ""
 
-#: builtin/grep.c:940
-msgid "--open-files-in-pager only works on the worktree"
+#: builtin/commit.c:996
+msgid "You are in the middle of a merge -- cannot amend."
 msgstr ""
 
-#: builtin/grep.c:963
-msgid "--cached or --untracked cannot be used with --no-index."
+#: builtin/commit.c:998
+msgid "You are in the middle of a cherry-pick -- cannot amend."
 msgstr ""
 
-#: builtin/grep.c:968
-msgid "--no-index or --untracked cannot be used with revs."
+#: builtin/commit.c:1001
+msgid "Options --squash and --fixup cannot be used together"
 msgstr ""
 
-#: builtin/grep.c:971
-msgid "--[no-]exclude-standard cannot be used for tracked contents."
+#: builtin/commit.c:1011
+msgid "Only one of -c/-C/-F/--fixup can be used."
 msgstr ""
 
-#: builtin/grep.c:979
-msgid "both --cached and trees are given."
+#: builtin/commit.c:1013
+msgid "Option -m cannot be combined with -c/-C/-F/--fixup."
 msgstr ""
 
-#: builtin/help.c:59
-#, c-format
-msgid "unrecognized help format '%s'"
+#: builtin/commit.c:1021
+msgid "--reset-author can be used only with -C, -c or --amend."
 msgstr ""
 
-#: builtin/help.c:87
-msgid "Failed to start emacsclient."
+#: builtin/commit.c:1038
+msgid "Only one of --include/--only/--all/--interactive/--patch can be used."
 msgstr ""
 
-#: builtin/help.c:100
-msgid "Failed to parse emacsclient version."
+#: builtin/commit.c:1040
+msgid "No paths with --include/--only does not make sense."
 msgstr ""
 
-#: builtin/help.c:108
-#, c-format
-msgid "emacsclient version '%d' too old (< 22)."
+#: builtin/commit.c:1042
+msgid "Clever... amending the last one with dirty index."
 msgstr ""
 
-#: builtin/help.c:126 builtin/help.c:154 builtin/help.c:163 builtin/help.c:171
-#, c-format
-msgid "failed to exec '%s': %s"
+#: builtin/commit.c:1044
+msgid "Explicit paths specified without -i nor -o; assuming --only paths..."
 msgstr ""
 
-#: builtin/help.c:211
+#: builtin/commit.c:1054 builtin/tag.c:577
 #, c-format
-msgid ""
-"'%s': path for unsupported man viewer.\n"
-"Please consider using 'man.<tool>.cmd' instead."
+msgid "Invalid cleanup mode %s"
 msgstr ""
 
-#: builtin/help.c:223
-#, c-format
-msgid ""
-"'%s': cmd for supported man viewer.\n"
-"Please consider using 'man.<tool>.path' instead."
+#: builtin/commit.c:1059
+msgid "Paths with -a does not make sense."
 msgstr ""
 
-#: builtin/help.c:287
-msgid "The most commonly used git commands are:"
+#: builtin/commit.c:1156 builtin/commit.c:1384
+msgid "show status concisely"
 msgstr ""
 
-#: builtin/help.c:355
-#, c-format
-msgid "'%s': unknown man viewer."
+#: builtin/commit.c:1158 builtin/commit.c:1386
+msgid "show branch information"
 msgstr ""
 
-#: builtin/help.c:372
-msgid "no man viewer handled the request"
+#: builtin/commit.c:1160 builtin/commit.c:1388 builtin/push.c:389
+msgid "machine-readable output"
 msgstr ""
 
-#: builtin/help.c:380
-msgid "no info viewer handled the request"
+#: builtin/commit.c:1163 builtin/commit.c:1390
+msgid "terminate entries with NUL"
 msgstr ""
 
-#: builtin/help.c:391
-#, c-format
-msgid "'%s': not a documentation directory."
+#: builtin/commit.c:1165 builtin/commit.c:1393 builtin/fast-export.c:636
+#: builtin/fast-export.c:639 builtin/tag.c:461
+msgid "mode"
 msgstr ""
 
-#: builtin/help.c:432 builtin/help.c:439
-#, c-format
-msgid "usage: %s%s"
+#: builtin/commit.c:1166 builtin/commit.c:1393
+msgid "show untracked files, optional modes: all, normal, no. (Default: all)"
 msgstr ""
 
-#: builtin/help.c:453
-#, c-format
-msgid "`git %s' is aliased to `%s'"
+#: builtin/commit.c:1169
+msgid "show ignored files"
 msgstr ""
 
-#: builtin/index-pack.c:169
-#, c-format
-msgid "object type mismatch at %s"
+#: builtin/commit.c:1170 parse-options.h:151
+msgid "when"
 msgstr ""
 
-#: builtin/index-pack.c:189
-msgid "object of unexpected type"
+#: builtin/commit.c:1171
+msgid ""
+"ignore changes to submodules, optional when: all, dirty, untracked. "
+"(Default: all)"
 msgstr ""
 
-#: builtin/index-pack.c:226
-#, c-format
-msgid "cannot fill %d byte"
-msgid_plural "cannot fill %d bytes"
-msgstr[0] ""
-msgstr[1] ""
+#: builtin/commit.c:1173
+msgid "list untracked files in columns"
+msgstr ""
 
-#: builtin/index-pack.c:236
-msgid "early EOF"
+#: builtin/commit.c:1242
+msgid "couldn't look up newly created commit"
 msgstr ""
 
-#: builtin/index-pack.c:237
-msgid "read error on input"
+#: builtin/commit.c:1244
+msgid "could not parse newly created commit"
 msgstr ""
 
-#: builtin/index-pack.c:249
-msgid "used more bytes than were available"
+#: builtin/commit.c:1285
+msgid "detached HEAD"
 msgstr ""
 
-#: builtin/index-pack.c:256
-msgid "pack too large for current definition of off_t"
+#: builtin/commit.c:1287
+msgid " (root-commit)"
 msgstr ""
 
-#: builtin/index-pack.c:272
-#, c-format
-msgid "unable to create '%s'"
+#: builtin/commit.c:1354
+msgid "suppress summary after successful commit"
 msgstr ""
 
-#: builtin/index-pack.c:277
-#, c-format
-msgid "cannot open packfile '%s'"
+#: builtin/commit.c:1355
+msgid "show diff in commit message template"
 msgstr ""
 
-#: builtin/index-pack.c:291
-msgid "pack signature mismatch"
+#: builtin/commit.c:1357
+msgid "Commit message options"
 msgstr ""
 
-#: builtin/index-pack.c:311
-#, c-format
-msgid "pack has bad object at offset %lu: %s"
+#: builtin/commit.c:1358 builtin/tag.c:459
+msgid "read message from file"
 msgstr ""
 
-#: builtin/index-pack.c:405
-#, c-format
-msgid "inflate returned %d"
+#: builtin/commit.c:1359
+msgid "author"
 msgstr ""
 
-#: builtin/index-pack.c:450
-msgid "offset value overflow for delta base object"
+#: builtin/commit.c:1359
+msgid "override author for commit"
 msgstr ""
 
-#: builtin/index-pack.c:458
-msgid "delta base offset is out of bound"
+#: builtin/commit.c:1360 builtin/gc.c:178
+msgid "date"
 msgstr ""
 
-#: builtin/index-pack.c:466
-#, c-format
-msgid "unknown object type %d"
+#: builtin/commit.c:1360
+msgid "override date for commit"
 msgstr ""
 
-#: builtin/index-pack.c:495
-msgid "cannot pread pack file"
+#: builtin/commit.c:1361 builtin/merge.c:206 builtin/notes.c:537
+#: builtin/notes.c:694 builtin/tag.c:457
+msgid "message"
 msgstr ""
 
-#: builtin/index-pack.c:497
-#, c-format
-msgid "premature end of pack file, %lu byte missing"
-msgid_plural "premature end of pack file, %lu bytes missing"
-msgstr[0] ""
-msgstr[1] ""
+#: builtin/commit.c:1361
+msgid "commit message"
+msgstr ""
 
-#: builtin/index-pack.c:510
-msgid "serious inflate inconsistency"
+#: builtin/commit.c:1362
+msgid "reuse and edit message from specified commit"
 msgstr ""
 
-#: builtin/index-pack.c:583
-#, c-format
-msgid "cannot read existing object %s"
+#: builtin/commit.c:1363
+msgid "reuse message from specified commit"
 msgstr ""
 
-#: builtin/index-pack.c:586
-#, c-format
-msgid "SHA1 COLLISION FOUND WITH %s !"
+#: builtin/commit.c:1364
+msgid "use autosquash formatted message to fixup specified commit"
 msgstr ""
 
-#: builtin/index-pack.c:598
-#, c-format
-msgid "invalid blob object %s"
+#: builtin/commit.c:1365
+msgid "use autosquash formatted message to squash specified commit"
 msgstr ""
 
-#: builtin/index-pack.c:610
-#, c-format
-msgid "invalid %s"
+#: builtin/commit.c:1366
+msgid "the commit is authored by me now (used with -C/-c/--amend)"
 msgstr ""
 
-#: builtin/index-pack.c:612
-msgid "Error in object"
+#: builtin/commit.c:1367 builtin/log.c:1068 builtin/revert.c:109
+msgid "add Signed-off-by:"
 msgstr ""
 
-#: builtin/index-pack.c:614
-#, c-format
-msgid "Not all child objects of %s are reachable"
+#: builtin/commit.c:1368
+msgid "use specified template file"
 msgstr ""
 
-#: builtin/index-pack.c:687 builtin/index-pack.c:713
-msgid "failed to apply delta"
+#: builtin/commit.c:1369
+msgid "force edit of commit"
 msgstr ""
 
-#: builtin/index-pack.c:850
-msgid "Receiving objects"
+#: builtin/commit.c:1370
+msgid "default"
 msgstr ""
 
-#: builtin/index-pack.c:850
-msgid "Indexing objects"
+#: builtin/commit.c:1370 builtin/tag.c:462
+msgid "how to strip spaces and #comments from message"
 msgstr ""
 
-#: builtin/index-pack.c:872
-msgid "pack is corrupted (SHA1 mismatch)"
+#: builtin/commit.c:1371
+msgid "include status in commit message template"
 msgstr ""
 
-#: builtin/index-pack.c:877
-msgid "cannot fstat packfile"
+#: builtin/commit.c:1372 builtin/merge.c:213 builtin/tag.c:463
+msgid "key id"
 msgstr ""
 
-#: builtin/index-pack.c:880
-msgid "pack has junk at the end"
+#: builtin/commit.c:1373 builtin/merge.c:214
+msgid "GPG sign commit"
 msgstr ""
 
-#: builtin/index-pack.c:903
-msgid "Resolving deltas"
+#. end commit message options
+#: builtin/commit.c:1376
+msgid "Commit contents options"
 msgstr ""
 
-#: builtin/index-pack.c:954
-msgid "confusion beyond insanity"
+#: builtin/commit.c:1377
+msgid "commit all changed files"
 msgstr ""
 
-#: builtin/index-pack.c:973
-#, c-format
-msgid "pack has %d unresolved delta"
-msgid_plural "pack has %d unresolved deltas"
-msgstr[0] ""
-msgstr[1] ""
+#: builtin/commit.c:1378
+msgid "add specified files to index for commit"
+msgstr ""
 
-#: builtin/index-pack.c:998
-#, c-format
-msgid "unable to deflate appended object (%d)"
+#: builtin/commit.c:1379
+msgid "interactively add files"
 msgstr ""
 
-#: builtin/index-pack.c:1077
-#, c-format
-msgid "local object %s is corrupt"
+#: builtin/commit.c:1380
+msgid "interactively add changes"
 msgstr ""
 
-#: builtin/index-pack.c:1101
-msgid "error while closing pack file"
+#: builtin/commit.c:1381
+msgid "commit only specified files"
 msgstr ""
 
-#: builtin/index-pack.c:1114
-#, c-format
-msgid "cannot write keep file '%s'"
+#: builtin/commit.c:1382
+msgid "bypass pre-commit hook"
 msgstr ""
 
-#: builtin/index-pack.c:1122
-#, c-format
-msgid "cannot close written keep file '%s'"
+#: builtin/commit.c:1383
+msgid "show what would be committed"
 msgstr ""
 
-#: builtin/index-pack.c:1135
-msgid "cannot store pack file"
+#: builtin/commit.c:1391
+msgid "amend previous commit"
 msgstr ""
 
-#: builtin/index-pack.c:1146
-msgid "cannot store index file"
+#: builtin/commit.c:1392
+msgid "bypass post-rewrite hook"
 msgstr ""
 
-#: builtin/index-pack.c:1247
-#, c-format
-msgid "Cannot open existing pack file '%s'"
+#: builtin/commit.c:1397
+msgid "ok to record an empty change"
 msgstr ""
 
-#: builtin/index-pack.c:1249
-#, c-format
-msgid "Cannot open existing pack idx file for '%s'"
+#: builtin/commit.c:1400
+msgid "ok to record a change with an empty message"
+msgstr ""
+
+#: builtin/commit.c:1432
+msgid "could not parse HEAD commit"
 msgstr ""
 
-#: builtin/index-pack.c:1296
+#: builtin/commit.c:1470 builtin/merge.c:508
 #, c-format
-msgid "non delta: %d object"
-msgid_plural "non delta: %d objects"
-msgstr[0] ""
-msgstr[1] ""
+msgid "could not open '%s' for reading"
+msgstr ""
 
-#: builtin/index-pack.c:1303
+#: builtin/commit.c:1477
 #, c-format
-msgid "chain length = %d: %lu object"
-msgid_plural "chain length = %d: %lu objects"
-msgstr[0] ""
-msgstr[1] ""
+msgid "Corrupt MERGE_HEAD file (%s)"
+msgstr ""
 
-#: builtin/index-pack.c:1330
-msgid "Cannot come back to cwd"
+#: builtin/commit.c:1484
+msgid "could not read MERGE_MODE"
 msgstr ""
 
-#: builtin/index-pack.c:1374 builtin/index-pack.c:1377
-#: builtin/index-pack.c:1389 builtin/index-pack.c:1393
+#: builtin/commit.c:1503
 #, c-format
-msgid "bad %s"
+msgid "could not read commit message: %s"
 msgstr ""
 
-#: builtin/index-pack.c:1407
-msgid "--fix-thin cannot be used without --stdin"
+#: builtin/commit.c:1517
+#, c-format
+msgid "Aborting commit; you did not edit the message.\n"
 msgstr ""
 
-#: builtin/index-pack.c:1411 builtin/index-pack.c:1421
+#: builtin/commit.c:1522
 #, c-format
-msgid "packfile name '%s' does not end with '.pack'"
+msgid "Aborting commit due to empty commit message.\n"
 msgstr ""
 
-#: builtin/index-pack.c:1430
-msgid "--verify with no packfile name given"
+#: builtin/commit.c:1537 builtin/merge.c:935 builtin/merge.c:960
+msgid "failed to write commit object"
 msgstr ""
 
-#: builtin/init-db.c:35
-#, c-format
-msgid "Could not make %s writable by group"
+#: builtin/commit.c:1558
+msgid "cannot lock HEAD ref"
 msgstr ""
 
-#: builtin/init-db.c:62
-#, c-format
-msgid "insanely long template name %s"
+#: builtin/commit.c:1562
+msgid "cannot update HEAD ref"
 msgstr ""
 
-#: builtin/init-db.c:67
-#, c-format
-msgid "cannot stat '%s'"
+#: builtin/commit.c:1573
+msgid ""
+"Repository has been updated, but unable to write\n"
+"new_index file. Check that disk is not full or quota is\n"
+"not exceeded, and then \"git reset HEAD\" to recover."
 msgstr ""
 
-#: builtin/init-db.c:73
-#, c-format
-msgid "cannot stat template '%s'"
+#: builtin/config.c:7
+msgid "git config [options]"
 msgstr ""
 
-#: builtin/init-db.c:80
-#, c-format
-msgid "cannot opendir '%s'"
+#: builtin/config.c:52
+msgid "Config file location"
 msgstr ""
 
-#: builtin/init-db.c:97
-#, c-format
-msgid "cannot readlink '%s'"
+#: builtin/config.c:53
+msgid "use global config file"
 msgstr ""
 
-#: builtin/init-db.c:99
-#, c-format
-msgid "insanely long symlink %s"
+#: builtin/config.c:54
+msgid "use system config file"
 msgstr ""
 
-#: builtin/init-db.c:102
-#, c-format
-msgid "cannot symlink '%s' '%s'"
+#: builtin/config.c:55
+msgid "use repository config file"
 msgstr ""
 
-#: builtin/init-db.c:106
-#, c-format
-msgid "cannot copy '%s' to '%s'"
+#: builtin/config.c:56
+msgid "use given config file"
 msgstr ""
 
-#: builtin/init-db.c:110
-#, c-format
-msgid "ignoring template %s"
+#: builtin/config.c:57
+msgid "Action"
 msgstr ""
 
-#: builtin/init-db.c:133
-#, c-format
-msgid "insanely long template path %s"
-msgstr ""
-
-#: builtin/init-db.c:141
-#, c-format
-msgid "templates not found %s"
+#: builtin/config.c:58
+msgid "get value: name [value-regex]"
 msgstr ""
 
-#: builtin/init-db.c:154
-#, c-format
-msgid "not copying templates of a wrong format version %d from '%s'"
-msgstr ""
-
-#: builtin/init-db.c:192
-#, c-format
-msgid "insane git directory %s"
+#: builtin/config.c:59
+msgid "get all values: key [value-regex]"
 msgstr ""
 
-#: builtin/init-db.c:322 builtin/init-db.c:325
-#, c-format
-msgid "%s already exists"
+#: builtin/config.c:60
+msgid "get values for regexp: name-regex [value-regex]"
 msgstr ""
 
-#: builtin/init-db.c:354
-#, c-format
-msgid "unable to handle file type %d"
+#: builtin/config.c:61
+msgid "replace all matching variables: name value [value_regex]"
 msgstr ""
 
-#: builtin/init-db.c:357
-#, c-format
-msgid "unable to move %s to %s"
+#: builtin/config.c:62
+msgid "add a new variable: name value"
 msgstr ""
 
-#: builtin/init-db.c:362
-#, c-format
-msgid "Could not create git link %s"
+#: builtin/config.c:63
+msgid "remove a variable: name [value-regex]"
 msgstr ""
 
-#.
-#. * TRANSLATORS: The first '%s' is either "Reinitialized
-#. * existing" or "Initialized empty", the second " shared" or
-#. * "", and the last '%s%s' is the verbatim directory name.
-#.
-#: builtin/init-db.c:419
-#, c-format
-msgid "%s%s Git repository in %s%s\n"
+#: builtin/config.c:64
+msgid "remove all matches: name [value-regex]"
 msgstr ""
 
-#: builtin/init-db.c:420
-msgid "Reinitialized existing"
+#: builtin/config.c:65
+msgid "rename section: old-name new-name"
 msgstr ""
 
-#: builtin/init-db.c:420
-msgid "Initialized empty"
+#: builtin/config.c:66
+msgid "remove a section: name"
 msgstr ""
 
-#: builtin/init-db.c:421
-msgid " shared"
+#: builtin/config.c:67
+msgid "list all"
 msgstr ""
 
-#: builtin/init-db.c:440
-msgid "cannot tell cwd"
+#: builtin/config.c:68
+msgid "open an editor"
 msgstr ""
 
-#: builtin/init-db.c:521 builtin/init-db.c:528
-#, c-format
-msgid "cannot mkdir %s"
+#: builtin/config.c:69 builtin/config.c:70
+msgid "slot"
 msgstr ""
 
-#: builtin/init-db.c:532
-#, c-format
-msgid "cannot chdir to %s"
+#: builtin/config.c:69
+msgid "find the color configured: [default]"
 msgstr ""
 
-#: builtin/init-db.c:554
-#, c-format
-msgid ""
-"%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-"
-"dir=<directory>)"
+#: builtin/config.c:70
+msgid "find the color setting: [stdout-is-tty]"
 msgstr ""
 
-#: builtin/init-db.c:578
-msgid "Cannot access current working directory"
+#: builtin/config.c:71
+msgid "Type"
 msgstr ""
 
-#: builtin/init-db.c:585
-#, c-format
-msgid "Cannot access work tree '%s'"
+#: builtin/config.c:72
+msgid "value is \"true\" or \"false\""
 msgstr ""
 
-#: builtin/log.c:188
-#, c-format
-msgid "Final output: %d %s\n"
+#: builtin/config.c:73
+msgid "value is decimal number"
 msgstr ""
 
-#: builtin/log.c:401 builtin/log.c:489
-#, c-format
-msgid "Could not read object %s"
+#: builtin/config.c:74
+msgid "value is --bool or --int"
 msgstr ""
 
-#: builtin/log.c:513
-#, c-format
-msgid "Unknown type: %d"
+#: builtin/config.c:75
+msgid "value is a path (file or directory name)"
 msgstr ""
 
-#: builtin/log.c:602
-msgid "format.headers without value"
+#: builtin/config.c:76
+msgid "Other"
 msgstr ""
 
-#: builtin/log.c:676
-msgid "name of output directory is too long"
+#: builtin/config.c:77
+msgid "terminate values with NUL byte"
 msgstr ""
 
-#: builtin/log.c:687
-#, c-format
-msgid "Cannot open patch file %s"
+#: builtin/config.c:78
+msgid "respect include directives on lookup"
 msgstr ""
 
-#: builtin/log.c:701
-msgid "Need exactly one range."
+#: builtin/count-objects.c:69
+msgid "git count-objects [-v]"
 msgstr ""
 
-#: builtin/log.c:709
-msgid "Not a range."
+#: builtin/describe.c:15
+msgid "git describe [options] <committish>*"
 msgstr ""
 
-#: builtin/log.c:786
-msgid "Cover letter needs email format"
+#: builtin/describe.c:16
+msgid "git describe [options] --dirty"
 msgstr ""
 
-#: builtin/log.c:859
+#: builtin/describe.c:234
 #, c-format
-msgid "insane in-reply-to: %s"
+msgid "annotated tag %s not available"
 msgstr ""
 
-#: builtin/log.c:932
-msgid "Two output directories?"
+#: builtin/describe.c:238
+#, c-format
+msgid "annotated tag %s has no embedded name"
 msgstr ""
 
-#: builtin/log.c:1153
+#: builtin/describe.c:240
 #, c-format
-msgid "bogus committer info %s"
+msgid "tag '%s' is really '%s' here"
 msgstr ""
 
-#: builtin/log.c:1198
-msgid "-n and -k are mutually exclusive."
+#: builtin/describe.c:267
+#, c-format
+msgid "Not a valid object name %s"
 msgstr ""
 
-#: builtin/log.c:1200
-msgid "--subject-prefix and -k are mutually exclusive."
+#: builtin/describe.c:270
+#, c-format
+msgid "%s is not a valid '%s' object"
 msgstr ""
 
-#: builtin/log.c:1208
-msgid "--name-only does not make sense"
+#: builtin/describe.c:287
+#, c-format
+msgid "no tag exactly matches '%s'"
 msgstr ""
 
-#: builtin/log.c:1210
-msgid "--name-status does not make sense"
+#: builtin/describe.c:289
+#, c-format
+msgid "searching to describe %s\n"
 msgstr ""
 
-#: builtin/log.c:1212
-msgid "--check does not make sense"
+#: builtin/describe.c:329
+#, c-format
+msgid "finished search at %s\n"
 msgstr ""
 
-#: builtin/log.c:1235
-msgid "standard output, or directory, which one?"
+#: builtin/describe.c:353
+#, c-format
+msgid ""
+"No annotated tags can describe '%s'.\n"
+"However, there were unannotated tags: try --tags."
 msgstr ""
 
-#: builtin/log.c:1237
+#: builtin/describe.c:357
 #, c-format
-msgid "Could not create directory '%s'"
+msgid ""
+"No tags can describe '%s'.\n"
+"Try --always, or create some tags."
 msgstr ""
 
-#: builtin/log.c:1390
-msgid "Failed to create output files"
+#: builtin/describe.c:378
+#, c-format
+msgid "traversed %lu commits\n"
 msgstr ""
 
-#: builtin/log.c:1494
+#: builtin/describe.c:381
 #, c-format
 msgid ""
-"Could not find a tracked remote branch, please specify <upstream> manually.\n"
+"more than %i tags found; listed %i most recent\n"
+"gave up search at %s\n"
 msgstr ""
 
-#: builtin/log.c:1510 builtin/log.c:1512 builtin/log.c:1524
-#, c-format
-msgid "Unknown commit %s"
+#: builtin/describe.c:403
+msgid "find the tag that comes after the commit"
 msgstr ""
 
-#: builtin/merge.c:90
-msgid "switch `m' requires a value"
+#: builtin/describe.c:404
+msgid "debug search strategy on stderr"
 msgstr ""
 
-#: builtin/merge.c:127
-#, c-format
-msgid "Could not find merge strategy '%s'.\n"
+#: builtin/describe.c:405
+msgid "use any ref in .git/refs"
 msgstr ""
 
-#: builtin/merge.c:128
-#, c-format
-msgid "Available strategies are:"
+#: builtin/describe.c:406
+msgid "use any tag in .git/refs/tags"
 msgstr ""
 
-#: builtin/merge.c:133
-#, c-format
-msgid "Available custom strategies are:"
+#: builtin/describe.c:407
+msgid "always use long format"
 msgstr ""
 
-#: builtin/merge.c:240
-msgid "could not run stash."
+#: builtin/describe.c:410
+msgid "only output exact matches"
 msgstr ""
 
-#: builtin/merge.c:245
-msgid "stash failed"
+#: builtin/describe.c:412
+msgid "consider <n> most recent tags (default: 10)"
 msgstr ""
 
-#: builtin/merge.c:250
-#, c-format
-msgid "not a valid object: %s"
+#: builtin/describe.c:414
+msgid "only consider tags matching <pattern>"
 msgstr ""
 
-#: builtin/merge.c:269 builtin/merge.c:286
-msgid "read-tree failed"
+#: builtin/describe.c:416 builtin/name-rev.c:238
+msgid "show abbreviated commit object as fallback"
 msgstr ""
 
-#: builtin/merge.c:316
-msgid " (nothing to squash)"
+#: builtin/describe.c:417
+msgid "mark"
 msgstr ""
 
-#: builtin/merge.c:329
-#, c-format
-msgid "Squash commit -- not updating HEAD\n"
+#: builtin/describe.c:418
+msgid "append <mark> on dirty working tree (default: \"-dirty\")"
 msgstr ""
 
-#: builtin/merge.c:361
-msgid "Writing SQUASH_MSG"
+#: builtin/describe.c:436
+msgid "--long is incompatible with --abbrev=0"
 msgstr ""
 
-#: builtin/merge.c:363
-msgid "Finishing SQUASH_MSG"
+#: builtin/describe.c:462
+msgid "No names found, cannot describe anything."
 msgstr ""
 
-#: builtin/merge.c:386
-#, c-format
-msgid "No merge message -- not updating HEAD\n"
+#: builtin/describe.c:482
+msgid "--dirty is incompatible with committishes"
 msgstr ""
 
-#: builtin/merge.c:437
+#: builtin/diff.c:79
 #, c-format
-msgid "'%s' does not point to a commit"
+msgid "'%s': not a regular file or symlink"
 msgstr ""
 
-#: builtin/merge.c:536
+#: builtin/diff.c:224
 #, c-format
-msgid "Bad branch.%s.mergeoptions string: %s"
+msgid "invalid option: %s"
 msgstr ""
 
-#: builtin/merge.c:629
-msgid "git write-tree failed to write a tree"
+#: builtin/diff.c:301
+msgid "Not a git repository"
 msgstr ""
 
-#: builtin/merge.c:679
-msgid "failed to read the cache"
+#: builtin/diff.c:344
+#, c-format
+msgid "invalid object '%s' given."
 msgstr ""
 
-#: builtin/merge.c:697
-msgid "Unable to write index."
+#: builtin/diff.c:349
+#, c-format
+msgid "more than %d trees given: '%s'"
 msgstr ""
 
-#: builtin/merge.c:710
-msgid "Not handling anything other than two heads merge."
+#: builtin/diff.c:359
+#, c-format
+msgid "more than two blobs given: '%s'"
 msgstr ""
 
-#: builtin/merge.c:724
+#: builtin/diff.c:367
 #, c-format
-msgid "Unknown option for merge-recursive: -X%s"
+msgid "unhandled object '%s' given."
 msgstr ""
 
-#: builtin/merge.c:738
-#, c-format
-msgid "unable to write %s"
+#: builtin/fast-export.c:22
+msgid "git fast-export [rev-list-opts]"
 msgstr ""
 
-#: builtin/merge.c:877
-#, c-format
-msgid "Could not read from '%s'"
+#: builtin/fast-export.c:635
+msgid "show progress after <n> objects"
 msgstr ""
 
-#: builtin/merge.c:886
-#, c-format
-msgid "Not committing merge; use 'git commit' to complete the merge.\n"
+#: builtin/fast-export.c:637
+msgid "select handling of signed tags"
 msgstr ""
 
-#: builtin/merge.c:892
-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"
-"\n"
-"Lines starting with '#' will be ignored, and an empty message aborts\n"
-"the commit.\n"
+#: builtin/fast-export.c:640
+msgid "select handling of tags that tag filtered objects"
 msgstr ""
 
-#: builtin/merge.c:916
-msgid "Empty commit message."
+#: builtin/fast-export.c:643
+msgid "Dump marks to this file"
 msgstr ""
 
-#: builtin/merge.c:928
-#, c-format
-msgid "Wonderful.\n"
+#: builtin/fast-export.c:645
+msgid "Import marks from this file"
 msgstr ""
 
-#: builtin/merge.c:993
-#, c-format
-msgid "Automatic merge failed; fix conflicts and then commit the result.\n"
+#: builtin/fast-export.c:647
+msgid "Fake a tagger when tags lack one"
 msgstr ""
 
-#: builtin/merge.c:1009
-#, c-format
-msgid "'%s' is not a commit"
+#: builtin/fast-export.c:649
+msgid "Output full tree for each commit"
 msgstr ""
 
-#: builtin/merge.c:1050
-msgid "No current branch."
+#: builtin/fast-export.c:651
+msgid "Use the done feature to terminate the stream"
 msgstr ""
 
-#: builtin/merge.c:1052
-msgid "No remote for the current branch."
+#: builtin/fast-export.c:652
+msgid "Skip output of blob data"
 msgstr ""
 
-#: builtin/merge.c:1054
-msgid "No default upstream defined for the current branch."
+#: builtin/fetch.c:20
+msgid "git fetch [<options>] [<repository> [<refspec>...]]"
 msgstr ""
 
-#: builtin/merge.c:1059
-#, c-format
-msgid "No remote tracking branch for %s from %s"
+#: builtin/fetch.c:21
+msgid "git fetch [<options>] <group>"
 msgstr ""
 
-#: builtin/merge.c:1146 builtin/merge.c:1303
-#, c-format
-msgid "%s - not something we can merge"
+#: builtin/fetch.c:22
+msgid "git fetch --multiple [<options>] [(<repository> | <group>)...]"
 msgstr ""
 
-#: builtin/merge.c:1214
-msgid "There is no merge to abort (MERGE_HEAD missing)."
+#: builtin/fetch.c:23
+msgid "git fetch --all [<options>]"
 msgstr ""
 
-#: builtin/merge.c:1230 git-pull.sh:31
-msgid ""
-"You have not concluded your merge (MERGE_HEAD exists).\n"
-"Please, commit your changes before you can merge."
+#: builtin/fetch.c:60
+msgid "fetch from all remotes"
 msgstr ""
 
-#: builtin/merge.c:1233 git-pull.sh:34
-msgid "You have not concluded your merge (MERGE_HEAD exists)."
+#: builtin/fetch.c:62
+msgid "append to .git/FETCH_HEAD instead of overwriting"
 msgstr ""
 
-#: builtin/merge.c:1237
-msgid ""
-"You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
-"Please, commit your changes before you can merge."
+#: builtin/fetch.c:64
+msgid "path to upload pack on remote end"
 msgstr ""
 
-#: builtin/merge.c:1240
-msgid "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)."
+#: builtin/fetch.c:65
+msgid "force overwrite of local branch"
 msgstr ""
 
-#: builtin/merge.c:1249
-msgid "You cannot combine --squash with --no-ff."
+#: builtin/fetch.c:67
+msgid "fetch from multiple remotes"
 msgstr ""
 
-#: builtin/merge.c:1254
-msgid "You cannot combine --no-ff with --ff-only."
+#: builtin/fetch.c:69
+msgid "fetch all tags and associated objects"
 msgstr ""
 
-#: builtin/merge.c:1261
-msgid "No commit specified and merge.defaultToUpstream not set."
+#: builtin/fetch.c:71
+msgid "do not fetch all tags (--no-tags)"
 msgstr ""
 
-#: builtin/merge.c:1293
-msgid "Can merge only exactly one commit into empty head"
+#: builtin/fetch.c:73
+msgid "prune remote-tracking branches no longer on remote"
 msgstr ""
 
-#: builtin/merge.c:1296
-msgid "Squash commit into empty head not supported yet"
+#: builtin/fetch.c:74
+msgid "on-demand"
 msgstr ""
 
-#: builtin/merge.c:1298
-msgid "Non-fast-forward commit does not make sense into an empty head"
+#: builtin/fetch.c:75
+msgid "control recursive fetching of submodules"
 msgstr ""
 
-#: builtin/merge.c:1413
-#, c-format
-msgid "Updating %s..%s\n"
+#: builtin/fetch.c:79
+msgid "keep downloaded pack"
 msgstr ""
 
-#: builtin/merge.c:1451
-#, c-format
-msgid "Trying really trivial in-index merge...\n"
+#: builtin/fetch.c:81
+msgid "allow updating of HEAD ref"
 msgstr ""
 
-#: builtin/merge.c:1458
-#, c-format
-msgid "Nope.\n"
+#: builtin/fetch.c:84
+msgid "deepen history of shallow clone"
 msgstr ""
 
-#: builtin/merge.c:1490
-msgid "Not possible to fast-forward, aborting."
+#: builtin/fetch.c:85 builtin/log.c:1083
+msgid "dir"
 msgstr ""
 
-#: builtin/merge.c:1513 builtin/merge.c:1592
-#, c-format
-msgid "Rewinding the tree to pristine...\n"
+#: builtin/fetch.c:86
+msgid "prepend this to submodule path output"
 msgstr ""
 
-#: builtin/merge.c:1517
-#, c-format
-msgid "Trying merge strategy %s...\n"
+#: builtin/fetch.c:89
+msgid "default mode for recursion"
 msgstr ""
 
-#: builtin/merge.c:1583
-#, c-format
-msgid "No merge strategy handled the merge.\n"
+#: builtin/fetch.c:201
+msgid "Couldn't find remote ref HEAD"
 msgstr ""
 
-#: builtin/merge.c:1585
+#: builtin/fetch.c:254
 #, c-format
-msgid "Merge with strategy %s failed.\n"
+msgid "object %s not found"
 msgstr ""
 
-#: builtin/merge.c:1594
-#, c-format
-msgid "Using the %s to prepare resolving by hand.\n"
+#: builtin/fetch.c:259
+msgid "[up to date]"
 msgstr ""
 
-#: builtin/merge.c:1606
+#: builtin/fetch.c:273
 #, c-format
-msgid "Automatic merge went well; stopped before committing as requested\n"
+msgid "! %-*s %-*s -> %s  (can't fetch in current branch)"
 msgstr ""
 
-#: builtin/mv.c:108
-#, c-format
-msgid "Checking rename of '%s' to '%s'\n"
+#: builtin/fetch.c:274 builtin/fetch.c:360
+msgid "[rejected]"
 msgstr ""
 
-#: builtin/mv.c:112
-msgid "bad source"
+#: builtin/fetch.c:285
+msgid "[tag update]"
 msgstr ""
 
-#: builtin/mv.c:115
-msgid "can not move directory into itself"
+#: builtin/fetch.c:287 builtin/fetch.c:322 builtin/fetch.c:340
+msgid "  (unable to update local ref)"
 msgstr ""
 
-#: builtin/mv.c:118
-msgid "cannot move directory over file"
+#: builtin/fetch.c:305
+msgid "[new tag]"
 msgstr ""
 
-#: builtin/mv.c:128
-#, c-format
-msgid "Huh? %.*s is in index?"
+#: builtin/fetch.c:308
+msgid "[new branch]"
 msgstr ""
 
-#: builtin/mv.c:140
-msgid "source directory is empty"
+#: builtin/fetch.c:311
+msgid "[new ref]"
 msgstr ""
 
-#: builtin/mv.c:171
-msgid "not under version control"
+#: builtin/fetch.c:356
+msgid "unable to update local ref"
 msgstr ""
 
-#: builtin/mv.c:173
-msgid "destination exists"
+#: builtin/fetch.c:356
+msgid "forced update"
 msgstr ""
 
-#: builtin/mv.c:181
-#, c-format
-msgid "overwriting '%s'"
+#: builtin/fetch.c:362
+msgid "(non-fast-forward)"
 msgstr ""
 
-#: builtin/mv.c:184
-msgid "Cannot overwrite"
+#: builtin/fetch.c:393 builtin/fetch.c:685
+#, c-format
+msgid "cannot open %s: %s\n"
 msgstr ""
 
-#: builtin/mv.c:187
-msgid "multiple sources for the same target"
+#: builtin/fetch.c:402
+#, c-format
+msgid "%s did not send all necessary objects\n"
 msgstr ""
 
-#: builtin/mv.c:202
+#: builtin/fetch.c:488
 #, c-format
-msgid "%s, source=%s, destination=%s"
+msgid "From %.*s\n"
 msgstr ""
 
-#: builtin/mv.c:212
+#: builtin/fetch.c:499
 #, c-format
-msgid "Renaming %s to %s\n"
+msgid ""
+"some local refs could not be updated; try running\n"
+" 'git remote prune %s' to remove any old, conflicting branches"
 msgstr ""
 
-#: builtin/mv.c:215 builtin/remote.c:731
+#: builtin/fetch.c:549
 #, c-format
-msgid "renaming '%s' failed"
+msgid "   (%s will become dangling)"
 msgstr ""
 
-#: builtin/notes.c:139
+#: builtin/fetch.c:550
 #, c-format
-msgid "unable to start 'show' for object '%s'"
+msgid "   (%s has become dangling)"
 msgstr ""
 
-#: builtin/notes.c:145
-msgid "can't fdopen 'show' output fd"
+#: builtin/fetch.c:557
+msgid "[deleted]"
 msgstr ""
 
-#: builtin/notes.c:155
-#, c-format
-msgid "failed to close pipe to 'show' for object '%s'"
+#: builtin/fetch.c:558 builtin/remote.c:1055
+msgid "(none)"
 msgstr ""
 
-#: builtin/notes.c:158
+#: builtin/fetch.c:675
 #, c-format
-msgid "failed to finish 'show' for object '%s'"
+msgid "Refusing to fetch into current branch %s of non-bare repository"
 msgstr ""
 
-#: builtin/notes.c:175 builtin/tag.c:347
+#: builtin/fetch.c:709
 #, c-format
-msgid "could not create file '%s'"
-msgstr ""
-
-#: builtin/notes.c:189
-msgid "Please supply the note contents using either -m or -F option"
+msgid "Don't know how to fetch from %s"
 msgstr ""
 
-#: builtin/notes.c:210 builtin/notes.c:973
+#: builtin/fetch.c:786
 #, c-format
-msgid "Removing note for object %s\n"
+msgid "Option \"%s\" value \"%s\" is not valid for %s"
 msgstr ""
 
-#: builtin/notes.c:215
-msgid "unable to write note object"
+#: builtin/fetch.c:789
+#, c-format
+msgid "Option \"%s\" is ignored for %s\n"
 msgstr ""
 
-#: builtin/notes.c:217
+#: builtin/fetch.c:891
 #, c-format
-msgid "The note contents has been left in %s"
+msgid "Fetching %s\n"
 msgstr ""
 
-#: builtin/notes.c:251 builtin/tag.c:542
+#: builtin/fetch.c:893 builtin/remote.c:100
 #, c-format
-msgid "cannot read '%s'"
+msgid "Could not fetch %s"
 msgstr ""
 
-#: builtin/notes.c:253 builtin/tag.c:545
-#, c-format
-msgid "could not open or read '%s'"
+#: 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."
 msgstr ""
 
-#: 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
-#, c-format
-msgid "Failed to resolve '%s' as a valid ref."
+#: builtin/fetch.c:932
+msgid "You need to specify a tag name."
 msgstr ""
 
-#: builtin/notes.c:275
-#, c-format
-msgid "Failed to read object '%s'."
+#: builtin/fetch.c:984
+msgid "fetch --all does not take a repository argument"
 msgstr ""
 
-#: builtin/notes.c:299
-msgid "Cannot commit uninitialized/unreferenced notes tree"
+#: builtin/fetch.c:986
+msgid "fetch --all does not make sense with refspecs"
 msgstr ""
 
-#: builtin/notes.c:340
+#: builtin/fetch.c:997
 #, c-format
-msgid "Bad notes.rewriteMode value: '%s'"
+msgid "No such remote or remote group: %s"
 msgstr ""
 
-#: builtin/notes.c:350
-#, c-format
-msgid "Refusing to rewrite notes in %s (outside of refs/notes/)"
+#: builtin/fetch.c:1005
+msgid "Fetching a group and specifying refspecs does not make sense"
 msgstr ""
 
-#. TRANSLATORS: The first %s is the name of the
-#. environment variable, the second %s is its value
-#: builtin/notes.c:377
-#, c-format
-msgid "Bad %s value: '%s'"
+#: builtin/fmt-merge-msg.c:13
+msgid "git fmt-merge-msg [-m <message>] [--log[=<n>]|--no-log] [--file <file>]"
 msgstr ""
 
-#: builtin/notes.c:441
-#, c-format
-msgid "Malformed input line: '%s'."
+#: 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/tag.c:448 parse-options.h:133 parse-options.h:235
+msgid "n"
 msgstr ""
 
-#: builtin/notes.c:456
-#, c-format
-msgid "Failed to copy notes from '%s' to '%s'"
+#: builtin/fmt-merge-msg.c:654
+msgid "populate log with at most <n> entries from shortlog"
 msgstr ""
 
-#: 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
-msgid "too many parameters"
+#: builtin/fmt-merge-msg.c:657
+msgid "alias for --log (deprecated)"
 msgstr ""
 
-#: builtin/notes.c:513 builtin/notes.c:772
-#, c-format
-msgid "No note found for object %s."
+#: builtin/fmt-merge-msg.c:660
+msgid "text"
 msgstr ""
 
-#: builtin/notes.c:580
-#, c-format
-msgid ""
-"Cannot add notes. Found existing notes for object %s. Use '-f' to overwrite "
-"existing notes"
+#: builtin/fmt-merge-msg.c:661
+msgid "use <text> as start of message"
 msgstr ""
 
-#: builtin/notes.c:585 builtin/notes.c:662
-#, c-format
-msgid "Overwriting existing notes for object %s\n"
+#: builtin/fmt-merge-msg.c:662
+msgid "file to read from"
 msgstr ""
 
-#: builtin/notes.c:635
-msgid "too few parameters"
+#: builtin/for-each-ref.c:979
+msgid "git for-each-ref [options] [<pattern>]"
 msgstr ""
 
-#: builtin/notes.c:656
-#, c-format
-msgid ""
-"Cannot copy notes. Found existing notes for object %s. Use '-f' to overwrite "
-"existing notes"
+#: builtin/for-each-ref.c:994
+msgid "quote placeholders suitably for shells"
 msgstr ""
 
-#: builtin/notes.c:668
-#, c-format
-msgid "Missing notes on source object %s. Cannot copy."
+#: builtin/for-each-ref.c:996
+msgid "quote placeholders suitably for perl"
 msgstr ""
 
-#: builtin/notes.c:717
-#, c-format
-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"
+#: builtin/for-each-ref.c:998
+msgid "quote placeholders suitably for python"
 msgstr ""
 
-#: builtin/notes.c:971
-#, c-format
-msgid "Object %s has no note\n"
+#: builtin/for-each-ref.c:1000
+msgid "quote placeholders suitably for tcl"
 msgstr ""
 
-#: builtin/notes.c:1103 builtin/remote.c:1598
-#, c-format
-msgid "Unknown subcommand: %s"
+#: builtin/for-each-ref.c:1003
+msgid "show only <n> matched refs"
 msgstr ""
 
-#: builtin/pack-objects.c:2337
-#, c-format
-msgid "unsupported index version %s"
+#: builtin/for-each-ref.c:1004
+msgid "format"
 msgstr ""
 
-#: builtin/pack-objects.c:2341
-#, c-format
-msgid "bad index version '%s'"
+#: builtin/for-each-ref.c:1004
+msgid "format to use for the output"
 msgstr ""
 
-#: builtin/pack-objects.c:2364
-#, c-format
-msgid "option %s does not accept negative form"
+#: builtin/for-each-ref.c:1005
+msgid "key"
 msgstr ""
 
-#: builtin/pack-objects.c:2368
-#, c-format
-msgid "unable to parse value '%s' for option %s"
+#: builtin/for-each-ref.c:1006
+msgid "field name to sort on"
 msgstr ""
 
-#: builtin/push.c:45
-msgid "tag shorthand without <tag>"
+#: builtin/fsck.c:608
+msgid "git fsck [options] [<object>...]"
 msgstr ""
 
-#: builtin/push.c:64
-msgid "--delete only accepts plain target ref names"
+#: builtin/fsck.c:614
+msgid "show unreachable objects"
 msgstr ""
 
-#: builtin/push.c:99
-msgid ""
-"\n"
-"To choose either option permanently, see push.default in 'git help config'."
+#: builtin/fsck.c:615
+msgid "show dangling objects"
 msgstr ""
 
-#: builtin/push.c:102
-#, c-format
-msgid ""
-"The upstream branch of your current branch does not match\n"
-"the name of your current branch.  To push to the upstream branch\n"
-"on the remote, use\n"
-"\n"
-"    git push %s HEAD:%s\n"
-"\n"
-"To push to the branch of the same name on the remote, use\n"
-"\n"
-"    git push %s %s\n"
-"%s"
+#: builtin/fsck.c:616
+msgid "report tags"
 msgstr ""
 
-#: builtin/push.c:121
-#, c-format
-msgid ""
-"You are not currently on a branch.\n"
-"To push the history leading to the current (detached HEAD)\n"
-"state now, use\n"
-"\n"
-"    git push %s HEAD:<name-of-remote-branch>\n"
+#: builtin/fsck.c:617
+msgid "report root nodes"
 msgstr ""
 
-#: builtin/push.c:128
-#, c-format
-msgid ""
-"The current branch %s has no upstream branch.\n"
-"To push the current branch and set the remote as upstream, use\n"
-"\n"
-"    git push --set-upstream %s %s\n"
+#: builtin/fsck.c:618
+msgid "make index objects head nodes"
 msgstr ""
 
-#: builtin/push.c:136
-#, c-format
-msgid "The current branch %s has multiple upstream branches, refusing to push."
+#: builtin/fsck.c:619
+msgid "make reflogs head nodes (default)"
 msgstr ""
 
-#: builtin/push.c:139
-#, c-format
-msgid ""
-"You are pushing to remote '%s', which is not the upstream of\n"
-"your current branch '%s', without telling me what to push\n"
-"to update which remote branch."
+#: builtin/fsck.c:620
+msgid "also consider packs and alternate objects"
 msgstr ""
 
-#: builtin/push.c:174
-msgid ""
-"You didn't specify any refspecs to push, and push.default is \"nothing\"."
+#: builtin/fsck.c:621
+msgid "enable more strict checking"
 msgstr ""
 
-#: builtin/push.c:181
-msgid ""
-"Updates were rejected because the tip of your current branch is behind\n"
-"its remote counterpart. Merge the remote changes (e.g. 'git pull')\n"
-"before pushing again.\n"
-"See the 'Note about fast-forwards' in 'git push --help' for details."
+#: builtin/fsck.c:623
+msgid "write dangling objects in .git/lost-found"
 msgstr ""
 
-#: builtin/push.c:187
-msgid ""
-"Updates were rejected because a pushed branch tip is behind its remote\n"
-"counterpart. If you did not intend to push that branch, you may want to\n"
-"specify branches to push or set the 'push.default' configuration\n"
-"variable to 'current' or 'upstream' to push only the current branch."
+#: builtin/fsck.c:624 builtin/prune.c:134
+msgid "show progress"
 msgstr ""
 
-#: builtin/push.c:193
-msgid ""
-"Updates were rejected because a pushed branch tip is behind its remote\n"
-"counterpart. Check out this branch and merge the remote changes\n"
-"(e.g. 'git pull') before pushing again.\n"
-"See the 'Note about fast-forwards' in 'git push --help' for details."
+#: builtin/gc.c:22
+msgid "git gc [options]"
 msgstr ""
 
-#: builtin/push.c:233
+#: builtin/gc.c:63
 #, c-format
-msgid "Pushing to %s\n"
+msgid "Invalid %s: '%s'"
 msgstr ""
 
-#: builtin/push.c:237
+#: builtin/gc.c:90
 #, c-format
-msgid "failed to push some refs to '%s'"
+msgid "insanely long object directory %.*s"
 msgstr ""
 
-#: builtin/push.c:269
-#, c-format
-msgid "bad repository '%s'"
+#: builtin/gc.c:179
+msgid "prune unreferenced objects"
 msgstr ""
 
-#: builtin/push.c:270
-msgid ""
-"No configured push destination.\n"
-"Either specify the URL from the command-line or configure a remote "
-"repository using\n"
-"\n"
-"    git remote add <name> <url>\n"
-"\n"
-"and then push using the remote name\n"
-"\n"
-"    git push <name>\n"
+#: builtin/gc.c:181
+msgid "be more thorough (increased runtime)"
 msgstr ""
 
-#: builtin/push.c:285
-msgid "--all and --tags are incompatible"
+#: builtin/gc.c:182
+msgid "enable auto-gc mode"
 msgstr ""
 
-#: builtin/push.c:286
-msgid "--all can't be combined with refspecs"
+#: builtin/gc.c:222
+#, c-format
+msgid ""
+"Auto packing the repository for optimum performance. You may also\n"
+"run \"git gc\" manually. See \"git help gc\" for more information.\n"
 msgstr ""
 
-#: builtin/push.c:291
-msgid "--mirror and --tags are incompatible"
+#: builtin/gc.c:249
+msgid ""
+"There are too many unreachable loose objects; run 'git prune' to remove them."
 msgstr ""
 
-#: builtin/push.c:292
-msgid "--mirror can't be combined with refspecs"
+#: builtin/grep.c:22
+msgid "git grep [options] [-e] <pattern> [<rev>...] [[--] <path>...]"
 msgstr ""
 
-#: builtin/push.c:297
-msgid "--all and --mirror are incompatible"
+#: builtin/grep.c:217
+#, c-format
+msgid "grep: failed to create thread: %s"
 msgstr ""
 
-#: builtin/push.c:385
-msgid "--delete is incompatible with --all, --mirror and --tags"
+#: builtin/grep.c:455
+#, c-format
+msgid "Failed to chdir: %s"
 msgstr ""
 
-#: builtin/push.c:387
-msgid "--delete doesn't make sense without any refs"
+#: builtin/grep.c:531 builtin/grep.c:565
+#, c-format
+msgid "unable to read tree (%s)"
 msgstr ""
 
-#: builtin/remote.c:98
+#: builtin/grep.c:579
 #, c-format
-msgid "Updating %s"
+msgid "unable to grep from object of type %s"
 msgstr ""
 
-#: builtin/remote.c:130
-msgid ""
-"--mirror is dangerous and deprecated; please\n"
-"\t use --mirror=fetch or --mirror=push instead"
+#: builtin/grep.c:637
+#, c-format
+msgid "switch `%c' expects a numerical value"
 msgstr ""
 
-#: builtin/remote.c:147
+#: builtin/grep.c:654
 #, c-format
-msgid "unknown mirror argument: %s"
+msgid "cannot open '%s'"
 msgstr ""
 
-#: builtin/remote.c:185
-msgid "specifying a master branch makes no sense with --mirror"
+#: builtin/grep.c:729
+msgid "search in index instead of in the work tree"
 msgstr ""
 
-#: builtin/remote.c:187
-msgid "specifying branches to track makes sense only with fetch mirrors"
+#: builtin/grep.c:731
+msgid "find in contents not managed by git"
 msgstr ""
 
-#: builtin/remote.c:195 builtin/remote.c:646
-#, c-format
-msgid "remote %s already exists."
+#: builtin/grep.c:733
+msgid "search in both tracked and untracked files"
 msgstr ""
 
-#: builtin/remote.c:199 builtin/remote.c:650
-#, c-format
-msgid "'%s' is not a valid remote name"
+#: builtin/grep.c:735
+msgid "search also in ignored files"
 msgstr ""
 
-#: builtin/remote.c:243
-#, c-format
-msgid "Could not setup master '%s'"
+#: builtin/grep.c:738
+msgid "show non-matching lines"
 msgstr ""
 
-#: builtin/remote.c:299
-#, c-format
-msgid "more than one %s"
+#: builtin/grep.c:740
+msgid "case insensitive matching"
+msgstr ""
+
+#: builtin/grep.c:742
+msgid "match patterns only at word boundaries"
+msgstr ""
+
+#: builtin/grep.c:744
+msgid "process binary files as text"
+msgstr ""
+
+#: builtin/grep.c:746
+msgid "don't match patterns in binary files"
+msgstr ""
+
+#: builtin/grep.c:749
+msgid "descend at most <depth> levels"
+msgstr ""
+
+#: builtin/grep.c:753
+msgid "use extended POSIX regular expressions"
+msgstr ""
+
+#: builtin/grep.c:756
+msgid "use basic POSIX regular expressions (default)"
+msgstr ""
+
+#: builtin/grep.c:759
+msgid "interpret patterns as fixed strings"
+msgstr ""
+
+#: builtin/grep.c:762
+msgid "use Perl-compatible regular expressions"
+msgstr ""
+
+#: builtin/grep.c:765
+msgid "show line numbers"
+msgstr ""
+
+#: builtin/grep.c:766
+msgid "don't show filenames"
+msgstr ""
+
+#: builtin/grep.c:767
+msgid "show filenames"
+msgstr ""
+
+#: builtin/grep.c:769
+msgid "show filenames relative to top directory"
+msgstr ""
+
+#: builtin/grep.c:771
+msgid "show only filenames instead of matching lines"
+msgstr ""
+
+#: builtin/grep.c:773
+msgid "synonym for --files-with-matches"
+msgstr ""
+
+#: builtin/grep.c:776
+msgid "show only the names of files without match"
+msgstr ""
+
+#: builtin/grep.c:778
+msgid "print NUL after filenames"
+msgstr ""
+
+#: builtin/grep.c:780
+msgid "show the number of matches instead of matching lines"
+msgstr ""
+
+#: builtin/grep.c:781
+msgid "highlight matches"
+msgstr ""
+
+#: builtin/grep.c:783
+msgid "print empty line between matches from different files"
+msgstr ""
+
+#: builtin/grep.c:785
+msgid "show filename only once above matches from same file"
+msgstr ""
+
+#: builtin/grep.c:788
+msgid "show <n> context lines before and after matches"
+msgstr ""
+
+#: builtin/grep.c:791
+msgid "show <n> context lines before matches"
+msgstr ""
+
+#: builtin/grep.c:793
+msgid "show <n> context lines after matches"
+msgstr ""
+
+#: builtin/grep.c:794
+msgid "shortcut for -C NUM"
+msgstr ""
+
+#: builtin/grep.c:797
+msgid "show a line with the function name before matches"
+msgstr ""
+
+#: builtin/grep.c:799
+msgid "show the surrounding function"
+msgstr ""
+
+#: builtin/grep.c:802
+msgid "read patterns from file"
+msgstr ""
+
+#: builtin/grep.c:804
+msgid "match <pattern>"
+msgstr ""
+
+#: builtin/grep.c:806
+msgid "combine patterns specified with -e"
+msgstr ""
+
+#: builtin/grep.c:818
+msgid "indicate hit with exit status without output"
+msgstr ""
+
+#: builtin/grep.c:820
+msgid "show only matches from files that match all patterns"
+msgstr ""
+
+#: builtin/grep.c:822
+msgid "show parse tree for grep expression"
+msgstr ""
+
+#: builtin/grep.c:826
+msgid "pager"
+msgstr ""
+
+#: builtin/grep.c:826
+msgid "show matching files in the pager"
+msgstr ""
+
+#: builtin/grep.c:829
+msgid "allow calling of grep(1) (ignored by this build)"
+msgstr ""
+
+#: builtin/grep.c:830 builtin/show-ref.c:201
+msgid "show usage"
+msgstr ""
+
+#: builtin/grep.c:921
+msgid "no pattern given."
+msgstr ""
+
+#: builtin/grep.c:935
+#, c-format
+msgid "bad object %s"
+msgstr ""
+
+#: builtin/grep.c:976
+msgid "--open-files-in-pager only works on the worktree"
+msgstr ""
+
+#: builtin/grep.c:999
+msgid "--cached or --untracked cannot be used with --no-index."
+msgstr ""
+
+#: builtin/grep.c:1004
+msgid "--no-index or --untracked cannot be used with revs."
+msgstr ""
+
+#: builtin/grep.c:1007
+msgid "--[no-]exclude-standard cannot be used for tracked contents."
+msgstr ""
+
+#: builtin/grep.c:1015
+msgid "both --cached and trees are given."
+msgstr ""
+
+#: builtin/hash-object.c:60
+msgid ""
+"git hash-object [-t <type>] [-w] [--path=<file>|--no-filters] [--stdin] [--] "
+"<file>..."
+msgstr ""
+
+#: builtin/hash-object.c:61
+msgid "git hash-object  --stdin-paths < <list-of-paths>"
+msgstr ""
+
+#: builtin/hash-object.c:72
+msgid "type"
+msgstr ""
+
+#: builtin/hash-object.c:72
+msgid "object type"
+msgstr ""
+
+#: builtin/hash-object.c:73
+msgid "write the object into the object database"
+msgstr ""
+
+#: builtin/hash-object.c:74
+msgid "read the object from stdin"
+msgstr ""
+
+#: builtin/hash-object.c:76
+msgid "store file as is without filters"
+msgstr ""
+
+#: builtin/hash-object.c:77
+msgid "process file as it were from this path"
+msgstr ""
+
+#: builtin/help.c:43
+msgid "print all available commands"
+msgstr ""
+
+#: builtin/help.c:44
+msgid "show man page"
+msgstr ""
+
+#: builtin/help.c:45
+msgid "show manual in web browser"
+msgstr ""
+
+#: builtin/help.c:47
+msgid "show info page"
+msgstr ""
+
+#: builtin/help.c:53
+msgid "git help [--all] [--man|--web|--info] [command]"
+msgstr ""
+
+#: builtin/help.c:65
+#, c-format
+msgid "unrecognized help format '%s'"
+msgstr ""
+
+#: builtin/help.c:93
+msgid "Failed to start emacsclient."
+msgstr ""
+
+#: builtin/help.c:106
+msgid "Failed to parse emacsclient version."
+msgstr ""
+
+#: builtin/help.c:114
+#, c-format
+msgid "emacsclient version '%d' too old (< 22)."
+msgstr ""
+
+#: 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 ""
+
+#: builtin/help.c:217
+#, c-format
+msgid ""
+"'%s': path for unsupported man viewer.\n"
+"Please consider using 'man.<tool>.cmd' instead."
+msgstr ""
+
+#: builtin/help.c:229
+#, c-format
+msgid ""
+"'%s': cmd for supported man viewer.\n"
+"Please consider using 'man.<tool>.path' instead."
+msgstr ""
+
+#: builtin/help.c:299
+msgid "The most commonly used git commands are:"
+msgstr ""
+
+#: builtin/help.c:367
+#, c-format
+msgid "'%s': unknown man viewer."
+msgstr ""
+
+#: builtin/help.c:384
+msgid "no man viewer handled the request"
+msgstr ""
+
+#: builtin/help.c:392
+msgid "no info viewer handled the request"
+msgstr ""
+
+#: builtin/help.c:447 builtin/help.c:454
+#, c-format
+msgid "usage: %s%s"
+msgstr ""
+
+#: builtin/help.c:470
+#, c-format
+msgid "`git %s' is aliased to `%s'"
+msgstr ""
+
+#: builtin/index-pack.c:170
+#, c-format
+msgid "object type mismatch at %s"
+msgstr ""
+
+#: builtin/index-pack.c:190
+msgid "object of unexpected type"
+msgstr ""
+
+#: builtin/index-pack.c:227
+#, c-format
+msgid "cannot fill %d byte"
+msgid_plural "cannot fill %d bytes"
+msgstr[0] ""
+msgstr[1] ""
+
+#: builtin/index-pack.c:237
+msgid "early EOF"
+msgstr ""
+
+#: builtin/index-pack.c:238
+msgid "read error on input"
+msgstr ""
+
+#: builtin/index-pack.c:250
+msgid "used more bytes than were available"
+msgstr ""
+
+#: builtin/index-pack.c:257
+msgid "pack too large for current definition of off_t"
+msgstr ""
+
+#: builtin/index-pack.c:273
+#, c-format
+msgid "unable to create '%s'"
+msgstr ""
+
+#: builtin/index-pack.c:278
+#, c-format
+msgid "cannot open packfile '%s'"
+msgstr ""
+
+#: builtin/index-pack.c:292
+msgid "pack signature mismatch"
+msgstr ""
+
+#: builtin/index-pack.c:294
+#, c-format
+msgid "pack version %<PRIu32> unsupported"
+msgstr ""
+
+#: builtin/index-pack.c:312
+#, c-format
+msgid "pack has bad object at offset %lu: %s"
+msgstr ""
+
+#: builtin/index-pack.c:434
+#, c-format
+msgid "inflate returned %d"
+msgstr ""
+
+#: builtin/index-pack.c:483
+msgid "offset value overflow for delta base object"
+msgstr ""
+
+#: builtin/index-pack.c:491
+msgid "delta base offset is out of bound"
+msgstr ""
+
+#: builtin/index-pack.c:499
+#, c-format
+msgid "unknown object type %d"
+msgstr ""
+
+#: builtin/index-pack.c:530
+msgid "cannot pread pack file"
+msgstr ""
+
+#: builtin/index-pack.c:532
+#, c-format
+msgid "premature end of pack file, %lu byte missing"
+msgid_plural "premature end of pack file, %lu bytes missing"
+msgstr[0] ""
+msgstr[1] ""
+
+#: builtin/index-pack.c:558
+msgid "serious inflate inconsistency"
+msgstr ""
+
+#: builtin/index-pack.c:649 builtin/index-pack.c:655 builtin/index-pack.c:678
+#: builtin/index-pack.c:712 builtin/index-pack.c:721
+#, c-format
+msgid "SHA1 COLLISION FOUND WITH %s !"
+msgstr ""
+
+#: builtin/index-pack.c:652 builtin/pack-objects.c:170
+#: builtin/pack-objects.c:262
+#, c-format
+msgid "unable to read %s"
+msgstr ""
+
+#: builtin/index-pack.c:718
+#, c-format
+msgid "cannot read existing object %s"
+msgstr ""
+
+#: builtin/index-pack.c:732
+#, c-format
+msgid "invalid blob object %s"
+msgstr ""
+
+#: builtin/index-pack.c:747
+#, c-format
+msgid "invalid %s"
+msgstr ""
+
+#: builtin/index-pack.c:749
+msgid "Error in object"
+msgstr ""
+
+#: builtin/index-pack.c:751
+#, c-format
+msgid "Not all child objects of %s are reachable"
+msgstr ""
+
+#: builtin/index-pack.c:821 builtin/index-pack.c:847
+msgid "failed to apply delta"
+msgstr ""
+
+#: builtin/index-pack.c:986
+msgid "Receiving objects"
+msgstr ""
+
+#: builtin/index-pack.c:986
+msgid "Indexing objects"
+msgstr ""
+
+#: builtin/index-pack.c:1012
+msgid "pack is corrupted (SHA1 mismatch)"
+msgstr ""
+
+#: builtin/index-pack.c:1017
+msgid "cannot fstat packfile"
+msgstr ""
+
+#: builtin/index-pack.c:1020
+msgid "pack has junk at the end"
+msgstr ""
+
+#: builtin/index-pack.c:1031
+msgid "confusion beyond insanity in parse_pack_objects()"
+msgstr ""
+
+#: builtin/index-pack.c:1054
+msgid "Resolving deltas"
+msgstr ""
+
+#: builtin/index-pack.c:1064
+#, c-format
+msgid "unable to create thread: %s"
+msgstr ""
+
+#: builtin/index-pack.c:1106
+msgid "confusion beyond insanity"
+msgstr ""
+
+#: builtin/index-pack.c:1112
+#, c-format
+msgid "completed with %d local objects"
+msgstr ""
+
+#: builtin/index-pack.c:1121
+#, c-format
+msgid "Unexpected tail checksum for %s (disk corruption?)"
+msgstr ""
+
+#: builtin/index-pack.c:1125
+#, c-format
+msgid "pack has %d unresolved delta"
+msgid_plural "pack has %d unresolved deltas"
+msgstr[0] ""
+msgstr[1] ""
+
+#: builtin/index-pack.c:1150
+#, c-format
+msgid "unable to deflate appended object (%d)"
+msgstr ""
+
+#: builtin/index-pack.c:1229
+#, c-format
+msgid "local object %s is corrupt"
+msgstr ""
+
+#: builtin/index-pack.c:1253
+msgid "error while closing pack file"
+msgstr ""
+
+#: builtin/index-pack.c:1266
+#, c-format
+msgid "cannot write keep file '%s'"
+msgstr ""
+
+#: builtin/index-pack.c:1274
+#, c-format
+msgid "cannot close written keep file '%s'"
+msgstr ""
+
+#: builtin/index-pack.c:1287
+msgid "cannot store pack file"
+msgstr ""
+
+#: builtin/index-pack.c:1298
+msgid "cannot store index file"
+msgstr ""
+
+#: builtin/index-pack.c:1331
+#, c-format
+msgid "bad pack.indexversion=%<PRIu32>"
+msgstr ""
+
+#: builtin/index-pack.c:1337
+#, c-format
+msgid "invalid number of threads specified (%d)"
+msgstr ""
+
+#: builtin/index-pack.c:1341 builtin/index-pack.c:1514
+#, c-format
+msgid "no threads support, ignoring %s"
+msgstr ""
+
+#: builtin/index-pack.c:1399
+#, c-format
+msgid "Cannot open existing pack file '%s'"
+msgstr ""
+
+#: builtin/index-pack.c:1401
+#, c-format
+msgid "Cannot open existing pack idx file for '%s'"
+msgstr ""
+
+#: builtin/index-pack.c:1448
+#, c-format
+msgid "non delta: %d object"
+msgid_plural "non delta: %d objects"
+msgstr[0] ""
+msgstr[1] ""
+
+#: builtin/index-pack.c:1455
+#, c-format
+msgid "chain length = %d: %lu object"
+msgid_plural "chain length = %d: %lu objects"
+msgstr[0] ""
+msgstr[1] ""
+
+#: builtin/index-pack.c:1482
+msgid "Cannot come back to cwd"
+msgstr ""
+
+#: 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 ""
+
+#: builtin/index-pack.c:1559
+msgid "--fix-thin cannot be used without --stdin"
+msgstr ""
+
+#: builtin/index-pack.c:1563 builtin/index-pack.c:1573
+#, c-format
+msgid "packfile name '%s' does not end with '.pack'"
+msgstr ""
+
+#: builtin/index-pack.c:1582
+msgid "--verify with no packfile name given"
+msgstr ""
+
+#: builtin/init-db.c:35
+#, c-format
+msgid "Could not make %s writable by group"
+msgstr ""
+
+#: builtin/init-db.c:62
+#, c-format
+msgid "insanely long template name %s"
+msgstr ""
+
+#: builtin/init-db.c:67
+#, c-format
+msgid "cannot stat '%s'"
+msgstr ""
+
+#: builtin/init-db.c:73
+#, c-format
+msgid "cannot stat template '%s'"
+msgstr ""
+
+#: builtin/init-db.c:80
+#, c-format
+msgid "cannot opendir '%s'"
+msgstr ""
+
+#: builtin/init-db.c:97
+#, c-format
+msgid "cannot readlink '%s'"
+msgstr ""
+
+#: builtin/init-db.c:99
+#, c-format
+msgid "insanely long symlink %s"
+msgstr ""
+
+#: builtin/init-db.c:102
+#, c-format
+msgid "cannot symlink '%s' '%s'"
+msgstr ""
+
+#: builtin/init-db.c:106
+#, c-format
+msgid "cannot copy '%s' to '%s'"
+msgstr ""
+
+#: builtin/init-db.c:110
+#, c-format
+msgid "ignoring template %s"
+msgstr ""
+
+#: builtin/init-db.c:133
+#, c-format
+msgid "insanely long template path %s"
+msgstr ""
+
+#: builtin/init-db.c:141
+#, c-format
+msgid "templates not found %s"
+msgstr ""
+
+#: builtin/init-db.c:154
+#, c-format
+msgid "not copying templates of a wrong format version %d from '%s'"
+msgstr ""
+
+#: builtin/init-db.c:192
+#, c-format
+msgid "insane git directory %s"
+msgstr ""
+
+#: builtin/init-db.c:323 builtin/init-db.c:326
+#, c-format
+msgid "%s already exists"
+msgstr ""
+
+#: builtin/init-db.c:355
+#, c-format
+msgid "unable to handle file type %d"
+msgstr ""
+
+#: builtin/init-db.c:358
+#, c-format
+msgid "unable to move %s to %s"
+msgstr ""
+
+#: builtin/init-db.c:363
+#, c-format
+msgid "Could not create git link %s"
+msgstr ""
+
+#.
+#. * TRANSLATORS: The first '%s' is either "Reinitialized
+#. * existing" or "Initialized empty", the second " shared" or
+#. * "", and the last '%s%s' is the verbatim directory name.
+#.
+#: builtin/init-db.c:420
+#, c-format
+msgid "%s%s Git repository in %s%s\n"
+msgstr ""
+
+#: builtin/init-db.c:421
+msgid "Reinitialized existing"
+msgstr ""
+
+#: builtin/init-db.c:421
+msgid "Initialized empty"
+msgstr ""
+
+#: builtin/init-db.c:422
+msgid " shared"
+msgstr ""
+
+#: builtin/init-db.c:441
+msgid "cannot tell cwd"
+msgstr ""
+
+#: builtin/init-db.c:467
+msgid ""
+"git init [-q | --quiet] [--bare] [--template=<template-directory>] [--shared"
+"[=<permissions>]] [directory]"
+msgstr ""
+
+#: builtin/init-db.c:490
+msgid "permissions"
+msgstr ""
+
+#: builtin/init-db.c:491
+msgid "specify that the git repository is to be shared amongst several users"
+msgstr ""
+
+#: builtin/init-db.c:493 builtin/prune-packed.c:77
+msgid "be quiet"
+msgstr ""
+
+#: builtin/init-db.c:522 builtin/init-db.c:529
+#, c-format
+msgid "cannot mkdir %s"
+msgstr ""
+
+#: builtin/init-db.c:533
+#, c-format
+msgid "cannot chdir to %s"
+msgstr ""
+
+#: builtin/init-db.c:555
+#, c-format
+msgid ""
+"%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-"
+"dir=<directory>)"
+msgstr ""
+
+#: builtin/init-db.c:579
+msgid "Cannot access current working directory"
+msgstr ""
+
+#: builtin/init-db.c:586
+#, c-format
+msgid "Cannot access work tree '%s'"
+msgstr ""
+
+#: builtin/log.c:37
+msgid "git log [<options>] [<since>..<until>] [[--] <path>...]\n"
+msgstr ""
+
+#: builtin/log.c:38
+msgid "   or: git show [options] <object>..."
+msgstr ""
+
+#: builtin/log.c:100
+msgid "suppress diff output"
+msgstr ""
+
+#: builtin/log.c:101
+msgid "show source"
+msgstr ""
+
+#: builtin/log.c:102
+msgid "decorate options"
+msgstr ""
+
+#: builtin/log.c:189
+#, c-format
+msgid "Final output: %d %s\n"
+msgstr ""
+
+#: builtin/log.c:403 builtin/log.c:494
+#, c-format
+msgid "Could not read object %s"
+msgstr ""
+
+#: builtin/log.c:518
+#, c-format
+msgid "Unknown type: %d"
+msgstr ""
+
+#: builtin/log.c:608
+msgid "format.headers without value"
+msgstr ""
+
+#: builtin/log.c:682
+msgid "name of output directory is too long"
+msgstr ""
+
+#: builtin/log.c:693
+#, c-format
+msgid "Cannot open patch file %s"
+msgstr ""
+
+#: builtin/log.c:707
+msgid "Need exactly one range."
+msgstr ""
+
+#: builtin/log.c:715
+msgid "Not a range."
+msgstr ""
+
+#: builtin/log.c:789
+msgid "Cover letter needs email format"
+msgstr ""
+
+#: builtin/log.c:862
+#, c-format
+msgid "insane in-reply-to: %s"
+msgstr ""
+
+#: builtin/log.c:890
+msgid "git format-patch [options] [<since> | <revision range>]"
+msgstr ""
+
+#: builtin/log.c:935
+msgid "Two output directories?"
+msgstr ""
+
+#: builtin/log.c:1063
+msgid "use [PATCH n/m] even with a single patch"
+msgstr ""
+
+#: builtin/log.c:1066
+msgid "use [PATCH] even with multiple patches"
+msgstr ""
+
+#: builtin/log.c:1070
+msgid "print patches to standard out"
+msgstr ""
+
+#: builtin/log.c:1072
+msgid "generate a cover letter"
+msgstr ""
+
+#: builtin/log.c:1074
+msgid "use simple number sequence for output file names"
+msgstr ""
+
+#: builtin/log.c:1075
+msgid "sfx"
+msgstr ""
+
+#: builtin/log.c:1076
+msgid "use <sfx> instead of '.patch'"
+msgstr ""
+
+#: builtin/log.c:1078
+msgid "start numbering patches at <n> instead of 1"
+msgstr ""
+
+#: builtin/log.c:1080
+msgid "Use [<prefix>] instead of [PATCH]"
+msgstr ""
+
+#: builtin/log.c:1083
+msgid "store resulting files in <dir>"
+msgstr ""
+
+#: builtin/log.c:1086
+msgid "don't strip/add [PATCH]"
+msgstr ""
+
+#: builtin/log.c:1089
+msgid "don't output binary diffs"
+msgstr ""
+
+#: builtin/log.c:1091
+msgid "don't include a patch matching a commit upstream"
+msgstr ""
+
+#: builtin/log.c:1093
+msgid "show patch format instead of default (patch + stat)"
+msgstr ""
+
+#: builtin/log.c:1095
+msgid "Messaging"
+msgstr ""
+
+#: builtin/log.c:1096
+msgid "header"
+msgstr ""
+
+#: builtin/log.c:1097
+msgid "add email header"
+msgstr ""
+
+#: builtin/log.c:1098 builtin/log.c:1100
+msgid "email"
+msgstr ""
+
+#: builtin/log.c:1098
+msgid "add To: header"
+msgstr ""
+
+#: builtin/log.c:1100
+msgid "add Cc: header"
+msgstr ""
+
+#: builtin/log.c:1102
+msgid "message-id"
+msgstr ""
+
+#: builtin/log.c:1103
+msgid "make first mail a reply to <message-id>"
+msgstr ""
+
+#: builtin/log.c:1104 builtin/log.c:1107
+msgid "boundary"
+msgstr ""
+
+#: builtin/log.c:1105
+msgid "attach the patch"
+msgstr ""
+
+#: builtin/log.c:1108
+msgid "inline the patch"
+msgstr ""
+
+#: builtin/log.c:1112
+msgid "enable message threading, styles: shallow, deep"
+msgstr ""
+
+#: builtin/log.c:1114
+msgid "signature"
+msgstr ""
+
+#: builtin/log.c:1115
+msgid "add a signature"
+msgstr ""
+
+#: builtin/log.c:1117
+msgid "don't print the patch filenames"
+msgstr ""
+
+#: builtin/log.c:1157
+#, c-format
+msgid "bogus committer info %s"
+msgstr ""
+
+#: builtin/log.c:1202
+msgid "-n and -k are mutually exclusive."
+msgstr ""
+
+#: builtin/log.c:1204
+msgid "--subject-prefix and -k are mutually exclusive."
+msgstr ""
+
+#: builtin/log.c:1212
+msgid "--name-only does not make sense"
+msgstr ""
+
+#: builtin/log.c:1214
+msgid "--name-status does not make sense"
+msgstr ""
+
+#: builtin/log.c:1216
+msgid "--check does not make sense"
+msgstr ""
+
+#: builtin/log.c:1239
+msgid "standard output, or directory, which one?"
+msgstr ""
+
+#: builtin/log.c:1241
+#, c-format
+msgid "Could not create directory '%s'"
+msgstr ""
+
+#: builtin/log.c:1394
+msgid "Failed to create output files"
+msgstr ""
+
+#: builtin/log.c:1443
+msgid "git cherry [-v] [<upstream> [<head> [<limit>]]]"
+msgstr ""
+
+#: builtin/log.c:1498
+#, 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
+#, c-format
+msgid "Unknown commit %s"
+msgstr ""
+
+#: builtin/ls-files.c:408
+msgid "git ls-files [options] [<file>...]"
+msgstr ""
+
+#: builtin/ls-files.c:463
+msgid "identify the file status with tags"
+msgstr ""
+
+#: builtin/ls-files.c:465
+msgid "use lowercase letters for 'assume unchanged' files"
+msgstr ""
+
+#: builtin/ls-files.c:467
+msgid "show cached files in the output (default)"
+msgstr ""
+
+#: builtin/ls-files.c:469
+msgid "show deleted files in the output"
+msgstr ""
+
+#: builtin/ls-files.c:471
+msgid "show modified files in the output"
+msgstr ""
+
+#: builtin/ls-files.c:473
+msgid "show other files in the output"
+msgstr ""
+
+#: builtin/ls-files.c:475
+msgid "show ignored files in the output"
+msgstr ""
+
+#: builtin/ls-files.c:478
+msgid "show staged contents' object name in the output"
+msgstr ""
+
+#: builtin/ls-files.c:480
+msgid "show files on the filesystem that need to be removed"
+msgstr ""
+
+#: builtin/ls-files.c:482
+msgid "show 'other' directories' name only"
+msgstr ""
+
+#: builtin/ls-files.c:485
+msgid "don't show empty directories"
+msgstr ""
+
+#: builtin/ls-files.c:488
+msgid "show unmerged files in the output"
+msgstr ""
+
+#: builtin/ls-files.c:490
+msgid "show resolve-undo information"
+msgstr ""
+
+#: builtin/ls-files.c:492
+msgid "skip files matching pattern"
+msgstr ""
+
+#: builtin/ls-files.c:495
+msgid "exclude patterns are read from <file>"
+msgstr ""
+
+#: builtin/ls-files.c:498
+msgid "read additional per-directory exclude patterns in <file>"
+msgstr ""
+
+#: builtin/ls-files.c:500
+msgid "add the standard git exclusions"
+msgstr ""
+
+#: builtin/ls-files.c:503
+msgid "make the output relative to the project top directory"
+msgstr ""
+
+#: builtin/ls-files.c:506
+msgid "if any <file> is not in the index, treat this as an error"
+msgstr ""
+
+#: builtin/ls-files.c:507
+msgid "tree-ish"
+msgstr ""
+
+#: builtin/ls-files.c:508
+msgid "pretend that paths removed since <tree-ish> are still present"
+msgstr ""
+
+#: builtin/ls-files.c:510
+msgid "show debugging data"
+msgstr ""
+
+#: builtin/ls-tree.c:27
+msgid "git ls-tree [<options>] <tree-ish> [<path>...]"
+msgstr ""
+
+#: builtin/ls-tree.c:125
+msgid "only show trees"
+msgstr ""
+
+#: builtin/ls-tree.c:127
+msgid "recurse into subtrees"
+msgstr ""
+
+#: builtin/ls-tree.c:129
+msgid "show trees when recursing"
+msgstr ""
+
+#: builtin/ls-tree.c:132
+msgid "terminate entries with NUL byte"
+msgstr ""
+
+#: builtin/ls-tree.c:133
+msgid "include object size"
+msgstr ""
+
+#: builtin/ls-tree.c:135 builtin/ls-tree.c:137
+msgid "list only filenames"
+msgstr ""
+
+#: builtin/ls-tree.c:140
+msgid "use full path names"
+msgstr ""
+
+#: builtin/ls-tree.c:142
+msgid "list entire tree; not just current directory (implies --full-name)"
+msgstr ""
+
+#: builtin/merge.c:43
+msgid "git merge [options] [<commit>...]"
+msgstr ""
+
+#: builtin/merge.c:44
+msgid "git merge [options] <msg> HEAD <commit>"
+msgstr ""
+
+#: builtin/merge.c:45
+msgid "git merge --abort"
+msgstr ""
+
+#: builtin/merge.c:90
+msgid "switch `m' requires a value"
+msgstr ""
+
+#: builtin/merge.c:127
+#, c-format
+msgid "Could not find merge strategy '%s'.\n"
+msgstr ""
+
+#: builtin/merge.c:128
+#, c-format
+msgid "Available strategies are:"
+msgstr ""
+
+#: builtin/merge.c:133
+#, c-format
+msgid "Available custom strategies are:"
+msgstr ""
+
+#: builtin/merge.c:183
+msgid "do not show a diffstat at the end of the merge"
+msgstr ""
+
+#: builtin/merge.c:186
+msgid "show a diffstat at the end of the merge"
+msgstr ""
+
+#: builtin/merge.c:187
+msgid "(synonym to --stat)"
+msgstr ""
+
+#: builtin/merge.c:189
+msgid "add (at most <n>) entries from shortlog to merge commit message"
+msgstr ""
+
+#: builtin/merge.c:192
+msgid "create a single commit instead of doing a merge"
+msgstr ""
+
+#: builtin/merge.c:194
+msgid "perform a commit if the merge succeeds (default)"
+msgstr ""
+
+#: builtin/merge.c:196
+msgid "edit message before committing"
+msgstr ""
+
+#: builtin/merge.c:198
+msgid "allow fast-forward (default)"
+msgstr ""
+
+#: builtin/merge.c:200
+msgid "abort if fast-forward is not possible"
+msgstr ""
+
+#: builtin/merge.c:202 builtin/notes.c:870 builtin/revert.c:112
+msgid "strategy"
+msgstr ""
+
+#: builtin/merge.c:203
+msgid "merge strategy to use"
+msgstr ""
+
+#: builtin/merge.c:204
+msgid "option=value"
+msgstr ""
+
+#: builtin/merge.c:205
+msgid "option for selected merge strategy"
+msgstr ""
+
+#: builtin/merge.c:207
+msgid "merge commit message (for a non-fast-forward merge)"
+msgstr ""
+
+#: builtin/merge.c:211
+msgid "abort the current in-progress merge"
+msgstr ""
+
+#: builtin/merge.c:240
+msgid "could not run stash."
+msgstr ""
+
+#: builtin/merge.c:245
+msgid "stash failed"
+msgstr ""
+
+#: builtin/merge.c:250
+#, c-format
+msgid "not a valid object: %s"
+msgstr ""
+
+#: builtin/merge.c:269 builtin/merge.c:286
+msgid "read-tree failed"
+msgstr ""
+
+#: builtin/merge.c:316
+msgid " (nothing to squash)"
+msgstr ""
+
+#: builtin/merge.c:329
+#, c-format
+msgid "Squash commit -- not updating HEAD\n"
+msgstr ""
+
+#: builtin/merge.c:361
+msgid "Writing SQUASH_MSG"
+msgstr ""
+
+#: builtin/merge.c:363
+msgid "Finishing SQUASH_MSG"
+msgstr ""
+
+#: builtin/merge.c:386
+#, c-format
+msgid "No merge message -- not updating HEAD\n"
+msgstr ""
+
+#: builtin/merge.c:436
+#, c-format
+msgid "'%s' does not point to a commit"
+msgstr ""
+
+#: builtin/merge.c:535
+#, c-format
+msgid "Bad branch.%s.mergeoptions string: %s"
+msgstr ""
+
+#: builtin/merge.c:628
+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
+msgid "Not handling anything other than two heads merge."
+msgstr ""
+
+#: builtin/merge.c:723
+#, c-format
+msgid "Unknown option for merge-recursive: -X%s"
+msgstr ""
+
+#: builtin/merge.c:737
+#, c-format
+msgid "unable to write %s"
+msgstr ""
+
+#: builtin/merge.c:876
+#, c-format
+msgid "Could not read from '%s'"
+msgstr ""
+
+#: builtin/merge.c:885
+#, c-format
+msgid "Not committing merge; use 'git commit' to complete the merge.\n"
+msgstr ""
+
+#: builtin/merge.c:891
+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"
+"\n"
+"Lines starting with '#' will be ignored, and an empty message aborts\n"
+"the commit.\n"
+msgstr ""
+
+#: builtin/merge.c:915
+msgid "Empty commit message."
+msgstr ""
+
+#: builtin/merge.c:927
+#, c-format
+msgid "Wonderful.\n"
+msgstr ""
+
+#: builtin/merge.c:992
+#, c-format
+msgid "Automatic merge failed; fix conflicts and then commit the result.\n"
+msgstr ""
+
+#: builtin/merge.c:1008
+#, c-format
+msgid "'%s' is not a commit"
+msgstr ""
+
+#: builtin/merge.c:1049
+msgid "No current branch."
+msgstr ""
+
+#: builtin/merge.c:1051
+msgid "No remote for the current branch."
+msgstr ""
+
+#: builtin/merge.c:1053
+msgid "No default upstream defined for the current branch."
+msgstr ""
+
+#: builtin/merge.c:1058
+#, c-format
+msgid "No remote tracking branch for %s from %s"
+msgstr ""
+
+#: builtin/merge.c:1145 builtin/merge.c:1302
+#, c-format
+msgid "%s - not something we can merge"
+msgstr ""
+
+#: builtin/merge.c:1213
+msgid "There is no merge to abort (MERGE_HEAD missing)."
+msgstr ""
+
+#: builtin/merge.c:1229 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
+msgid "You have not concluded your merge (MERGE_HEAD exists)."
+msgstr ""
+
+#: builtin/merge.c:1236
+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
+msgid "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)."
+msgstr ""
+
+#: builtin/merge.c:1248
+msgid "You cannot combine --squash with --no-ff."
+msgstr ""
+
+#: builtin/merge.c:1253
+msgid "You cannot combine --no-ff with --ff-only."
+msgstr ""
+
+#: builtin/merge.c:1260
+msgid "No commit specified and merge.defaultToUpstream not set."
+msgstr ""
+
+#: builtin/merge.c:1292
+msgid "Can merge only exactly one commit into empty head"
+msgstr ""
+
+#: builtin/merge.c:1295
+msgid "Squash commit into empty head not supported yet"
+msgstr ""
+
+#: builtin/merge.c:1297
+msgid "Non-fast-forward commit does not make sense into an empty head"
+msgstr ""
+
+#: builtin/merge.c:1412
+#, c-format
+msgid "Updating %s..%s\n"
+msgstr ""
+
+#: builtin/merge.c:1450
+#, c-format
+msgid "Trying really trivial in-index merge...\n"
+msgstr ""
+
+#: builtin/merge.c:1457
+#, c-format
+msgid "Nope.\n"
+msgstr ""
+
+#: builtin/merge.c:1489
+msgid "Not possible to fast-forward, aborting."
+msgstr ""
+
+#: builtin/merge.c:1512 builtin/merge.c:1591
+#, c-format
+msgid "Rewinding the tree to pristine...\n"
+msgstr ""
+
+#: builtin/merge.c:1516
+#, c-format
+msgid "Trying merge strategy %s...\n"
+msgstr ""
+
+#: builtin/merge.c:1582
+#, c-format
+msgid "No merge strategy handled the merge.\n"
+msgstr ""
+
+#: builtin/merge.c:1584
+#, c-format
+msgid "Merge with strategy %s failed.\n"
+msgstr ""
+
+#: builtin/merge.c:1593
+#, c-format
+msgid "Using the %s to prepare resolving by hand.\n"
+msgstr ""
+
+#: builtin/merge.c:1605
+#, c-format
+msgid "Automatic merge went well; stopped before committing as requested\n"
+msgstr ""
+
+#: builtin/merge-base.c:26
+msgid "git merge-base [-a|--all] <commit> <commit>..."
+msgstr ""
+
+#: builtin/merge-base.c:27
+msgid "git merge-base [-a|--all] --octopus <commit>..."
+msgstr ""
+
+#: builtin/merge-base.c:28
+msgid "git merge-base --independent <commit>..."
+msgstr ""
+
+#: builtin/merge-base.c:29
+msgid "git merge-base --is-ancestor <commit> <commit>"
+msgstr ""
+
+#: builtin/merge-base.c:98
+msgid "output all common ancestors"
+msgstr ""
+
+#: builtin/merge-base.c:99
+msgid "find ancestors for a single n-way merge"
+msgstr ""
+
+#: builtin/merge-base.c:100
+msgid "list revs not reachable from others"
+msgstr ""
+
+#: builtin/merge-base.c:102
+msgid "is the first one ancestor of the other?"
+msgstr ""
+
+#: builtin/merge-file.c:8
+msgid ""
+"git merge-file [options] [-L name1 [-L orig [-L name2]]] file1 orig_file "
+"file2"
+msgstr ""
+
+#: builtin/merge-file.c:33
+msgid "send results to standard output"
+msgstr ""
+
+#: builtin/merge-file.c:34
+msgid "use a diff3 based merge"
+msgstr ""
+
+#: builtin/merge-file.c:35
+msgid "for conflicts, use our version"
+msgstr ""
+
+#: builtin/merge-file.c:37
+msgid "for conflicts, use their version"
+msgstr ""
+
+#: builtin/merge-file.c:39
+msgid "for conflicts, use a union version"
+msgstr ""
+
+#: builtin/merge-file.c:42
+msgid "for conflicts, use this marker size"
+msgstr ""
+
+#: builtin/merge-file.c:43
+msgid "do not warn about conflicts"
+msgstr ""
+
+#: builtin/merge-file.c:45
+msgid "set labels for file1/orig_file/file2"
+msgstr ""
+
+#: builtin/mktree.c:67
+msgid "git mktree [-z] [--missing] [--batch]"
+msgstr ""
+
+#: builtin/mktree.c:153
+msgid "input is NUL terminated"
+msgstr ""
+
+#: builtin/mktree.c:154 builtin/write-tree.c:24
+msgid "allow missing objects"
+msgstr ""
+
+#: builtin/mktree.c:155
+msgid "allow creation of more than one tree"
+msgstr ""
+
+#: builtin/mv.c:14
+msgid "git mv [options] <source>... <destination>"
+msgstr ""
+
+#: builtin/mv.c:64
+msgid "force move/rename even if target exists"
+msgstr ""
+
+#: builtin/mv.c:65
+msgid "skip move/rename errors"
+msgstr ""
+
+#: builtin/mv.c:108
+#, c-format
+msgid "Checking rename of '%s' to '%s'\n"
+msgstr ""
+
+#: builtin/mv.c:112
+msgid "bad source"
+msgstr ""
+
+#: builtin/mv.c:115
+msgid "can not move directory into itself"
+msgstr ""
+
+#: builtin/mv.c:118
+msgid "cannot move directory over file"
+msgstr ""
+
+#: builtin/mv.c:128
+#, c-format
+msgid "Huh? %.*s is in index?"
+msgstr ""
+
+#: builtin/mv.c:140
+msgid "source directory is empty"
+msgstr ""
+
+#: builtin/mv.c:171
+msgid "not under version control"
+msgstr ""
+
+#: builtin/mv.c:173
+msgid "destination exists"
+msgstr ""
+
+#: builtin/mv.c:181
+#, c-format
+msgid "overwriting '%s'"
+msgstr ""
+
+#: builtin/mv.c:184
+msgid "Cannot overwrite"
+msgstr ""
+
+#: builtin/mv.c:187
+msgid "multiple sources for the same target"
+msgstr ""
+
+#: builtin/mv.c:202
+#, c-format
+msgid "%s, source=%s, destination=%s"
+msgstr ""
+
+#: builtin/mv.c:212
+#, c-format
+msgid "Renaming %s to %s\n"
+msgstr ""
+
+#: builtin/mv.c:215 builtin/remote.c:731
+#, c-format
+msgid "renaming '%s' failed"
+msgstr ""
+
+#: builtin/name-rev.c:175
+msgid "git name-rev [options] <commit>..."
+msgstr ""
+
+#: builtin/name-rev.c:176
+msgid "git name-rev [options] --all"
+msgstr ""
+
+#: builtin/name-rev.c:177
+msgid "git name-rev [options] --stdin"
+msgstr ""
+
+#: builtin/name-rev.c:229
+msgid "print only names (no SHA-1)"
+msgstr ""
+
+#: builtin/name-rev.c:230
+msgid "only use tags to name the commits"
+msgstr ""
+
+#: builtin/name-rev.c:232
+msgid "only use refs matching <pattern>"
+msgstr ""
+
+#: builtin/name-rev.c:234
+msgid "list all commits reachable from all refs"
+msgstr ""
+
+#: builtin/name-rev.c:235
+msgid "read from stdin"
+msgstr ""
+
+#: builtin/name-rev.c:236
+msgid "allow to print `undefined` names"
+msgstr ""
+
+#: builtin/notes.c:26
+msgid "git notes [--ref <notes_ref>] [list [<object>]]"
+msgstr ""
+
+#: builtin/notes.c:27
+msgid ""
+"git notes [--ref <notes_ref>] add [-f] [-m <msg> | -F <file> | (-c | -C) "
+"<object>] [<object>]"
+msgstr ""
+
+#: builtin/notes.c:28
+msgid "git notes [--ref <notes_ref>] copy [-f] <from-object> <to-object>"
+msgstr ""
+
+#: builtin/notes.c:29
+msgid ""
+"git notes [--ref <notes_ref>] append [-m <msg> | -F <file> | (-c | -C) "
+"<object>] [<object>]"
+msgstr ""
+
+#: builtin/notes.c:30
+msgid "git notes [--ref <notes_ref>] edit [<object>]"
+msgstr ""
+
+#: builtin/notes.c:31
+msgid "git notes [--ref <notes_ref>] show [<object>]"
+msgstr ""
+
+#: builtin/notes.c:32
+msgid ""
+"git notes [--ref <notes_ref>] merge [-v | -q] [-s <strategy> ] <notes_ref>"
+msgstr ""
+
+#: builtin/notes.c:33
+msgid "git notes merge --commit [-v | -q]"
+msgstr ""
+
+#: builtin/notes.c:34
+msgid "git notes merge --abort [-v | -q]"
+msgstr ""
+
+#: builtin/notes.c:35
+msgid "git notes [--ref <notes_ref>] remove [<object>...]"
+msgstr ""
+
+#: builtin/notes.c:36
+msgid "git notes [--ref <notes_ref>] prune [-n | -v]"
+msgstr ""
+
+#: builtin/notes.c:37
+msgid "git notes [--ref <notes_ref>] get-ref"
+msgstr ""
+
+#: builtin/notes.c:42
+msgid "git notes [list [<object>]]"
+msgstr ""
+
+#: builtin/notes.c:47
+msgid "git notes add [<options>] [<object>]"
+msgstr ""
+
+#: builtin/notes.c:52
+msgid "git notes copy [<options>] <from-object> <to-object>"
+msgstr ""
+
+#: builtin/notes.c:53
+msgid "git notes copy --stdin [<from-object> <to-object>]..."
+msgstr ""
+
+#: builtin/notes.c:58
+msgid "git notes append [<options>] [<object>]"
+msgstr ""
+
+#: builtin/notes.c:63
+msgid "git notes edit [<object>]"
+msgstr ""
+
+#: builtin/notes.c:68
+msgid "git notes show [<object>]"
+msgstr ""
+
+#: builtin/notes.c:73
+msgid "git notes merge [<options>] <notes_ref>"
+msgstr ""
+
+#: builtin/notes.c:74
+msgid "git notes merge --commit [<options>]"
+msgstr ""
+
+#: builtin/notes.c:75
+msgid "git notes merge --abort [<options>]"
+msgstr ""
+
+#: builtin/notes.c:80
+msgid "git notes remove [<object>]"
+msgstr ""
+
+#: builtin/notes.c:85
+msgid "git notes prune [<options>]"
+msgstr ""
+
+#: builtin/notes.c:90
+msgid "git notes get-ref"
+msgstr ""
+
+#: builtin/notes.c:142
+#, c-format
+msgid "unable to start 'show' for object '%s'"
+msgstr ""
+
+#: builtin/notes.c:148
+msgid "can't fdopen 'show' output fd"
+msgstr ""
+
+#: builtin/notes.c:158
+#, c-format
+msgid "failed to close pipe to 'show' for object '%s'"
+msgstr ""
+
+#: builtin/notes.c:161
+#, c-format
+msgid "failed to finish 'show' for object '%s'"
+msgstr ""
+
+#: builtin/notes.c:178 builtin/tag.c:347
+#, c-format
+msgid "could not create file '%s'"
+msgstr ""
+
+#: builtin/notes.c:192
+msgid "Please supply the note contents using either -m or -F option"
+msgstr ""
+
+#: builtin/notes.c:213 builtin/notes.c:976
+#, c-format
+msgid "Removing note for object %s\n"
+msgstr ""
+
+#: builtin/notes.c:218
+msgid "unable to write note object"
+msgstr ""
+
+#: builtin/notes.c:220
+#, c-format
+msgid "The note contents has been left in %s"
+msgstr ""
+
+#: builtin/notes.c:254 builtin/tag.c:542
+#, c-format
+msgid "cannot read '%s'"
+msgstr ""
+
+#: builtin/notes.c:256 builtin/tag.c:545
+#, c-format
+msgid "could not open or read '%s'"
+msgstr ""
+
+#: 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 ""
+
+#: builtin/notes.c:278
+#, c-format
+msgid "Failed to read object '%s'."
+msgstr ""
+
+#: builtin/notes.c:302
+msgid "Cannot commit uninitialized/unreferenced notes tree"
+msgstr ""
+
+#: builtin/notes.c:343
+#, c-format
+msgid "Bad notes.rewriteMode value: '%s'"
+msgstr ""
+
+#: builtin/notes.c:353
+#, c-format
+msgid "Refusing to rewrite notes in %s (outside of refs/notes/)"
+msgstr ""
+
+#. TRANSLATORS: The first %s is the name of the
+#. environment variable, the second %s is its value
+#: builtin/notes.c:380
+#, c-format
+msgid "Bad %s value: '%s'"
+msgstr ""
+
+#: builtin/notes.c:444
+#, c-format
+msgid "Malformed input line: '%s'."
+msgstr ""
+
+#: builtin/notes.c:459
+#, c-format
+msgid "Failed to copy notes from '%s' to '%s'"
+msgstr ""
+
+#: 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 ""
+
+#: builtin/notes.c:516 builtin/notes.c:775
+#, c-format
+msgid "No note found for object %s."
+msgstr ""
+
+#: builtin/notes.c:538 builtin/notes.c:695
+msgid "note contents as a string"
+msgstr ""
+
+#: builtin/notes.c:541 builtin/notes.c:698
+msgid "note contents in a file"
+msgstr ""
+
+#: builtin/notes.c:543 builtin/notes.c:546 builtin/notes.c:700
+#: builtin/notes.c:703 builtin/tag.c:476
+msgid "object"
+msgstr ""
+
+#: builtin/notes.c:544 builtin/notes.c:701
+msgid "reuse and edit specified note object"
+msgstr ""
+
+#: builtin/notes.c:547 builtin/notes.c:704
+msgid "reuse specified note object"
+msgstr ""
+
+#: builtin/notes.c:549 builtin/notes.c:617
+msgid "replace existing notes"
+msgstr ""
+
+#: builtin/notes.c:583
+#, c-format
+msgid ""
+"Cannot add notes. Found existing notes for object %s. Use '-f' to overwrite "
+"existing notes"
+msgstr ""
+
+#: builtin/notes.c:588 builtin/notes.c:665
+#, c-format
+msgid "Overwriting existing notes for object %s\n"
+msgstr ""
+
+#: builtin/notes.c:618
+msgid "read objects from stdin"
+msgstr ""
+
+#: builtin/notes.c:620
+msgid "load rewriting config for <command> (implies --stdin)"
+msgstr ""
+
+#: builtin/notes.c:638
+msgid "too few parameters"
+msgstr ""
+
+#: builtin/notes.c:659
+#, c-format
+msgid ""
+"Cannot copy notes. Found existing notes for object %s. Use '-f' to overwrite "
+"existing notes"
+msgstr ""
+
+#: builtin/notes.c:671
+#, c-format
+msgid "Missing notes on source object %s. Cannot copy."
+msgstr ""
+
+#: builtin/notes.c:720
+#, c-format
+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 ""
+
+#: builtin/notes.c:867
+msgid "General options"
+msgstr ""
+
+#: builtin/notes.c:869
+msgid "Merge options"
+msgstr ""
+
+#: builtin/notes.c:871
+msgid ""
+"resolve notes conflicts using the given strategy (manual/ours/theirs/union/"
+"cat_sort_uniq)"
+msgstr ""
+
+#: builtin/notes.c:873
+msgid "Committing unmerged notes"
+msgstr ""
+
+#: builtin/notes.c:875
+msgid "finalize notes merge by committing unmerged notes"
+msgstr ""
+
+#: builtin/notes.c:877
+msgid "Aborting notes merge resolution"
+msgstr ""
+
+#: builtin/notes.c:879
+msgid "abort notes merge"
+msgstr ""
+
+#: builtin/notes.c:974
+#, c-format
+msgid "Object %s has no note\n"
+msgstr ""
+
+#: builtin/notes.c:986
+msgid "attempt to remove non-existent note is not an error"
+msgstr ""
+
+#: builtin/notes.c:989
+msgid "read object names from the standard input"
+msgstr ""
+
+#: builtin/notes.c:1070
+msgid "notes_ref"
+msgstr ""
+
+#: builtin/notes.c:1071
+msgid "use notes from <notes_ref>"
+msgstr ""
+
+#: builtin/notes.c:1106 builtin/remote.c:1598
+#, c-format
+msgid "Unknown subcommand: %s"
+msgstr ""
+
+#: builtin/pack-objects.c:23
+msgid "git pack-objects --stdout [options...] [< ref-list | < object-list]"
+msgstr ""
+
+#: builtin/pack-objects.c:24
+msgid "git pack-objects [options...] base-name [< ref-list | < object-list]"
+msgstr ""
+
+#: builtin/pack-objects.c:183 builtin/pack-objects.c:186
+#, c-format
+msgid "deflate error (%d)"
+msgstr ""
+
+#: builtin/pack-objects.c:2398
+#, c-format
+msgid "unsupported index version %s"
+msgstr ""
+
+#: builtin/pack-objects.c:2402
+#, c-format
+msgid "bad index version '%s'"
+msgstr ""
+
+#: builtin/pack-objects.c:2425
+#, c-format
+msgid "option %s does not accept negative form"
+msgstr ""
+
+#: builtin/pack-objects.c:2429
+#, c-format
+msgid "unable to parse value '%s' for option %s"
+msgstr ""
+
+#: builtin/pack-objects.c:2448
+msgid "do not show progress meter"
+msgstr ""
+
+#: builtin/pack-objects.c:2450
+msgid "show progress meter"
+msgstr ""
+
+#: builtin/pack-objects.c:2452
+msgid "show progress meter during object writing phase"
+msgstr ""
+
+#: builtin/pack-objects.c:2455
+msgid "similar to --all-progress when progress meter is shown"
+msgstr ""
+
+#: builtin/pack-objects.c:2456
+msgid "version[,offset]"
+msgstr ""
+
+#: builtin/pack-objects.c:2457
+msgid "write the pack index file in the specified idx format version"
+msgstr ""
+
+#: builtin/pack-objects.c:2460
+msgid "maximum size of each output pack file"
+msgstr ""
+
+#: builtin/pack-objects.c:2462
+msgid "ignore borrowed objects from alternate object store"
+msgstr ""
+
+#: builtin/pack-objects.c:2464
+msgid "ignore packed objects"
+msgstr ""
+
+#: builtin/pack-objects.c:2466
+msgid "limit pack window by objects"
+msgstr ""
+
+#: builtin/pack-objects.c:2468
+msgid "limit pack window by memory in addition to object limit"
+msgstr ""
+
+#: builtin/pack-objects.c:2470
+msgid "maximum length of delta chain allowed in the resulting pack"
+msgstr ""
+
+#: builtin/pack-objects.c:2472
+msgid "reuse existing deltas"
+msgstr ""
+
+#: builtin/pack-objects.c:2474
+msgid "reuse existing objects"
+msgstr ""
+
+#: builtin/pack-objects.c:2476
+msgid "use OFS_DELTA objects"
+msgstr ""
+
+#: builtin/pack-objects.c:2478
+msgid "use threads when searching for best delta matches"
+msgstr ""
+
+#: builtin/pack-objects.c:2480
+msgid "do not create an empty pack output"
+msgstr ""
+
+#: builtin/pack-objects.c:2482
+msgid "read revision arguments from standard input"
+msgstr ""
+
+#: builtin/pack-objects.c:2484
+msgid "limit the objects to those that are not yet packed"
+msgstr ""
+
+#: builtin/pack-objects.c:2487
+msgid "include objects reachable from any reference"
+msgstr ""
+
+#: builtin/pack-objects.c:2490
+msgid "include objects referred by reflog entries"
+msgstr ""
+
+#: builtin/pack-objects.c:2493
+msgid "output pack to stdout"
+msgstr ""
+
+#: builtin/pack-objects.c:2495
+msgid "include tag objects that refer to objects to be packed"
+msgstr ""
+
+#: builtin/pack-objects.c:2497
+msgid "keep unreachable objects"
+msgstr ""
+
+#: builtin/pack-objects.c:2498 parse-options.h:141
+msgid "time"
+msgstr ""
+
+#: builtin/pack-objects.c:2499
+msgid "unpack unreachable objects newer than <time>"
+msgstr ""
+
+#: builtin/pack-objects.c:2502
+msgid "create thin packs"
+msgstr ""
+
+#: builtin/pack-objects.c:2504
+msgid "ignore packs that have companion .keep file"
+msgstr ""
+
+#: builtin/pack-objects.c:2506
+msgid "pack compression level"
+msgstr ""
+
+#: builtin/pack-objects.c:2508
+msgid "do not hide commits by grafts"
+msgstr ""
+
+#: builtin/pack-refs.c:6
+msgid "git pack-refs [options]"
+msgstr ""
+
+#: builtin/pack-refs.c:14
+msgid "pack everything"
+msgstr ""
+
+#: builtin/pack-refs.c:15
+msgid "prune loose refs (default)"
+msgstr ""
+
+#: builtin/prune-packed.c:7
+msgid "git prune-packed [-n|--dry-run] [-q|--quiet]"
+msgstr ""
+
+#: builtin/prune.c:12
+msgid "git prune [-n] [-v] [--expire <time>] [--] [<head>...]"
+msgstr ""
+
+#: builtin/prune.c:132
+msgid "do not remove, show only"
+msgstr ""
+
+#: builtin/prune.c:133
+msgid "report pruned objects"
+msgstr ""
+
+#: builtin/prune.c:136
+msgid "expire objects older than <time>"
+msgstr ""
+
+#: builtin/push.c:14
+msgid "git push [<options>] [<repository> [<refspec>...]]"
+msgstr ""
+
+#: builtin/push.c:45
+msgid "tag shorthand without <tag>"
+msgstr ""
+
+#: builtin/push.c:64
+msgid "--delete only accepts plain target ref names"
+msgstr ""
+
+#: builtin/push.c:99
+msgid ""
+"\n"
+"To choose either option permanently, see push.default in 'git help config'."
+msgstr ""
+
+#: builtin/push.c:102
+#, c-format
+msgid ""
+"The upstream branch of your current branch does not match\n"
+"the name of your current branch.  To push to the upstream branch\n"
+"on the remote, use\n"
+"\n"
+"    git push %s HEAD:%s\n"
+"\n"
+"To push to the branch of the same name on the remote, use\n"
+"\n"
+"    git push %s %s\n"
+"%s"
+msgstr ""
+
+#: builtin/push.c:121
+#, c-format
+msgid ""
+"You are not currently on a branch.\n"
+"To push the history leading to the current (detached HEAD)\n"
+"state now, use\n"
+"\n"
+"    git push %s HEAD:<name-of-remote-branch>\n"
+msgstr ""
+
+#: builtin/push.c:128
+#, c-format
+msgid ""
+"The current branch %s has no upstream branch.\n"
+"To push the current branch and set the remote as upstream, use\n"
+"\n"
+"    git push --set-upstream %s %s\n"
+msgstr ""
+
+#: builtin/push.c:136
+#, c-format
+msgid "The current branch %s has multiple upstream branches, refusing to push."
+msgstr ""
+
+#: builtin/push.c:139
+#, c-format
+msgid ""
+"You are pushing to remote '%s', which is not the upstream of\n"
+"your current branch '%s', without telling me what to push\n"
+"to update which remote branch."
+msgstr ""
+
+#: builtin/push.c:151
+msgid ""
+"push.default is unset; its implicit value is changing in\n"
+"Git 2.0 from 'matching' to 'simple'. To squelch this message\n"
+"and maintain the current behavior after the default changes, use:\n"
+"\n"
+"  git config --global push.default matching\n"
+"\n"
+"To squelch this message and adopt the new behavior now, use:\n"
+"\n"
+"  git config --global push.default simple\n"
+"\n"
+"See 'git help config' and search for 'push.default' for further "
+"information.\n"
+"(the 'simple' mode was introduced in Git 1.7.11. Use the similar mode\n"
+"'current' instead of 'simple' if you sometimes use older versions of Git)"
+msgstr ""
+
+#: builtin/push.c:199
+msgid ""
+"You didn't specify any refspecs to push, and push.default is \"nothing\"."
+msgstr ""
+
+#: builtin/push.c:206
+msgid ""
+"Updates were rejected because the tip of your current branch is behind\n"
+"its remote counterpart. Merge the remote changes (e.g. 'git pull')\n"
+"before pushing again.\n"
+"See the 'Note about fast-forwards' in 'git push --help' for details."
+msgstr ""
+
+#: builtin/push.c:212
+msgid ""
+"Updates were rejected because a pushed branch tip is behind its remote\n"
+"counterpart. If you did not intend to push that branch, you may want to\n"
+"specify branches to push or set the 'push.default' configuration variable\n"
+"to 'simple', 'current' or 'upstream' to push only the current branch."
+msgstr ""
+
+#: builtin/push.c:218
+msgid ""
+"Updates were rejected because a pushed branch tip is behind its remote\n"
+"counterpart. Check out this branch and merge the remote changes\n"
+"(e.g. 'git pull') before pushing again.\n"
+"See the 'Note about fast-forwards' in 'git push --help' for details."
+msgstr ""
+
+#: builtin/push.c:258
+#, c-format
+msgid "Pushing to %s\n"
+msgstr ""
+
+#: builtin/push.c:262
+#, c-format
+msgid "failed to push some refs to '%s'"
+msgstr ""
+
+#: builtin/push.c:294
+#, c-format
+msgid "bad repository '%s'"
+msgstr ""
+
+#: builtin/push.c:295
+msgid ""
+"No configured push destination.\n"
+"Either specify the URL from the command-line or configure a remote "
+"repository using\n"
+"\n"
+"    git remote add <name> <url>\n"
+"\n"
+"and then push using the remote name\n"
+"\n"
+"    git push <name>\n"
+msgstr ""
+
+#: builtin/push.c:310
+msgid "--all and --tags are incompatible"
+msgstr ""
+
+#: builtin/push.c:311
+msgid "--all can't be combined with refspecs"
+msgstr ""
+
+#: builtin/push.c:316
+msgid "--mirror and --tags are incompatible"
+msgstr ""
+
+#: builtin/push.c:317
+msgid "--mirror can't be combined with refspecs"
+msgstr ""
+
+#: builtin/push.c:322
+msgid "--all and --mirror are incompatible"
+msgstr ""
+
+#: builtin/push.c:382
+msgid "repository"
+msgstr ""
+
+#: builtin/push.c:383
+msgid "push all refs"
+msgstr ""
+
+#: builtin/push.c:384
+msgid "mirror all refs"
+msgstr ""
+
+#: builtin/push.c:386
+msgid "delete refs"
+msgstr ""
+
+#: builtin/push.c:387
+msgid "push tags (can't be used with --all or --mirror)"
+msgstr ""
+
+#: builtin/push.c:390
+msgid "force updates"
+msgstr ""
+
+#: builtin/push.c:391
+msgid "check"
+msgstr ""
+
+#: builtin/push.c:392
+msgid "control recursive pushing of submodules"
+msgstr ""
+
+#: builtin/push.c:394
+msgid "use thin pack"
+msgstr ""
+
+#: builtin/push.c:395 builtin/push.c:396
+msgid "receive pack program"
+msgstr ""
+
+#: builtin/push.c:397
+msgid "set upstream for git pull/status"
+msgstr ""
+
+#: builtin/push.c:400
+msgid "prune locally removed refs"
+msgstr ""
+
+#: builtin/push.c:410
+msgid "--delete is incompatible with --all, --mirror and --tags"
+msgstr ""
+
+#: builtin/push.c:412
+msgid "--delete doesn't make sense without any refs"
+msgstr ""
+
+#: 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 ""
+
+#: builtin/read-tree.c:108
+msgid "write resulting index to <file>"
+msgstr ""
+
+#: builtin/read-tree.c:111
+msgid "only empty the index"
+msgstr ""
+
+#: builtin/read-tree.c:113
+msgid "Merging"
+msgstr ""
+
+#: builtin/read-tree.c:115
+msgid "perform a merge in addition to a read"
+msgstr ""
+
+#: builtin/read-tree.c:117
+msgid "3-way merge if no file level merging required"
+msgstr ""
+
+#: builtin/read-tree.c:119
+msgid "3-way merge in presence of adds and removes"
+msgstr ""
+
+#: builtin/read-tree.c:121
+msgid "same as -m, but discard unmerged entries"
+msgstr ""
+
+#: builtin/read-tree.c:122
+msgid "<subdirectory>/"
+msgstr ""
+
+#: builtin/read-tree.c:123
+msgid "read the tree into the index under <subdirectory>/"
+msgstr ""
+
+#: builtin/read-tree.c:126
+msgid "update working tree with merge result"
+msgstr ""
+
+#: builtin/read-tree.c:128
+msgid "gitignore"
+msgstr ""
+
+#: builtin/read-tree.c:129
+msgid "allow explicitly ignored files to be overwritten"
+msgstr ""
+
+#: builtin/read-tree.c:132
+msgid "don't check the working tree after merging"
+msgstr ""
+
+#: builtin/read-tree.c:133
+msgid "don't update the index or the work tree"
+msgstr ""
+
+#: builtin/read-tree.c:135
+msgid "skip applying sparse checkout filter"
+msgstr ""
+
+#: builtin/read-tree.c:137
+msgid "debug unpack-trees"
+msgstr ""
+
+#: builtin/remote.c:11
+msgid "git remote [-v | --verbose]"
+msgstr ""
+
+#: builtin/remote.c:12
+msgid ""
+"git remote add [-t <branch>] [-m <master>] [-f] [--tags|--no-tags] [--"
+"mirror=<fetch|push>] <name> <url>"
+msgstr ""
+
+#: builtin/remote.c:13 builtin/remote.c:32
+msgid "git remote rename <old> <new>"
+msgstr ""
+
+#: builtin/remote.c:14 builtin/remote.c:37
+msgid "git remote remove <name>"
+msgstr ""
+
+#: builtin/remote.c:15
+msgid "git remote set-head <name> (-a | -d | <branch>)"
+msgstr ""
+
+#: builtin/remote.c:16
+msgid "git remote [-v | --verbose] show [-n] <name>"
+msgstr ""
+
+#: builtin/remote.c:17
+msgid "git remote prune [-n | --dry-run] <name>"
+msgstr ""
+
+#: builtin/remote.c:18
+msgid ""
+"git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]"
+msgstr ""
+
+#: builtin/remote.c:19
+msgid "git remote set-branches [--add] <name> <branch>..."
+msgstr ""
+
+#: builtin/remote.c:20 builtin/remote.c:68
+msgid "git remote set-url [--push] <name> <newurl> [<oldurl>]"
+msgstr ""
+
+#: builtin/remote.c:21 builtin/remote.c:69
+msgid "git remote set-url --add <name> <newurl>"
+msgstr ""
+
+#: builtin/remote.c:22 builtin/remote.c:70
+msgid "git remote set-url --delete <name> <url>"
+msgstr ""
+
+#: builtin/remote.c:27
+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 ""
+
+#: builtin/remote.c:48
+msgid "git remote set-branches --add <name> <branch>..."
+msgstr ""
+
+#: builtin/remote.c:53
+msgid "git remote show [<options>] <name>"
+msgstr ""
+
+#: builtin/remote.c:58
+msgid "git remote prune [<options>] <name>"
+msgstr ""
+
+#: builtin/remote.c:63
+msgid "git remote update [<options>] [<group> | <remote>]..."
+msgstr ""
+
+#: builtin/remote.c:98
+#, c-format
+msgid "Updating %s"
+msgstr ""
+
+#: builtin/remote.c:130
+msgid ""
+"--mirror is dangerous and deprecated; please\n"
+"\t use --mirror=fetch or --mirror=push instead"
+msgstr ""
+
+#: builtin/remote.c:147
+#, c-format
+msgid "unknown mirror argument: %s"
+msgstr ""
+
+#: builtin/remote.c:163
+msgid "fetch the remote branches"
+msgstr ""
+
+#: builtin/remote.c:165
+msgid "import all tags and associated objects when fetching"
+msgstr ""
+
+#: builtin/remote.c:168
+msgid "or do not fetch any tag at all (--no-tags)"
+msgstr ""
+
+#: builtin/remote.c:170
+msgid "branch(es) to track"
+msgstr ""
+
+#: builtin/remote.c:171
+msgid "master branch"
+msgstr ""
+
+#: builtin/remote.c:172
+msgid "push|fetch"
+msgstr ""
+
+#: builtin/remote.c:173
+msgid "set up remote as a mirror to push to or fetch from"
+msgstr ""
+
+#: builtin/remote.c:185
+msgid "specifying a master branch makes no sense with --mirror"
+msgstr ""
+
+#: builtin/remote.c:187
+msgid "specifying branches to track makes sense only with fetch mirrors"
+msgstr ""
+
+#: builtin/remote.c:195 builtin/remote.c:646
+#, c-format
+msgid "remote %s already exists."
+msgstr ""
+
+#: builtin/remote.c:199 builtin/remote.c:650
+#, c-format
+msgid "'%s' is not a valid remote name"
+msgstr ""
+
+#: builtin/remote.c:243
+#, c-format
+msgid "Could not setup master '%s'"
+msgstr ""
+
+#: builtin/remote.c:299
+#, c-format
+msgid "more than one %s"
 msgstr ""
 
 #: builtin/remote.c:339
 #, c-format
-msgid "Could not get fetch map for refspec %s"
+msgid "Could not get fetch map for refspec %s"
+msgstr ""
+
+#: builtin/remote.c:440 builtin/remote.c:448
+msgid "(matching)"
+msgstr ""
+
+#: builtin/remote.c:452
+msgid "(delete)"
+msgstr ""
+
+#: builtin/remote.c:595 builtin/remote.c:601 builtin/remote.c:607
+#, c-format
+msgid "Could not append '%s' to '%s'"
+msgstr ""
+
+#: builtin/remote.c:639 builtin/remote.c:792 builtin/remote.c:890
+#, c-format
+msgid "No such remote: %s"
+msgstr ""
+
+#: builtin/remote.c:656
+#, c-format
+msgid "Could not rename config section '%s' to '%s'"
+msgstr ""
+
+#: builtin/remote.c:662 builtin/remote.c:799
+#, c-format
+msgid "Could not remove config section '%s'"
+msgstr ""
+
+#: builtin/remote.c:677
+#, c-format
+msgid ""
+"Not updating non-default fetch refspec\n"
+"\t%s\n"
+"\tPlease update the configuration manually if necessary."
+msgstr ""
+
+#: builtin/remote.c:683
+#, c-format
+msgid "Could not append '%s'"
+msgstr ""
+
+#: builtin/remote.c:694
+#, c-format
+msgid "Could not set '%s'"
+msgstr ""
+
+#: builtin/remote.c:716
+#, c-format
+msgid "deleting '%s' failed"
+msgstr ""
+
+#: builtin/remote.c:750
+#, c-format
+msgid "creating '%s' failed"
+msgstr ""
+
+#: builtin/remote.c:764
+#, c-format
+msgid "Could not remove branch %s"
+msgstr ""
+
+#: builtin/remote.c:834
+msgid ""
+"Note: A branch outside the refs/remotes/ hierarchy was not removed;\n"
+"to delete it, use:"
+msgid_plural ""
+"Note: Some branches outside the refs/remotes/ hierarchy were not removed;\n"
+"to delete them, use:"
+msgstr[0] ""
+msgstr[1] ""
+
+#: builtin/remote.c:943
+#, c-format
+msgid " new (next fetch will store in remotes/%s)"
+msgstr ""
+
+#: builtin/remote.c:946
+msgid " tracked"
+msgstr ""
+
+#: builtin/remote.c:948
+msgid " stale (use 'git remote prune' to remove)"
+msgstr ""
+
+#: builtin/remote.c:950
+msgid " ???"
+msgstr ""
+
+#: builtin/remote.c:991
+#, c-format
+msgid "invalid branch.%s.merge; cannot rebase onto > 1 branch"
+msgstr ""
+
+#: builtin/remote.c:998
+#, c-format
+msgid "rebases onto remote %s"
+msgstr ""
+
+#: builtin/remote.c:1001
+#, c-format
+msgid " merges with remote %s"
+msgstr ""
+
+#: builtin/remote.c:1002
+msgid "    and with remote"
+msgstr ""
+
+#: builtin/remote.c:1004
+#, c-format
+msgid "merges with remote %s"
+msgstr ""
+
+#: builtin/remote.c:1005
+msgid "   and with remote"
+msgstr ""
+
+#: builtin/remote.c:1051
+msgid "create"
+msgstr ""
+
+#: builtin/remote.c:1054
+msgid "delete"
+msgstr ""
+
+#: builtin/remote.c:1058
+msgid "up to date"
+msgstr ""
+
+#: builtin/remote.c:1061
+msgid "fast-forwardable"
+msgstr ""
+
+#: builtin/remote.c:1064
+msgid "local out of date"
+msgstr ""
+
+#: builtin/remote.c:1071
+#, c-format
+msgid "    %-*s forces to %-*s (%s)"
+msgstr ""
+
+#: builtin/remote.c:1074
+#, c-format
+msgid "    %-*s pushes to %-*s (%s)"
+msgstr ""
+
+#: builtin/remote.c:1078
+#, c-format
+msgid "    %-*s forces to %s"
+msgstr ""
+
+#: builtin/remote.c:1081
+#, c-format
+msgid "    %-*s pushes to %s"
+msgstr ""
+
+#: builtin/remote.c:1091
+msgid "do not query remotes"
+msgstr ""
+
+#: builtin/remote.c:1118
+#, c-format
+msgid "* remote %s"
+msgstr ""
+
+#: builtin/remote.c:1119
+#, c-format
+msgid "  Fetch URL: %s"
+msgstr ""
+
+#: builtin/remote.c:1120 builtin/remote.c:1285
+msgid "(no URL)"
+msgstr ""
+
+#: builtin/remote.c:1129 builtin/remote.c:1131
+#, c-format
+msgid "  Push  URL: %s"
+msgstr ""
+
+#: builtin/remote.c:1133 builtin/remote.c:1135 builtin/remote.c:1137
+#, c-format
+msgid "  HEAD branch: %s"
+msgstr ""
+
+#: builtin/remote.c:1139
+#, c-format
+msgid ""
+"  HEAD branch (remote HEAD is ambiguous, may be one of the following):\n"
+msgstr ""
+
+#: builtin/remote.c:1151
+#, c-format
+msgid "  Remote branch:%s"
+msgid_plural "  Remote branches:%s"
+msgstr[0] ""
+msgstr[1] ""
+
+#: builtin/remote.c:1154 builtin/remote.c:1181
+msgid " (status not queried)"
+msgstr ""
+
+#: builtin/remote.c:1163
+msgid "  Local branch configured for 'git pull':"
+msgid_plural "  Local branches configured for 'git pull':"
+msgstr[0] ""
+msgstr[1] ""
+
+#: builtin/remote.c:1171
+msgid "  Local refs will be mirrored by 'git push'"
+msgstr ""
+
+#: 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] ""
+msgstr[1] ""
+
+#: builtin/remote.c:1199
+msgid "set refs/remotes/<name>/HEAD according to remote"
+msgstr ""
+
+#: builtin/remote.c:1201
+msgid "delete refs/remotes/<name>/HEAD"
+msgstr ""
+
+#: builtin/remote.c:1216
+msgid "Cannot determine remote HEAD"
+msgstr ""
+
+#: builtin/remote.c:1218
+msgid "Multiple remote HEAD branches. Please choose one explicitly with:"
+msgstr ""
+
+#: builtin/remote.c:1228
+#, c-format
+msgid "Could not delete %s"
+msgstr ""
+
+#: builtin/remote.c:1236
+#, c-format
+msgid "Not a valid ref: %s"
+msgstr ""
+
+#: builtin/remote.c:1238
+#, c-format
+msgid "Could not setup %s"
+msgstr ""
+
+#: builtin/remote.c:1274
+#, c-format
+msgid " %s will become dangling!"
+msgstr ""
+
+#: builtin/remote.c:1275
+#, c-format
+msgid " %s has become dangling!"
+msgstr ""
+
+#: builtin/remote.c:1281
+#, c-format
+msgid "Pruning %s"
+msgstr ""
+
+#: builtin/remote.c:1282
+#, c-format
+msgid "URL: %s"
+msgstr ""
+
+#: builtin/remote.c:1295
+#, c-format
+msgid " * [would prune] %s"
+msgstr ""
+
+#: builtin/remote.c:1298
+#, c-format
+msgid " * [pruned] %s"
+msgstr ""
+
+#: builtin/remote.c:1321
+msgid "prune remotes after fetching"
+msgstr ""
+
+#: builtin/remote.c:1387 builtin/remote.c:1461
+#, c-format
+msgid "No such remote '%s'"
+msgstr ""
+
+#: builtin/remote.c:1407
+msgid "add branch"
+msgstr ""
+
+#: builtin/remote.c:1414
+msgid "no remote specified"
+msgstr ""
+
+#: builtin/remote.c:1436
+msgid "manipulate push URLs"
+msgstr ""
+
+#: builtin/remote.c:1438
+msgid "add URL"
+msgstr ""
+
+#: builtin/remote.c:1440
+msgid "delete URLs"
+msgstr ""
+
+#: builtin/remote.c:1447
+msgid "--add --delete doesn't make sense"
+msgstr ""
+
+#: builtin/remote.c:1487
+#, c-format
+msgid "Invalid old URL pattern: %s"
+msgstr ""
+
+#: builtin/remote.c:1495
+#, c-format
+msgid "No such URL found: %s"
+msgstr ""
+
+#: builtin/remote.c:1497
+msgid "Will not delete all non-push URLs"
+msgstr ""
+
+#: builtin/remote.c:1569
+msgid "be verbose; must be placed before a subcommand"
+msgstr ""
+
+#: builtin/replace.c:17
+msgid "git replace [-f] <object> <replacement>"
+msgstr ""
+
+#: builtin/replace.c:18
+msgid "git replace -d <object>..."
+msgstr ""
+
+#: builtin/replace.c:19
+msgid "git replace -l [<pattern>]"
+msgstr ""
+
+#: builtin/replace.c:118
+msgid "list replace refs"
+msgstr ""
+
+#: builtin/replace.c:119
+msgid "delete replace refs"
+msgstr ""
+
+#: builtin/replace.c:120
+msgid "replace the ref if it exists"
+msgstr ""
+
+#: builtin/rerere.c:11
+msgid "git rerere [clear | forget path... | status | remaining | diff | gc]"
+msgstr ""
+
+#: builtin/rerere.c:56
+msgid "register clean resolutions in index"
+msgstr ""
+
+#: builtin/reset.c:25
+msgid ""
+"git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]"
+msgstr ""
+
+#: builtin/reset.c:26
+msgid "git reset [-q] <commit> [--] <paths>..."
+msgstr ""
+
+#: builtin/reset.c:27
+msgid "git reset --patch [<commit>] [--] [<paths>...]"
+msgstr ""
+
+#: builtin/reset.c:33
+msgid "mixed"
 msgstr ""
 
-#: builtin/remote.c:440 builtin/remote.c:448
-msgid "(matching)"
+#: builtin/reset.c:33
+msgid "soft"
 msgstr ""
 
-#: builtin/remote.c:452
-msgid "(delete)"
+#: builtin/reset.c:33
+msgid "hard"
 msgstr ""
 
-#: builtin/remote.c:595 builtin/remote.c:601 builtin/remote.c:607
-#, c-format
-msgid "Could not append '%s' to '%s'"
+#: builtin/reset.c:33
+msgid "merge"
 msgstr ""
 
-#: builtin/remote.c:639 builtin/remote.c:792 builtin/remote.c:890
-#, c-format
-msgid "No such remote: %s"
+#: builtin/reset.c:33
+msgid "keep"
 msgstr ""
 
-#: builtin/remote.c:656
-#, c-format
-msgid "Could not rename config section '%s' to '%s'"
+#: builtin/reset.c:77
+msgid "You do not have a valid HEAD."
 msgstr ""
 
-#: builtin/remote.c:662 builtin/remote.c:799
+#: builtin/reset.c:79
+msgid "Failed to find tree of HEAD."
+msgstr ""
+
+#: builtin/reset.c:85
 #, c-format
-msgid "Could not remove config section '%s'"
+msgid "Failed to find tree of %s."
 msgstr ""
 
-#: builtin/remote.c:677
+#: builtin/reset.c:96
+msgid "Could not write new index file."
+msgstr ""
+
+#: builtin/reset.c:106
 #, c-format
-msgid ""
-"Not updating non-default fetch refspec\n"
-"\t%s\n"
-"\tPlease update the configuration manually if necessary."
+msgid "HEAD is now at %s"
 msgstr ""
 
-#: builtin/remote.c:683
+#: builtin/reset.c:130
+msgid "Could not read index"
+msgstr ""
+
+#: builtin/reset.c:133
+msgid "Unstaged changes after reset:"
+msgstr ""
+
+#: builtin/reset.c:223
 #, c-format
-msgid "Could not append '%s'"
+msgid "Cannot do a %s reset in the middle of a merge."
 msgstr ""
 
-#: builtin/remote.c:694
+#: builtin/reset.c:238
+msgid "be quiet, only report errors"
+msgstr ""
+
+#: builtin/reset.c:240
+msgid "reset HEAD and index"
+msgstr ""
+
+#: builtin/reset.c:241
+msgid "reset only HEAD"
+msgstr ""
+
+#: builtin/reset.c:243 builtin/reset.c:245
+msgid "reset HEAD, index and working tree"
+msgstr ""
+
+#: builtin/reset.c:247
+msgid "reset HEAD but keep local changes"
+msgstr ""
+
+#: builtin/reset.c:303
 #, c-format
-msgid "Could not set '%s'"
+msgid "Could not parse object '%s'."
 msgstr ""
 
-#: builtin/remote.c:716
+#: builtin/reset.c:308
+msgid "--patch is incompatible with --{hard,mixed,soft}"
+msgstr ""
+
+#: builtin/reset.c:317
+msgid "--mixed with paths is deprecated; use 'git reset -- <paths>' instead."
+msgstr ""
+
+#: builtin/reset.c:319
 #, c-format
-msgid "deleting '%s' failed"
+msgid "Cannot do %s reset with paths."
 msgstr ""
 
-#: builtin/remote.c:750
+#: builtin/reset.c:331
 #, c-format
-msgid "creating '%s' failed"
+msgid "%s reset is not allowed in a bare repository"
 msgstr ""
 
-#: builtin/remote.c:764
+#: builtin/reset.c:347
 #, c-format
-msgid "Could not remove branch %s"
+msgid "Could not reset index file to revision '%s'."
 msgstr ""
 
-#: builtin/remote.c:834
+#: builtin/rev-parse.c:339
+msgid "git rev-parse --parseopt [options] -- [<args>...]"
+msgstr ""
+
+#: builtin/rev-parse.c:344
+msgid "keep the `--` passed as an arg"
+msgstr ""
+
+#: builtin/rev-parse.c:346
+msgid "stop parsing after the first non-option argument"
+msgstr ""
+
+#: builtin/rev-parse.c:464
 msgid ""
-"Note: A branch outside the refs/remotes/ hierarchy was not removed;\n"
-"to delete it, use:"
-msgid_plural ""
-"Note: Some branches outside the refs/remotes/ hierarchy were not removed;\n"
-"to delete them, use:"
-msgstr[0] ""
-msgstr[1] ""
+"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 ""
 
-#: builtin/remote.c:943
-#, c-format
-msgid " new (next fetch will store in remotes/%s)"
+#: builtin/revert.c:22
+msgid "git revert [options] <commit-ish>"
 msgstr ""
 
-#: builtin/remote.c:946
-msgid " tracked"
+#: builtin/revert.c:23
+msgid "git revert <subcommand>"
 msgstr ""
 
-#: builtin/remote.c:948
-msgid " stale (use 'git remote prune' to remove)"
+#: builtin/revert.c:28
+msgid "git cherry-pick [options] <commit-ish>"
 msgstr ""
 
-#: builtin/remote.c:950
-msgid " ???"
+#: builtin/revert.c:29
+msgid "git cherry-pick <subcommand>"
 msgstr ""
 
-#: builtin/remote.c:991
+#: builtin/revert.c:70 builtin/revert.c:92
 #, c-format
-msgid "invalid branch.%s.merge; cannot rebase onto > 1 branch"
+msgid "%s: %s cannot be used with %s"
 msgstr ""
 
-#: builtin/remote.c:998
-#, c-format
-msgid "rebases onto remote %s"
+#: builtin/revert.c:103
+msgid "end revert or cherry-pick sequence"
 msgstr ""
 
-#: builtin/remote.c:1001
-#, c-format
-msgid " merges with remote %s"
+#: builtin/revert.c:104
+msgid "resume revert or cherry-pick sequence"
 msgstr ""
 
-#: builtin/remote.c:1002
-msgid "    and with remote"
+#: builtin/revert.c:105
+msgid "cancel revert or cherry-pick sequence"
 msgstr ""
 
-#: builtin/remote.c:1004
-#, c-format
-msgid "merges with remote %s"
+#: builtin/revert.c:106
+msgid "don't automatically commit"
 msgstr ""
 
-#: builtin/remote.c:1005
-msgid "   and with remote"
+#: builtin/revert.c:107
+msgid "edit the commit message"
 msgstr ""
 
-#: builtin/remote.c:1051
-msgid "create"
+#: builtin/revert.c:110
+msgid "parent number"
 msgstr ""
 
-#: builtin/remote.c:1054
-msgid "delete"
+#: builtin/revert.c:112
+msgid "merge strategy"
 msgstr ""
 
-#: builtin/remote.c:1058
-msgid "up to date"
+#: builtin/revert.c:113
+msgid "option"
 msgstr ""
 
-#: builtin/remote.c:1061
-msgid "fast-forwardable"
+#: builtin/revert.c:114
+msgid "option for merge strategy"
 msgstr ""
 
-#: builtin/remote.c:1064
-msgid "local out of date"
+#: builtin/revert.c:125
+msgid "append commit name"
 msgstr ""
 
-#: builtin/remote.c:1071
-#, c-format
-msgid "    %-*s forces to %-*s (%s)"
+#: builtin/revert.c:126
+msgid "allow fast-forward"
 msgstr ""
 
-#: builtin/remote.c:1074
-#, c-format
-msgid "    %-*s pushes to %-*s (%s)"
+#: builtin/revert.c:127
+msgid "preserve initially empty commits"
 msgstr ""
 
-#: builtin/remote.c:1078
-#, c-format
-msgid "    %-*s forces to %s"
+#: builtin/revert.c:128
+msgid "allow commits with empty messages"
 msgstr ""
 
-#: builtin/remote.c:1081
-#, c-format
-msgid "    %-*s pushes to %s"
+#: builtin/revert.c:129
+msgid "keep redundant, empty commits"
 msgstr ""
 
-#: builtin/remote.c:1118
-#, c-format
-msgid "* remote %s"
+#: builtin/revert.c:133
+msgid "program error"
 msgstr ""
 
-#: builtin/remote.c:1119
-#, c-format
-msgid "  Fetch URL: %s"
+#: builtin/revert.c:223
+msgid "revert failed"
 msgstr ""
 
-#: builtin/remote.c:1120 builtin/remote.c:1285
-msgid "(no URL)"
+#: builtin/revert.c:238
+msgid "cherry-pick failed"
 msgstr ""
 
-#: builtin/remote.c:1129 builtin/remote.c:1131
-#, c-format
-msgid "  Push  URL: %s"
+#: builtin/rm.c:14
+msgid "git rm [options] [--] <file>..."
 msgstr ""
 
-#: builtin/remote.c:1133 builtin/remote.c:1135 builtin/remote.c:1137
+#: builtin/rm.c:109
 #, c-format
-msgid "  HEAD branch: %s"
+msgid ""
+"'%s' has staged content different from both the file and the HEAD\n"
+"(use -f to force removal)"
 msgstr ""
 
-#: builtin/remote.c:1139
+#: builtin/rm.c:115
 #, c-format
 msgid ""
-"  HEAD branch (remote HEAD is ambiguous, may be one of the following):\n"
+"'%s' has changes staged in the index\n"
+"(use --cached to keep the file, or -f to force removal)"
 msgstr ""
 
-#: builtin/remote.c:1151
+#: builtin/rm.c:119
 #, c-format
-msgid "  Remote branch:%s"
-msgid_plural "  Remote branches:%s"
-msgstr[0] ""
-msgstr[1] ""
-
-#: builtin/remote.c:1154 builtin/remote.c:1181
-msgid " (status not queried)"
+msgid ""
+"'%s' has local modifications\n"
+"(use --cached to keep the file, or -f to force removal)"
 msgstr ""
 
-#: builtin/remote.c:1163
-msgid "  Local branch configured for 'git pull':"
-msgid_plural "  Local branches configured for 'git pull':"
-msgstr[0] ""
-msgstr[1] ""
+#: builtin/rm.c:134
+msgid "do not list removed files"
+msgstr ""
 
-#: builtin/remote.c:1171
-msgid "  Local refs will be mirrored by 'git push'"
+#: builtin/rm.c:135
+msgid "only remove from the index"
 msgstr ""
 
-#: 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] ""
-msgstr[1] ""
+#: builtin/rm.c:136
+msgid "override the up-to-date check"
+msgstr ""
 
-#: builtin/remote.c:1216
-msgid "Cannot determine remote HEAD"
+#: builtin/rm.c:137
+msgid "allow recursive removal"
 msgstr ""
 
-#: builtin/remote.c:1218
-msgid "Multiple remote HEAD branches. Please choose one explicitly with:"
+#: builtin/rm.c:139
+msgid "exit with a zero status even if nothing matched"
 msgstr ""
 
-#: builtin/remote.c:1228
+#: builtin/rm.c:194
 #, c-format
-msgid "Could not delete %s"
+msgid "not removing '%s' recursively without -r"
 msgstr ""
 
-#: builtin/remote.c:1236
+#: builtin/rm.c:230
 #, c-format
-msgid "Not a valid ref: %s"
+msgid "git rm: unable to remove %s"
 msgstr ""
 
-#: builtin/remote.c:1238
-#, c-format
-msgid "Could not setup %s"
+#: builtin/shortlog.c:13
+msgid "git shortlog [-n] [-s] [-e] [-w] [rev-opts] [--] [<commit-id>... ]"
 msgstr ""
 
-#: builtin/remote.c:1274
+#: builtin/shortlog.c:157
 #, c-format
-msgid " %s will become dangling!"
+msgid "Missing author: %s"
 msgstr ""
 
-#: builtin/remote.c:1275
-#, c-format
-msgid " %s has become dangling!"
+#: builtin/shortlog.c:253
+msgid "sort output according to the number of commits per author"
 msgstr ""
 
-#: builtin/remote.c:1281
-#, c-format
-msgid "Pruning %s"
+#: builtin/shortlog.c:255
+msgid "Suppress commit descriptions, only provides commit count"
 msgstr ""
 
-#: builtin/remote.c:1282
-#, c-format
-msgid "URL: %s"
+#: builtin/shortlog.c:257
+msgid "Show the email address of each author"
 msgstr ""
 
-#: builtin/remote.c:1295
-#, c-format
-msgid " * [would prune] %s"
+#: builtin/shortlog.c:258
+msgid "w[,i1[,i2]]"
 msgstr ""
 
-#: builtin/remote.c:1298
-#, c-format
-msgid " * [pruned] %s"
+#: builtin/shortlog.c:259
+msgid "Linewrap output"
 msgstr ""
 
-#: builtin/remote.c:1387 builtin/remote.c:1461
-#, c-format
-msgid "No such remote '%s'"
+#: 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 ""
 
-#: builtin/remote.c:1414
-msgid "no remote specified"
+#: builtin/show-branch.c:10
+msgid "git show-branch (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]"
 msgstr ""
 
-#: builtin/remote.c:1447
-msgid "--add --delete doesn't make sense"
+#: builtin/show-branch.c:651
+msgid "show remote-tracking and local branches"
 msgstr ""
 
-#: builtin/remote.c:1487
-#, c-format
-msgid "Invalid old URL pattern: %s"
+#: builtin/show-branch.c:653
+msgid "show remote-tracking branches"
 msgstr ""
 
-#: builtin/remote.c:1495
-#, c-format
-msgid "No such URL found: %s"
+#: builtin/show-branch.c:655
+msgid "color '*!+-' corresponding to the branch"
 msgstr ""
 
-#: builtin/remote.c:1497
-msgid "Will not delete all non-push URLs"
+#: builtin/show-branch.c:657
+msgid "show <n> more commits after the common ancestor"
 msgstr ""
 
-#: builtin/reset.c:33
-msgid "mixed"
+#: builtin/show-branch.c:659
+msgid "synonym to more=-1"
+msgstr ""
+
+#: builtin/show-branch.c:660
+msgid "suppress naming strings"
+msgstr ""
+
+#: builtin/show-branch.c:662
+msgid "include the current branch"
 msgstr ""
 
-#: builtin/reset.c:33
-msgid "soft"
+#: builtin/show-branch.c:664
+msgid "name commits with their object names"
 msgstr ""
 
-#: builtin/reset.c:33
-msgid "hard"
+#: builtin/show-branch.c:666
+msgid "show possible merge bases"
 msgstr ""
 
-#: builtin/reset.c:33
-msgid "merge"
+#: builtin/show-branch.c:668
+msgid "show refs unreachable from any other ref"
 msgstr ""
 
-#: builtin/reset.c:33
-msgid "keep"
+#: builtin/show-branch.c:670
+msgid "show commits in topological order"
 msgstr ""
 
-#: builtin/reset.c:77
-msgid "You do not have a valid HEAD."
+#: builtin/show-branch.c:672
+msgid "show only commits not on the first branch"
 msgstr ""
 
-#: builtin/reset.c:79
-msgid "Failed to find tree of HEAD."
+#: builtin/show-branch.c:674
+msgid "show merges reachable from only one tip"
 msgstr ""
 
-#: builtin/reset.c:85
-#, c-format
-msgid "Failed to find tree of %s."
+#: builtin/show-branch.c:676
+msgid "show commits where no parent comes before its children"
 msgstr ""
 
-#: builtin/reset.c:96
-msgid "Could not write new index file."
+#: builtin/show-branch.c:678
+msgid "<n>[,<base>]"
 msgstr ""
 
-#: builtin/reset.c:106
-#, c-format
-msgid "HEAD is now at %s"
+#: builtin/show-branch.c:679
+msgid "show <n> most recent ref-log entries starting at base"
 msgstr ""
 
-#: builtin/reset.c:130
-msgid "Could not read index"
+#: builtin/show-ref.c:10
+msgid ""
+"git show-ref [-q|--quiet] [--verify] [--head] [-d|--dereference] [-s|--hash"
+"[=<n>]] [--abbrev[=<n>]] [--tags] [--heads] [--] [pattern*] "
 msgstr ""
 
-#: builtin/reset.c:133
-msgid "Unstaged changes after reset:"
+#: builtin/show-ref.c:11
+msgid "git show-ref --exclude-existing[=pattern] < ref-list"
 msgstr ""
 
-#: builtin/reset.c:223
-#, c-format
-msgid "Cannot do a %s reset in the middle of a merge."
+#: builtin/show-ref.c:182
+msgid "only show tags (can be combined with heads)"
 msgstr ""
 
-#: builtin/reset.c:297
-#, c-format
-msgid "Could not parse object '%s'."
+#: builtin/show-ref.c:183
+msgid "only show heads (can be combined with tags)"
 msgstr ""
 
-#: builtin/reset.c:302
-msgid "--patch is incompatible with --{hard,mixed,soft}"
+#: builtin/show-ref.c:184
+msgid "stricter reference checking, requires exact ref path"
 msgstr ""
 
-#: builtin/reset.c:311
-msgid "--mixed with paths is deprecated; use 'git reset -- <paths>' instead."
+#: builtin/show-ref.c:187 builtin/show-ref.c:189
+msgid "show the HEAD reference"
 msgstr ""
 
-#: builtin/reset.c:313
-#, c-format
-msgid "Cannot do %s reset with paths."
+#: builtin/show-ref.c:191
+msgid "dereference tags into object IDs"
 msgstr ""
 
-#: builtin/reset.c:325
-#, c-format
-msgid "%s reset is not allowed in a bare repository"
+#: builtin/show-ref.c:193
+msgid "only show SHA1 hash using <n> digits"
 msgstr ""
 
-#: builtin/reset.c:341
-#, c-format
-msgid "Could not reset index file to revision '%s'."
+#: builtin/show-ref.c:197
+msgid "do not print results to stdout (useful with --verify)"
 msgstr ""
 
-#: builtin/revert.c:70 builtin/revert.c:92
-#, c-format
-msgid "%s: %s cannot be used with %s"
+#: builtin/show-ref.c:199
+msgid "show refs from stdin that aren't in local repository"
 msgstr ""
 
-#: builtin/revert.c:131
-msgid "program error"
+#: builtin/symbolic-ref.c:7
+msgid "git symbolic-ref [options] name [ref]"
 msgstr ""
 
-#: builtin/revert.c:221
-msgid "revert failed"
+#: builtin/symbolic-ref.c:38
+msgid "suppress error message for non-symbolic (detached) refs"
 msgstr ""
 
-#: builtin/revert.c:236
-msgid "cherry-pick failed"
+#: builtin/symbolic-ref.c:39
+msgid "shorten ref output"
 msgstr ""
 
-#: builtin/rm.c:109
-#, c-format
-msgid ""
-"'%s' has staged content different from both the file and the HEAD\n"
-"(use -f to force removal)"
+#: builtin/symbolic-ref.c:40 builtin/update-ref.c:18
+msgid "reason"
 msgstr ""
 
-#: builtin/rm.c:115
-#, c-format
-msgid ""
-"'%s' has changes staged in the index\n"
-"(use --cached to keep the file, or -f to force removal)"
+#: builtin/symbolic-ref.c:40 builtin/update-ref.c:18
+msgid "reason of the update"
 msgstr ""
 
-#: builtin/rm.c:119
-#, c-format
+#: builtin/tag.c:22
 msgid ""
-"'%s' has local modifications\n"
-"(use --cached to keep the file, or -f to force removal)"
+"git tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]"
 msgstr ""
 
-#: builtin/rm.c:194
-#, c-format
-msgid "not removing '%s' recursively without -r"
+#: builtin/tag.c:23
+msgid "git tag -d <tagname>..."
 msgstr ""
 
-#: builtin/rm.c:230
-#, c-format
-msgid "git rm: unable to remove %s"
+#: builtin/tag.c:24
+msgid ""
+"git tag -l [-n[<num>]] [--contains <commit>] [--points-at <object>] \n"
+"\t\t[<pattern>...]"
 msgstr ""
 
-#: builtin/shortlog.c:157
-#, c-format
-msgid "Missing author: %s"
+#: builtin/tag.c:26
+msgid "git tag -v <tagname>..."
 msgstr ""
 
 #: builtin/tag.c:60
@@ -4417,6 +7845,62 @@ msgstr ""
 msgid "malformed object name '%s'"
 msgstr ""
 
+#: builtin/tag.c:447
+msgid "list tag names"
+msgstr ""
+
+#: builtin/tag.c:449
+msgid "print <n> lines of each tag message"
+msgstr ""
+
+#: builtin/tag.c:451
+msgid "delete tags"
+msgstr ""
+
+#: builtin/tag.c:452
+msgid "verify tags"
+msgstr ""
+
+#: builtin/tag.c:454
+msgid "Tag creation options"
+msgstr ""
+
+#: builtin/tag.c:456
+msgid "annotated tag, needs a message"
+msgstr ""
+
+#: builtin/tag.c:458
+msgid "tag message"
+msgstr ""
+
+#: builtin/tag.c:460
+msgid "annotated and GPG-signed tag"
+msgstr ""
+
+#: builtin/tag.c:464
+msgid "use another key to sign the tag"
+msgstr ""
+
+#: builtin/tag.c:465
+msgid "replace the tag if exists"
+msgstr ""
+
+#: builtin/tag.c:466
+msgid "show tag list in columns"
+msgstr ""
+
+#: builtin/tag.c:468
+msgid "Tag listing options"
+msgstr ""
+
+#: builtin/tag.c:471
+msgid "print only tags that contain the commit"
+msgstr ""
+
+#: builtin/tag.c:477
+msgid "print only tags of the object"
+msgstr ""
+
 #: builtin/tag.c:506
 msgid "--column and -n are incompatible"
 msgstr ""
@@ -4466,24 +7950,180 @@ msgstr ""
 msgid "Updated tag '%s' (was %s)\n"
 msgstr ""
 
-#: 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 ""
 
-#: parse-options.h:133 parse-options.h:235
-msgid "n"
+#: builtin/update-index.c:717
+msgid "continue refresh even when index needs update"
 msgstr ""
 
-#: parse-options.h:141
-msgid "time"
+#: builtin/update-index.c:720
+msgid "refresh: ignore submodules"
 msgstr ""
 
-#: parse-options.h:149
-msgid "file"
+#: builtin/update-index.c:723
+msgid "do not ignore new files"
 msgstr ""
 
-#: parse-options.h:151
-msgid "when"
+#: builtin/update-index.c:725
+msgid "let files replace directories and vice-versa"
+msgstr ""
+
+#: builtin/update-index.c:727
+msgid "notice files missing from worktree"
+msgstr ""
+
+#: builtin/update-index.c:729
+msgid "refresh even if index contains unmerged entries"
+msgstr ""
+
+#: builtin/update-index.c:732
+msgid "refresh stat information"
+msgstr ""
+
+#: builtin/update-index.c:736
+msgid "like --refresh, but ignore assume-unchanged setting"
+msgstr ""
+
+#: builtin/update-index.c:740
+msgid "<mode> <object> <path>"
+msgstr ""
+
+#: builtin/update-index.c:741
+msgid "add the specified entry to the index"
+msgstr ""
+
+#: builtin/update-index.c:745
+msgid "(+/-)x"
+msgstr ""
+
+#: builtin/update-index.c:746
+msgid "override the executable bit of the listed files"
+msgstr ""
+
+#: builtin/update-index.c:750
+msgid "mark files as \"not changing\""
+msgstr ""
+
+#: builtin/update-index.c:753
+msgid "clear assumed-unchanged bit"
+msgstr ""
+
+#: builtin/update-index.c:756
+msgid "mark files as \"index-only\""
+msgstr ""
+
+#: builtin/update-index.c:759
+msgid "clear skip-worktree bit"
+msgstr ""
+
+#: builtin/update-index.c:762
+msgid "add to index only; do not add content to object database"
+msgstr ""
+
+#: builtin/update-index.c:764
+msgid "remove named paths even if present in worktree"
+msgstr ""
+
+#: builtin/update-index.c:766
+msgid "with --stdin: input lines are terminated by null bytes"
+msgstr ""
+
+#: builtin/update-index.c:768
+msgid "read list of paths to be updated from standard input"
+msgstr ""
+
+#: builtin/update-index.c:772
+msgid "add entries from standard input to the index"
+msgstr ""
+
+#: builtin/update-index.c:776
+msgid "repopulate stages #2 and #3 for the listed paths"
+msgstr ""
+
+#: builtin/update-index.c:780
+msgid "only update entries that differ from HEAD"
+msgstr ""
+
+#: builtin/update-index.c:784
+msgid "ignore files missing from worktree"
+msgstr ""
+
+#: builtin/update-index.c:787
+msgid "report actions to standard output"
+msgstr ""
+
+#: builtin/update-index.c:789
+msgid "(for porcelains) forget saved unresolved conflicts"
+msgstr ""
+
+#: builtin/update-index.c:793
+msgid "write index in this format"
+msgstr ""
+
+#: builtin/update-ref.c:7
+msgid "git update-ref [options] -d <refname> [<oldval>]"
+msgstr ""
+
+#: builtin/update-ref.c:8
+msgid "git update-ref [options]    <refname> <newval> [<oldval>]"
+msgstr ""
+
+#: builtin/update-ref.c:19
+msgid "delete the reference"
+msgstr ""
+
+#: builtin/update-ref.c:21
+msgid "update <refname> not the one it points to"
+msgstr ""
+
+#: builtin/update-server-info.c:6
+msgid "git update-server-info [--force]"
+msgstr ""
+
+#: builtin/update-server-info.c:14
+msgid "update the info files from scratch"
+msgstr ""
+
+#: builtin/verify-pack.c:56
+msgid "git verify-pack [-v|--verbose] [-s|--stat-only] <pack>..."
+msgstr ""
+
+#: builtin/verify-pack.c:66
+msgid "verbose"
+msgstr ""
+
+#: builtin/verify-pack.c:68
+msgid "show statistics only"
+msgstr ""
+
+#: builtin/verify-tag.c:17
+msgid "git verify-tag [-v|--verbose] <tag>..."
+msgstr ""
+
+#: builtin/verify-tag.c:73
+msgid "print tag contents"
+msgstr ""
+
+#: builtin/write-tree.c:13
+msgid "git write-tree [--missing-ok] [--prefix=<prefix>/]"
+msgstr ""
+
+#: builtin/write-tree.c:26
+msgid "<prefix>/"
+msgstr ""
+
+#: builtin/write-tree.c:27
+msgid "write tree object for a subdirectory <prefix>"
+msgstr ""
+
+#: builtin/write-tree.c:30
+msgid "only useful for debugging"
+msgstr ""
+
+#: git.c:16
+msgid "See 'git help <command>' for more information on a specific command."
 msgstr ""
 
 #: parse-options.h:156
@@ -4599,9 +8239,9 @@ msgstr ""
 #: git-am.sh:105
 #, sh-format
 msgid ""
-"When you have resolved this problem run \"$cmdline --resolved\".\n"
-"If you would prefer to skip this patch, instead run \"$cmdline --skip\".\n"
-"To restore the original branch and stop patching run \"$cmdline --abort\"."
+"When you have resolved this problem, run \"$cmdline --resolved\".\n"
+"If you prefer to skip this patch, run \"$cmdline --skip\" instead.\n"
+"To restore the original branch and stop patching, run \"$cmdline --abort\"."
 msgstr ""
 
 #: git-am.sh:121
@@ -4612,6 +8252,10 @@ msgstr ""
 msgid "Repository lacks necessary blobs to fall back on 3-way merge."
 msgstr ""
 
+#: git-am.sh:139
+msgid "Using index info to reconstruct a base tree..."
+msgstr ""
+
 #: git-am.sh:154
 msgid ""
 "Did you hand edit your patch?\n"
@@ -4622,42 +8266,48 @@ msgstr ""
 msgid "Falling back to patching base and 3-way merge..."
 msgstr ""
 
-#: git-am.sh:275
+#: git-am.sh:179
+msgid "Failed to merge in the changes."
+msgstr ""
+
+#: git-am.sh:274
 msgid "Only one StGIT patch series can be applied at once"
 msgstr ""
 
-#: git-am.sh:362
+#: git-am.sh:361
 #, sh-format
 msgid "Patch format $patch_format is not supported."
 msgstr ""
 
-#: git-am.sh:364
+#: git-am.sh:363
 msgid "Patch format detection failed."
 msgstr ""
 
-#: git-am.sh:418
-msgid "-d option is no longer supported.  Do not use."
+#: git-am.sh:389
+msgid ""
+"The -b/--binary option has been a no-op for long time, and\n"
+"it will be removed. Please do not use it anymore."
 msgstr ""
 
-#: git-am.sh:481
+#: git-am.sh:477
 #, sh-format
 msgid "previous rebase directory $dotest still exists but mbox given."
 msgstr ""
 
-#: git-am.sh:486
+#: git-am.sh:482
 msgid "Please make up your mind. --skip or --abort?"
 msgstr ""
 
-#: git-am.sh:513
+#: git-am.sh:509
 msgid "Resolve operation not in progress, we are not resuming."
 msgstr ""
 
-#: git-am.sh:579
+#: git-am.sh:575
 #, sh-format
 msgid "Dirty index: cannot apply patches (dirty: $files)"
 msgstr ""
 
-#: git-am.sh:671
+#: git-am.sh:679
 #, sh-format
 msgid ""
 "Patch is empty.  Was it split wrong?\n"
@@ -4665,53 +8315,60 @@ msgid ""
 "To restore the original branch and stop patching run \"$cmdline --abort\"."
 msgstr ""
 
-#: git-am.sh:708
+#: git-am.sh:706
 msgid "Patch does not have a valid e-mail address."
 msgstr ""
 
-#: git-am.sh:755
+#: git-am.sh:753
 msgid "cannot be interactive without stdin connected to a terminal."
 msgstr ""
 
-#: git-am.sh:759
+#: git-am.sh:757
 msgid "Commit Body is:"
 msgstr ""
 
 #. TRANSLATORS: Make sure to include [y], [n], [e], [v] and [a]
 #. in your translation. The program will only accept English
 #. input at this point.
-#: git-am.sh:766
+#: git-am.sh:764
 msgid "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all "
 msgstr ""
 
-#: git-am.sh:802
+#: git-am.sh:800
 #, sh-format
 msgid "Applying: $FIRSTLINE"
 msgstr ""
 
-#: git-am.sh:823
+#: git-am.sh:821
 msgid ""
 "No changes - did you forget to use 'git add'?\n"
 "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 ""
 
-#: git-am.sh:831
+#: git-am.sh:829
 msgid ""
 "You still have unmerged paths in your index\n"
 "did you forget to use 'git add'?"
 msgstr ""
 
-#: git-am.sh:847
+#: git-am.sh:845
 msgid "No changes -- Patch already applied."
 msgstr ""
 
-#: git-am.sh:857
+#: git-am.sh:855
 #, sh-format
 msgid "Patch failed at $msgnum $FIRSTLINE"
 msgstr ""
 
-#: git-am.sh:873
+#: git-am.sh:858
+#, sh-format
+msgid ""
+"The copy of the patch that failed is found in:\n"
+"   $dotest/patch"
+msgstr ""
+
+#: git-am.sh:876
 msgid "applying to an empty history"
 msgstr ""
 
@@ -4894,6 +8551,116 @@ msgstr ""
 msgid "Cannot rebase onto multiple branches"
 msgstr ""
 
+#: 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"
+"To check out the original branch and stop rebasing, run \"git rebase --abort"
+"\"."
+msgstr ""
+
+#: git-rebase.sh:160
+msgid "The pre-rebase hook refused to rebase."
+msgstr ""
+
+#: git-rebase.sh:165
+msgid "It looks like git-am is in progress. Cannot rebase."
+msgstr ""
+
+#: git-rebase.sh:296
+msgid "The --exec option must be used with the --interactive option"
+msgstr ""
+
+#: git-rebase.sh:301
+msgid "No rebase in progress?"
+msgstr ""
+
+#: git-rebase.sh:312
+msgid "The --edit-todo action can only be used during interactive rebase."
+msgstr ""
+
+#: git-rebase.sh:319
+msgid "Cannot read HEAD"
+msgstr ""
+
+#: git-rebase.sh:322
+msgid ""
+"You must edit all merge conflicts and then\n"
+"mark them as resolved using git add"
+msgstr ""
+
+#: git-rebase.sh:340
+#, sh-format
+msgid "Could not move back to $head_name"
+msgstr ""
+
+#: git-rebase.sh:359
+#, sh-format
+msgid ""
+"It seems that there is already a $state_dir_base directory, and\n"
+"I wonder if you are in the middle of another rebase.  If that is the\n"
+"case, please try\n"
+"\t$cmd_live_rebase\n"
+"If that is not the case, please\n"
+"\t$cmd_clear_stale_rebase\n"
+"and run me again.  I am stopping in case you still have something\n"
+"valuable there."
+msgstr ""
+
+#: git-rebase.sh:404
+#, sh-format
+msgid "invalid upstream $upstream_name"
+msgstr ""
+
+#: git-rebase.sh:428
+#, sh-format
+msgid "$onto_name: there are more than one merge bases"
+msgstr ""
+
+#: git-rebase.sh:431 git-rebase.sh:435
+#, sh-format
+msgid "$onto_name: there is no merge base"
+msgstr ""
+
+#: git-rebase.sh:440
+#, sh-format
+msgid "Does not point to a valid commit: $onto_name"
+msgstr ""
+
+#: git-rebase.sh:463
+#, sh-format
+msgid "fatal: no such branch: $branch_name"
+msgstr ""
+
+#: git-rebase.sh:483
+msgid "Please commit or stash them."
+msgstr ""
+
+#: git-rebase.sh:501
+#, sh-format
+msgid "Current branch $branch_name is up to date."
+msgstr ""
+
+#: git-rebase.sh:504
+#, sh-format
+msgid "Current branch $branch_name is up to date, rebase forced."
+msgstr ""
+
+#: git-rebase.sh:515
+#, sh-format
+msgid "Changes from $mb to $onto:"
+msgstr ""
+
+#. Detach HEAD and reset the tree
+#: git-rebase.sh:524
+msgid "First, rewinding head to replay your work on top of it..."
+msgstr ""
+
+#: git-rebase.sh:532
+#, sh-format
+msgid "Fast-forwarded $branch_name to $onto_name."
+msgstr ""
+
 #: git-stash.sh:51
 msgid "git stash clear with parameters is unimplemented"
 msgstr ""
@@ -4999,59 +8766,59 @@ msgstr ""
 msgid "Cannot unstage modified files"
 msgstr ""
 
-#: git-stash.sh:474
+#: git-stash.sh:475
 msgid "Index was not unstashed."
 msgstr ""
 
-#: git-stash.sh:491
+#: git-stash.sh:492
 #, sh-format
 msgid "Dropped ${REV} ($s)"
 msgstr ""
 
-#: git-stash.sh:492
+#: git-stash.sh:493
 #, sh-format
 msgid "${REV}: Could not drop stash entry"
 msgstr ""
 
-#: git-stash.sh:499
+#: git-stash.sh:500
 msgid "No branch name specified"
 msgstr ""
 
-#: git-stash.sh:570
+#: git-stash.sh:571
 msgid "(To restore them type \"git stash apply\")"
 msgstr ""
 
-#: git-submodule.sh:56
+#: git-submodule.sh:88
 #, sh-format
 msgid "cannot strip one component off url '$remoteurl'"
 msgstr ""
 
-#: git-submodule.sh:109
+#: git-submodule.sh:167
 #, sh-format
 msgid "No submodule mapping found in .gitmodules for path '$sm_path'"
 msgstr ""
 
-#: git-submodule.sh:150
+#: git-submodule.sh:211
 #, sh-format
 msgid "Clone of '$url' into submodule path '$sm_path' failed"
 msgstr ""
 
-#: git-submodule.sh:160
+#: git-submodule.sh:223
 #, sh-format
 msgid "Gitdir '$a' is part of the submodule path '$b' or vice versa"
 msgstr ""
 
-#: git-submodule.sh:249
+#: git-submodule.sh:312
 #, sh-format
 msgid "repo URL: '$repo' must be absolute or begin with ./|../"
 msgstr ""
 
-#: git-submodule.sh:266
+#: git-submodule.sh:329
 #, sh-format
 msgid "'$sm_path' already exists in the index"
 msgstr ""
 
-#: git-submodule.sh:270
+#: git-submodule.sh:333
 #, sh-format
 msgid ""
 "The following path is ignored by one of your .gitignore files:\n"
@@ -5059,155 +8826,151 @@ msgid ""
 "Use -f if you really want to add it."
 msgstr ""
 
-#: git-submodule.sh:281
+#: git-submodule.sh:344
 #, sh-format
 msgid "Adding existing repo at '$sm_path' to the index"
 msgstr ""
 
-#: git-submodule.sh:283
+#: git-submodule.sh:346
 #, sh-format
 msgid "'$sm_path' already exists and is not a valid git repo"
 msgstr ""
 
-#: git-submodule.sh:297
+#: git-submodule.sh:360
 #, sh-format
 msgid "Unable to checkout submodule '$sm_path'"
 msgstr ""
 
-#: git-submodule.sh:302
+#: git-submodule.sh:365
 #, sh-format
 msgid "Failed to add submodule '$sm_path'"
 msgstr ""
 
-#: git-submodule.sh:307
+#: git-submodule.sh:370
 #, sh-format
 msgid "Failed to register submodule '$sm_path'"
 msgstr ""
 
-#: git-submodule.sh:349
+#: git-submodule.sh:413
 #, sh-format
 msgid "Entering '$prefix$sm_path'"
 msgstr ""
 
-#: git-submodule.sh:363
+#: git-submodule.sh:427
 #, sh-format
 msgid "Stopping at '$sm_path'; script returned non-zero status."
 msgstr ""
 
-#: git-submodule.sh:406
+#: git-submodule.sh:471
 #, sh-format
 msgid "No url found for submodule path '$sm_path' in .gitmodules"
 msgstr ""
 
-#: git-submodule.sh:415
+#: git-submodule.sh:480
 #, sh-format
 msgid "Failed to register url for submodule path '$sm_path'"
 msgstr ""
 
-#: git-submodule.sh:417
+#: git-submodule.sh:482
 #, sh-format
 msgid "Submodule '$name' ($url) registered for path '$sm_path'"
 msgstr ""
 
-#: git-submodule.sh:425
+#: git-submodule.sh:490
 #, sh-format
 msgid "Failed to register update mode for submodule path '$sm_path'"
 msgstr ""
 
-#: git-submodule.sh:524
+#: git-submodule.sh:590
 #, sh-format
 msgid ""
 "Submodule path '$sm_path' not initialized\n"
 "Maybe you want to use 'update --init'?"
 msgstr ""
 
-#: git-submodule.sh:537
+#: git-submodule.sh:603
 #, sh-format
 msgid "Unable to find current revision in submodule path '$sm_path'"
 msgstr ""
 
-#: git-submodule.sh:556
+#: git-submodule.sh:622
 #, sh-format
 msgid "Unable to fetch in submodule path '$sm_path'"
 msgstr ""
 
-#: git-submodule.sh:570
+#: git-submodule.sh:636
 #, sh-format
 msgid "Unable to rebase '$sha1' in submodule path '$sm_path'"
 msgstr ""
 
-#: git-submodule.sh:571
+#: git-submodule.sh:637
 #, sh-format
 msgid "Submodule path '$sm_path': rebased into '$sha1'"
 msgstr ""
 
-#: git-submodule.sh:576
+#: git-submodule.sh:642
 #, sh-format
 msgid "Unable to merge '$sha1' in submodule path '$sm_path'"
 msgstr ""
 
-#: git-submodule.sh:577
+#: git-submodule.sh:643
 #, sh-format
 msgid "Submodule path '$sm_path': merged in '$sha1'"
 msgstr ""
 
-#: git-submodule.sh:582
+#: git-submodule.sh:648
 #, sh-format
 msgid "Unable to checkout '$sha1' in submodule path '$sm_path'"
 msgstr ""
 
-#: git-submodule.sh:583
+#: git-submodule.sh:649
 #, sh-format
 msgid "Submodule path '$sm_path': checked out '$sha1'"
 msgstr ""
 
-#: git-submodule.sh:605 git-submodule.sh:928
+#: git-submodule.sh:671 git-submodule.sh:995
 #, sh-format
 msgid "Failed to recurse into submodule path '$sm_path'"
 msgstr ""
 
-#: git-submodule.sh:713
-msgid "--cached cannot be used with --files"
+#: git-submodule.sh:779
+msgid "The --cached option cannot be used with the --files option"
 msgstr ""
 
 #. unexpected type
-#: git-submodule.sh:753
+#: git-submodule.sh:819
 #, sh-format
 msgid "unexpected mode $mod_dst"
 msgstr ""
 
-#: git-submodule.sh:771
+#: git-submodule.sh:837
 #, sh-format
 msgid "  Warn: $name doesn't contain commit $sha1_src"
 msgstr ""
 
-#: git-submodule.sh:774
+#: git-submodule.sh:840
 #, sh-format
 msgid "  Warn: $name doesn't contain commit $sha1_dst"
 msgstr ""
 
-#: git-submodule.sh:777
+#: git-submodule.sh:843
 #, sh-format
 msgid "  Warn: $name doesn't contain commits $sha1_src and $sha1_dst"
 msgstr ""
 
-#: git-submodule.sh:802
+#: git-submodule.sh:868
 msgid "blob"
 msgstr ""
 
-#: git-submodule.sh:803
-msgid "submodule"
-msgstr ""
-
-#: git-submodule.sh:840
+#: git-submodule.sh:906
 msgid "# Submodules changed but not updated:"
 msgstr ""
 
-#: git-submodule.sh:842
+#: git-submodule.sh:908
 msgid "# Submodule changes to be committed:"
 msgstr ""
 
-#: git-submodule.sh:974
+#: git-submodule.sh:1054
 #, sh-format
 msgid "Synchronizing submodule url for '$name'"
 msgstr ""
index b0ff6f99a76f25e07517d337356691f662302f3b..9b3aa744bc781cb3963e7eefd91bda8a754a8a47 100644 (file)
--- a/po/sv.po
+++ b/po/sv.po
@@ -5,10 +5,10 @@
 #
 msgid ""
 msgstr ""
-"Project-Id-Version: git 1.7.10\n"
+"Project-Id-Version: git 1.7.12\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2012-06-08 10:20+0800\n"
-"PO-Revision-Date: 2012-07-01 22:59+0100\n"
+"POT-Creation-Date: 2012-10-16 08:38+0800\n"
+"PO-Revision-Date: 2012-10-16 08:36+0100\n"
 "Last-Translator: Peter Krefting <peter@softwolves.pp.se>\n"
 "Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n"
 "Language: sv\n"
@@ -38,6 +38,93 @@ msgstr ""
 "lämpligt för att ange lösning och checka in,\n"
 "eller använd \"git commit -a\"."
 
+#: archive.c:10
+msgid "git archive [options] <tree-ish> [<path>...]"
+msgstr "git archive [flaggor] <träd-igt> [<sökväg>...]"
+
+#: 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 <arkiv> [--exec <kmd>] [flaggor] <träd-igt> "
+"[<sökväg>...]"
+
+#: archive.c:13
+msgid "git archive --remote <repo> [--exec <cmd>] --list"
+msgstr "git archive --remote <arkiv> [--exec <kmd>] --list"
+
+#: archive.c:322
+msgid "fmt"
+msgstr "fmt"
+
+#: archive.c:322
+msgid "archive format"
+msgstr "arkivformat"
+
+#: archive.c:323 builtin/log.c:1079
+msgid "prefix"
+msgstr "prefix"
+
+#: archive.c:324
+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
+#: 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 "fil"
+
+#: archive.c:326 builtin/archive.c:92
+msgid "write the archive to this file"
+msgstr "skriv arkivet till filen"
+
+#: archive.c:328
+msgid "read .gitattributes in working directory"
+msgstr "läs .gitattributes i arbetskatalogen"
+
+#: archive.c:329
+msgid "report archived files on stderr"
+msgstr "rapportera arkiverade filer på standard fel"
+
+#: archive.c:330
+msgid "store only"
+msgstr "endast spara"
+
+#: archive.c:331
+msgid "compress faster"
+msgstr "komprimera snabbare"
+
+#: archive.c:339
+msgid "compress better"
+msgstr "komprimera bättre"
+
+#: archive.c:342
+msgid "list supported archive formats"
+msgstr "visa understödda arkivformat"
+
+#: archive.c:344 builtin/archive.c:93 builtin/clone.c:85
+msgid "repo"
+msgstr "arkiv"
+
+#: archive.c:345 builtin/archive.c:94
+msgid "retrieve the archive from remote repository <repo>"
+msgstr "hämta arkivet från fjärrarkivet <arkiv>"
+
+#: archive.c:346 builtin/archive.c:95 builtin/notes.c:619
+msgid "command"
+msgstr "kommando"
+
+#: archive.c:347 builtin/archive.c:96
+msgid "path to the remote git-upload-archive command"
+msgstr "sökväg till kommandot git-upload-archive på fjärren"
+
 #: bundle.c:36
 #, c-format
 msgid "'%s' does not look like a v2 bundle file"
@@ -48,7 +135,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:696
+#: bundle.c:89 builtin/commit.c:672
 #, c-format
 msgid "could not open '%s'"
 msgstr "kunde inte öppna \"%s\""
@@ -57,8 +144,8 @@ msgstr "kunde inte öppna \"%s\""
 msgid "Repository lacks these prerequisite commits:"
 msgstr "Arkivet saknar dessa nödvändiga incheckningar:"
 
-#: bundle.c:164 sequencer.c:550 sequencer.c:982 builtin/log.c:289
-#: builtin/log.c:720 builtin/log.c:1309 builtin/log.c:1528 builtin/merge.c:347
+#: 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/shortlog.c:181
 msgid "revision walk setup failed"
 msgstr "misslyckades skapa revisionstraversering"
@@ -71,53 +158,57 @@ msgstr[0] "Paketet (bundlen) innehåller %d referens"
 msgstr[1] "Paketet (bundlen) innehåller %d referenser"
 
 #: bundle.c:192
+msgid "The bundle records a complete history."
+msgstr "Paketet (bundlen) beskriver en komplett historik."
+
+#: bundle.c:195
 #, c-format
 msgid "The bundle requires this ref"
 msgid_plural "The bundle requires these %d refs"
 msgstr[0] "Paketet (bundlen) kräver denna referens"
 msgstr[1] "Paketet (bundlen) kräver dessa %d referenser"
 
-#: bundle.c:290
+#: bundle.c:294
 msgid "rev-list died"
 msgstr "rev-list dog"
 
-#: bundle.c:296 builtin/log.c:1205 builtin/shortlog.c:284
+#: bundle.c:300 builtin/log.c:1209 builtin/shortlog.c:284
 #, c-format
 msgid "unrecognized argument: %s"
 msgstr "okänt argument: %s"
 
-#: bundle.c:331
+#: bundle.c:335
 #, c-format
 msgid "ref '%s' is excluded by the rev-list options"
 msgstr "referensen \"%s\" exkluderas av argumenten till rev-list"
 
-#: bundle.c:376
+#: bundle.c:380
 msgid "Refusing to create empty bundle."
 msgstr "Vägrar skapa ett tomt paket (bundle)."
 
-#: bundle.c:394
+#: bundle.c:398
 msgid "Could not spawn pack-objects"
 msgstr "Kunde inte starta pack-objects"
 
-#: bundle.c:412
+#: bundle.c:416
 msgid "pack-objects died"
 msgstr "pack-objects misslyckades"
 
-#: bundle.c:415
+#: bundle.c:419
 #, c-format
 msgid "cannot create '%s'"
 msgstr "kan inte skapa \"%s\""
 
-#: bundle.c:437
+#: bundle.c:441
 msgid "index-pack died"
 msgstr "index-pack dog"
 
-#: commit.c:48
+#: commit.c:50
 #, c-format
 msgid "could not parse %s"
 msgstr "kunde inte tolka %s"
 
-#: commit.c:50
+#: commit.c:52
 #, c-format
 msgid "%s %s is not a commit!"
 msgstr "%s %s är inte en incheckning!"
@@ -226,32 +317,7 @@ msgstr ""
 "Hittade fel i konfigurationsvariabeln \"diff.dirstat\":\n"
 "%s"
 
-#: diff.c:1400
-msgid " 0 files changed\n"
-msgstr " 0 filer ändrade\n"
-
-#: diff.c:1404
-#, c-format
-msgid " %d file changed"
-msgid_plural " %d files changed"
-msgstr[0] " %d fil ändrad"
-msgstr[1] " %d filer ändrade"
-
-#: diff.c:1421
-#, c-format
-msgid ", %d insertion(+)"
-msgid_plural ", %d insertions(+)"
-msgstr[0] ", %d tillägg(+)"
-msgstr[1] ", %d tillägg(+)"
-
-#: diff.c:1432
-#, c-format
-msgid ", %d deletion(-)"
-msgid_plural ", %d deletions(-)"
-msgstr[0] ", %d borttagning(-)"
-msgstr[1] ", %d borttagningar(-)"
-
-#: diff.c:3478
+#: diff.c:3458
 #, c-format
 msgid ""
 "Failed to parse --dirstat/-X option parameter:\n"
@@ -272,31 +338,31 @@ msgstr "gpg godtog inte data"
 msgid "gpg failed to sign the data"
 msgstr "gpg misslyckades signera data"
 
-#: grep.c:1320
+#: grep.c:1441
 #, c-format
 msgid "'%s': unable to read %s"
 msgstr "\"%s\" kunde inte läsa %s"
 
-#: grep.c:1337
+#: grep.c:1458
 #, c-format
 msgid "'%s': %s"
 msgstr "\"%s\": %s"
 
-#: grep.c:1348
+#: grep.c:1469
 #, c-format
 msgid "'%s': short read %s"
 msgstr "\"%s\": kort läsning %s"
 
-#: help.c:207
+#: help.c:212
 #, c-format
 msgid "available git commands in '%s'"
 msgstr "git-kommandon tillgängliga i \"%s\""
 
-#: help.c:214
+#: help.c:219
 msgid "git commands available from elsewhere on your $PATH"
 msgstr "git-kommandon från andra platser i din $PATH"
 
-#: help.c:270
+#: help.c:275
 #, c-format
 msgid ""
 "'%s' appears to be a git command, but we were not\n"
@@ -305,11 +371,11 @@ msgstr ""
 "\"%s\" verkar vara ett git-kommando, men vi kan inte\n"
 "köra det. Kanske git-%s är trasigt?"
 
-#: help.c:327
+#: help.c:332
 msgid "Uh oh. Your system reports no Git commands at all."
 msgstr "Oj då. Ditt system rapporterar inga Git-kommandon alls."
 
-#: help.c:349
+#: help.c:354
 #, c-format
 msgid ""
 "WARNING: You called a Git command named '%s', which does not exist.\n"
@@ -318,17 +384,17 @@ msgstr ""
 "VARNING: Du anropade ett Git-kommando vid namn \"%s\", som inte finns.\n"
 "Fortsätter under förutsättningen att du menade \"%s\""
 
-#: help.c:354
+#: help.c:359
 #, c-format
 msgid "in %0.1f seconds automatically..."
 msgstr "automatiskt om %0.1f sekunder..."
 
-#: help.c:361
+#: help.c:366
 #, c-format
 msgid "git: '%s' is not a git command. See 'git --help'."
 msgstr "git: \"%s\" är inte ett git-kommando. Se \"git --help\"."
 
-#: help.c:365
+#: help.c:370
 msgid ""
 "\n"
 "Did you mean this?"
@@ -342,35 +408,289 @@ msgstr[1] ""
 "\n"
 "Menade du ett av dessa?"
 
-#: parse-options.c:493
+#: merge-recursive.c:190
+#, c-format
+msgid "(bad commit)\n"
+msgstr "(felaktig incheckning)\n"
+
+#: merge-recursive.c:206
+#, c-format
+msgid "addinfo_cache failed for path '%s'"
+msgstr "addinfo_cache misslyckades för sökvägen \"%s\""
+
+#: merge-recursive.c:268
+msgid "error building trees"
+msgstr "fel vid byggande av träd"
+
+#: merge-recursive.c:672
+#, c-format
+msgid "failed to create path '%s'%s"
+msgstr "misslyckades skapa sökvägen \"%s\"%s"
+
+#: merge-recursive.c:683
+#, c-format
+msgid "Removing %s to make room for subdirectory\n"
+msgstr "Tar bort %s för att göra plats för underkatalog\n"
+
+#. something else exists
+#. .. but not some other error (who really cares what?)
+#: merge-recursive.c:697 merge-recursive.c:718
+msgid ": perhaps a D/F conflict?"
+msgstr ": kanske en K/F-konflikt?"
+
+#: merge-recursive.c:708
+#, c-format
+msgid "refusing to lose untracked file at '%s'"
+msgstr "vägrar förlora ospårad fil vid \"%s\""
+
+#: merge-recursive.c:748
+#, c-format
+msgid "cannot read object %s '%s'"
+msgstr "kan inte läsa objektet %s: \"%s\""
+
+#: merge-recursive.c:750
+#, c-format
+msgid "blob expected for %s '%s'"
+msgstr "blob förväntades för %s \"%s\""
+
+#: merge-recursive.c:773 builtin/clone.c:302
+#, c-format
+msgid "failed to open '%s'"
+msgstr "misslyckades öppna \"%s\""
+
+#: merge-recursive.c:781
+#, c-format
+msgid "failed to symlink '%s'"
+msgstr "misslyckades ta skapa symboliska länken \"%s\""
+
+#: merge-recursive.c:784
+#, c-format
+msgid "do not know what to do with %06o %s '%s'"
+msgstr "vet inte hur %06o %s \"%s\" skall hanteras"
+
+#: merge-recursive.c:922
+msgid "Failed to execute internal merge"
+msgstr "Misslyckades exekvera intern sammanslagning"
+
+#: merge-recursive.c:926
+#, c-format
+msgid "Unable to add %s to database"
+msgstr "Kunde inte lägga till %s till databasen"
+
+#: merge-recursive.c:942
+msgid "unsupported object type in the tree"
+msgstr "objekttyp som ej stöds upptäcktes i trädet"
+
+#: 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 "
+"in tree."
+msgstr ""
+"KONFLIKT (%s/radera): %s raderad i %s och %s i %s. Versionen %s av %s lämnad "
+"i trädet."
+
+#: 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 "
+"in tree at %s."
+msgstr ""
+"KONFLIKT (%s/radera): %s raderad i %s och %s i %s. Versionen %s av %s lämnad "
+"i trädet vid %s."
+
+#: merge-recursive.c:1081
+msgid "rename"
+msgstr "namnbyte"
+
+#: merge-recursive.c:1081
+msgid "renamed"
+msgstr "namnbytt"
+
+#: merge-recursive.c:1137
+#, c-format
+msgid "%s is a directory in %s adding as %s instead"
+msgstr "%s är en katalog i %s lägger till som %s istället"
+
+#: merge-recursive.c:1159
+#, c-format
+msgid ""
+"CONFLICT (rename/rename): Rename \"%s\"->\"%s\" in branch \"%s\" rename \"%s"
+"\"->\"%s\" in \"%s\"%s"
+msgstr ""
+"KONFLIKT (namnbyte/namnbyte): Namnbyte \"%s\"->\"%s\" på grenen \"%s\" "
+"namnbyte \"%s\"->\"%s\" i \"%s\"%s"
+
+#: merge-recursive.c:1164
+msgid " (left unresolved)"
+msgstr " (lämnad olöst)"
+
+#: merge-recursive.c:1218
+#, c-format
+msgid "CONFLICT (rename/rename): Rename %s->%s in %s. Rename %s->%s in %s"
+msgstr ""
+"KONFLIKT (namnbyte/namnbyte): Namnbyte %s->%s i %s. Namnbyte %s->%s i %s"
+
+#: merge-recursive.c:1248
+#, c-format
+msgid "Renaming %s to %s and %s to %s instead"
+msgstr "Byter namn på %s till %s och %s till %s istället"
+
+#: merge-recursive.c:1447
+#, c-format
+msgid "CONFLICT (rename/add): Rename %s->%s in %s. %s added in %s"
+msgstr "KONFLIKT (namnbyte/tillägg): Namnbyte %s->%s i %s. %s tillagd i %s"
+
+#: merge-recursive.c:1457
+#, c-format
+msgid "Adding merged %s"
+msgstr "Lägger till sammanslagen %s"
+
+#: merge-recursive.c:1462 merge-recursive.c:1660
+#, c-format
+msgid "Adding as %s instead"
+msgstr "Lägger till som %s iställer"
+
+#: merge-recursive.c:1513
+#, c-format
+msgid "cannot read object %s"
+msgstr "kan inte läsa objektet %s"
+
+#: merge-recursive.c:1516
+#, c-format
+msgid "object %s is not a blob"
+msgstr "objektet %s är inte en blob"
+
+#: merge-recursive.c:1564
+msgid "modify"
+msgstr "ändra"
+
+#: merge-recursive.c:1564
+msgid "modified"
+msgstr "ändrad"
+
+#: merge-recursive.c:1574
+msgid "content"
+msgstr "innehåll"
+
+#: merge-recursive.c:1581
+msgid "add/add"
+msgstr "tillägg/tillägg"
+
+#: merge-recursive.c:1615
+#, c-format
+msgid "Skipped %s (merged same as existing)"
+msgstr "Hoppade över %s (sammanslagen samma som befintlig)"
+
+#: merge-recursive.c:1629
+#, c-format
+msgid "Auto-merging %s"
+msgstr "Slår ihop %s automatiskt"
+
+#: merge-recursive.c:1633 git-submodule.sh:869
+msgid "submodule"
+msgstr "undermodul"
+
+#: merge-recursive.c:1634
+#, c-format
+msgid "CONFLICT (%s): Merge conflict in %s"
+msgstr "KONFLIKT (%s): Sammanslagningskonflikt i %s"
+
+#: merge-recursive.c:1724
+#, c-format
+msgid "Removing %s"
+msgstr "Tar bort %s"
+
+#: merge-recursive.c:1749
+msgid "file/directory"
+msgstr "fil/katalog"
+
+#: merge-recursive.c:1755
+msgid "directory/file"
+msgstr "katalog/fil"
+
+#: 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): Det finns en katalog med namnet %s i %s. Lägger till %s som %s"
+
+#: merge-recursive.c:1770
+#, c-format
+msgid "Adding %s"
+msgstr "Lägger till %s"
+
+#: merge-recursive.c:1787
+msgid "Fatal merge failure, shouldn't happen."
+msgstr "Ödesdigert sammanslagningsfel, borde inte inträffa."
+
+#: merge-recursive.c:1806
+msgid "Already up-to-date!"
+msgstr "Redan à jour!"
+
+#: merge-recursive.c:1815
+#, c-format
+msgid "merging of trees %s and %s failed"
+msgstr "sammanslagning av träden %s och %s misslyckades"
+
+#: merge-recursive.c:1845
+#, c-format
+msgid "Unprocessed path??? %s"
+msgstr "Obehandlad sökväg??? %s"
+
+#: merge-recursive.c:1890
+msgid "Merging:"
+msgstr "Slår ihop:"
+
+#: merge-recursive.c:1903
+#, c-format
+msgid "found %u common ancestor:"
+msgid_plural "found %u common ancestors:"
+msgstr[0] "hittade %u gemensam förfader:"
+msgstr[1] "hittade %u gemensamma förfäder:"
+
+#: merge-recursive.c:1940
+msgid "merge returned no commit"
+msgstr "sammanslagningen returnerade ingen incheckning"
+
+#: merge-recursive.c:1997
+#, c-format
+msgid "Could not parse object '%s'"
+msgstr "Kunde inte tolka objektet \"%s\""
+
+#: merge-recursive.c:2009 builtin/merge.c:696
+msgid "Unable to write index."
+msgstr "Kunde inte skriva indexet."
+
+#: parse-options.c:494
 msgid "..."
 msgstr "..."
 
-#: parse-options.c:511
+#: parse-options.c:512
 #, c-format
 msgid "usage: %s"
 msgstr "användning: %s"
 
 #. TRANSLATORS: the colon here should align with the
 #. one in "usage: %s" translation
-#: parse-options.c:515
+#: parse-options.c:516
 #, c-format
 msgid "   or: %s"
 msgstr "     eller: %s"
 
-#: parse-options.c:518
+#: parse-options.c:519
 #, c-format
 msgid "    %s"
 msgstr "    %s"
 
-#: remote.c:1629
+#: remote.c:1632
 #, 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] "Din gren ligger före \"%s\" med %d incheckning.\n"
 msgstr[1] "Din gren ligger före \"%s\" med %d incheckningar.\n"
 
-#: remote.c:1635
+#: remote.c:1638
 #, c-format
 msgid "Your branch is behind '%s' by %d commit, and can be fast-forwarded.\n"
 msgid_plural ""
@@ -380,7 +700,7 @@ msgstr[0] ""
 msgstr[1] ""
 "Din gren ligger efter \"%s\" med %d incheckningar, och kan snabbspolas.\n"
 
-#: remote.c:1643
+#: remote.c:1646
 #, c-format
 msgid ""
 "Your branch and '%s' have diverged,\n"
@@ -395,19 +715,19 @@ msgstr[1] ""
 "Din gren och \"%s\" har divergerat,\n"
 "och har %d respektive %d olika incheckningar.\n"
 
-#: sequencer.c:121 builtin/merge.c:865 builtin/merge.c:978
-#: builtin/merge.c:1088 builtin/merge.c:1098
+#: sequencer.c:123 builtin/merge.c:864 builtin/merge.c:977
+#: builtin/merge.c:1087 builtin/merge.c:1097
 #, c-format
 msgid "Could not open '%s' for writing"
 msgstr "Kunde inte öppna \"%s\" för skrivning"
 
-#: sequencer.c:123 builtin/merge.c:333 builtin/merge.c:868
-#: builtin/merge.c:1090 builtin/merge.c:1103
+#: sequencer.c:125 builtin/merge.c:333 builtin/merge.c:867
+#: builtin/merge.c:1089 builtin/merge.c:1102
 #, c-format
 msgid "Could not write to '%s'"
 msgstr "Kunde inte skriva till \"%s\""
 
-#: sequencer.c:144
+#: sequencer.c:146
 msgid ""
 "after resolving the conflicts, mark the corrected paths\n"
 "with 'git add <paths>' or 'git rm <paths>'"
@@ -415,7 +735,7 @@ msgstr ""
 "efter att ha löst konflikterna, markera de rättade sökvägarna\n"
 "med \"git add <sökvägar>\" eller \"git rm <sökvägar>\""
 
-#: 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"
@@ -425,488 +745,610 @@ msgstr ""
 "med \"git add <sökvägar>\" eller \"git rm <sökvägar>\"\n"
 "och checka in resultatet med \"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 "Kunde inte skriva till %s"
 
-#: sequencer.c:163
+#: sequencer.c:165
 #, c-format
 msgid "Error wrapping up %s"
 msgstr "Fel vid ombrytning av %s"
 
-#: sequencer.c:178
+#: sequencer.c:180
 msgid "Your local changes would be overwritten by cherry-pick."
 msgstr "Dina lokala ändringar skulle skrivas över av \"cherry-pick\"."
 
-#: sequencer.c:180
+#: sequencer.c:182
 msgid "Your local changes would be overwritten by revert."
 msgstr "Dina lokala ändringar skulle skrivas över av \"revert\"."
 
-#: sequencer.c:183
+#: sequencer.c:185
 msgid "Commit your changes or stash them to proceed."
 msgstr "Checka in dina ändringar eller använd \"stash\" för att fortsätta."
 
 #. 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: Kunde inte skriva ny indexfil"
 
-#: sequencer.c:261
+#: sequencer.c:266
 msgid "Could not resolve HEAD commit\n"
 msgstr "Kunde inte bestämma HEAD:s incheckning\n"
 
-#: sequencer.c:282
+#: sequencer.c:287
 msgid "Unable to update cache tree\n"
 msgstr "Kan inte uppdatera cacheträd\n"
 
-#: sequencer.c:324
+#: sequencer.c:332
 #, c-format
 msgid "Could not parse commit %s\n"
 msgstr "Kunde inte tolka incheckningen %s\n"
 
-#: sequencer.c:329
+#: sequencer.c:337
 #, c-format
 msgid "Could not parse parent commit %s\n"
 msgstr "Kunde inte tolka föräldraincheckningen %s\n"
 
-#: sequencer.c:395
+#: sequencer.c:403
 msgid "Your index file is unmerged."
 msgstr "Din indexfil har inte slagits ihop."
 
-#: sequencer.c:398
+#: sequencer.c:406
 msgid "You do not have a valid HEAD"
 msgstr "Du har ingen giltig HEAD"
 
-#: sequencer.c:413
+#: sequencer.c:421
 #, c-format
 msgid "Commit %s is a merge but no -m option was given."
 msgstr "Incheckning %s är en sammanslagning, men flaggan -m angavs inte."
 
-#: sequencer.c:421
+#: sequencer.c:429
 #, c-format
 msgid "Commit %s does not have parent %d"
 msgstr "Incheckning %s har inte förälder %d"
 
-#: sequencer.c:425
+#: sequencer.c:433
 #, c-format
 msgid "Mainline was specified but commit %s is not a merge."
 msgstr "Huvudlinje angavs, men incheckningen %s är inte en sammanslagning"
 
 #. 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: kan inte tolka föräldraincheckningen %s"
 
-#: sequencer.c:440
+#: sequencer.c:448
 #, c-format
 msgid "Cannot get commit message for %s"
 msgstr "Kan inte hämta incheckningsmeddelande för %s"
 
-#: sequencer.c:524
+#: sequencer.c:532
 #, c-format
 msgid "could not revert %s... %s"
 msgstr "kunde inte ångra %s... %s"
 
-#: sequencer.c:525
+#: sequencer.c:533
 #, c-format
 msgid "could not apply %s... %s"
 msgstr "kunde inte tillämpa %s... %s"
 
-#: sequencer.c:553
+#: sequencer.c:565
 msgid "empty commit set passed"
 msgstr "den angivna uppsättningen incheckningar är tom"
 
-#: sequencer.c:561
+#: sequencer.c:573
 #, c-format
 msgid "git %s: failed to read the index"
 msgstr "git %s: misslyckades läsa indexet"
 
-#: sequencer.c:566
+#: sequencer.c:578
 #, c-format
 msgid "git %s: failed to refresh the index"
 msgstr "git %s: misslyckades uppdatera indexet"
 
-#: sequencer.c:624
+#: sequencer.c:636
 #, c-format
 msgid "Cannot %s during a %s"
 msgstr "kan inte %s under en %s"
 
-#: sequencer.c:646
+#: sequencer.c:658
 #, c-format
 msgid "Could not parse line %d."
 msgstr "Kan inte tolka rad %d."
 
-#: sequencer.c:651
+#: sequencer.c:663
 msgid "No commits parsed."
 msgstr "Inga incheckningar lästes."
 
-#: sequencer.c:664
+#: sequencer.c:676
 #, c-format
 msgid "Could not open %s"
 msgstr "Kunde inte öppna %s"
 
-#: sequencer.c:668
+#: sequencer.c:680
 #, c-format
 msgid "Could not read %s."
 msgstr "kunde inte läsa %s."
 
-#: sequencer.c:675
+#: sequencer.c:687
 #, c-format
 msgid "Unusable instruction sheet: %s"
 msgstr "Oanvändbart manus: %s"
 
-#: sequencer.c:703
+#: sequencer.c:715
 #, c-format
 msgid "Invalid key: %s"
 msgstr "Felaktig nyckel: %s"
 
-#: sequencer.c:706
+#: sequencer.c:718
 #, c-format
 msgid "Invalid value for %s: %s"
 msgstr "Felaktigt värde för %s: %s"
 
-#: sequencer.c:718
+#: sequencer.c:730
 #, c-format
 msgid "Malformed options sheet: %s"
 msgstr "Trasigt manus: %s"
 
-#: sequencer.c:739
+#: sequencer.c:751
 msgid "a cherry-pick or revert is already in progress"
 msgstr "en \"cherry-pick\" eller \"revert\" pågår redan"
 
-#: sequencer.c:740
+#: sequencer.c:752
 msgid "try \"git cherry-pick (--continue | --quit | --abort)\""
 msgstr "testa \"git cherry-pick (--continue | --quit | --abort)\""
 
-#: sequencer.c:744
+#: sequencer.c:756
 #, c-format
 msgid "Could not create sequencer directory %s"
 msgstr "Kunde inte skapa \"sequencer\"-katalogen \"%s\""
 
-#: sequencer.c:760 sequencer.c:845
+#: sequencer.c:772 sequencer.c:857
 #, c-format
 msgid "Error wrapping up %s."
 msgstr "Fel vid ombrytning av %s."
 
-#: sequencer.c:779 sequencer.c:913
+#: sequencer.c:791 sequencer.c:925
 msgid "no cherry-pick or revert in progress"
 msgstr "ingen \"cherry-pick\" eller \"revert\" pågår"
 
-#: sequencer.c:781
+#: sequencer.c:793
 msgid "cannot resolve HEAD"
 msgstr "kan inte bestämma HEAD"
 
-#: sequencer.c:783
+#: sequencer.c:795
 msgid "cannot abort from a branch yet to be born"
 msgstr "kan inte avbryta från en gren som ännu inte är född"
 
-#: sequencer.c:805 builtin/apply.c:3697
+#: sequencer.c:817 builtin/apply.c:4005
 #, c-format
 msgid "cannot open %s: %s"
 msgstr "kan inte öppna %s: %s"
 
-#: sequencer.c:808
+#: sequencer.c:820
 #, c-format
 msgid "cannot read %s: %s"
 msgstr "kan inte läsa %s: %s"
 
-#: sequencer.c:809
+#: sequencer.c:821
 msgid "unexpected end of file"
 msgstr "oväntat filslut"
 
-#: sequencer.c:815
+#: sequencer.c:827
 #, c-format
 msgid "stored pre-cherry-pick HEAD file '%s' is corrupt"
 msgstr "sparad HEAD-fil från före \"cherry-pick\", \"%s\", är trasig"
 
-#: sequencer.c:838
+#: sequencer.c:850
 #, c-format
 msgid "Could not format %s."
 msgstr "Kunde inte formatera %s."
 
-#: sequencer.c:1000
+#: sequencer.c:1012
 msgid "Can't revert as initial commit"
 msgstr "Kan inte ångra som första incheckning"
 
-#: sequencer.c:1001
+#: sequencer.c:1013
 msgid "Can't cherry-pick into empty head"
 msgstr "Kan inte göra \"cherry-pick\" i ett tomt huvud"
 
-#: sha1_name.c:864
+#: sha1_name.c:1044
 msgid "HEAD does not point to a branch"
 msgstr "HEAD pekar inte på en gren"
 
-#: sha1_name.c:867
+#: sha1_name.c:1047
 #, c-format
 msgid "No such branch: '%s'"
 msgstr "Okänd gren: \"%s\""
 
-#: sha1_name.c:869
+#: sha1_name.c:1049
 #, c-format
 msgid "No upstream configured for branch '%s'"
 msgstr "Ingen standarduppström angiven för grenen \"%s\""
 
-#: sha1_name.c:872
+#: sha1_name.c:1052
 #, c-format
 msgid "Upstream branch '%s' not stored as a remote-tracking branch"
 msgstr "Uppströmsgrenen \"%s\" är inte lagrad som en fjärrspårande gren"
 
-#: wrapper.c:413
+#: wrapper.c:408
+#, c-format
+msgid "unable to access '%s': %s"
+msgstr "kan inte komma åt \"%s\": %s"
+
+#: wrapper.c:426
 #, c-format
 msgid "unable to look up current user in the passwd file: %s"
 msgstr "kan inte slå upp aktuell användare i passwd-filen: %s"
 
-#: wrapper.c:414
+#: wrapper.c:427
 msgid "no such user"
 msgstr "okänd användare"
 
-#: wt-status.c:135
+#: wt-status.c:140
 msgid "Unmerged paths:"
 msgstr "Ej sammanslagna sökvägar:"
 
-#: wt-status.c:141 wt-status.c:158
+#: wt-status.c:167 wt-status.c:194
 #, c-format
 msgid "  (use \"git reset %s <file>...\" to unstage)"
 msgstr "  (använd \"git reset %s <fil>...\" för att ta bort från kö)"
 
-#: wt-status.c:143 wt-status.c:160
+#: wt-status.c:169 wt-status.c:196
 msgid "  (use \"git rm --cached <file>...\" to unstage)"
 msgstr "  (använd \"git rm --cached <fil>...\" för att ta bort från kö)"
 
-#: wt-status.c:144
+#: wt-status.c:173
+msgid "  (use \"git add <file>...\" to mark resolution)"
+msgstr "  (använd \"git add <fil>...\" för att ange lösning)"
+
+#: wt-status.c:175 wt-status.c:179
 msgid "  (use \"git add/rm <file>...\" as appropriate to mark resolution)"
 msgstr "  (använd \"git add/rm <fil>...\" som lämpligt för att ange lösning)"
 
-#: wt-status.c:152
+#: wt-status.c:177
+msgid "  (use \"git rm <file>...\" to mark resolution)"
+msgstr "  (använd \"git rm <fil>...\" för att ange lösning)"
+
+#: wt-status.c:188
 msgid "Changes to be committed:"
 msgstr "Ändringar att checka in:"
 
-#: wt-status.c:170
+#: wt-status.c:206
 msgid "Changes not staged for commit:"
 msgstr "Ändringar ej i incheckningskön:"
 
-#: wt-status.c:174
+#: wt-status.c:210
 msgid "  (use \"git add <file>...\" to update what will be committed)"
 msgstr ""
 "  (använd \"git add <fil>...\" för att uppdatera vad som skall checkas in)"
 
-#: wt-status.c:176
+#: wt-status.c:212
 msgid "  (use \"git add/rm <file>...\" to update what will be committed)"
 msgstr ""
 "  (använd \"git add/rm <fil>...\" för att uppdatera vad som skall checkas in)"
 
-#: wt-status.c:177
+#: wt-status.c:213
 msgid ""
 "  (use \"git checkout -- <file>...\" to discard changes in working directory)"
 msgstr ""
 "  (använd \"git checkout -- <fil>...\" för att förkasta ändringar i "
 "arbetskatalogen)"
 
-#: wt-status.c:179
+#: wt-status.c:215
 msgid "  (commit or discard the untracked or modified content in submodules)"
 msgstr ""
 "  (checka in eller förkasta ospårat eller ändrat innehåll i undermoduler)"
 
-# %s är ett verb ("Untracked"/"Ignored"); lägg till ett -e.
-#: wt-status.c:188
-#, c-format
-msgid "%s files:"
-msgstr "%se filer:"
-
-#: wt-status.c:191
+#: wt-status.c:227
 #, c-format
 msgid "  (use \"git %s <file>...\" to include in what will be committed)"
 msgstr ""
-"  (använd \"git %s <fil>...\" för att ta med i vad som skall checkas in)"
+"  (använd \"git %s <fil>...\" för att ta med i det som skall checkas in)"
 
-#: wt-status.c:208
+#: wt-status.c:244
 msgid "bug"
 msgstr "programfel"
 
-#: wt-status.c:213
+#: wt-status.c:249
 msgid "both deleted:"
 msgstr "borttaget av bägge:"
 
-#: wt-status.c:214
+#: wt-status.c:250
 msgid "added by us:"
 msgstr "tillagt av oss:"
 
-#: wt-status.c:215
+#: wt-status.c:251
 msgid "deleted by them:"
 msgstr "borttaget av dem:"
 
-#: wt-status.c:216
+#: wt-status.c:252
 msgid "added by them:"
 msgstr "tillagt av dem:"
 
-#: wt-status.c:217
+#: wt-status.c:253
 msgid "deleted by us:"
 msgstr "borttaget av oss:"
 
-#: wt-status.c:218
+#: wt-status.c:254
 msgid "both added:"
 msgstr "tillagt av bägge:"
 
-#: wt-status.c:219
+#: wt-status.c:255
 msgid "both modified:"
 msgstr "ändrat av bägge:"
 
-#: wt-status.c:249
+#: wt-status.c:285
 msgid "new commits, "
 msgstr "nya incheckningar, "
 
-#: wt-status.c:251
+#: wt-status.c:287
 msgid "modified content, "
 msgstr "ändrat innehåll, "
 
-#: wt-status.c:253
+#: wt-status.c:289
 msgid "untracked content, "
 msgstr "ospårat innehåll, "
 
-#: wt-status.c:267
+#: wt-status.c:303
 #, c-format
 msgid "new file:   %s"
 msgstr "ny fil:     %s"
 
-#: wt-status.c:270
+#: wt-status.c:306
 #, c-format
 msgid "copied:     %s -> %s"
 msgstr "kopierad:   %s -> %s"
 
-#: wt-status.c:273
+#: wt-status.c:309
 #, c-format
 msgid "deleted:    %s"
 msgstr "borttagen:  %s"
 
-#: wt-status.c:276
+#: wt-status.c:312
 #, c-format
 msgid "modified:   %s"
 msgstr "ändrad:     %s"
 
-#: wt-status.c:279
+#: wt-status.c:315
 #, c-format
 msgid "renamed:    %s -> %s"
 msgstr "namnbyte:   %s -> %s"
 
-#: wt-status.c:282
+#: wt-status.c:318
 #, c-format
 msgid "typechange: %s"
 msgstr "typbyte:    %s"
 
-#: wt-status.c:285
+#: wt-status.c:321
 #, c-format
 msgid "unknown:    %s"
 msgstr "okänd:      %s"
 
-#: wt-status.c:288
+#: wt-status.c:324
 #, c-format
 msgid "unmerged:   %s"
 msgstr "osammansl.: %s"
 
-#: wt-status.c:291
+#: wt-status.c:327
 #, c-format
 msgid "bug: unhandled diff status %c"
 msgstr "programfel: diff-status %c ej hanterad"
 
-#: wt-status.c:737
+#: wt-status.c:785
+msgid "You have unmerged paths."
+msgstr "Du har ej sammanslagna sökvägar."
+
+#: wt-status.c:788 wt-status.c:912
+msgid "  (fix conflicts and run \"git commit\")"
+msgstr "  (rätta konflikter och kör \"git commit\")"
+
+#: wt-status.c:791
+msgid "All conflicts fixed but you are still merging."
+msgstr "Alla konflikter har rättats men du är fortfarande i en sammanslagning."
+
+#: wt-status.c:794
+msgid "  (use \"git commit\" to conclude merge)"
+msgstr "  (använd \"git commit\" för att slutföra sammanslagningen)"
+
+#: wt-status.c:804
+msgid "You are in the middle of an am session."
+msgstr "Du är i mitten av en körning av \"git am\"."
+
+#: wt-status.c:807
+msgid "The current patch is empty."
+msgstr "Aktuell patch är tom."
+
+#: wt-status.c:811
+msgid "  (fix conflicts and then run \"git am --resolved\")"
+msgstr "  (rätta konflikter och kör sedan \"git am --resolved\")"
+
+#: wt-status.c:813
+msgid "  (use \"git am --skip\" to skip this patch)"
+msgstr "  (använd \"git am --skip\" för att hoppa över patchen)"
+
+#: wt-status.c:815
+msgid "  (use \"git am --abort\" to restore the original branch)"
+msgstr "  (använd \"git am --abort\" för att återställa ursprungsgrenen)"
+
+#: wt-status.c:873 wt-status.c:883
+msgid "You are currently rebasing."
+msgstr "Du håller på med en ombasering."
+
+#: wt-status.c:876
+msgid "  (fix conflicts and then run \"git rebase --continue\")"
+msgstr "  (rätta konflikter och kör sedan \"git rebase --continue\")"
+
+#: wt-status.c:878
+msgid "  (use \"git rebase --skip\" to skip this patch)"
+msgstr "  (använd \"git rebase --skip\" för att hoppa över patchen)"
+
+#: wt-status.c:880
+msgid "  (use \"git rebase --abort\" to check out the original branch)"
+msgstr "  (använd \"git rebase --abort\" för att checka ut ursprungsgrenen)"
+
+#: wt-status.c:886
+msgid "  (all conflicts fixed: run \"git rebase --continue\")"
+msgstr "  (alla konflikter rättade: kör \"git rebase --continue\")"
+
+#: wt-status.c:888
+msgid "You are currently splitting a commit during a rebase."
+msgstr "Du håller på att dela upp en incheckning i en ombasering."
+
+#: wt-status.c:891
+msgid "  (Once your working directory is clean, run \"git rebase --continue\")"
+msgstr "  (Så fort din arbetskatalog är ren, kör \"git rebase --continue\")"
+
+#: wt-status.c:893
+msgid "You are currently editing a commit during a rebase."
+msgstr "Du håller på att redigera en incheckning under en ombasering."
+
+#: wt-status.c:896
+msgid "  (use \"git commit --amend\" to amend the current commit)"
+msgstr ""
+"  (använd \"git commit --amend\" för att lägga till på aktuell incheckning)"
+
+#: wt-status.c:898
+msgid ""
+"  (use \"git rebase --continue\" once you are satisfied with your changes)"
+msgstr "  (använd \"git rebase --continue\" när du är nöjd med dina ändringar)"
+
+#: wt-status.c:908
+msgid "You are currently cherry-picking."
+msgstr "Du håller på med en \"cherry-pick\"."
+
+#: wt-status.c:915
+msgid "  (all conflicts fixed: run \"git commit\")"
+msgstr "  (alla konflikter har rättats: kör \"git commit\")"
+
+#: wt-status.c:924
+msgid "You are currently bisecting."
+msgstr "Du håller på med en \"bisect\"."
+
+#: wt-status.c:927
+msgid "  (use \"git bisect reset\" to get back to the original branch)"
+msgstr ""
+"  (använd \"git bisect reset\" för att komma tillbaka till ursprungsgrenen)"
+
+#: wt-status.c:978
 msgid "On branch "
 msgstr "På grenen "
 
-#: wt-status.c:744
+#: wt-status.c:985
 msgid "Not currently on any branch."
 msgstr "Inte på någon gren för närvarande."
 
-#: wt-status.c:755
+#: wt-status.c:997
 msgid "Initial commit"
 msgstr "Första incheckning"
 
-#: wt-status.c:769
-msgid "Untracked"
-msgstr "Ospårad"
+#: wt-status.c:1011
+msgid "Untracked files"
+msgstr "Ospårade filer"
 
-#: wt-status.c:771
-msgid "Ignored"
-msgstr "Ignorerad"
+#: wt-status.c:1013
+msgid "Ignored files"
+msgstr "Ignorerade filer"
 
 # %s är nästa sträng eller tom.
-#: wt-status.c:773
+#: wt-status.c:1015
 #, c-format
 msgid "Untracked files not listed%s"
 msgstr "Ospårade filer visas ej%s"
 
-#: wt-status.c:775
+#: wt-status.c:1017
 msgid " (use -u option to show untracked files)"
 msgstr " (använd flaggan -u för att visa ospårade filer)"
 
-#: wt-status.c:781
+#: wt-status.c:1023
 msgid "No changes"
 msgstr "Inga ändringar"
 
-#: wt-status.c:785
+#: wt-status.c:1028
 #, c-format
-msgid "no changes added to commit%s\n"
-msgstr "inga ändringar att checka in%s\n"
+msgid "no changes added to commit (use \"git add\" and/or \"git commit -a\")\n"
+msgstr ""
+"inga ändringar att checka in (använd \"git add\" och/eller \"git commit -a"
+"\")\n"
 
-#: wt-status.c:787
-msgid " (use \"git add\" and/or \"git commit -a\")"
-msgstr " (använd \"git add\" och/eller \"git commit -a\")"
+#: wt-status.c:1031
+#, c-format
+msgid "no changes added to commit\n"
+msgstr "inga ändringar att checka in\n"
 
-#: wt-status.c:789
+#: wt-status.c:1034
 #, c-format
-msgid "nothing added to commit but untracked files present%s\n"
-msgstr "inget köat för incheckning, men ospårade filer finns%s\n"
+msgid ""
+"nothing added to commit but untracked files present (use \"git add\" to "
+"track)\n"
+msgstr ""
+"inget köat för incheckning, men ospårade filer finns (spåra med \"git add"
+"\")\n"
 
-#: wt-status.c:791
-msgid " (use \"git add\" to track)"
-msgstr " (använd \"git add\" för att spåra)"
+#: wt-status.c:1037
+#, c-format
+msgid "nothing added to commit but untracked files present\n"
+msgstr "inget köat för incheckning, men ospårade filer finns\n"
 
-#: wt-status.c:793 wt-status.c:796 wt-status.c:799
+#: wt-status.c:1040
 #, c-format
-msgid "nothing to commit%s\n"
-msgstr "inget att checka in%s\n"
+msgid "nothing to commit (create/copy files and use \"git add\" to track)\n"
+msgstr "inget att checka in (skapa/kopiera filer och spåra med \"git add\")\n"
 
-#: wt-status.c:794
-msgid " (create/copy files and use \"git add\" to track)"
-msgstr " (skapa/kopiera filer och använd \"git add\" för att spåra)"
+#: wt-status.c:1043 wt-status.c:1048
+#, c-format
+msgid "nothing to commit\n"
+msgstr "inget att checka in\n"
 
-#: wt-status.c:797
-msgid " (use -u to show untracked files)"
-msgstr " (använd -u för att visa ospårade filer)"
+#: wt-status.c:1046
+#, c-format
+msgid "nothing to commit (use -u to show untracked files)\n"
+msgstr "inget att checka in (använd -u för att visa ospårade filer)\n"
 
-#: wt-status.c:800
-msgid " (working directory clean)"
-msgstr " (arbetskatalogen ren)"
+#: wt-status.c:1050
+#, c-format
+msgid "nothing to commit, working directory clean\n"
+msgstr "inget att checka in, arbetskatalogen ren\n"
 
-#: wt-status.c:908
+#: wt-status.c:1158
 msgid "HEAD (no branch)"
 msgstr "HEAD (ingen gren)"
 
-#: wt-status.c:914
+#: wt-status.c:1164
 msgid "Initial commit on "
 msgstr "Första incheckning på "
 
-#: wt-status.c:929
+#: wt-status.c:1179
 msgid "behind "
 msgstr "efter "
 
-#: wt-status.c:932 wt-status.c:935
+#: wt-status.c:1182 wt-status.c:1185
 msgid "ahead "
 msgstr "före "
 
-#: wt-status.c:937
+#: wt-status.c:1187
 msgid ", behind "
 msgstr ", efter "
 
+#: compat/precompose_utf8.c:58 builtin/clone.c:341
+#, c-format
+msgid "failed to unlink '%s'"
+msgstr "misslyckades ta bort länken \"%s\""
+
+#: builtin/add.c:19
+msgid "git add [options] [--] <filepattern>..."
+msgstr "git add [flaggor] [--] <filmönster>..."
+
 #: builtin/add.c:62
 #, c-format
 msgid "unexpected diff status %c"
 msgstr "diff-status %c förväntades inte"
 
-#: builtin/add.c:67 builtin/commit.c:226
+#: builtin/add.c:67 builtin/commit.c:230
 msgid "updating files failed"
 msgstr "misslyckades uppdatera filer"
 
@@ -924,7 +1366,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:456 builtin/rm.c:186
+#: builtin/add.c:195 builtin/add.c:460 builtin/rm.c:186
 #, c-format
 msgid "pathspec '%s' did not match any files"
 msgstr "sökvägsangivelsen \"%s\" motsvarade inte några filer"
@@ -961,110 +1403,162 @@ msgstr "Tom patch. Avbryter."
 msgid "Could not apply '%s'"
 msgstr "Kunde inte tillämpa \"%s\""
 
-#: builtin/add.c:312
+#: builtin/add.c:313
 msgid "The following paths are ignored by one of your .gitignore files:\n"
 msgstr "Följande sökvägar ignoreras av en av dina .gitignore-filer:\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:133
+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/mv.c:62 builtin/read-tree.c:112
+msgid "be verbose"
+msgstr "var pratsam"
+
+#: builtin/add.c:322
+msgid "interactive picking"
+msgstr "plocka interaktivt"
+
+#: builtin/add.c:323 builtin/checkout.c:1028 builtin/reset.c:248
+msgid "select hunks interactively"
+msgstr "välj stycken interaktivt"
+
+#: builtin/add.c:324
+msgid "edit current diff and apply"
+msgstr "redigera aktuell diff och applicera"
+
+#: builtin/add.c:325
+msgid "allow adding otherwise ignored files"
+msgstr "tillåt lägga till annars ignorerade filer"
+
+#: builtin/add.c:326
+msgid "update tracked files"
+msgstr "uppdatera spårade filer"
+
+#: builtin/add.c:327
+msgid "record only the fact that the path will be added later"
+msgstr "registrera endast att sökvägen kommer läggas till senare"
+
+#: builtin/add.c:328
+msgid "add changes from all tracked and untracked files"
+msgstr "lägg till ändringar från alla spårade och ospårade filer"
+
+#: builtin/add.c:329
+msgid "don't add, only refresh the index"
+msgstr "lägg inte till, uppdatera endast indexet"
+
+#: builtin/add.c:330
+msgid "just skip files which cannot be added because of errors"
+msgstr "hoppa bara över filer som inte kan läggas till på grund av fel"
+
+#: builtin/add.c:331
+msgid "check if - even missing - files are ignored in dry run"
+msgstr "se om - även saknade - filer ignoreras i testkörning"
+
+#: builtin/add.c:353
 #, c-format
 msgid "Use -f if you really want to add them.\n"
 msgstr "Använd -f om du verkligen vill lägga till dem.\n"
 
-#: builtin/add.c:353
+#: builtin/add.c:354
 msgid "no files added"
 msgstr "inga filer har lagts till"
 
-#: builtin/add.c:359
+#: builtin/add.c:360
 msgid "adding files failed"
 msgstr "misslyckades lägga till filer"
 
-#: builtin/add.c:391
+#: builtin/add.c:392
 msgid "-A and -u are mutually incompatible"
 msgstr "-A och -u är ömsesidigt inkompatibla"
 
-#: builtin/add.c:393
+#: builtin/add.c:394
 msgid "Option --ignore-missing can only be used together with --dry-run"
 msgstr "Flaggan --ignore-missing kan endast användas tillsammans med --dry-run"
 
-#: builtin/add.c:413
+#: builtin/add.c:414
 #, c-format
 msgid "Nothing specified, nothing added.\n"
 msgstr "Inget angivet, inget tillagt.\n"
 
-#: builtin/add.c:414
+#: builtin/add.c:415
 #, c-format
 msgid "Maybe you wanted to say 'git add .'?\n"
 msgstr "Kanske menade du att skriva \"git add .\"?\n"
 
-#: builtin/add.c:420 builtin/clean.c:95 builtin/commit.c:286 builtin/mv.c:82
+#: builtin/add.c:421 builtin/clean.c:95 builtin/commit.c:290 builtin/mv.c:82
 #: builtin/rm.c:162
 msgid "index file corrupt"
 msgstr "indexfilen trasig"
 
-#: builtin/add.c:476 builtin/apply.c:4108 builtin/mv.c:229 builtin/rm.c:260
+#: builtin/add.c:481 builtin/apply.c:4450 builtin/mv.c:229 builtin/rm.c:260
 msgid "Unable to write new index file"
 msgstr "Kunde inte skriva ny indexfil"
 
-#: builtin/apply.c:53
+#: builtin/apply.c:57
 msgid "git apply [options] [<patch>...]"
 msgstr "git apply [flaggor] [<patch>...]"
 
-#: builtin/apply.c:106
+#: builtin/apply.c:110
 #, c-format
 msgid "unrecognized whitespace option '%s'"
 msgstr "okänt alternativ för whitespace: \"%s\""
 
-#: builtin/apply.c:121
+#: builtin/apply.c:125
 #, c-format
 msgid "unrecognized whitespace ignore option '%s'"
 msgstr "okänt alternativ för ignore-whitespace: \"%s\""
 
-#: builtin/apply.c:815
+#: builtin/apply.c:823
 #, c-format
 msgid "Cannot prepare timestamp regexp %s"
 msgstr "Kan inte förbereda reguljärt uttryck för tidsstämpeln %s"
 
-#: builtin/apply.c:824
+#: builtin/apply.c:832
 #, c-format
 msgid "regexec returned %d for input: %s"
 msgstr "regexec returnerade %d för indata: %s"
 
-#: builtin/apply.c:905
+#: builtin/apply.c:913
 #, c-format
 msgid "unable to find filename in patch at line %d"
 msgstr "kan inte hitta filnamn i patchen på rad %d"
 
-#: builtin/apply.c:937
+#: builtin/apply.c:945
 #, c-format
 msgid "git apply: bad git-diff - expected /dev/null, got %s on line %d"
 msgstr "git apply: dålig git-diff - förväntade /dev/null, fick %s på rad %d"
 
-#: builtin/apply.c:941
+#: builtin/apply.c:949
 #, c-format
 msgid "git apply: bad git-diff - inconsistent new filename on line %d"
 msgstr "git apply: dålig git-diff - motsägande nytt filnamn på rad %d"
 
-#: builtin/apply.c:942
+#: builtin/apply.c:950
 #, c-format
 msgid "git apply: bad git-diff - inconsistent old filename on line %d"
 msgstr "git apply: dålig git-diff - motsägande gammalt filnamn på rad %d"
 
-#: builtin/apply.c:949
+#: builtin/apply.c:957
 #, c-format
 msgid "git apply: bad git-diff - expected /dev/null on line %d"
 msgstr "git apply: dålig git-diff - förväntade /dev/null på rad %d"
 
-#: builtin/apply.c:1394
+#: builtin/apply.c:1420
 #, c-format
 msgid "recount: unexpected line: %.*s"
 msgstr "recount: förväntade rad: %.*s"
 
-#: builtin/apply.c:1451
+#: builtin/apply.c:1477
 #, c-format
 msgid "patch fragment without header at line %d: %.*s"
 msgstr "patch-fragment utan huvud på rad %d: %.*s"
 
-#: builtin/apply.c:1468
+#: builtin/apply.c:1494
 #, c-format
 msgid ""
 "git diff header lacks filename information when removing %d leading pathname "
@@ -1080,82 +1574,82 @@ msgstr[1] ""
 "sökvägskomponenter\n"
 "tas bort (rad %d)"
 
-#: builtin/apply.c:1628
+#: builtin/apply.c:1654
 msgid "new file depends on old contents"
 msgstr "ny fil beror på gammalt innehåll"
 
-#: builtin/apply.c:1630
+#: builtin/apply.c:1656
 msgid "deleted file still has contents"
 msgstr "borttagen fil har fortfarande innehåll"
 
-#: builtin/apply.c:1656
+#: builtin/apply.c:1682
 #, c-format
 msgid "corrupt patch at line %d"
 msgstr "trasig patch på rad %d"
 
-#: builtin/apply.c:1692
+#: builtin/apply.c:1718
 #, c-format
 msgid "new file %s depends on old contents"
 msgstr "nya filen %s beror på gammalt innehåll"
 
-#: builtin/apply.c:1694
+#: builtin/apply.c:1720
 #, c-format
 msgid "deleted file %s still has contents"
 msgstr "borttagna filen %s har fortfarande innehåll"
 
-#: builtin/apply.c:1697
+#: builtin/apply.c:1723
 #, c-format
 msgid "** warning: file %s becomes empty but is not deleted"
 msgstr "** varning: filen %s blir tom men har inte tagits bort"
 
-#: builtin/apply.c:1843
+#: builtin/apply.c:1869
 #, c-format
 msgid "corrupt binary patch at line %d: %.*s"
 msgstr "trasig binärpatch på rad %d: %.*s"
 
 #. there has to be one hunk (forward hunk)
-#: builtin/apply.c:1872
+#: builtin/apply.c:1898
 #, c-format
 msgid "unrecognized binary patch at line %d"
 msgstr "binärpatchen på rad %d känns inte igen"
 
-#: builtin/apply.c:1958
+#: builtin/apply.c:1984
 #, c-format
 msgid "patch with only garbage at line %d"
 msgstr "patch med bara skräp på rad %d"
 
-#: builtin/apply.c:2048
+#: builtin/apply.c:2074
 #, c-format
 msgid "unable to read symlink %s"
 msgstr "kunde inte läsa symboliska länken %s"
 
-#: builtin/apply.c:2052
+#: builtin/apply.c:2078
 #, c-format
 msgid "unable to open or read %s"
 msgstr "kunde inte öppna eller läsa %s"
 
-#: builtin/apply.c:2123
+#: builtin/apply.c:2149
 msgid "oops"
 msgstr "hoppsan"
 
-#: builtin/apply.c:2645
+#: builtin/apply.c:2671
 #, c-format
 msgid "invalid start of line: '%c'"
 msgstr "felaktig inledning på rad: \"%c\""
 
-#: builtin/apply.c:2763
+#: 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)."
 msgstr[0] "Stycke %d lyckades på %d (offset %d rad)."
 msgstr[1] "Stycke %d lyckades på %d (offset %d rader)."
 
-#: builtin/apply.c:2775
+#: builtin/apply.c:2801
 #, c-format
 msgid "Context reduced to (%ld/%ld) to apply fragment at %d"
 msgstr "Sammanhang reducerat till (%ld/%ld) för att tillämpa fragment vid %d"
 
-#: builtin/apply.c:2781
+#: builtin/apply.c:2807
 #, c-format
 msgid ""
 "while searching for:\n"
@@ -1164,313 +1658,318 @@ msgstr ""
 "vid sökning efter:\n"
 "%.*s"
 
-#: builtin/apply.c:2800
+#: builtin/apply.c:2826
 #, c-format
 msgid "missing binary patch data for '%s'"
 msgstr "saknar binära patchdata för \"%s\""
 
-#: builtin/apply.c:2903
+#: builtin/apply.c:2929
 #, c-format
 msgid "binary patch does not apply to '%s'"
 msgstr "binärpatchen kan inte tillämpas på \"%s\""
 
-#: builtin/apply.c:2909
+#: builtin/apply.c:2935
 #, c-format
 msgid "binary patch to '%s' creates incorrect result (expecting %s, got %s)"
 msgstr "binärpatchen på \"%s\" ger felaktigt resultat (förväntade %s, fick %s)"
 
-#: builtin/apply.c:2930
+#: builtin/apply.c:2956
 #, c-format
 msgid "patch failed: %s:%ld"
 msgstr "patch misslyckades: %s:%ld"
 
-#: builtin/apply.c:3045
+#: builtin/apply.c:3078
 #, c-format
-msgid "patch %s has been renamed/deleted"
-msgstr "patchen %s har ändrat namn/tagits bort"
+msgid "cannot checkout %s"
+msgstr "kan inte checka ut %s"
 
-#: builtin/apply.c:3052 builtin/apply.c:3069
+#: builtin/apply.c:3123 builtin/apply.c:3132 builtin/apply.c:3176
 #, c-format
 msgid "read of %s failed"
 msgstr "misslyckades läsa %s"
 
-#: builtin/apply.c:3084
-msgid "removal patch leaves file contents"
-msgstr "patch för borttagning lämnar kvar filinnehåll"
-
-#: builtin/apply.c:3105
+#: builtin/apply.c:3156 builtin/apply.c:3378
 #, c-format
-msgid "%s: already exists in working directory"
-msgstr "%s: finns redan i arbetskatalogen"
+msgid "path %s has been renamed/deleted"
+msgstr "sökvägen %s har ändrat namn/tagits bort"
 
-#: builtin/apply.c:3143
+#: builtin/apply.c:3237 builtin/apply.c:3392
 #, c-format
-msgid "%s: has been deleted/renamed"
-msgstr "%s: har tagits bort/ändrat namn"
+msgid "%s: does not exist in index"
+msgstr "%s: finns inte i indexet"
 
-#: builtin/apply.c:3148 builtin/apply.c:3179
+#: builtin/apply.c:3241 builtin/apply.c:3384 builtin/apply.c:3406
 #, c-format
 msgid "%s: %s"
 msgstr "%s: %s"
 
-#: builtin/apply.c:3159
-#, c-format
-msgid "%s: does not exist in index"
-msgstr "%s: finns inte i indexet"
-
-#: builtin/apply.c:3173
+#: builtin/apply.c:3246 builtin/apply.c:3400
 #, c-format
 msgid "%s: does not match index"
 msgstr "%s: motsvarar inte indexet"
 
-#: builtin/apply.c:3190
+#: builtin/apply.c:3348
+msgid "removal patch leaves file contents"
+msgstr "patch för borttagning lämnar kvar filinnehåll"
+
+#: builtin/apply.c:3417
 #, c-format
 msgid "%s: wrong type"
 msgstr "%s: fel typ"
 
-#: builtin/apply.c:3192
+#: builtin/apply.c:3419
 #, c-format
 msgid "%s has type %o, expected %o"
 msgstr "%s har typen %o, förväntade %o"
 
-#: builtin/apply.c:3247
+#: builtin/apply.c:3520
 #, c-format
 msgid "%s: already exists in index"
 msgstr "%s: finns redan i indexet"
 
-#: builtin/apply.c:3267
+#: builtin/apply.c:3523
+#, c-format
+msgid "%s: already exists in working directory"
+msgstr "%s: finns redan i arbetskatalogen"
+
+#: builtin/apply.c:3543
 #, c-format
 msgid "new mode (%o) of %s does not match old mode (%o)"
 msgstr "nytt läge (%o) för %s motsvarar inte gammalt läge (%o)"
 
-#: builtin/apply.c:3272
+#: builtin/apply.c:3548
 #, c-format
 msgid "new mode (%o) of %s does not match old mode (%o) of %s"
 msgstr "nytt läge (%o) för %s motsvarar inte gammalt läge (%o) för %s"
 
-#: builtin/apply.c:3280
+#: builtin/apply.c:3556
 #, c-format
 msgid "%s: patch does not apply"
 msgstr "%s: patchen kan inte tillämpas"
 
-#: builtin/apply.c:3293
+#: builtin/apply.c:3569
 #, c-format
 msgid "Checking patch %s..."
 msgstr "Kontrollerar patchen %s..."
 
-#: builtin/apply.c:3348 builtin/checkout.c:212 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 misslyckades för sökvägen \"%s\""
 
-#: builtin/apply.c:3491
+#: builtin/apply.c:3767
 #, c-format
 msgid "unable to remove %s from index"
 msgstr "kan inte ta bort %s från indexet"
 
-#: builtin/apply.c:3518
+#: builtin/apply.c:3795
 #, c-format
 msgid "corrupt patch for subproject %s"
 msgstr "trasig patch för underprojektet %s"
 
-#: builtin/apply.c:3522
+#: builtin/apply.c:3799
 #, c-format
 msgid "unable to stat newly created file '%s'"
 msgstr "kan inte ta status på nyligen skapade filen \"%s\""
 
-#: builtin/apply.c:3527
+#: builtin/apply.c:3804
 #, c-format
 msgid "unable to create backing store for newly created file %s"
 msgstr "kan inte skapa säkerhetsminne för nyligen skapade filen %s"
 
-#: builtin/apply.c:3530
+#: builtin/apply.c:3807 builtin/apply.c:3915
 #, c-format
 msgid "unable to add cache entry for %s"
 msgstr "kan inte lägga till cachepost för %s"
 
-#: builtin/apply.c:3563
+#: builtin/apply.c:3840
 #, c-format
 msgid "closing file '%s'"
 msgstr "stänger filen \"%s\""
 
-#: builtin/apply.c:3612
+#: builtin/apply.c:3889
 #, c-format
 msgid "unable to write file '%s' mode %o"
 msgstr "kan inte skriva filen \"%s\" läge %o"
 
-#: builtin/apply.c:3668
+#: builtin/apply.c:3976
 #, c-format
 msgid "Applied patch %s cleanly."
 msgstr "Tillämpade patchen %s rent."
 
-#: builtin/apply.c:3676
+#: builtin/apply.c:3984
 msgid "internal error"
 msgstr "internt fel"
 
 #. Say this even without --verbose
-#: builtin/apply.c:3679
+#: builtin/apply.c:3987
 #, c-format
 msgid "Applying patch %%s with %d reject..."
 msgid_plural "Applying patch %%s with %d rejects..."
 msgstr[0] "Tillämpade patchen %%s med %d refuserad..."
 msgstr[1] "Tillämpade patchen %%s med %d refuserade..."
 
-#: builtin/apply.c:3689
+#: builtin/apply.c:3997
 #, c-format
 msgid "truncating .rej filename to %.*s.rej"
 msgstr "trunkerar .rej-filnamnet till %.*s.rej"
 
-#: builtin/apply.c:3710
+#: builtin/apply.c:4018
 #, c-format
 msgid "Hunk #%d applied cleanly."
 msgstr "Stycke %d tillämpades rent."
 
-#: builtin/apply.c:3713
+#: builtin/apply.c:4021
 #, c-format
 msgid "Rejected hunk #%d."
 msgstr "Refuserar stycke %d."
 
-#: builtin/apply.c:3844
+#: builtin/apply.c:4171
 msgid "unrecognized input"
 msgstr "indata känns inte igen"
 
-#: builtin/apply.c:3855
+#: builtin/apply.c:4182
 msgid "unable to read index file"
 msgstr "kan inte läsa indexfilen"
 
-#: builtin/apply.c:3970 builtin/apply.c:3973
+#: builtin/apply.c:4301 builtin/apply.c:4304 builtin/clone.c:91
+#: builtin/fetch.c:63
 msgid "path"
 msgstr "sökväg"
 
-#: builtin/apply.c:3971
+#: builtin/apply.c:4302
 msgid "don't apply changes matching the given path"
 msgstr "tillämpa inte ändringar som motsvarar given sökväg"
 
-#: builtin/apply.c:3974
+#: builtin/apply.c:4305
 msgid "apply changes matching the given path"
 msgstr "tillämpa ändringar som motsvarar given sökväg"
 
-#: builtin/apply.c:3976
+#: builtin/apply.c:4307
 msgid "num"
 msgstr "antal"
 
-#: builtin/apply.c:3977
+#: builtin/apply.c:4308
 msgid "remove <num> leading slashes from traditional diff paths"
 msgstr "ta bort <antal> inledande snedstreck från traditionella diff-sökvägar"
 
-#: builtin/apply.c:3980
+#: builtin/apply.c:4311
 msgid "ignore additions made by the patch"
 msgstr "ignorera tillägg gjorda av patchen"
 
-#: builtin/apply.c:3982
+#: builtin/apply.c:4313
 msgid "instead of applying the patch, output diffstat for the input"
 msgstr "istället för att tillämpa patchen, skriv ut diffstat för indata"
 
-#: builtin/apply.c:3986
-msgid "shows number of added and deleted lines in decimal notation"
-msgstr "visar antal tillagda och borttagna rader decimalt"
+#: builtin/apply.c:4317
+msgid "show number of added and deleted lines in decimal notation"
+msgstr "visa antal tillagda och borttagna rader decimalt"
 
-#: builtin/apply.c:3988
+#: builtin/apply.c:4319
 msgid "instead of applying the patch, output a summary for the input"
 msgstr "istället för att tillämpa patchen, skriv ut en summering av indata"
 
-#: builtin/apply.c:3990
+#: builtin/apply.c:4321
 msgid "instead of applying the patch, see if the patch is applicable"
 msgstr "istället för att tillämpa patchen, se om patchen kan tillämpas"
 
-#: builtin/apply.c:3992
+#: builtin/apply.c:4323
 msgid "make sure the patch is applicable to the current index"
 msgstr "se till att patchen kan tillämpas på aktuellt index"
 
-#: builtin/apply.c:3994
+#: builtin/apply.c:4325
 msgid "apply a patch without touching the working tree"
 msgstr "tillämpa en patch utan att röra arbetskatalogen"
 
-#: builtin/apply.c:3996
+#: builtin/apply.c:4327
 msgid "also apply the patch (use with --stat/--summary/--check)"
 msgstr "tillämpa också patchen (använd med --stat/--summary/--check)"
 
-#: builtin/apply.c:3998
+#: builtin/apply.c:4329
+msgid "attempt three-way merge if a patch does not apply"
+msgstr "försök en trevägssammanslagning om patchen inte kan tillämpas"
+
+#: builtin/apply.c:4331
 msgid "build a temporary index based on embedded index information"
 msgstr "bygg ett temporärt index baserat på inbyggd indexinformation"
 
-#: builtin/apply.c:4000
+#: builtin/apply.c:4333 builtin/checkout-index.c:197 builtin/ls-files.c:460
 msgid "paths are separated with NUL character"
 msgstr "sökvägar avdelas med NUL-tecken"
 
-#: builtin/apply.c:4003
+#: builtin/apply.c:4336
 msgid "ensure at least <n> lines of context match"
 msgstr "se till att åtminstone <n> rader sammanhang är lika"
 
-#: builtin/apply.c:4004
+#: builtin/apply.c:4337
 msgid "action"
 msgstr "åtgärd"
 
-#: builtin/apply.c:4005
+#: builtin/apply.c:4338
 msgid "detect new or modified lines that have whitespace errors"
 msgstr "detektera nya eller ändrade rader som har fel i blanktecken"
 
-#: builtin/apply.c:4008 builtin/apply.c:4011
+#: builtin/apply.c:4341 builtin/apply.c:4344
 msgid "ignore changes in whitespace when finding context"
 msgstr "ignorera ändringar i blanktecken för sammanhang"
 
-#: builtin/apply.c:4014
+#: builtin/apply.c:4347
 msgid "apply the patch in reverse"
 msgstr "tillämpa patchen baklänges"
 
-#: builtin/apply.c:4016
+#: builtin/apply.c:4349
 msgid "don't expect at least one line of context"
 msgstr "förvänta inte minst en rad sammanhang"
 
-#: builtin/apply.c:4018
+#: builtin/apply.c:4351
 msgid "leave the rejected hunks in corresponding *.rej files"
 msgstr "lämna refuserade stycken i motsvarande *.rej-filer"
 
-#: builtin/apply.c:4020
+#: builtin/apply.c:4353
 msgid "allow overlapping hunks"
 msgstr "tillåt överlappande stycken"
 
-#: builtin/apply.c:4021
-msgid "be verbose"
-msgstr "var pratsam"
-
-#: builtin/apply.c:4023
+#: builtin/apply.c:4356
 msgid "tolerate incorrectly detected missing new-line at the end of file"
 msgstr "tolerera felaktigt detekterade saknade nyradstecken vid filslut"
 
-#: builtin/apply.c:4026
+#: builtin/apply.c:4359
 msgid "do not trust the line counts in the hunk headers"
 msgstr "lite inte på antalet linjer i styckehuvuden"
 
-#: builtin/apply.c:4028
+#: builtin/apply.c:4361
 msgid "root"
 msgstr "rot"
 
-#: builtin/apply.c:4029
+#: builtin/apply.c:4362
 msgid "prepend <root> to all filenames"
 msgstr "lägg till <rot> i alla filnamn"
 
-#: builtin/apply.c:4050
+#: builtin/apply.c:4384
+msgid "--3way outside a repository"
+msgstr "--3way utanför arkiv"
+
+#: builtin/apply.c:4392
 msgid "--index outside a repository"
 msgstr "--index utanför arkiv"
 
-#: builtin/apply.c:4053
+#: builtin/apply.c:4395
 msgid "--cached outside a repository"
 msgstr "--cached utanför arkiv"
 
-#: builtin/apply.c:4069
+#: builtin/apply.c:4411
 #, c-format
 msgid "can't open patch '%s'"
 msgstr "kan inte öppna patchen \"%s\""
 
-#: builtin/apply.c:4083
+#: builtin/apply.c:4425
 #, c-format
 msgid "squelched %d whitespace error"
 msgid_plural "squelched %d whitespace errors"
 msgstr[0] "undertryckte %d fel i blanksteg"
 msgstr[1] "undertryckte %d fel i blanksteg"
 
-#: builtin/apply.c:4089 builtin/apply.c:4099
+#: builtin/apply.c:4431 builtin/apply.c:4441
 #, c-format
 msgid "%d line adds whitespace errors."
 msgid_plural "%d lines add whitespace errors."
@@ -1512,16 +2011,144 @@ msgstr "git archive: protokollfel"
 msgid "git archive: expected a flush"
 msgstr "git archive: förväntade en tömning (flush)"
 
-#: builtin/branch.c:144
-#, c-format
-msgid ""
-"deleting branch '%s' that has been merged to\n"
+#: 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 "utför 'git bisect next'"
+
+#: builtin/bisect--helper.c:19
+msgid "update BISECT_HEAD instead of checking out the current commit"
+msgstr "uppdatera BISECT_HEAD istället för att checka ut aktuell incheckning"
+
+#: builtin/blame.c:25
+msgid "git blame [options] [rev-opts] [rev] [--] file"
+msgstr "git blame [flaggor] [rev-flaggor] [rev] [--] fil"
+
+#: builtin/blame.c:30 builtin/shortlog.c:15
+msgid "[rev-opts] are documented in git-rev-list(1)"
+msgstr "[rev-flaggor] dokumenteras i git-rev-list(1)"
+
+#: builtin/blame.c:2373
+msgid "Show blame entries as we find them, incrementally"
+msgstr "Visa klandringsposter när vi hittar dem, interaktivt"
+
+#: builtin/blame.c:2374
+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
+msgid "Do not treat root commits as boundaries (Default: off)"
+msgstr "Behandla inte rotincheckningar som gränser (Standard: av)"
+
+#: builtin/blame.c:2376
+msgid "Show work cost statistics"
+msgstr "Visa statistik över arbetskostnad"
+
+#: builtin/blame.c:2377
+msgid "Show output score for blame entries"
+msgstr "Visa utdatapoäng för klandringsposter"
+
+#: builtin/blame.c:2378
+msgid "Show original filename (Default: auto)"
+msgstr "Visa originalfilnamn (Standard: auto)"
+
+#: builtin/blame.c:2379
+msgid "Show original linenumber (Default: off)"
+msgstr "Visa ursprungligt radnummer (Standard: av)"
+
+#: builtin/blame.c:2380
+msgid "Show in a format designed for machine consumption"
+msgstr "Visa i ett format avsett för maskinkonsumtion"
+
+#: builtin/blame.c:2381
+msgid "Show porcelain format with per-line commit information"
+msgstr "Visa porslinsformat med per-rad-incheckningsinformation"
+
+#: builtin/blame.c:2382
+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
+msgid "Show raw timestamp (Default: off)"
+msgstr "Visa rå tidsstämpel (Standard: av)"
+
+#: builtin/blame.c:2384
+msgid "Show long commit SHA1 (Default: off)"
+msgstr "Visa lång inchecknings-SHA1 (Standard: av)"
+
+#: builtin/blame.c:2385
+msgid "Suppress author name and timestamp (Default: off)"
+msgstr "Undertryck författarnamn och tidsstämpel (Standard: av)"
+
+#: builtin/blame.c:2386
+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
+msgid "Ignore whitespace differences"
+msgstr "Ignorera ändringar i blanksteg"
+
+#: builtin/blame.c:2388
+msgid "Spend extra cycles to find better match"
+msgstr "Slösa extra cykler med att hitta bättre träff"
+
+#: builtin/blame.c:2389
+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
+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
+msgid "score"
+msgstr "poäng"
+
+#: builtin/blame.c:2391
+msgid "Find line copies within and across files"
+msgstr "Hitta kopierade rader inuti och mellan filer"
+
+#: builtin/blame.c:2392
+msgid "Find line movements within and across files"
+msgstr "Hitta flyttade rader inuti och mellan filer"
+
+#: builtin/blame.c:2393
+msgid "n,m"
+msgstr "n,m"
+
+#: builtin/blame.c:2393
+msgid "Process only line range n,m, counting from 1"
+msgstr "Behandla endast radintervallet n,m, med början på 1"
+
+#: builtin/branch.c:23
+msgid "git branch [options] [-r | -a] [--merged | --no-merged]"
+msgstr "git branch [flaggor] [-r | -a] [--merged | --no-merged]"
+
+#: builtin/branch.c:24
+msgid "git branch [options] [-l] [-f] <branchname> [<start-point>]"
+msgstr "git branch [flaggor] [-l] [-f] <grennamn> [<startpunkt>]"
+
+#: builtin/branch.c:25
+msgid "git branch [options] [-r] (-d | -D) <branchname>..."
+msgstr "git branch [flaggor] [-r] (-d | -D) <grennamn>..."
+
+#: builtin/branch.c:26
+msgid "git branch [options] (-m | -M) [<oldbranch>] <newbranch>"
+msgstr "git branch [flaggor] (-m | -M) [<gammal_gren>] <ny_gren>"
+
+#: builtin/branch.c:145
+#, c-format
+msgid ""
+"deleting branch '%s' that has been merged to\n"
 "         '%s', but not yet merged to HEAD."
 msgstr ""
 "tar bort grenen \"%s\" som har slagits ihop med\n"
 "         \"%s\", men ännu inte slagits ihop med HEAD."
 
-#: builtin/branch.c:148
+#: builtin/branch.c:149
 #, c-format
 msgid ""
 "not deleting branch '%s' that is not yet merged to\n"
@@ -1530,35 +2157,35 @@ 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:180
+#: builtin/branch.c:181
 msgid "cannot use -a with -d"
 msgstr "kan inte ange -a med -d"
 
-#: builtin/branch.c:186
+#: builtin/branch.c:187
 msgid "Couldn't look up commit object for HEAD"
 msgstr "Kunde inte slå upp incheckningsobjekt för HEAD"
 
-#: builtin/branch.c:191
+#: builtin/branch.c:192
 #, 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:202
+#: builtin/branch.c:203
 #, c-format
 msgid "remote branch '%s' not found."
 msgstr "fjärrgrenen \"%s\" hittades inte."
 
-#: builtin/branch.c:203
+#: builtin/branch.c:204
 #, c-format
 msgid "branch '%s' not found."
 msgstr "grenen \"%s\" hittades inte."
 
-#: builtin/branch.c:210
+#: 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:216
+#: builtin/branch.c:217
 #, c-format
 msgid ""
 "The branch '%s' is not fully merged.\n"
@@ -1567,129 +2194,259 @@ 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:225
+#: builtin/branch.c:226
 #, c-format
 msgid "Error deleting remote branch '%s'"
 msgstr "Fel vid borttagning av fjärrgrenen \"%s\""
 
-#: builtin/branch.c:226
+#: builtin/branch.c:227
 #, c-format
 msgid "Error deleting branch '%s'"
 msgstr "Fel vid borttagning av grenen \"%s\""
 
-#: builtin/branch.c:233
+#: builtin/branch.c:234
 #, c-format
 msgid "Deleted remote branch %s (was %s).\n"
 msgstr "Tog bort fjärrgrenen %s (var %s).\n"
 
-#: builtin/branch.c:234
+#: builtin/branch.c:235
 #, c-format
 msgid "Deleted branch %s (was %s).\n"
 msgstr "Tog bort grenen %s (var %s).\n"
 
-#: builtin/branch.c:239
+#: builtin/branch.c:240
 msgid "Update of config-file failed"
 msgstr "Misslyckades uppdatera konfigurationsfil"
 
-#: builtin/branch.c:337
+#: builtin/branch.c:338
 #, c-format
 msgid "branch '%s' does not point at a commit"
 msgstr "grenen \"%s\" pekar inte på en incheckning"
 
-#: builtin/branch.c:409
+#: builtin/branch.c:410
 #, c-format
 msgid "[%s: behind %d]"
 msgstr "[%s: bakom %d] "
 
-#: builtin/branch.c:411
+#: builtin/branch.c:412
 #, c-format
 msgid "[behind %d]"
 msgstr "[bakom %d] "
 
-#: builtin/branch.c:415
+#: builtin/branch.c:416
 #, c-format
 msgid "[%s: ahead %d]"
 msgstr "[%s: före %d] "
 
-#: builtin/branch.c:417
+#: builtin/branch.c:418
 #, c-format
 msgid "[ahead %d]"
 msgstr "[före %d] "
 
-#: builtin/branch.c:420
+#: builtin/branch.c:421
 #, c-format
 msgid "[%s: ahead %d, behind %d]"
 msgstr "[%s: före %d, bakom %d] "
 
-#: builtin/branch.c:423
+#: builtin/branch.c:424
 #, c-format
 msgid "[ahead %d, behind %d]"
 msgstr "[före %d, bakom %d] "
 
-#: builtin/branch.c:535
+#: builtin/branch.c:537
 msgid "(no branch)"
 msgstr "(ingen gren)"
 
-#: builtin/branch.c:600
+#: builtin/branch.c:602
 msgid "some refs could not be read"
 msgstr "vissa referenser kunde inte läsas"
 
-#: builtin/branch.c:613
+#: builtin/branch.c:615
 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:623
+#: builtin/branch.c:625
 #, c-format
 msgid "Invalid branch name: '%s'"
 msgstr "Felaktigt namn på gren: \"%s\""
 
-#: builtin/branch.c:638
+#: builtin/branch.c:640
 msgid "Branch rename failed"
 msgstr "Misslyckades byta namn på gren"
 
-#: builtin/branch.c:642
+#: builtin/branch.c:644
 #, c-format
 msgid "Renamed a misnamed branch '%s' away"
 msgstr "Bytte bort namn på en felaktigt namngiven gren \"%s\""
 
-#: builtin/branch.c:646
+#: builtin/branch.c:648
 #, 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:653
+#: builtin/branch.c:655
 msgid "Branch is renamed, but update of config-file failed"
 msgstr "Grenen namnbytt, men misslyckades uppdatera konfigurationsfilen"
 
-#: builtin/branch.c:668
+#: builtin/branch.c:670
 #, c-format
 msgid "malformed object name %s"
 msgstr "felformat objektnamn %s"
 
-#: builtin/branch.c:692
+#: builtin/branch.c:694
 #, c-format
 msgid "could not write branch description template: %s"
 msgstr "kunde inte skriva grenbeskrivningsmall: %s"
 
-#: builtin/branch.c:783
+#: builtin/branch.c:724
+msgid "Generic options"
+msgstr "Allmänna flaggor"
+
+#: builtin/branch.c:726
+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
+msgid "suppress informational messages"
+msgstr "undertryck informationsmeddelanden"
+
+#: builtin/branch.c:728
+msgid "set up tracking mode (see git-pull(1))"
+msgstr "ställ in spårningsläge (se git-pull(1))"
+
+#: builtin/branch.c:730
+msgid "change upstream info"
+msgstr "ändra uppströmsinformation"
+
+#: builtin/branch.c:734
+msgid "use colored output"
+msgstr "använd färgad utdata"
+
+#: builtin/branch.c:735
+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
+msgid "commit"
+msgstr "incheckning"
+
+#: builtin/branch.c:739 builtin/branch.c:745
+msgid "print only branches that contain the commit"
+msgstr "visa endast grenar som innehåller incheckningen"
+
+#: builtin/branch.c:751
+msgid "Specific git-branch actions:"
+msgstr "Specifika git-branch-åtgärder:"
+
+#: builtin/branch.c:752
+msgid "list both remote-tracking and local branches"
+msgstr "visa både fjärrspårande och lokala grenar"
+
+#: builtin/branch.c:754
+msgid "delete fully merged branch"
+msgstr "ta bort helt sammanslagen gren"
+
+#: builtin/branch.c:755
+msgid "delete branch (even if not merged)"
+msgstr "ta bort gren (även om inte helt sammanslagen)"
+
+#: builtin/branch.c:756
+msgid "move/rename a branch and its reflog"
+msgstr "flytta/ta bort en gren och dess reflogg"
+
+#: builtin/branch.c:757
+msgid "move/rename a branch, even if target exists"
+msgstr "flytta/ta bort en gren, även om målet finns"
+
+#: builtin/branch.c:758
+msgid "list branch names"
+msgstr "lista namn på grenar"
+
+#: builtin/branch.c:759
+msgid "create the branch's reflog"
+msgstr "skapa grenens reflogg"
+
+#: builtin/branch.c:761
+msgid "edit the description for the branch"
+msgstr "redigera beskrivning för grenen"
+
+#: builtin/branch.c:762
+msgid "force creation (when already exists)"
+msgstr "tvinga skapande (när den redan finns)"
+
+#: builtin/branch.c:765
+msgid "print only not merged branches"
+msgstr "visa endast ej sammanslagna grenar"
+
+#: builtin/branch.c:771
+msgid "print only merged branches"
+msgstr "visa endast sammanslagna grenar"
+
+#: builtin/branch.c:775
+msgid "list branches in columns"
+msgstr "visa grenar i spalter"
+
+#: builtin/branch.c:788
 msgid "Failed to resolve HEAD as a valid ref."
 msgstr "Misslyckades slå upp HEAD som giltig referens"
 
-#: builtin/branch.c:788 builtin/clone.c:558
+#: builtin/branch.c:793 builtin/clone.c:561
 msgid "HEAD not found below refs/heads!"
 msgstr "HEAD hittades inte under refs/heads!"
 
-#: builtin/branch.c:808
+#: builtin/branch.c:813
 msgid "--column and --verbose are incompatible"
 msgstr "--column och --verbose är inkompatibla"
 
-#: builtin/branch.c:857
+#: builtin/branch.c:864
+#, c-format
+msgid "branch '%s' does not exist"
+msgstr "grenen \"%s\" finns inte"
+
+#: builtin/branch.c:876
+#, c-format
+msgid "Branch '%s' has no upstream information"
+msgstr "Grenen \"%s\" har ingen uppströmsinformation"
+
+#: builtin/branch.c:891
 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
+#, c-format
+msgid ""
+"The --set-upstream flag is deprecated and will be removed. Consider using --"
+"track or --set-upstream-to\n"
+msgstr ""
+"Flaggan --set-upstream rekommenderas ej och kommer tas bort. Använd --track "
+"eller --set-upstream-to\n"
+
+#: builtin/branch.c:911
+#, c-format
+msgid ""
+"\n"
+"If you wanted to make '%s' track '%s', do this:\n"
+"\n"
+msgstr ""
+"\n"
+"Om du vill göra så att \"%s\" spårar \"%s\" gör du så här:\n"
+"\n"
+
+#: builtin/branch.c:912
+#, c-format
+msgid "    git branch -d %s\n"
+msgstr "    git branch -d %s\n"
+
+#: builtin/branch.c:913
+#, 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"
@@ -1703,99 +2460,227 @@ msgstr "Behöver ett arkiv för att skapa ett paket (bundle)."
 msgid "Need a repository to unbundle."
 msgstr "Behöver ett arkiv för att packa upp ett paket (bundle)."
 
-#: builtin/checkout.c:113 builtin/checkout.c:146
+#: builtin/cat-file.c:247
+msgid "git cat-file (-t|-s|-e|-p|<type>|--textconv) <object>"
+msgstr "git cat-file (-t|-s|-e|-p|<typ>|--textconv) <objekt>"
+
+#: builtin/cat-file.c:248
+msgid "git cat-file (--batch|--batch-check) < <list_of_objects>"
+msgstr "git cat-file (--batch|--batch-check) < <objektlista>"
+
+#: builtin/cat-file.c:266
+msgid "<type> can be one of: blob, tree, commit, tag"
+msgstr "<typ> kan vara en av: blob, tree, commit, tag"
+
+#: builtin/cat-file.c:267
+msgid "show object type"
+msgstr "visa objekttyp"
+
+#: builtin/cat-file.c:268
+msgid "show object size"
+msgstr "visa objektstorlek"
+
+#: builtin/cat-file.c:270
+msgid "exit with zero when there's no error"
+msgstr "avsluta med noll när det inte uppstått något fel"
+
+#: builtin/cat-file.c:271
+msgid "pretty-print object's content"
+msgstr "visa objektets innehåll snyggt"
+
+#: builtin/cat-file.c:273
+msgid "for blob objects, run textconv on object's content"
+msgstr "för blob-objekt, kör textconv på objektets innehåll"
+
+#: builtin/cat-file.c:275
+msgid "show info and content of objects fed from the standard input"
+msgstr "visa information och innehåll för objekt som listas på standard in"
+
+#: builtin/cat-file.c:278
+msgid "show info about objects fed from the standard input"
+msgstr "visa information för objekt som listas på standard in"
+
+#: builtin/check-attr.c:11
+msgid "git check-attr [-a | --all | attr...] [--] pathname..."
+msgstr "git check-attr [-a | --all | attr...] [--] sökväg..."
+
+#: 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 | attr...] < <sökvägslista>"
+
+#: builtin/check-attr.c:19
+msgid "report all attributes set on file"
+msgstr "visa alla attribut som satts på filen"
+
+#: builtin/check-attr.c:20
+msgid "use .gitattributes only from the index"
+msgstr "använd .gitattributes endast från indexet"
+
+#: builtin/check-attr.c:21 builtin/hash-object.c:75
+msgid "read file names from stdin"
+msgstr "läs filnamn från standard in"
+
+#: builtin/check-attr.c:23
+msgid "input paths are terminated by a null character"
+msgstr "sökvägar avdelas med null-tecken"
+
+#: builtin/checkout-index.c:126
+msgid "git checkout-index [options] [--] [<file>...]"
+msgstr "git checkout-index [flaggor] [--] [<fil>...]"
+
+#: builtin/checkout-index.c:187
+msgid "check out all files in the index"
+msgstr "checka ut alla filer i indexet"
+
+#: builtin/checkout-index.c:188
+msgid "force overwrite of existing files"
+msgstr "tvinga överskrivning av befintliga filer"
+
+#: builtin/checkout-index.c:190
+msgid "no warning for existing files and files not in index"
+msgstr "ingen varning för existerande filer och filer ej i indexet"
+
+#: builtin/checkout-index.c:192
+msgid "don't checkout new files"
+msgstr "checka inte ut nya filer"
+
+#: builtin/checkout-index.c:194
+msgid "update stat information in the index file"
+msgstr "uppdatera stat-information i indexfilen"
+
+#: builtin/checkout-index.c:200
+msgid "read list of paths from the standard input"
+msgstr "läs listan över sökvägar från standard in"
+
+#: builtin/checkout-index.c:202
+msgid "write the content to temporary files"
+msgstr "skriv innehåll till temporära filer"
+
+#: builtin/checkout-index.c:203 builtin/column.c:30
+msgid "string"
+msgstr "sträng"
+
+#: builtin/checkout-index.c:204
+msgid "when creating files, prepend <string>"
+msgstr "när filer skapas, lägg till <sträng> först"
+
+#: builtin/checkout-index.c:207
+msgid "copy out the files from named stage"
+msgstr "kopiera ut filer från namngiven etapp"
+
+#: builtin/checkout.c:25
+msgid "git checkout [options] <branch>"
+msgstr "git checkout [flaggor] <gren>"
+
+#: builtin/checkout.c:26
+msgid "git checkout [options] [<branch>] -- <file>..."
+msgstr "git checkout [flaggor] [<gren>] -- <fil>..."
+
+#: builtin/checkout.c:116 builtin/checkout.c:149
 #, c-format
 msgid "path '%s' does not have our version"
 msgstr "sökvägen \"%s\" har inte vår version"
 
-#: builtin/checkout.c:115 builtin/checkout.c:148
+#: builtin/checkout.c:118 builtin/checkout.c:151
 #, c-format
 msgid "path '%s' does not have their version"
 msgstr "sökvägen \"%s\" har inte deras version"
 
-#: builtin/checkout.c:131
+#: builtin/checkout.c:134
 #, c-format
 msgid "path '%s' does not have all necessary versions"
 msgstr "sökvägen \"%s\" innehåller inte alla nödvändiga versioner"
 
-#: builtin/checkout.c:175
+#: builtin/checkout.c:178
 #, c-format
 msgid "path '%s' does not have necessary versions"
 msgstr "sökvägen \"%s\" innehåller inte nödvändiga versioner"
 
-#: builtin/checkout.c:192
+#: builtin/checkout.c:195
 #, c-format
 msgid "path '%s': cannot merge"
 msgstr "sökväg \"%s\": kan inte slå ihop"
 
-#: builtin/checkout.c:209
+#: builtin/checkout.c:212
 #, c-format
 msgid "Unable to add merge result for '%s'"
 msgstr "Kunde inte lägga till sammanslagningsresultat för \"%s\""
 
-#: builtin/checkout.c:234 builtin/checkout.c:392
+#: 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\" kan inte användas vid uppdatering av sökvägar"
+
+#: builtin/checkout.c:248 builtin/checkout.c:251
+#, c-format
+msgid "'%s' cannot be used with %s"
+msgstr "\"%s\" kan inte användas med %s"
+
+#: builtin/checkout.c:254
+#, c-format
+msgid "Cannot update paths and switch to branch '%s' at the same time."
+msgstr "Kan inte uppdatera sökvägar och växla till grenen \"%s\" samtidigt."
+
+#: builtin/checkout.c:265 builtin/checkout.c:426
 msgid "corrupt index file"
 msgstr "indexfilen är trasig"
 
-#: builtin/checkout.c:264 builtin/checkout.c:271
+#: builtin/checkout.c:295 builtin/checkout.c:302
 #, c-format
 msgid "path '%s' is unmerged"
 msgstr "sökvägen \"%s\" har inte slagits ihop"
 
-#: builtin/checkout.c:302 builtin/checkout.c:498 builtin/clone.c:583
-#: builtin/merge.c:812
+#: 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:319 builtin/diff.c:302 builtin/merge.c:408
-msgid "diff_setup_done failed"
-msgstr "diff_setup_done misslyckades"
-
-#: builtin/checkout.c:414
+#: builtin/checkout.c:448
 msgid "you need to resolve your current index first"
 msgstr "du måste lösa ditt befintliga index först"
 
-#: builtin/checkout.c:533
+#: builtin/checkout.c:569
 #, c-format
 msgid "Can not do reflog for '%s'\n"
 msgstr "Kan inte skapa referenslog för \"%s\"\n"
 
-#: builtin/checkout.c:566
+#: builtin/checkout.c:602
 msgid "HEAD is now at"
 msgstr "HEAD är nu på"
 
-#: builtin/checkout.c:573
+#: builtin/checkout.c:609
 #, c-format
 msgid "Reset branch '%s'\n"
 msgstr "Återställ gren \"%s\"\n"
 
-#: builtin/checkout.c:576
+#: builtin/checkout.c:612
 #, c-format
 msgid "Already on '%s'\n"
 msgstr "Redan på \"%s\"\n"
 
-#: builtin/checkout.c:580
+#: builtin/checkout.c:616
 #, c-format
 msgid "Switched to and reset branch '%s'\n"
 msgstr "Växlade till och nollställde grenen \"%s\"\n"
 
-#: builtin/checkout.c:582
+#: builtin/checkout.c:618
 #, c-format
 msgid "Switched to a new branch '%s'\n"
 msgstr "Växlade till en ny gren \"%s\"\n"
 
-#: builtin/checkout.c:584
+#: builtin/checkout.c:620
 #, c-format
 msgid "Switched to branch '%s'\n"
 msgstr "Växlade till grenen \"%s\"\n"
 
-#: builtin/checkout.c:640
+#: builtin/checkout.c:676
 #, c-format
 msgid " ... and %d more.\n"
 msgstr " ... och %d till.\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"
@@ -1818,7 +2703,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"
@@ -1833,88 +2718,150 @@ msgstr ""
 " git branch nytt_grennamn %s\n"
 "\n"
 
-#: builtin/checkout.c:694
+#: builtin/checkout.c:730
 msgid "internal error in revision walk"
 msgstr "internt fel vid genomgång av revisioner (revision walk)"
 
-#: builtin/checkout.c:698
+#: builtin/checkout.c:734
 msgid "Previous HEAD position was"
 msgstr "Tidigare position för HEAD var"
 
-#: builtin/checkout.c:724
+#: builtin/checkout.c:761 builtin/checkout.c:950
 msgid "You are on a branch yet to be born"
 msgstr "Du är på en gren som ännu inte är född"
 
 #. case (1)
-#: builtin/checkout.c:855
+#: builtin/checkout.c:886
 #, c-format
 msgid "invalid reference: %s"
 msgstr "felaktig referens: %s"
 
 #. case (1): want a tree
-#: builtin/checkout.c:894
+#: builtin/checkout.c:925
 #, c-format
 msgid "reference is not a tree: %s"
 msgstr "referensen är inte ett träd: %s"
 
-#: builtin/checkout.c:974
-msgid "-B cannot be used with -b"
-msgstr "-B kan inte användas med -b"
+#: builtin/checkout.c:961
+msgid "paths cannot be used with switching branches"
+msgstr "sökvägar kan inte användas vid byte av gren"
 
-#: builtin/checkout.c:983
-msgid "--patch is incompatible with all other options"
-msgstr "--patch är inkompatibel med alla andra flaggor"
+#: builtin/checkout.c:964 builtin/checkout.c:968
+#, c-format
+msgid "'%s' cannot be used with switching branches"
+msgstr "\"%s\" kan inte användas vid byte av gren"
 
-#: builtin/checkout.c:986
-msgid "--detach cannot be used with -b/-B/--orphan"
-msgstr "--detcah kan inte användas med -b/-B/--orphan"
+#: builtin/checkout.c:972 builtin/checkout.c:975 builtin/checkout.c:980
+#: builtin/checkout.c:983
+#, c-format
+msgid "'%s' cannot be used with '%s'"
+msgstr "\"%s\" kan inte användas med \"%s\""
 
 #: builtin/checkout.c:988
-msgid "--detach cannot be used with -t"
-msgstr "--detach kan inte användas med -t"
+#, c-format
+msgid "Cannot switch branch to a non-commit '%s'"
+msgstr "Kan inte växla gren till icke-incheckningen \"%s\""
 
-#: builtin/checkout.c:994
-msgid "--track needs a branch name"
-msgstr "--track behöver ett namn på en gren"
+#: builtin/checkout.c:1009 builtin/gc.c:177
+msgid "suppress progress reporting"
+msgstr "undertryck förloppsrapportering"
 
-#: builtin/checkout.c:1001
-msgid "Missing branch name; try -b"
-msgstr "Grennamn saknas; försök med -b"
+#: builtin/checkout.c:1010 builtin/checkout.c:1012 builtin/clone.c:89
+#: builtin/remote.c:169 builtin/remote.c:171
+msgid "branch"
+msgstr "gren"
 
-#: builtin/checkout.c:1007
-msgid "--orphan and -b|-B are mutually exclusive"
-msgstr "--orphan och -b|-B kan inte användas samtidigt"
+#: builtin/checkout.c:1011
+msgid "create and checkout a new branch"
+msgstr "skapa och checka ut en ny gren"
 
-#: builtin/checkout.c:1009
-msgid "--orphan cannot be used with -t"
-msgstr "--orphan kan inte användas med -t"
+#: builtin/checkout.c:1013
+msgid "create/reset and checkout a branch"
+msgstr "skapa/nollställ och checka ut en gren"
+
+#: builtin/checkout.c:1014
+msgid "create reflog for new branch"
+msgstr "skapa reflogg för ny gren"
+
+#: builtin/checkout.c:1015
+msgid "detach the HEAD at named commit"
+msgstr "koppla från HEAD vid namngiven incheckning"
+
+#: builtin/checkout.c:1016
+msgid "set upstream info for new branch"
+msgstr "sätt uppströmsinformation för ny gren"
+
+#: builtin/checkout.c:1018
+msgid "new branch"
+msgstr "ny gren"
+
+#: builtin/checkout.c:1018
+msgid "new unparented branch"
+msgstr "ny gren utan förälder"
 
 #: builtin/checkout.c:1019
-msgid "git checkout: -f and -m are incompatible"
-msgstr "git checkout: -f och -m är inkompatibla"
+msgid "checkout our version for unmerged files"
+msgstr "checka ut vår version för ej sammanslagna filer"
+
+#: builtin/checkout.c:1021
+msgid "checkout their version for unmerged files"
+msgstr "checka ut deras version för ej sammanslagna filer"
+
+#: builtin/checkout.c:1023
+msgid "force checkout (throw away local modifications)"
+msgstr "tvinga utcheckning (kasta bort lokala ändringar)"
+
+#: builtin/checkout.c:1024
+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
+msgid "update ignored files (default)"
+msgstr "uppdatera ignorerade filer (standard)"
+
+#: builtin/checkout.c:1026 builtin/log.c:1111 parse-options.h:241
+msgid "style"
+msgstr "stil"
+
+#: builtin/checkout.c:1027
+msgid "conflict style (merge or diff3)"
+msgstr "konfliktstil (merge eller diff3)"
+
+#: builtin/checkout.c:1030
+msgid "second guess 'git checkout no-such-branch'"
+msgstr "förutspå \"git checkout gren-saknas\""
+
+#: builtin/checkout.c:1054
+msgid "-b, -B and --orphan are mutually exclusive"
+msgstr "-b, -B och --orphan är ömsesidigt uteslutande"
+
+#: builtin/checkout.c:1071
+msgid "--track needs a branch name"
+msgstr "--track behöver ett namn på en gren"
+
+#: builtin/checkout.c:1078
+msgid "Missing branch name; try -b"
+msgstr "Grennamn saknas; försök med -b"
 
-#: builtin/checkout.c:1053
+#: builtin/checkout.c:1113
 msgid "invalid path specification"
 msgstr "felaktig sökvägsangivelse"
 
-#: builtin/checkout.c:1061
+#: builtin/checkout.c:1120
 #, 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: uppdatera sökvägar är inkompatibelt med att växla gren.\n"
-"Ville du checka ut \"%s\" som inte kan lösas som en sammanslaning?"
+"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:1063
-msgid "git checkout: updating paths is incompatible with switching branches."
-msgstr "git checkout: uppdatera sökvägar är inkompatibelt med att växla gren."
-
-#: builtin/checkout.c:1068
-msgid "git checkout: --detach does not take a path argument"
-msgstr "git checkout: --detach tar inte en sökväg som argument"
+#: builtin/checkout.c:1125
+#, 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:1071
+#: builtin/checkout.c:1129
 msgid ""
 "git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
 "checking out of the index."
@@ -1922,13 +2869,39 @@ msgstr ""
 "git checkout: --ours/--theirs, --force och --merge är inkompatibla när\n"
 "du checkar ut från indexet."
 
-#: builtin/checkout.c:1090
-msgid "Cannot switch branch to a non-commit."
-msgstr "Kan inte växla gren på en icke-incheckning."
+#: builtin/clean.c:19
+msgid "git clean [-d] [-f] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>..."
+msgstr ""
+"git clean [-d] [-f] [-n] [-q] [-e <mönster>] [-x | -X] [--] <sökvägar>..."
+
+#: builtin/clean.c:51
+msgid "do not print names of files removed"
+msgstr "skriv inte ut namn på borttagna filer"
+
+#: builtin/clean.c:53
+msgid "force"
+msgstr "tvinga"
+
+#: builtin/clean.c:55
+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
+msgid "pattern"
+msgstr "mönster"
 
-#: builtin/checkout.c:1093
-msgid "--ours/--theirs is incompatible with switching branches."
-msgstr "--ours/--theirs är inkompatibla med att byta gren."
+#: builtin/clean.c:57
+msgid "add <pattern> to ignore rules"
+msgstr "lägg till <mönster> till ignoreringsregler"
+
+#: builtin/clean.c:58
+msgid "remove ignored files, too"
+msgstr "ta även bort ignorerade filer"
+
+#: builtin/clean.c:60
+msgid "remove only ignored files"
+msgstr "ta endast bort ignorerade filer"
 
 #: builtin/clean.c:78
 msgid "-x and -X cannot be used together"
@@ -1974,22 +2947,110 @@ msgstr "Skulle inte ta bort %s\n"
 msgid "Not removing %s\n"
 msgstr "Tar inte bort %s\n"
 
+#: builtin/clone.c:36
+msgid "git clone [options] [--] <repo> [<dir>]"
+msgstr "git clone [flaggor] [--] <arkiv> [<kat>]"
+
+#: builtin/clone.c:64 builtin/fetch.c:82 builtin/merge.c:212
+#: builtin/push.c:399
+msgid "force progress reporting"
+msgstr "tvinga förloppsrapportering"
+
+#: builtin/clone.c:66
+msgid "don't create a checkout"
+msgstr "skapa inte någon utcheckning"
+
+#: builtin/clone.c:67 builtin/clone.c:69 builtin/init-db.c:488
+msgid "create a bare repository"
+msgstr "skapa ett naket (\"bare\") arkiv"
+
+#: builtin/clone.c:72
+msgid "create a mirror repository (implies bare)"
+msgstr "skapa ett spegelarkiv (implicerar \"bare\")"
+
+#: builtin/clone.c:74
+msgid "to clone from a local repository"
+msgstr "för att klona från ett lokalt arkiv"
+
+#: builtin/clone.c:76
+msgid "don't use local hardlinks, always copy"
+msgstr "skapa inte lokala hårda länkar, kopiera alltid"
+
+#: builtin/clone.c:78
+msgid "setup as shared repository"
+msgstr "skapa som ett delat arkiv"
+
+#: builtin/clone.c:80 builtin/clone.c:82
+msgid "initialize submodules in the clone"
+msgstr "initiera undermoduler i klonen"
+
+#: builtin/clone.c:83 builtin/init-db.c:485
+msgid "template-directory"
+msgstr "mallkatalog"
+
+#: builtin/clone.c:84 builtin/init-db.c:486
+msgid "directory from which templates will be used"
+msgstr "katalog att använda mallar från"
+
+#: builtin/clone.c:86
+msgid "reference repository"
+msgstr "referensarkiv"
+
+#: builtin/clone.c:87 builtin/column.c:26 builtin/merge-file.c:44
+msgid "name"
+msgstr "namn"
+
+#: builtin/clone.c:88
+msgid "use <name> instead of 'origin' to track upstream"
+msgstr "använd <namn> istället för \"origin\" för att spåra uppströms"
+
+#: builtin/clone.c:90
+msgid "checkout <branch> instead of the remote's HEAD"
+msgstr "checka ut <gren> istället för fjärrens HEAD"
+
+#: builtin/clone.c:92
+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
+msgid "depth"
+msgstr "djup"
+
+#: builtin/clone.c:94
+msgid "create a shallow clone of that depth"
+msgstr "skapa en grund klon på detta djup"
+
+#: builtin/clone.c:96
+msgid "clone only one branch, HEAD or --branch"
+msgstr "klona endast en gren, HEAD eller --branch"
+
+#: builtin/clone.c:97 builtin/init-db.c:494
+msgid "gitdir"
+msgstr "gitkat"
+
+#: builtin/clone.c:98 builtin/init-db.c:495
+msgid "separate git dir from working tree"
+msgstr "separera gitkatalogen från arbetskatalogen"
+
+#: builtin/clone.c:99
+msgid "key=value"
+msgstr "nyckel=värde"
+
+#: builtin/clone.c:100
+msgid "set config inside the new repository"
+msgstr "ställ in konfiguration i det nya arkivet"
+
 #: builtin/clone.c:243
 #, c-format
 msgid "reference repository '%s' is not a local directory."
 msgstr "referensarkivet \"%s\" är inte en lokal katalog."
 
-#: builtin/clone.c:302
-#, c-format
-msgid "failed to open '%s'"
-msgstr "misslyckades öppna \"%s\""
-
 #: builtin/clone.c:306
 #, c-format
 msgid "failed to create directory '%s'"
 msgstr "misslyckades skapa katalogen \"%s\""
 
-#: builtin/clone.c:308 builtin/diff.c:75
+#: builtin/clone.c:308 builtin/diff.c:77
 #, c-format
 msgid "failed to stat '%s'"
 msgstr "misslyckades ta status på \"%s\""
@@ -2004,11 +3065,6 @@ msgstr "%s finns och är ingen katalog"
 msgid "failed to stat %s\n"
 msgstr "misslyckades ta status på %s\n"
 
-#: builtin/clone.c:341
-#, c-format
-msgid "failed to unlink '%s'"
-msgstr "misslyckades ta bort länken \"%s\""
-
 #: builtin/clone.c:346
 #, c-format
 msgid "failed to create link '%s'"
@@ -2024,87 +3080,123 @@ msgstr "misslyckades kopiera filen till \"%s\""
 msgid "done.\n"
 msgstr "klart.\n"
 
-#: builtin/clone.c:440
+#: builtin/clone.c:443
 #, c-format
 msgid "Could not find remote branch %s to clone."
 msgstr "Kunde inte hitta fjärrgrenen %s för att klona."
 
-#: builtin/clone.c:549
+#: builtin/clone.c:552
 msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n"
 msgstr ""
 "HEAD hos fjärren pekar på en obefintlig referens, kan inte checka ut.\n"
 
-#: builtin/clone.c:639
+#: builtin/clone.c:690
 msgid "Too many arguments."
 msgstr "För många argument."
 
-#: builtin/clone.c:643
+#: builtin/clone.c:694
 msgid "You must specify a repository to clone."
 msgstr "Du måste ange ett arkiv att klona."
 
-#: builtin/clone.c:654
+#: builtin/clone.c:705
 #, c-format
 msgid "--bare and --origin %s options are incompatible."
 msgstr "flaggorna --bare och --origin %s är inkompatibla."
 
-#: builtin/clone.c:668
+#: builtin/clone.c:719
 #, c-format
 msgid "repository '%s' does not exist"
 msgstr "arkivet \"%s\" finns inte"
 
-#: builtin/clone.c:673
+#: builtin/clone.c:724
 msgid "--depth is ignored in local clones; use file:// instead."
 msgstr "--depth ignoreras i lokala kloningar; använd file:// istället"
 
-#: builtin/clone.c:683
+#: builtin/clone.c:734
 #, c-format
 msgid "destination path '%s' already exists and is not an empty directory."
 msgstr "destinationssökvägen \"%s\" finns redan och är inte en tom katalog."
 
-#: builtin/clone.c:693
+#: builtin/clone.c:744
 #, c-format
 msgid "working tree '%s' already exists."
 msgstr "arbetsträdet \"%s\" finns redan."
 
-#: builtin/clone.c:706 builtin/clone.c:720
+#: builtin/clone.c:757 builtin/clone.c:771
 #, c-format
 msgid "could not create leading directories of '%s'"
 msgstr "kunde inte skapa inledande kataloger för \"%s\""
 
-#: builtin/clone.c:709
+#: builtin/clone.c:760
 #, c-format
 msgid "could not create work tree dir '%s'."
 msgstr "kunde inte skapa arbetskatalogen \"%s\""
 
-#: builtin/clone.c:728
+#: builtin/clone.c:779
 #, c-format
 msgid "Cloning into bare repository '%s'...\n"
 msgstr "Klonar till ett naket arkiv \"%s\"...\n"
 
-#: builtin/clone.c:730
+#: builtin/clone.c:781
 #, c-format
 msgid "Cloning into '%s'...\n"
 msgstr "Klonar till \"%s\"...\n"
 
-#: builtin/clone.c:786
+#: builtin/clone.c:823
 #, c-format
 msgid "Don't know how to clone %s"
 msgstr "Vet inte hur man klonar %s"
 
-#: builtin/clone.c:835
+#: builtin/clone.c:872
 #, c-format
 msgid "Remote branch %s not found in upstream %s"
 msgstr "Fjärrgrenen %s hittades inte i uppströmsarkivet %s"
 
-#: builtin/clone.c:842
+#: builtin/clone.c:879
 msgid "You appear to have cloned an empty repository."
 msgstr "Du verkar ha klonat ett tomt arkiv."
 
+#: builtin/column.c:9
+msgid "git column [options]"
+msgstr "git column [flaggor]"
+
+#: builtin/column.c:26
+msgid "lookup config vars"
+msgstr "slå upp konfigurationsvariabler"
+
+#: builtin/column.c:27 builtin/column.c:28
+msgid "layout to use"
+msgstr "utseende att använda"
+
+#: builtin/column.c:29
+msgid "Maximum width"
+msgstr "Maximal bredd"
+
+#: builtin/column.c:30
+msgid "Padding space on left border"
+msgstr "Spaltfyllnad i vänsterkanten"
+
+#: builtin/column.c:31
+msgid "Padding space on right border"
+msgstr "Spaltfyllnad i högerkanten"
+
+#: builtin/column.c:32
+msgid "Padding space between columns"
+msgstr "Spaltfyllnad mellan spalter"
+
 #: builtin/column.c:51
 msgid "--command must be the first argument"
 msgstr "--command måste vara första argument"
 
-#: builtin/commit.c:43
+#: builtin/commit.c:34
+msgid "git commit [options] [--] <filepattern>..."
+msgstr "git commit [flaggor] [--] <filmöster>..."
+
+#: builtin/commit.c:39
+msgid "git status [options] [--] <filepattern>..."
+msgstr "git status [flaggor] [--] <filmönster>..."
+
+#: 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"
@@ -2129,7 +3221,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"
@@ -2139,7 +3231,7 @@ msgstr ""
 "blir den tom. Du kan köra kommandot på nytt med --allow-empty, eller\n"
 "så kan du ta bort incheckningen helt med \"git reset HEAD^\".\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"
@@ -2155,93 +3247,93 @@ msgstr ""
 "\n"
 "Annars använder du \"git reset\"\n"
 
-#: builtin/commit.c:253
+#: builtin/commit.c:257
 msgid "failed to unpack HEAD tree object"
 msgstr "misslyckades packa upp HEAD:s trädobjekt"
 
-#: builtin/commit.c:295
+#: builtin/commit.c:299
 msgid "unable to create temporary index"
 msgstr "kunde inte skapa temporär indexfil"
 
-#: builtin/commit.c:301
+#: builtin/commit.c:305
 msgid "interactive add failed"
 msgstr "interaktiv tilläggning misslyckades"
 
-#: builtin/commit.c:334 builtin/commit.c:355 builtin/commit.c:405
+#: builtin/commit.c:338 builtin/commit.c:359 builtin/commit.c:409
 msgid "unable to write new_index file"
 msgstr "kunde inte skriva filen new_index"
 
-#: builtin/commit.c:386
+#: builtin/commit.c:390
 msgid "cannot do a partial commit during a merge."
 msgstr "kan inte utföra en delvis incheckning under en sammanslagning."
 
-#: builtin/commit.c:388
+#: builtin/commit.c:392
 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:398
+#: builtin/commit.c:402
 msgid "cannot read the index"
 msgstr "kan inte läsa indexet"
 
-#: builtin/commit.c:418
+#: builtin/commit.c:422
 msgid "unable to write temporary index file"
 msgstr "kunde inte skriva temporär indexfil"
 
-#: builtin/commit.c:493 builtin/commit.c:499
+#: builtin/commit.c:509 builtin/commit.c:515
 #, c-format
 msgid "invalid commit: %s"
 msgstr "felaktig incheckning: %s"
 
-#: builtin/commit.c:522
+#: builtin/commit.c:538
 msgid "malformed --author parameter"
 msgstr "felformad \"--author\"-flagga"
 
-#: builtin/commit.c:582
+#: builtin/commit.c:558
 #, c-format
 msgid "Malformed ident string: '%s'"
 msgstr "Felaktig indragningssträng: \"%s\""
 
-#: builtin/commit.c:620 builtin/commit.c:653 builtin/commit.c:967
+#: builtin/commit.c:596 builtin/commit.c:629 builtin/commit.c:952
 #, c-format
 msgid "could not lookup commit %s"
 msgstr "kunde inte slå upp incheckningen %s"
 
-#: builtin/commit.c:632 builtin/shortlog.c:296
+#: builtin/commit.c:608 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:634
+#: builtin/commit.c:610
 msgid "could not read log from standard input"
 msgstr "kunde inte läsa logg från standard in"
 
-#: builtin/commit.c:638
+#: builtin/commit.c:614
 #, c-format
 msgid "could not read log file '%s'"
 msgstr "kunde inte läsa loggfilen \"%s\""
 
-#: builtin/commit.c:644
+#: builtin/commit.c:620
 msgid "commit has empty message"
 msgstr "incheckningen har ett tomt meddelande"
 
-#: builtin/commit.c:660
+#: builtin/commit.c:636
 msgid "could not read MERGE_MSG"
 msgstr "kunde inte läsa MERGE_MSG"
 
-#: builtin/commit.c:664
+#: builtin/commit.c:640
 msgid "could not read SQUASH_MSG"
 msgstr "kunde inte läsa SQUASH_MSG"
 
-#: builtin/commit.c:668
+#: builtin/commit.c:644
 #, c-format
 msgid "could not read '%s'"
 msgstr "kunde inte läsa \"%s\""
 
-#: builtin/commit.c:720
+#: builtin/commit.c:705
 msgid "could not write commit template"
 msgstr "kunde inte skriva incheckningsmall"
 
-#: builtin/commit.c:731
+#: builtin/commit.c:716
 #, c-format
 msgid ""
 "\n"
@@ -2256,7 +3348,7 @@ msgstr ""
 "\t%s\n"
 "och försöker igen.\n"
 
-#: builtin/commit.c:736
+#: builtin/commit.c:721
 #, c-format
 msgid ""
 "\n"
@@ -2271,7 +3363,7 @@ msgstr ""
 "\t%s\n"
 "och försöker igen.\n"
 
-#: builtin/commit.c:748
+#: builtin/commit.c:733
 msgid ""
 "Please enter the commit message for your changes. Lines starting\n"
 "with '#' will be ignored, and an empty message aborts the commit.\n"
@@ -2279,7 +3371,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:753
+#: builtin/commit.c:738
 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"
@@ -2289,168 +3381,486 @@ 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:766
+#: builtin/commit.c:751
 #, c-format
 msgid "%sAuthor:    %s"
 msgstr "%sFörfattare: %s"
 
-#: builtin/commit.c:773
+#: builtin/commit.c:758
 #, c-format
 msgid "%sCommitter: %s"
 msgstr "%sIncheckare: %s"
 
-#: builtin/commit.c:793
+#: builtin/commit.c:778
 msgid "Cannot read index"
 msgstr "Kan inte läsa indexet"
 
-#: builtin/commit.c:830
+#: builtin/commit.c:815
 msgid "Error building trees"
 msgstr "Fel vid byggande av träd"
 
-#: builtin/commit.c:845 builtin/tag.c:361
+#: builtin/commit.c:830 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:942
+#: builtin/commit.c:927
 #, c-format
 msgid "No existing author found with '%s'"
 msgstr "Hittade ingen befintlig författare med \"%s\""
 
-#: builtin/commit.c:957 builtin/commit.c:1157
+#: builtin/commit.c:942 builtin/commit.c:1142
 #, c-format
 msgid "Invalid untracked files mode '%s'"
 msgstr "Ogiltigt läge för ospårade filer: \"%s\""
 
-#: builtin/commit.c:997
+#: builtin/commit.c:982
 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:1008
+#: builtin/commit.c:993
 msgid "You have nothing to amend."
 msgstr "Du har inget att utöka."
 
-#: builtin/commit.c:1011
+#: builtin/commit.c:996
 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:1013
+#: builtin/commit.c:998
 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:1016
+#: builtin/commit.c:1001
 msgid "Options --squash and --fixup cannot be used together"
 msgstr "Flaggorna --squash och --fixup kan inte användas samtidigt"
 
-#: builtin/commit.c:1026
+#: builtin/commit.c:1011
 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:1028
+#: builtin/commit.c:1013
 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:1036
+#: builtin/commit.c:1021
 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:1053
+#: builtin/commit.c:1038
 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:1055
+#: builtin/commit.c:1040
 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:1057
+#: builtin/commit.c:1042
 msgid "Clever... amending the last one with dirty index."
 msgstr "Smart... utöka den senaste med smutsigt index."
 
-#: builtin/commit.c:1059
+#: builtin/commit.c:1044
 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:1069 builtin/tag.c:577
+#: builtin/commit.c:1054 builtin/tag.c:577
 #, c-format
 msgid "Invalid cleanup mode %s"
 msgstr "Felaktigt städningsläge %s"
 
-#: builtin/commit.c:1074
+#: builtin/commit.c:1059
 msgid "Paths with -a does not make sense."
 msgstr "Kan inte ange sökvägar med -a."
 
-#: builtin/commit.c:1257
+#: builtin/commit.c:1156 builtin/commit.c:1384
+msgid "show status concisely"
+msgstr "vis koncis status"
+
+#: builtin/commit.c:1158 builtin/commit.c:1386
+msgid "show branch information"
+msgstr "visa information om gren"
+
+#: builtin/commit.c:1160 builtin/commit.c:1388 builtin/push.c:389
+msgid "machine-readable output"
+msgstr "maskinläsbar utdata"
+
+#: builtin/commit.c:1163 builtin/commit.c:1390
+msgid "terminate entries with NUL"
+msgstr "terminera poster med NUL"
+
+#: builtin/commit.c:1165 builtin/commit.c:1393 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
+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
+msgid "show ignored files"
+msgstr "visa ignorerade filer"
+
+#: builtin/commit.c:1170 parse-options.h:151
+msgid "when"
+msgstr "när"
+
+#: builtin/commit.c:1171
+msgid ""
+"ignore changes to submodules, optional when: all, dirty, untracked. "
+"(Default: all)"
+msgstr ""
+"ignorera ändringar i undermoduler, valfritt när: all, dirty, untracked. "
+"(Default: all)"
+
+#: builtin/commit.c:1173
+msgid "list untracked files in columns"
+msgstr "visa ospårade filer i spalter"
+
+#: builtin/commit.c:1242
 msgid "couldn't look up newly created commit"
 msgstr "kunde inte slå upp en precis skapad incheckning"
 
-#: builtin/commit.c:1259
+#: builtin/commit.c:1244
 msgid "could not parse newly created commit"
 msgstr "kunde inte tolka en precis skapad incheckning"
 
-#: builtin/commit.c:1300
+#: builtin/commit.c:1285
 msgid "detached HEAD"
 msgstr "frånkopplad HEAD"
 
-#: builtin/commit.c:1302
+#: builtin/commit.c:1287
 msgid " (root-commit)"
 msgstr " (rotincheckning)"
 
-#: builtin/commit.c:1446
-msgid "could not parse HEAD commit"
-msgstr "kunde inte tolka HEAD:s incheckning"
+#: builtin/commit.c:1354
+msgid "suppress summary after successful commit"
+msgstr "undertryck sammanfattning efter framgångsrik incheckning"
 
-#: builtin/commit.c:1484 builtin/merge.c:509
-#, c-format
-msgid "could not open '%s' for reading"
-msgstr "kunde inte öppna \"%s\" för läsning"
+#: builtin/commit.c:1355
+msgid "show diff in commit message template"
+msgstr "visa diff i mallen för incheckningsmeddelandet"
 
-#: builtin/commit.c:1491
-#, c-format
-msgid "Corrupt MERGE_HEAD file (%s)"
-msgstr "Trasig MERGE_HEAD-fil (%s)"
+#: builtin/commit.c:1357
+msgid "Commit message options"
+msgstr "Alternativ för incheckningsmeddelande"
 
-#: builtin/commit.c:1498
-msgid "could not read MERGE_MODE"
-msgstr "kunde inte läsa MERGE_MODE"
+#: builtin/commit.c:1358 builtin/tag.c:459
+msgid "read message from file"
+msgstr "läs meddelande från fil"
 
-#: builtin/commit.c:1517
-#, c-format
-msgid "could not read commit message: %s"
-msgstr "kunde inte läsa incheckningsmeddelande: %s"
+#: builtin/commit.c:1359
+msgid "author"
+msgstr "författare"
 
-#: builtin/commit.c:1531
-#, c-format
-msgid "Aborting commit; you did not edit the message.\n"
-msgstr "Avbryter incheckning; meddelandet inte redigerat.\n"
+#: builtin/commit.c:1359
+msgid "override author for commit"
+msgstr "överstyr författare för incheckningen"
 
-#: builtin/commit.c:1536
-#, c-format
-msgid "Aborting commit due to empty commit message.\n"
-msgstr "Avbryter på grund av tomt incheckningsmeddelande.\n"
+#: builtin/commit.c:1360 builtin/gc.c:178
+msgid "date"
+msgstr "datum"
 
-#: builtin/commit.c:1551 builtin/merge.c:936 builtin/merge.c:961
-msgid "failed to write commit object"
-msgstr "kunde inte skriva incheckningsobjekt"
+#: builtin/commit.c:1360
+msgid "override date for commit"
+msgstr "överstyr datum för inchecknignen"
 
-#: builtin/commit.c:1572
-msgid "cannot lock HEAD ref"
-msgstr "kunde inte låsa HEAD-referens"
+#: builtin/commit.c:1361 builtin/merge.c:206 builtin/notes.c:537
+#: builtin/notes.c:694 builtin/tag.c:457
+msgid "message"
+msgstr "meddelande"
 
-#: builtin/commit.c:1576
-msgid "cannot update HEAD ref"
-msgstr "kunde inte uppdatera HEAD-referens"
+#: builtin/commit.c:1361
+msgid "commit message"
+msgstr "incheckningsmeddelande"
 
-#: builtin/commit.c:1587
-msgid ""
-"Repository has been updated, but unable to write\n"
-"new_index file. Check that disk is not full or quota is\n"
-"not exceeded, and then \"git reset HEAD\" to recover."
+#: builtin/commit.c:1362
+msgid "reuse and edit message from specified commit"
+msgstr "återanvänd och redigera meddelande från angiven incheckning"
+
+#: builtin/commit.c:1363
+msgid "reuse message from specified commit"
+msgstr "återanvänd meddelande från angiven incheckning"
+
+#: builtin/commit.c:1364
+msgid "use autosquash formatted message to fixup specified commit"
 msgstr ""
-"Arkivet har uppdaterats, men kunde inte skriva filen\n"
-"new_index. Kontrollera att disken inte är full och\n"
-"att kvoten inte har överskridits, och kör sedan\n"
-"\"git reset HEAD\" för att återställa."
+"använd autosquash-formaterat meddelande för att fixa angiven incheckning"
+
+#: builtin/commit.c:1365
+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
+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
+msgid "add Signed-off-by:"
+msgstr "lägg till Signed-off-by:"
+
+#: builtin/commit.c:1368
+msgid "use specified template file"
+msgstr "använd angiven mallfil"
+
+#: builtin/commit.c:1369
+msgid "force edit of commit"
+msgstr "tvinga redigering av incheckning"
+
+#: builtin/commit.c:1370
+msgid "default"
+msgstr "standard"
+
+#: builtin/commit.c:1370 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
+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
+msgid "key id"
+msgstr "nyckel-id"
+
+#: builtin/commit.c:1373 builtin/merge.c:214
+msgid "GPG sign commit"
+msgstr "GPG-signera incheckning"
+
+#. end commit message options
+#: builtin/commit.c:1376
+msgid "Commit contents options"
+msgstr "Alternativ för incheckningens innehåll"
+
+#: builtin/commit.c:1377
+msgid "commit all changed files"
+msgstr "checka in alla ändrade filer"
+
+#: builtin/commit.c:1378
+msgid "add specified files to index for commit"
+msgstr "lägg till angivna filer till indexet för incheckning"
+
+#: builtin/commit.c:1379
+msgid "interactively add files"
+msgstr "lägg till filer interaktivt"
+
+#: builtin/commit.c:1380
+msgid "interactively add changes"
+msgstr "lägg till ändringar interaktivt"
+
+#: builtin/commit.c:1381
+msgid "commit only specified files"
+msgstr "checka endast in angivna filer"
+
+#: builtin/commit.c:1382
+msgid "bypass pre-commit hook"
+msgstr "förbigå pre-commit-krok"
+
+#: builtin/commit.c:1383
+msgid "show what would be committed"
+msgstr "visa vad som skulle checkas in"
+
+#: builtin/commit.c:1391
+msgid "amend previous commit"
+msgstr "lägg till föregående incheckning"
+
+#: builtin/commit.c:1392
+msgid "bypass post-rewrite hook"
+msgstr "förbigå post-rewrite-krok"
+
+#: builtin/commit.c:1397
+msgid "ok to record an empty change"
+msgstr "ok att registrera en tom ändring"
+
+#: builtin/commit.c:1400
+msgid "ok to record a change with an empty message"
+msgstr "ok att registrera en ändring med tomt meddelande"
+
+#: builtin/commit.c:1432
+msgid "could not parse HEAD commit"
+msgstr "kunde inte tolka HEAD:s incheckning"
+
+#: builtin/commit.c:1470 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
+#, c-format
+msgid "Corrupt MERGE_HEAD file (%s)"
+msgstr "Trasig MERGE_HEAD-fil (%s)"
+
+#: builtin/commit.c:1484
+msgid "could not read MERGE_MODE"
+msgstr "kunde inte läsa MERGE_MODE"
+
+#: builtin/commit.c:1503
+#, c-format
+msgid "could not read commit message: %s"
+msgstr "kunde inte läsa incheckningsmeddelande: %s"
+
+#: builtin/commit.c:1517
+#, c-format
+msgid "Aborting commit; you did not edit the message.\n"
+msgstr "Avbryter incheckning; meddelandet inte redigerat.\n"
+
+#: builtin/commit.c:1522
+#, 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
+msgid "failed to write commit object"
+msgstr "kunde inte skriva incheckningsobjekt"
+
+#: builtin/commit.c:1558
+msgid "cannot lock HEAD ref"
+msgstr "kunde inte låsa HEAD-referens"
+
+#: builtin/commit.c:1562
+msgid "cannot update HEAD ref"
+msgstr "kunde inte uppdatera HEAD-referens"
+
+#: builtin/commit.c:1573
+msgid ""
+"Repository has been updated, but unable to write\n"
+"new_index file. Check that disk is not full or quota is\n"
+"not exceeded, and then \"git reset HEAD\" to recover."
+msgstr ""
+"Arkivet har uppdaterats, men kunde inte skriva filen\n"
+"new_index. Kontrollera att disken inte är full och\n"
+"att kvoten inte har överskridits, och kör sedan\n"
+"\"git reset HEAD\" för att återställa."
+
+#: builtin/config.c:7
+msgid "git config [options]"
+msgstr "git config [flaggor]"
+
+#: builtin/config.c:52
+msgid "Config file location"
+msgstr "Konfigurationsfilens plats"
+
+#: builtin/config.c:53
+msgid "use global config file"
+msgstr "använd global konfigurationsfil"
+
+#: builtin/config.c:54
+msgid "use system config file"
+msgstr "använd systemets konfigurationsfil"
+
+#: builtin/config.c:55
+msgid "use repository config file"
+msgstr "använd arkivets konfigurationsfil"
+
+#: builtin/config.c:56
+msgid "use given config file"
+msgstr "använd angiven konfigurationsil"
+
+#: builtin/config.c:57
+msgid "Action"
+msgstr "Åtgärd"
+
+#: builtin/config.c:58
+msgid "get value: name [value-regex]"
+msgstr "hämta värde: namn [värde-reguttr]"
+
+#: builtin/config.c:59
+msgid "get all values: key [value-regex]"
+msgstr "hämta alla värden: nyckel [värde-reguttr]"
+
+#: builtin/config.c:60
+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
+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
+msgid "add a new variable: name value"
+msgstr "lägg till en ny variabel: namn värde"
+
+#: builtin/config.c:63
+msgid "remove a variable: name [value-regex]"
+msgstr "ta bort en variabel: namn [värde-reguttr]"
+
+#: builtin/config.c:64
+msgid "remove all matches: name [value-regex]"
+msgstr "ta bort alla träffar: namn [värde-reguttr]"
+
+#: builtin/config.c:65
+msgid "rename section: old-name new-name"
+msgstr "byt namn på sektion: gammalt-namn nytt-namn"
+
+#: builtin/config.c:66
+msgid "remove a section: name"
+msgstr "ta bort en sektion: namn"
+
+#: builtin/config.c:67
+msgid "list all"
+msgstr "visa alla"
+
+#: builtin/config.c:68
+msgid "open an editor"
+msgstr "öppna textredigeringsprogram"
+
+#: builtin/config.c:69 builtin/config.c:70
+msgid "slot"
+msgstr "plats"
+
+#: builtin/config.c:69
+msgid "find the color configured: [default]"
+msgstr "hitta den inställda färgen: [default]"
+
+#: builtin/config.c:70
+msgid "find the color setting: [stdout-is-tty]"
+msgstr "hitta färginställningen: [stdout-is-tty]"
+
+#: builtin/config.c:71
+msgid "Type"
+msgstr "Typ"
+
+#: builtin/config.c:72
+msgid "value is \"true\" or \"false\""
+msgstr "värdet är \"true\" eller \"false\""
+
+#: builtin/config.c:73
+msgid "value is decimal number"
+msgstr "värdet är ett decimalt tal"
+
+#: builtin/config.c:74
+msgid "value is --bool or --int"
+msgstr "värdet är --bool eller --int"
+
+#: builtin/config.c:75
+msgid "value is a path (file or directory name)"
+msgstr "värdet är en sökväg (fil- eller katalognamn)"
+
+#: builtin/config.c:76
+msgid "Other"
+msgstr "Andra"
+
+#: builtin/config.c:77
+msgid "terminate values with NUL byte"
+msgstr "terminera värden med NUL-byte"
+
+#: builtin/config.c:78
+msgid "respect include directives on lookup"
+msgstr "respektera inkluderingsdirektiv vid uppslag"
+
+#: 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 [flaggor] <incheckning-igt>*"
+
+#: builtin/describe.c:16
+msgid "git describe [options] --dirty"
+msgstr "git describe [flaggor] --dirty"
 
 #: builtin/describe.c:234
 #, c-format
@@ -2524,6 +3934,50 @@ msgstr ""
 "mer än %i taggar hittades; listar de %i senaste\n"
 "gav upp sökningen vid %s\n"
 
+#: builtin/describe.c:403
+msgid "find the tag that comes after the commit"
+msgstr "hitta taggen som kommer efter incheckningen"
+
+#: builtin/describe.c:404
+msgid "debug search strategy on stderr"
+msgstr "felsök sökstrategin på standard fel"
+
+#: builtin/describe.c:405
+msgid "use any ref in .git/refs"
+msgstr "använd alla referenser i .git/refs"
+
+#: builtin/describe.c:406
+msgid "use any tag in .git/refs/tags"
+msgstr "använd alla taggar i .git/refs/tags"
+
+#: builtin/describe.c:407
+msgid "always use long format"
+msgstr "använd alltid långt format"
+
+#: builtin/describe.c:410
+msgid "only output exact matches"
+msgstr "skriv endast ut exakta träffar"
+
+#: builtin/describe.c:412
+msgid "consider <n> most recent tags (default: 10)"
+msgstr "överväg de <n> nyaste taggarna (standard: 10)"
+
+#: builtin/describe.c:414
+msgid "only consider tags matching <pattern>"
+msgstr "överväg endast taggar som motsvarar <mönster>"
+
+#: builtin/describe.c:416 builtin/name-rev.c:238
+msgid "show abbreviated commit object as fallback"
+msgstr "visa förkortade incheckningsobjekt som standard"
+
+#: builtin/describe.c:417
+msgid "mark"
+msgstr "märke"
+
+#: builtin/describe.c:418
+msgid "append <mark> on dirty working tree (default: \"-dirty\")"
+msgstr "lägg till <märke> på lortigt arbetsträd (standard: \"-dirty\")"
+
 #: builtin/describe.c:436
 msgid "--long is incompatible with --abbrev=0"
 msgstr "--long är inkompatibel med --abbrev=0"
@@ -2536,45 +3990,165 @@ msgstr "Inga namn hittades, kan inte beskriva något."
 msgid "--dirty is incompatible with committishes"
 msgstr "--dirty är inkompatibelt med \"committish\"-värden"
 
-#: builtin/diff.c:77
+#: builtin/diff.c:79
 #, c-format
 msgid "'%s': not a regular file or symlink"
 msgstr "\"%s\": inte en normal fil eller symbolisk länk"
 
-#: builtin/diff.c:220
+#: builtin/diff.c:224
 #, c-format
 msgid "invalid option: %s"
 msgstr "ogiltig flagga: %s"
 
-#: builtin/diff.c:297
+#: builtin/diff.c:301
 msgid "Not a git repository"
 msgstr "Inte ett git-arkiv"
 
-#: builtin/diff.c:347
+#: builtin/diff.c:344
 #, c-format
 msgid "invalid object '%s' given."
 msgstr "objektet \"%s\" som angavs är felaktigt."
 
-#: builtin/diff.c:352
+#: builtin/diff.c:349
 #, c-format
 msgid "more than %d trees given: '%s'"
 msgstr "mer än %d träd angavs: \"%s\""
 
-#: builtin/diff.c:362
+#: builtin/diff.c:359
 #, c-format
 msgid "more than two blobs given: '%s'"
 msgstr "mer än två blobbar angavs: \"%s\""
 
-#: builtin/diff.c:370
+#: builtin/diff.c:367
 #, c-format
 msgid "unhandled object '%s' given."
 msgstr "ej hanterat objekt \"%s\" angavs."
 
-#: builtin/fetch.c:200
+#: builtin/fast-export.c:22
+msgid "git fast-export [rev-list-opts]"
+msgstr "git fast-export [rev-list-flaggor]"
+
+#: builtin/fast-export.c:635
+msgid "show progress after <n> objects"
+msgstr "visa förlopp efter <n> objekt"
+
+#: builtin/fast-export.c:637
+msgid "select handling of signed tags"
+msgstr "välj hantering av signerade taggar"
+
+#: builtin/fast-export.c:640
+msgid "select handling of tags that tag filtered objects"
+msgstr "välj hantering av taggar som har taggfiltrerade objekt"
+
+#: builtin/fast-export.c:643
+msgid "Dump marks to this file"
+msgstr "Dump märken till filen"
+
+#: builtin/fast-export.c:645
+msgid "Import marks from this file"
+msgstr "Importera märken från filen"
+
+#: builtin/fast-export.c:647
+msgid "Fake a tagger when tags lack one"
+msgstr "Fejka taggare när taggen saknar en"
+
+#: builtin/fast-export.c:649
+msgid "Output full tree for each commit"
+msgstr "Skriv ut hela trädet för varje incheckning"
+
+#: builtin/fast-export.c:651
+msgid "Use the done feature to terminate the stream"
+msgstr "Använd done-funktionen för att avsluta strömmen"
+
+#: builtin/fast-export.c:652
+msgid "Skip output of blob data"
+msgstr "Hoppa över skrivning av blob-data"
+
+#: builtin/fetch.c:20
+msgid "git fetch [<options>] [<repository> [<refspec>...]]"
+msgstr "git fetch [<flaggor>] [<arkiv> [<refspec>...]]"
+
+#: builtin/fetch.c:21
+msgid "git fetch [<options>] <group>"
+msgstr "git fetch [<flaggor>] <grupp>"
+
+#: builtin/fetch.c:22
+msgid "git fetch --multiple [<options>] [(<repository> | <group>)...]"
+msgstr "git fetch --multiple [<flaggor>] [(<arkiv> | <grupp>)...]"
+
+#: builtin/fetch.c:23
+msgid "git fetch --all [<options>]"
+msgstr "git fetch --all [<flaggor>]"
+
+#: builtin/fetch.c:60
+msgid "fetch from all remotes"
+msgstr "hämta från alla fjärrar"
+
+#: builtin/fetch.c:62
+msgid "append to .git/FETCH_HEAD instead of overwriting"
+msgstr "lägg till i .git/FETCH_HEAD istället för att skriva över"
+
+#: builtin/fetch.c:64
+msgid "path to upload pack on remote end"
+msgstr "sökväg till upload pack på fjärren"
+
+#: builtin/fetch.c:65
+msgid "force overwrite of local branch"
+msgstr "tvinga överskrivning av lokal gren"
+
+#: builtin/fetch.c:67
+msgid "fetch from multiple remotes"
+msgstr "hämta från flera fjärrar"
+
+#: builtin/fetch.c:69
+msgid "fetch all tags and associated objects"
+msgstr "hämta alla taggar och associerade objekt"
+
+#: builtin/fetch.c:71
+msgid "do not fetch all tags (--no-tags)"
+msgstr "hämta inte alla taggar (--no-tags)"
+
+#: builtin/fetch.c:73
+msgid "prune remote-tracking branches no longer on remote"
+msgstr "rensa fjärrspårande grenar ej längre på fjärren"
+
+#: builtin/fetch.c:74
+msgid "on-demand"
+msgstr "on-demand"
+
+#: builtin/fetch.c:75
+msgid "control recursive fetching of submodules"
+msgstr "styr rekursiv hämtning av undermoduler"
+
+#: builtin/fetch.c:79
+msgid "keep downloaded pack"
+msgstr "behåll hämtade paket"
+
+#: builtin/fetch.c:81
+msgid "allow updating of HEAD ref"
+msgstr "tillåt uppdatering av HEAD-referens"
+
+#: builtin/fetch.c:84
+msgid "deepen history of shallow clone"
+msgstr "fördjupa historik för grund klon"
+
+#: builtin/fetch.c:85 builtin/log.c:1083
+msgid "dir"
+msgstr "kat"
+
+#: builtin/fetch.c:86
+msgid "prepend this to submodule path output"
+msgstr "lägg till i början av undermodulens sökvägsutdata"
+
+#: builtin/fetch.c:89
+msgid "default mode for recursion"
+msgstr "standardläge för rekursion"
+
+#: builtin/fetch.c:201
 msgid "Couldn't find remote ref HEAD"
 msgstr "Kunde inte hitta fjärr-referensen HEAD"
 
-#: builtin/fetch.c:253
+#: builtin/fetch.c:254
 #, c-format
 msgid "object %s not found"
 msgstr "objektet %s hittades inte"
@@ -2686,17 +4260,17 @@ msgstr "Flaggan \"%s\" och värdet \"%s\" är inte giltigt för %s"
 msgid "Option \"%s\" is ignored for %s\n"
 msgstr "Flaggan \"%s\" ignoreras för %s\n"
 
-#: builtin/fetch.c:888
+#: builtin/fetch.c:891
 #, c-format
 msgid "Fetching %s\n"
 msgstr "Hämtar %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 "Kunde inte hämta %s"
 
-#: 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."
@@ -2704,27 +4278,146 @@ msgstr ""
 "Inget fjärrarkiv angavs. Ange antingen en URL eller namnet på ett\n"
 "fjärrarkiv som nya incheckningar skall hämtas från."
 
-#: builtin/fetch.c:927
+#: builtin/fetch.c:932
 msgid "You need to specify a tag name."
 msgstr "Du måste ange namnet på en tagg."
 
-#: builtin/fetch.c:979
+#: builtin/fetch.c:984
 msgid "fetch --all does not take a repository argument"
 msgstr "fetch --all tar inte namnet på ett arkiv som argument"
 
-#: builtin/fetch.c:981
+#: builtin/fetch.c:986
 msgid "fetch --all does not make sense with refspecs"
 msgstr "fetch --all kan inte anges med referensspecifikationer"
 
-#: builtin/fetch.c:992
+#: builtin/fetch.c:997
 #, c-format
 msgid "No such remote or remote group: %s"
 msgstr "Fjärren eller fjärrgruppen finns inte: %s"
 
-#: builtin/fetch.c:1000
+#: builtin/fetch.c:1005
 msgid "Fetching a group and specifying refspecs does not make sense"
 msgstr "Kan inte hämta från grupp och ange referensspecifikationer"
 
+#: 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 <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/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 "fyll i loggen med som mest <n> poster från shortlog"
+
+#: builtin/fmt-merge-msg.c:657
+msgid "alias for --log (deprecated)"
+msgstr "alias för --log (avråds)"
+
+#: builtin/fmt-merge-msg.c:660
+msgid "text"
+msgstr "text"
+
+#: builtin/fmt-merge-msg.c:661
+msgid "use <text> as start of message"
+msgstr "inled meddelande med <text>"
+
+#: builtin/fmt-merge-msg.c:662
+msgid "file to read from"
+msgstr "fil att läsa från"
+
+#: builtin/for-each-ref.c:979
+msgid "git for-each-ref [options] [<pattern>]"
+msgstr "git for-each-ref [flaggor] [<mönster>]"
+
+#: builtin/for-each-ref.c:994
+msgid "quote placeholders suitably for shells"
+msgstr "citera platshållare passande för skal"
+
+#: builtin/for-each-ref.c:996
+msgid "quote placeholders suitably for perl"
+msgstr "citera platshållare passande för perl"
+
+#: builtin/for-each-ref.c:998
+msgid "quote placeholders suitably for python"
+msgstr "citera platshållare passande för python"
+
+#: builtin/for-each-ref.c:1000
+msgid "quote placeholders suitably for tcl"
+msgstr "citera platshållare passande för tcl"
+
+#: builtin/for-each-ref.c:1003
+msgid "show only <n> matched refs"
+msgstr "visa endast <n> träffade refs"
+
+#: builtin/for-each-ref.c:1004
+msgid "format"
+msgstr "format"
+
+#: builtin/for-each-ref.c:1004
+msgid "format to use for the output"
+msgstr "format att använda för utdata"
+
+#: builtin/for-each-ref.c:1005
+msgid "key"
+msgstr "nyckel"
+
+#: builtin/for-each-ref.c:1006
+msgid "field name to sort on"
+msgstr "fältnamn att sortera på"
+
+#: builtin/fsck.c:608
+msgid "git fsck [options] [<object>...]"
+msgstr "git fsck [flaggor] [<objekt>...]"
+
+#: builtin/fsck.c:614
+msgid "show unreachable objects"
+msgstr "visa onåbara objekt"
+
+#: builtin/fsck.c:615
+msgid "show dangling objects"
+msgstr "visa dinglande objekt"
+
+#: builtin/fsck.c:616
+msgid "report tags"
+msgstr "rapportera taggar"
+
+#: builtin/fsck.c:617
+msgid "report root nodes"
+msgstr "rapportera rotnoder"
+
+#: builtin/fsck.c:618
+msgid "make index objects head nodes"
+msgstr "gör indexojekt till huvudnoder"
+
+#: builtin/fsck.c:619
+msgid "make reflogs head nodes (default)"
+msgstr "gör refloggar till huvudnoder (standard)"
+
+#: builtin/fsck.c:620
+msgid "also consider packs and alternate objects"
+msgstr "ta även hänsyn till paket och alternativa objekt"
+
+#: builtin/fsck.c:621
+msgid "enable more strict checking"
+msgstr "aktivera striktare kontroll"
+
+#: builtin/fsck.c:623
+msgid "write dangling objects in .git/lost-found"
+msgstr "skriv dinglande objekt i .git/lost-found"
+
+#: builtin/fsck.c:624 builtin/prune.c:134
+msgid "show progress"
+msgstr "visa förlopp"
+
+#: builtin/gc.c:22
+msgid "git gc [options]"
+msgstr "git gc [flaggor]"
+
 #: builtin/gc.c:63
 #, c-format
 msgid "Invalid %s: '%s'"
@@ -2735,12 +4428,19 @@ msgstr "Felaktigt %s: \"%s\""
 msgid "insanely long object directory %.*s"
 msgstr "tokigt lång objektkatalog %.*s"
 
-#: builtin/gc.c:221
-#, c-format
-msgid "Auto packing the repository for optimum performance.\n"
-msgstr "Packar arkivet automatiskt för optimal prestanda.\n"
+#: builtin/gc.c:179
+msgid "prune unreferenced objects"
+msgstr "rensa ej refererade objekt"
+
+#: builtin/gc.c:181
+msgid "be more thorough (increased runtime)"
+msgstr "var mer grundlig (ökar körtiden)"
 
-#: builtin/gc.c:224
+#: builtin/gc.c:182
+msgid "enable auto-gc mode"
+msgstr "aktivera auto-gc-läge"
+
+#: builtin/gc.c:222
 #, c-format
 msgid ""
 "Auto packing the repository for optimum performance. You may also\n"
@@ -2749,96 +4449,324 @@ msgstr ""
 "Packar arkivet automatiskt för optimal prestanda. Du kan även\n"
 "köra \"git gc\" manuellt. Se \"git help gc\" för mer information.\n"
 
-#: builtin/gc.c:251
+#: builtin/gc.c:249
 msgid ""
 "There are too many unreachable loose objects; run 'git prune' to remove them."
 msgstr ""
 "Det finns för många onåbara lösa objekt; kör \"git prune\" för att ta bort "
 "dem."
 
-#: builtin/grep.c:216
+#: builtin/grep.c:22
+msgid "git grep [options] [-e] <pattern> [<rev>...] [[--] <path>...]"
+msgstr "git grep [flaggor] [-e] <mönster> [<rev>...] [[--] <sökväg>...]"
+
+#: builtin/grep.c:217
 #, c-format
 msgid "grep: failed to create thread: %s"
 msgstr "grep: misslyckades skapa tråd. %s"
 
-#: builtin/grep.c:402
+#: builtin/grep.c:455
 #, c-format
 msgid "Failed to chdir: %s"
 msgstr "Kunde inte byta katalog (chdir): %s"
 
-#: builtin/grep.c:478 builtin/grep.c:512
+#: builtin/grep.c:531 builtin/grep.c:565
 #, c-format
 msgid "unable to read tree (%s)"
 msgstr "kunde inte läsa träd (%s)"
 
-#: builtin/grep.c:526
+#: builtin/grep.c:579
 #, c-format
 msgid "unable to grep from object of type %s"
 msgstr "Kunde inte \"grep\" från objekt av typen %s"
 
-#: builtin/grep.c:584
+#: builtin/grep.c:637
 #, c-format
 msgid "switch `%c' expects a numerical value"
 msgstr "flaggan \"%c\" antar ett numeriskt värde"
 
-#: builtin/grep.c:601
+#: builtin/grep.c:654
 #, c-format
 msgid "cannot open '%s'"
 msgstr "kan inte öppna \"%s\""
 
-#: builtin/grep.c:885
+#: builtin/grep.c:729
+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
+msgid "find in contents not managed by git"
+msgstr "sök i innehål som inte hanteras av git"
+
+#: builtin/grep.c:733
+msgid "search in both tracked and untracked files"
+msgstr "sök i både spårade och ospårade filer"
+
+#: builtin/grep.c:735
+msgid "search also in ignored files"
+msgstr "sök även i ignorerade filer"
+
+#: builtin/grep.c:738
+msgid "show non-matching lines"
+msgstr "vis rader som inte träffas"
+
+#: builtin/grep.c:740
+msgid "case insensitive matching"
+msgstr "skiftlägesokänslig sökning"
+
+#: builtin/grep.c:742
+msgid "match patterns only at word boundaries"
+msgstr "matcha endast mönster vid ordgränser"
+
+#: builtin/grep.c:744
+msgid "process binary files as text"
+msgstr "hantera binärfiler som text"
+
+#: builtin/grep.c:746
+msgid "don't match patterns in binary files"
+msgstr "träffa inte mönster i binärfiler"
+
+#: builtin/grep.c:749
+msgid "descend at most <depth> levels"
+msgstr "gå som mest ned <djup> nivåer"
+
+#: builtin/grep.c:753
+msgid "use extended POSIX regular expressions"
+msgstr "använd utökade POSIX-reguljära uttryck"
+
+#: builtin/grep.c:756
+msgid "use basic POSIX regular expressions (default)"
+msgstr "använd grundläggande POSIX-reguljära uttryck (standard)"
+
+#: builtin/grep.c:759
+msgid "interpret patterns as fixed strings"
+msgstr "tolka mönster som fixerade strängar"
+
+#: builtin/grep.c:762
+msgid "use Perl-compatible regular expressions"
+msgstr "använd Perlkompatibla reguljära uttryck"
+
+#: builtin/grep.c:765
+msgid "show line numbers"
+msgstr "visa radnummer"
+
+#: builtin/grep.c:766
+msgid "don't show filenames"
+msgstr "visa inte filnamn"
+
+#: builtin/grep.c:767
+msgid "show filenames"
+msgstr "visa filnamn"
+
+#: builtin/grep.c:769
+msgid "show filenames relative to top directory"
+msgstr "visa filnamn relativa till toppkatalogen"
+
+#: builtin/grep.c:771
+msgid "show only filenames instead of matching lines"
+msgstr "visa endast filnamn istället för träffade rader"
+
+#: builtin/grep.c:773
+msgid "synonym for --files-with-matches"
+msgstr "synonym för --files-with-matches"
+
+#: builtin/grep.c:776
+msgid "show only the names of files without match"
+msgstr "visa endast namn på filer utan träffar"
+
+#: builtin/grep.c:778
+msgid "print NUL after filenames"
+msgstr "skriv NUL efter filnamn"
+
+#: builtin/grep.c:780
+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
+msgid "highlight matches"
+msgstr "ljusmarkera träffar"
+
+#: builtin/grep.c:783
+msgid "print empty line between matches from different files"
+msgstr "skriv tomma rader mellan träffar från olika filer"
+
+#: builtin/grep.c:785
+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
+msgid "show <n> context lines before and after matches"
+msgstr "visa <n> rader sammanhang före och efter träffar"
+
+#: builtin/grep.c:791
+msgid "show <n> context lines before matches"
+msgstr "visa <n> rader sammanhang före träffar"
+
+#: builtin/grep.c:793
+msgid "show <n> context lines after matches"
+msgstr "visa <n> rader sammanhang efter träffar"
+
+#: builtin/grep.c:794
+msgid "shortcut for -C NUM"
+msgstr "genväg för -C NUM"
+
+#: builtin/grep.c:797
+msgid "show a line with the function name before matches"
+msgstr "visa en rad med funktionsnamnet före träffen"
+
+#: builtin/grep.c:799
+msgid "show the surrounding function"
+msgstr "visa den omkringliggande funktionen"
+
+#: builtin/grep.c:802
+msgid "read patterns from file"
+msgstr "läs mönster från fil"
+
+#: builtin/grep.c:804
+msgid "match <pattern>"
+msgstr "träffa <mönster>"
+
+#: builtin/grep.c:806
+msgid "combine patterns specified with -e"
+msgstr "kombinera mönster som anges med -e"
+
+#: builtin/grep.c:818
+msgid "indicate hit with exit status without output"
+msgstr "ange träff med slutstatuskod utan utdata"
+
+#: builtin/grep.c:820
+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
+msgid "show parse tree for grep expression"
+msgstr "visa analysträd för grep-uttryck"
+
+#: builtin/grep.c:826
+msgid "pager"
+msgstr "bläddrare"
+
+#: builtin/grep.c:826
+msgid "show matching files in the pager"
+msgstr "visa träffade filer i filbläddraren"
+
+#: builtin/grep.c:829
+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
+msgid "show usage"
+msgstr "visa användning"
+
+#: builtin/grep.c:921
 msgid "no pattern given."
 msgstr "inget mönster angavs."
 
-#: builtin/grep.c:899
+#: builtin/grep.c:935
 #, c-format
 msgid "bad object %s"
 msgstr "felaktigt objekt %s"
 
-#: builtin/grep.c:940
+#: builtin/grep.c:976
 msgid "--open-files-in-pager only works on the worktree"
 msgstr "--open-files-in-pager fungerar endast i arbetskatalogen"
 
-#: builtin/grep.c:963
+#: builtin/grep.c:999
 msgid "--cached or --untracked cannot be used with --no-index."
 msgstr "--cached och --untracked kan inte användas med --no-index."
 
-#: builtin/grep.c:968
+#: builtin/grep.c:1004
 msgid "--no-index or --untracked cannot be used with revs."
 msgstr "--no-index och --untracked kan inte användas med revisioner."
 
-#: builtin/grep.c:971
+#: builtin/grep.c:1007
 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:979
+#: builtin/grep.c:1015
 msgid "both --cached and trees are given."
 msgstr "både --cached och träd angavs."
 
-#: builtin/help.c:59
+#: builtin/hash-object.c:60
+msgid ""
+"git hash-object [-t <type>] [-w] [--path=<file>|--no-filters] [--stdin] [--] "
+"<file>..."
+msgstr ""
+"git hash-object [-t <typ>] [-w] [--path=<fil>|--no-filters] [--stdin] [--] "
+"<fil>..."
+
+#: builtin/hash-object.c:61
+msgid "git hash-object  --stdin-paths < <list-of-paths>"
+msgstr "git hash-object  --stdin-paths < <sökvägslista>"
+
+#: builtin/hash-object.c:72
+msgid "type"
+msgstr "typ"
+
+#: builtin/hash-object.c:72
+msgid "object type"
+msgstr "objekttyp"
+
+#: builtin/hash-object.c:73
+msgid "write the object into the object database"
+msgstr "skriv objektet till objektdatabasen"
+
+#: builtin/hash-object.c:74
+msgid "read the object from stdin"
+msgstr "läs objektet från standard in"
+
+#: builtin/hash-object.c:76
+msgid "store file as is without filters"
+msgstr "spara filen som den är utan filer"
+
+#: builtin/hash-object.c:77
+msgid "process file as it were from this path"
+msgstr "hantera filen som om den kom från sökvägen"
+
+#: builtin/help.c:43
+msgid "print all available commands"
+msgstr "visa alla tillgängliga kommandon"
+
+#: builtin/help.c:44
+msgid "show man page"
+msgstr "visa manualsida"
+
+#: builtin/help.c:45
+msgid "show manual in web browser"
+msgstr "visa manual i webbläsare"
+
+#: builtin/help.c:47
+msgid "show info page"
+msgstr "visa info-sida"
+
+#: 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'"
 msgstr "okänt hjälpformat: %s"
 
-#: builtin/help.c:87
+#: builtin/help.c:93
 msgid "Failed to start emacsclient."
 msgstr "Misslyckades starta emacsclient."
 
-#: builtin/help.c:100
+#: builtin/help.c:106
 msgid "Failed to parse emacsclient version."
 msgstr "Kunde inte tolka emacsclient-version."
 
-#: builtin/help.c:108
+#: builtin/help.c:114
 #, c-format
 msgid "emacsclient version '%d' too old (< 22)."
 msgstr "emacsclient version \"%d\" för gammal (< 22)."
 
-#: builtin/help.c:126 builtin/help.c:154 builtin/help.c:163 builtin/help.c:171
+#: 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 "exec misslyckades för \"%s\": %s"
 
-#: builtin/help.c:211
+#: builtin/help.c:217
 #, c-format
 msgid ""
 "'%s': path for unsupported man viewer.\n"
@@ -2847,7 +4775,7 @@ msgstr ""
 "\"%s\": sökväg för man-visare som ej stöds.\n"
 "Använd \"man.<verktyg>.cmd\" istället."
 
-#: builtin/help.c:223
+#: builtin/help.c:229
 #, c-format
 msgid ""
 "'%s': cmd for supported man viewer.\n"
@@ -2856,266 +4784,307 @@ msgstr ""
 "\"%s\": kommando för man-visare som stöds.\n"
 "Använd \"man.<verktyg>.path\" istället."
 
-#: builtin/help.c:287
+#: builtin/help.c:299
 msgid "The most commonly used git commands are:"
 msgstr "De mest använda git-kommandona är:"
 
-#: builtin/help.c:355
+#: builtin/help.c:367
 #, c-format
 msgid "'%s': unknown man viewer."
 msgstr "\"%s\": okänd man-visare."
 
-#: builtin/help.c:372
+#: builtin/help.c:384
 msgid "no man viewer handled the request"
 msgstr "ingen man-visare hanterade förfrågan"
 
-#: builtin/help.c:380
+#: builtin/help.c:392
 msgid "no info viewer handled the request"
 msgstr "ingen info-visare hanterade förfrågan"
 
-#: builtin/help.c:391
-#, c-format
-msgid "'%s': not a documentation directory."
-msgstr "\"%s\": inte en dokumentationskatalog."
-
-#: builtin/help.c:432 builtin/help.c:439
+#: builtin/help.c:447 builtin/help.c:454
 #, c-format
 msgid "usage: %s%s"
 msgstr "användning: %s%s"
 
-#: builtin/help.c:453
+#: builtin/help.c:470
 #, c-format
 msgid "`git %s' is aliased to `%s'"
 msgstr "\"git %s\" är ett alias för \"%s\""
 
-#: builtin/index-pack.c:169
+#: builtin/index-pack.c:170
 #, c-format
 msgid "object type mismatch at %s"
 msgstr "objekttyp stämmer inte överens vid %s"
 
-#: builtin/index-pack.c:189
+#: builtin/index-pack.c:190
 msgid "object of unexpected type"
 msgstr "objekt av oväntad typ"
 
-#: builtin/index-pack.c:226
+#: builtin/index-pack.c:227
 #, c-format
 msgid "cannot fill %d byte"
 msgid_plural "cannot fill %d bytes"
 msgstr[0] "kan inte fylla %d byte"
 msgstr[1] "kan inte fylla %d byte"
 
-#: builtin/index-pack.c:236
+#: builtin/index-pack.c:237
 msgid "early EOF"
 msgstr "tidigt filslut"
 
-#: builtin/index-pack.c:237
+#: builtin/index-pack.c:238
 msgid "read error on input"
 msgstr "indataläsfel"
 
-#: builtin/index-pack.c:249
+#: builtin/index-pack.c:250
 msgid "used more bytes than were available"
 msgstr "använde fler byte än tillgängligt"
 
-#: builtin/index-pack.c:256
+#: builtin/index-pack.c:257
 msgid "pack too large for current definition of off_t"
 msgstr "paket för stort för nuvarande definition av off_t"
 
-#: builtin/index-pack.c:272
+#: builtin/index-pack.c:273
 #, c-format
 msgid "unable to create '%s'"
 msgstr "kunde inte skapa \"%s\""
 
-#: builtin/index-pack.c:277
+#: builtin/index-pack.c:278
 #, c-format
 msgid "cannot open packfile '%s'"
 msgstr "kan inte öppna paketfilen \"%s\""
 
-#: builtin/index-pack.c:291
+#: builtin/index-pack.c:292
 msgid "pack signature mismatch"
 msgstr "paketsignatur stämmer inte överens"
 
-#: builtin/index-pack.c:311
+#: builtin/index-pack.c:294
+#, c-format
+msgid "pack version %<PRIu32> unsupported"
+msgstr "paketversion %<PRIu32> stöds ej"
+
+#: builtin/index-pack.c:312
 #, c-format
 msgid "pack has bad object at offset %lu: %s"
 msgstr "paketet har felaktigt objekt vid index %lu: %s"
 
-#: builtin/index-pack.c:405
+#: builtin/index-pack.c:434
 #, c-format
 msgid "inflate returned %d"
 msgstr "inflate returnerade %d"
 
-#: builtin/index-pack.c:450
+#: builtin/index-pack.c:483
 msgid "offset value overflow for delta base object"
 msgstr "indexvärdespill för deltabasobjekt"
 
-#: builtin/index-pack.c:458
+#: builtin/index-pack.c:491
 msgid "delta base offset is out of bound"
 msgstr "deltabasindex utanför gränsen"
 
-#: builtin/index-pack.c:466
+#: builtin/index-pack.c:499
 #, c-format
 msgid "unknown object type %d"
 msgstr "okänd objekttyp %d"
 
-#: builtin/index-pack.c:495
+#: builtin/index-pack.c:530
 msgid "cannot pread pack file"
 msgstr "kan inte utföra \"pread\" på paketfil"
 
-#: builtin/index-pack.c:497
+#: builtin/index-pack.c:532
 #, c-format
 msgid "premature end of pack file, %lu byte missing"
 msgid_plural "premature end of pack file, %lu bytes missing"
 msgstr[0] "för tidigt slut på paketfilen, %lu byte saknas"
 msgstr[1] "för tidigt slut på paketfilen, %lu byte saknas"
 
-#: builtin/index-pack.c:510
+#: builtin/index-pack.c:558
 msgid "serious inflate inconsistency"
 msgstr "allvarlig inflate-inkonsekvens"
 
-#: builtin/index-pack.c:583
-#, c-format
-msgid "cannot read existing object %s"
-msgstr "kan inte läsa befintligt objekt %s"
-
-#: builtin/index-pack.c:586
+#: builtin/index-pack.c:649 builtin/index-pack.c:655 builtin/index-pack.c:678
+#: builtin/index-pack.c:712 builtin/index-pack.c:721
 #, c-format
 msgid "SHA1 COLLISION FOUND WITH %s !"
 msgstr "SHA1-KOLLISION UPPTÄCKT VID %s !"
 
-#: builtin/index-pack.c:598
+#: builtin/index-pack.c:652 builtin/pack-objects.c:170
+#: builtin/pack-objects.c:262
+#, c-format
+msgid "unable to read %s"
+msgstr "kunde inte läsa %s"
+
+#: builtin/index-pack.c:718
+#, c-format
+msgid "cannot read existing object %s"
+msgstr "kan inte läsa befintligt objekt %s"
+
+#: builtin/index-pack.c:732
 #, c-format
 msgid "invalid blob object %s"
 msgstr "ogiltigt blob-objekt %s"
 
-#: builtin/index-pack.c:610
+#: builtin/index-pack.c:747
 #, c-format
 msgid "invalid %s"
 msgstr "ogiltigt %s"
 
-#: builtin/index-pack.c:612
+#: builtin/index-pack.c:749
 msgid "Error in object"
 msgstr "Fel i objekt"
 
-#: builtin/index-pack.c:614
+#: builtin/index-pack.c:751
 #, c-format
 msgid "Not all child objects of %s are reachable"
 msgstr "Inte alla barnobjekt för %s kan nås"
 
-#: builtin/index-pack.c:687 builtin/index-pack.c:713
+#: builtin/index-pack.c:821 builtin/index-pack.c:847
 msgid "failed to apply delta"
 msgstr "misslyckades tillämpa delta"
 
-#: builtin/index-pack.c:850
+#: builtin/index-pack.c:986
 msgid "Receiving objects"
-msgstr "Tar bort objeckt"
+msgstr "Tar emot objekt"
 
-#: builtin/index-pack.c:850
+#: builtin/index-pack.c:986
 msgid "Indexing objects"
 msgstr "Skapar index för objekt"
 
-#: builtin/index-pack.c:872
+#: builtin/index-pack.c:1012
 msgid "pack is corrupted (SHA1 mismatch)"
 msgstr "paketet är trasigt (SHA1 stämmer inte)"
 
-#: builtin/index-pack.c:877
+#: builtin/index-pack.c:1017
 msgid "cannot fstat packfile"
 msgstr "kan inte utföra \"fstat\" på paketfil"
 
-#: builtin/index-pack.c:880
+#: builtin/index-pack.c:1020
 msgid "pack has junk at the end"
 msgstr "paket har skräp i slutet"
 
-#: builtin/index-pack.c:903
+#: builtin/index-pack.c:1031
+msgid "confusion beyond insanity in parse_pack_objects()"
+msgstr "förvirrad bortom vanvett i parse_pack_objects()"
+
+#: builtin/index-pack.c:1054
 msgid "Resolving deltas"
 msgstr "Analyserar delta"
 
-#: builtin/index-pack.c:954
+#: builtin/index-pack.c:1064
+#, c-format
+msgid "unable to create thread: %s"
+msgstr "kunde inte skapa tråd: %s"
+
+#: builtin/index-pack.c:1106
 msgid "confusion beyond insanity"
 msgstr "förvirrad bortom vanvett"
 
-#: builtin/index-pack.c:973
+#: builtin/index-pack.c:1112
+#, c-format
+msgid "completed with %d local objects"
+msgstr "slutfördes med %d lokala objekt"
+
+#: builtin/index-pack.c:1121
+#, c-format
+msgid "Unexpected tail checksum for %s (disk corruption?)"
+msgstr "Oväntad svanschecksumma för %s (trasig disk?)"
+
+#: builtin/index-pack.c:1125
 #, c-format
 msgid "pack has %d unresolved delta"
 msgid_plural "pack has %d unresolved deltas"
 msgstr[0] "paketet har %d oanalyserat delta"
 msgstr[1] "paketet har %d oanalyserade delta"
 
-#: builtin/index-pack.c:998
+#: builtin/index-pack.c:1150
 #, c-format
 msgid "unable to deflate appended object (%d)"
 msgstr "kunde inte utföra \"deflate\" på tillagt objekt (%d)"
 
-#: builtin/index-pack.c:1077
+#: builtin/index-pack.c:1229
 #, c-format
 msgid "local object %s is corrupt"
 msgstr "lokalt objekt %s är trasigt"
 
-#: builtin/index-pack.c:1101
+#: builtin/index-pack.c:1253
 msgid "error while closing pack file"
 msgstr "fel vid stängning av paketfil"
 
-#: builtin/index-pack.c:1114
+#: builtin/index-pack.c:1266
 #, c-format
 msgid "cannot write keep file '%s'"
 msgstr "kan inte ta skriva \"keep\"-fil \"%s\""
 
-#: builtin/index-pack.c:1122
+#: builtin/index-pack.c:1274
 #, c-format
 msgid "cannot close written keep file '%s'"
 msgstr "akn inte stänga skriven \"keep\"-fil \"%s\""
 
-#: builtin/index-pack.c:1135
+#: builtin/index-pack.c:1287
 msgid "cannot store pack file"
 msgstr "kan inte spara paketfil"
 
-#: builtin/index-pack.c:1146
+#: builtin/index-pack.c:1298
 msgid "cannot store index file"
 msgstr "kan inte spara indexfil"
 
-#: builtin/index-pack.c:1247
+#: builtin/index-pack.c:1331
+#, c-format
+msgid "bad pack.indexversion=%<PRIu32>"
+msgstr "felaktig pack.indexversion=%<PRIu32>"
+
+#: builtin/index-pack.c:1337
+#, c-format
+msgid "invalid number of threads specified (%d)"
+msgstr "felaktigt antal trådar angivet (%d)"
+
+#: builtin/index-pack.c:1341 builtin/index-pack.c:1514
+#, c-format
+msgid "no threads support, ignoring %s"
+msgstr "trådstöd saknas, ignorerar %s"
+
+#: builtin/index-pack.c:1399
 #, c-format
 msgid "Cannot open existing pack file '%s'"
 msgstr "Kan inte öppna befintlig paketfil \"%s\""
 
-#: builtin/index-pack.c:1249
+#: builtin/index-pack.c:1401
 #, c-format
 msgid "Cannot open existing pack idx file for '%s'"
 msgstr "Kan inte öppna befintligt paket-idx-fil för \"%s\""
 
-#: builtin/index-pack.c:1296
+#: builtin/index-pack.c:1448
 #, c-format
 msgid "non delta: %d object"
 msgid_plural "non delta: %d objects"
 msgstr[0] "icke-delta: %d objekt"
 msgstr[1] "icke-delta: %d objekt"
 
-#: builtin/index-pack.c:1303
+#: builtin/index-pack.c:1455
 #, c-format
 msgid "chain length = %d: %lu object"
 msgid_plural "chain length = %d: %lu objects"
 msgstr[0] "kedjelängd = %d: %lu objekt"
 msgstr[1] "kedjelängd = %d: %lu objekt"
 
-#: builtin/index-pack.c:1330
+#: builtin/index-pack.c:1482
 msgid "Cannot come back to cwd"
 msgstr "Kan inte gå tillbaka till arbetskatalogen (cwd)"
 
-#: builtin/index-pack.c:1374 builtin/index-pack.c:1377
-#: builtin/index-pack.c:1389 builtin/index-pack.c:1393
+#: 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 "felaktig %s"
 
-#: builtin/index-pack.c:1407
+#: builtin/index-pack.c:1559
 msgid "--fix-thin cannot be used without --stdin"
 msgstr "--fix-thin kan inte användas med --stdin"
 
-#: builtin/index-pack.c:1411 builtin/index-pack.c:1421
+#: builtin/index-pack.c:1563 builtin/index-pack.c:1573
 #, c-format
 msgid "packfile name '%s' does not end with '.pack'"
 msgstr "paketfilnamnet \"%s\" slutar inte med \".pack\""
 
-#: builtin/index-pack.c:1430
+#: builtin/index-pack.c:1582
 msgid "--verify with no packfile name given"
 msgstr "--verify angavs utan paketfilnamn"
 
@@ -3189,22 +5158,22 @@ msgstr "kopierade inte mallar från felaktig formatversion %d från \"%s\""
 msgid "insane git directory %s"
 msgstr "tokig git-katalog %s"
 
-#: builtin/init-db.c:322 builtin/init-db.c:325
+#: builtin/init-db.c:323 builtin/init-db.c:326
 #, c-format
 msgid "%s already exists"
 msgstr "%s finns redan"
 
-#: builtin/init-db.c:354
+#: builtin/init-db.c:355
 #, c-format
 msgid "unable to handle file type %d"
 msgstr "kan inte hantera filtyp %d"
 
-#: builtin/init-db.c:357
+#: builtin/init-db.c:358
 #, c-format
 msgid "unable to move %s to %s"
 msgstr "kan inte flytta %s till %s"
 
-#: builtin/init-db.c:362
+#: builtin/init-db.c:363
 #, c-format
 msgid "Could not create git link %s"
 msgstr "Kunde inte skapa gitlänk %s"
@@ -3214,38 +5183,58 @@ msgstr "Kunde inte skapa gitlänk %s"
 #. * existing" or "Initialized empty", the second " shared" or
 #. * "", and the last '%s%s' is the verbatim directory name.
 #.
-#: builtin/init-db.c:419
+#: builtin/init-db.c:420
 #, c-format
 msgid "%s%s Git repository in %s%s\n"
 msgstr "%s%s Git-arkiv i %s%s\n"
 
-#: builtin/init-db.c:420
+#: builtin/init-db.c:421
 msgid "Reinitialized existing"
 msgstr "Ominitierade befintligt"
 
-#: builtin/init-db.c:420
+#: builtin/init-db.c:421
 msgid "Initialized empty"
 msgstr "Initierade tomt"
 
-#: builtin/init-db.c:421
+#: builtin/init-db.c:422
 msgid " shared"
 msgstr " delat"
 
-#: builtin/init-db.c:440
+#: builtin/init-db.c:441
 msgid "cannot tell cwd"
 msgstr "kan inte läsa aktuell katalog (cwd)"
 
-#: builtin/init-db.c:521 builtin/init-db.c:528
+#: builtin/init-db.c:467
+msgid ""
+"git init [-q | --quiet] [--bare] [--template=<template-directory>] [--shared"
+"[=<permissions>]] [directory]"
+msgstr ""
+"git init [-q | --quiet] [--bare] [--template=<mallkatalog>] [--shared"
+"[=<behörigheter>]] [katalog]"
+
+#: builtin/init-db.c:490
+msgid "permissions"
+msgstr "behörigheter"
+
+#: builtin/init-db.c:491
+msgid "specify that the git repository is to be shared amongst several users"
+msgstr "ange att git-arkivet skall delas bland flera användare"
+
+#: builtin/init-db.c:493 builtin/prune-packed.c:77
+msgid "be quiet"
+msgstr "var tyst"
+
+#: builtin/init-db.c:522 builtin/init-db.c:529
 #, c-format
 msgid "cannot mkdir %s"
 msgstr "kan inte skapa katalogen (mkdir) %s"
 
-#: builtin/init-db.c:532
+#: builtin/init-db.c:533
 #, c-format
 msgid "cannot chdir to %s"
 msgstr "kan inte byta katalog (chdir) till %s"
 
-#: builtin/init-db.c:554
+#: builtin/init-db.c:555
 #, c-format
 msgid ""
 "%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-"
@@ -3254,112 +5243,396 @@ msgstr ""
 "%s (eller --work-tree=<katalog>) inte tillåtet utan att ange %s (eller --git-"
 "dir=<katalog>)"
 
-#: builtin/init-db.c:578
+#: builtin/init-db.c:579
 msgid "Cannot access current working directory"
 msgstr "Kan inte komma åt aktuell arbetskatalog"
 
-#: builtin/init-db.c:585
+#: builtin/init-db.c:586
 #, c-format
 msgid "Cannot access work tree '%s'"
 msgstr "Kan inte komma åt arbetskatalogen \"%s\""
 
-#: builtin/log.c:188
+#: builtin/log.c:37
+msgid "git log [<options>] [<since>..<until>] [[--] <path>...]\n"
+msgstr "git log [<flaggor>] [<sedan>..<till>] [[--] <sökväg>...]\n"
+
+#: builtin/log.c:38
+msgid "   or: git show [options] <object>..."
+msgstr "     eller: git show [flaggor] <objekt>..."
+
+#: builtin/log.c:100
+msgid "suppress diff output"
+msgstr "undertryck diff-utdata"
+
+#: builtin/log.c:101
+msgid "show source"
+msgstr "visa källkod"
+
+#: builtin/log.c:102
+msgid "decorate options"
+msgstr "dekoreringsflaggor"
+
+#: builtin/log.c:189
 #, c-format
 msgid "Final output: %d %s\n"
 msgstr "Slututdata: %d %s\n"
 
-#: builtin/log.c:401 builtin/log.c:489
+#: builtin/log.c:403 builtin/log.c:494
 #, c-format
 msgid "Could not read object %s"
 msgstr "Kunde inte läsa objektet %s"
 
-#: builtin/log.c:513
+#: builtin/log.c:518
 #, c-format
 msgid "Unknown type: %d"
 msgstr "Okänd typ: %d"
 
-#: builtin/log.c:602
+#: builtin/log.c:608
 msgid "format.headers without value"
 msgstr "format.headers utan värde"
 
-#: builtin/log.c:676
+#: builtin/log.c:682
 msgid "name of output directory is too long"
 msgstr "namnet på utdatakatalogen är för långt"
 
-#: builtin/log.c:687
+#: builtin/log.c:693
 #, c-format
 msgid "Cannot open patch file %s"
 msgstr "Kan inte öppna patchfilen %s"
 
-#: builtin/log.c:701
+#: builtin/log.c:707
 msgid "Need exactly one range."
 msgstr "Behöver precis ett intervall."
 
-#: builtin/log.c:709
+#: builtin/log.c:715
 msgid "Not a range."
 msgstr "Inte ett intervall."
 
-#: builtin/log.c:786
+#: builtin/log.c:789
 msgid "Cover letter needs email format"
 msgstr "Omslagsbrevet behöver e-postformat"
 
-#: builtin/log.c:859
+#: builtin/log.c:862
 #, c-format
 msgid "insane in-reply-to: %s"
 msgstr "tokigt in-reply-to: %s"
 
-#: builtin/log.c:932
+#: builtin/log.c:890
+msgid "git format-patch [options] [<since> | <revision range>]"
+msgstr "git format-patch [flaggor] [<sedan> | <revisionsintervall>]"
+
+#: builtin/log.c:935
 msgid "Two output directories?"
 msgstr "Två utdatakataloger?"
 
-#: builtin/log.c:1153
+#: builtin/log.c:1063
+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
+msgid "use [PATCH] even with multiple patches"
+msgstr "använd [PATCH] även för flera patchar"
+
+#: builtin/log.c:1070
+msgid "print patches to standard out"
+msgstr "skriv patcharna på stnadard ut"
+
+#: builtin/log.c:1072
+msgid "generate a cover letter"
+msgstr "generera ett följebrev"
+
+#: builtin/log.c:1074
+msgid "use simple number sequence for output file names"
+msgstr "använd enkel nummersekvens för utdatafilnamn"
+
+#: builtin/log.c:1075
+msgid "sfx"
+msgstr "sfx"
+
+#: builtin/log.c:1076
+msgid "use <sfx> instead of '.patch'"
+msgstr "använd <sfx> istället för \".patch\""
+
+#: builtin/log.c:1078
+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
+msgid "Use [<prefix>] instead of [PATCH]"
+msgstr "Använd [<prefix>] istället för [PATCH]"
+
+#: builtin/log.c:1083
+msgid "store resulting files in <dir>"
+msgstr "spara filerna i <katalog>"
+
+#: builtin/log.c:1086
+msgid "don't strip/add [PATCH]"
+msgstr "ta inte bort eller lägg till [PATCH]"
+
+#: builtin/log.c:1089
+msgid "don't output binary diffs"
+msgstr "skriv inte binära diffar"
+
+#: builtin/log.c:1091
+msgid "don't include a patch matching a commit upstream"
+msgstr "ta inte med patchar som motsvarar en uppströmsincheckning"
+
+#: builtin/log.c:1093
+msgid "show patch format instead of default (patch + stat)"
+msgstr "visa patchformat istället för standard (patch + stat)"
+
+#: builtin/log.c:1095
+msgid "Messaging"
+msgstr "E-post"
+
+#: builtin/log.c:1096
+msgid "header"
+msgstr "huvud"
+
+#: builtin/log.c:1097
+msgid "add email header"
+msgstr "lägg till e-posthuvud"
+
+#: builtin/log.c:1098 builtin/log.c:1100
+msgid "email"
+msgstr "epost"
+
+#: builtin/log.c:1098
+msgid "add To: header"
+msgstr "Lägg till mottagarhuvud (\"To:\")"
+
+#: builtin/log.c:1100
+msgid "add Cc: header"
+msgstr "Lägg till kopiehuvud (\"Cc:\")"
+
+#: builtin/log.c:1102
+msgid "message-id"
+msgstr "meddelande-id"
+
+#: builtin/log.c:1103
+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
+msgid "boundary"
+msgstr "gräns"
+
+#: builtin/log.c:1105
+msgid "attach the patch"
+msgstr "bifoga patchen"
+
+#: builtin/log.c:1108
+msgid "inline the patch"
+msgstr "gör patchen ett inline-objekt"
+
+#: builtin/log.c:1112
+msgid "enable message threading, styles: shallow, deep"
+msgstr "aktivera brevtrådning, typer: shallow, deep"
+
+#: builtin/log.c:1114
+msgid "signature"
+msgstr "signatur"
+
+#: builtin/log.c:1115
+msgid "add a signature"
+msgstr "lägg till signatur"
+
+#: builtin/log.c:1117
+msgid "don't print the patch filenames"
+msgstr "visa inte filnamn för patchar"
+
+#: builtin/log.c:1157
 #, c-format
 msgid "bogus committer info %s"
 msgstr "felaktig incheckarinformation %s"
 
-#: builtin/log.c:1198
+#: builtin/log.c:1202
 msgid "-n and -k are mutually exclusive."
 msgstr "-n och -k kan inte användas samtidigt."
 
-#: builtin/log.c:1200
+#: builtin/log.c:1204
 msgid "--subject-prefix and -k are mutually exclusive."
 msgstr "--subject-prefix och -k kan inte användas samtidigt."
 
-#: builtin/log.c:1208
-msgid "--name-only does not make sense"
-msgstr "kan inte använda --name-only"
+#: builtin/log.c:1212
+msgid "--name-only does not make sense"
+msgstr "kan inte använda --name-only"
+
+#: builtin/log.c:1214
+msgid "--name-status does not make sense"
+msgstr "kan inte använda --name-status"
+
+#: builtin/log.c:1216
+msgid "--check does not make sense"
+msgstr "kan inte använda --check"
+
+#: builtin/log.c:1239
+msgid "standard output, or directory, which one?"
+msgstr "standard ut, eller katalog, vilken skall det vara?"
+
+#: builtin/log.c:1241
+#, c-format
+msgid "Could not create directory '%s'"
+msgstr "Kunde inte skapa katalogen \"%s\""
+
+#: builtin/log.c:1394
+msgid "Failed to create output files"
+msgstr "Misslyckades skapa utdatafiler"
+
+#: builtin/log.c:1443
+msgid "git cherry [-v] [<upstream> [<head> [<limit>]]]"
+msgstr "git cherry [-v] [<uppström> [<huvud> [<gräns>]]]"
+
+#: builtin/log.c:1498
+#, 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
+#, c-format
+msgid "Unknown commit %s"
+msgstr "Okänd incheckning %s"
+
+#: builtin/ls-files.c:408
+msgid "git ls-files [options] [<file>...]"
+msgstr "git ls-files [flaggor] [<fil>...]"
+
+#: builtin/ls-files.c:463
+msgid "identify the file status with tags"
+msgstr "identifiera filstatus med taggar"
+
+#: builtin/ls-files.c:465
+msgid "use lowercase letters for 'assume unchanged' files"
+msgstr "använd små bokstäver för \"anta oförändrade\"-filer"
+
+#: builtin/ls-files.c:467
+msgid "show cached files in the output (default)"
+msgstr "visa cachade filer i utdata (standard)"
+
+#: builtin/ls-files.c:469
+msgid "show deleted files in the output"
+msgstr "visa borttagna filer i utdata"
+
+#: builtin/ls-files.c:471
+msgid "show modified files in the output"
+msgstr "visa modifierade filer i utdata"
+
+#: builtin/ls-files.c:473
+msgid "show other files in the output"
+msgstr "visa andra filer i utdata"
+
+#: builtin/ls-files.c:475
+msgid "show ignored files in the output"
+msgstr "visa ignorerade filer i utdata"
+
+#: builtin/ls-files.c:478
+msgid "show staged contents' object name in the output"
+msgstr "visa köat innehålls objektnamn i utdata"
+
+#: builtin/ls-files.c:480
+msgid "show files on the filesystem that need to be removed"
+msgstr "visa filer i filsystemet som behöver tas bort"
+
+#: builtin/ls-files.c:482
+msgid "show 'other' directories' name only"
+msgstr "visa endast namn för \"andra\" kataloger"
+
+#: builtin/ls-files.c:485
+msgid "don't show empty directories"
+msgstr "visa inte tomma kataloger"
+
+#: builtin/ls-files.c:488
+msgid "show unmerged files in the output"
+msgstr "visa ej sammanslagna filer i utdata"
+
+#: builtin/ls-files.c:490
+msgid "show resolve-undo information"
+msgstr "visa \"resolve-undo\"-information"
+
+#: builtin/ls-files.c:492
+msgid "skip files matching pattern"
+msgstr "hoppa över filer som motsvarar mönster"
+
+#: builtin/ls-files.c:495
+msgid "exclude patterns are read from <file>"
+msgstr "exkludera mönster som läses från <fil>"
+
+#: builtin/ls-files.c:498
+msgid "read additional per-directory exclude patterns in <file>"
+msgstr "läs ytterligare per-katalog-exkluderingsmönster från <fil>"
+
+#: builtin/ls-files.c:500
+msgid "add the standard git exclusions"
+msgstr "lägg till git:s standardexkluderingar"
+
+#: builtin/ls-files.c:503
+msgid "make the output relative to the project top directory"
+msgstr "gör utdata relativ till projektets toppkatalog"
+
+#: builtin/ls-files.c:506
+msgid "if any <file> is not in the index, treat this as an error"
+msgstr "om en <fil> inte är indexet, betrakta det som ett fel"
+
+#: builtin/ls-files.c:507
+msgid "tree-ish"
+msgstr "träd-igt"
+
+#: builtin/ls-files.c:508
+msgid "pretend that paths removed since <tree-ish> are still present"
+msgstr "låtsas att sökvägar borttagna sedan <träd-igt> fortfarande finns"
+
+#: builtin/ls-files.c:510
+msgid "show debugging data"
+msgstr "visa felsökningsutdata"
+
+#: builtin/ls-tree.c:27
+msgid "git ls-tree [<options>] <tree-ish> [<path>...]"
+msgstr "git ls-tree [<flaggor>] <träd-igt> [<sökväg>...]"
+
+#: builtin/ls-tree.c:125
+msgid "only show trees"
+msgstr "visa endast träd"
+
+#: builtin/ls-tree.c:127
+msgid "recurse into subtrees"
+msgstr "rekursera ner i underträd"
+
+#: builtin/ls-tree.c:129
+msgid "show trees when recursing"
+msgstr "visa träd medan rekursering"
+
+#: builtin/ls-tree.c:132
+msgid "terminate entries with NUL byte"
+msgstr "terminera poster med NUL-byte"
 
-#: builtin/log.c:1210
-msgid "--name-status does not make sense"
-msgstr "kan inte använda --name-status"
+#: builtin/ls-tree.c:133
+msgid "include object size"
+msgstr "inkludera objektstorlek"
 
-#: builtin/log.c:1212
-msgid "--check does not make sense"
-msgstr "kan inte använda --check"
+#: builtin/ls-tree.c:135 builtin/ls-tree.c:137
+msgid "list only filenames"
+msgstr "visa endast filnamn"
 
-#: builtin/log.c:1235
-msgid "standard output, or directory, which one?"
-msgstr "standard ut, eller katalog, vilken skall det vara?"
+#: builtin/ls-tree.c:140
+msgid "use full path names"
+msgstr "använd fullständiga sökvägsnamn"
 
-#: builtin/log.c:1237
-#, c-format
-msgid "Could not create directory '%s'"
-msgstr "Kunde inte skapa katalogen \"%s\""
+#: builtin/ls-tree.c:142
+msgid "list entire tree; not just current directory (implies --full-name)"
+msgstr "visa hela trädet; inte bara aktuell katalog (implicerar --full-name)"
 
-#: builtin/log.c:1390
-msgid "Failed to create output files"
-msgstr "Misslyckades skapa utdatafiler"
+#: builtin/merge.c:43
+msgid "git merge [options] [<commit>...]"
+msgstr "git merge [flaggor] [<incheckning>...]"
 
-#: builtin/log.c:1494
-#, 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/merge.c:44
+msgid "git merge [options] <msg> HEAD <commit>"
+msgstr "git merge [flaggor] <meddelande> HEAD <incheckning>"
 
-#: builtin/log.c:1510 builtin/log.c:1512 builtin/log.c:1524
-#, c-format
-msgid "Unknown commit %s"
-msgstr "Okänd incheckning %s"
+#: builtin/merge.c:45
+msgid "git merge --abort"
+msgstr "git merge --abort"
 
 #: builtin/merge.c:90
 msgid "switch `m' requires a value"
@@ -3380,6 +5653,67 @@ msgstr "Tillgängliga strategier är:"
 msgid "Available custom strategies are:"
 msgstr "Tillgängliga skräddarsydda strategier är:"
 
+#: builtin/merge.c:183
+msgid "do not show a diffstat at the end of the merge"
+msgstr "visa inte en diffstat när sammanslagningen är färdig"
+
+#: builtin/merge.c:186
+msgid "show a diffstat at the end of the merge"
+msgstr "visa en diffstat när sammanslagningen är färdig"
+
+#: builtin/merge.c:187
+msgid "(synonym to --stat)"
+msgstr "(synonym till --stat)"
+
+#: builtin/merge.c:189
+msgid "add (at most <n>) entries from shortlog to merge commit message"
+msgstr ""
+"lägg till (som mest <n>) poster från shortlog till incheckningsmeddelandet"
+
+#: builtin/merge.c:192
+msgid "create a single commit instead of doing a merge"
+msgstr "skapa en ensam incheckning istället för en sammanslagning"
+
+#: builtin/merge.c:194
+msgid "perform a commit if the merge succeeds (default)"
+msgstr "utför en incheckning om sammanslagningen lyckades (standard)"
+
+#: builtin/merge.c:196
+msgid "edit message before committing"
+msgstr "redigera meddelande innan incheckning"
+
+#: builtin/merge.c:198
+msgid "allow fast-forward (default)"
+msgstr "tillåt snabbspolning (standard)"
+
+#: builtin/merge.c:200
+msgid "abort if fast-forward is not possible"
+msgstr "avbryt om snabbspolning inte är möjlig"
+
+#: builtin/merge.c:202 builtin/notes.c:870 builtin/revert.c:112
+msgid "strategy"
+msgstr "strategi"
+
+#: builtin/merge.c:203
+msgid "merge strategy to use"
+msgstr "sammanslagninsstrategi att använda"
+
+#: builtin/merge.c:204
+msgid "option=value"
+msgstr "alternativ=värde"
+
+#: builtin/merge.c:205
+msgid "option for selected merge strategy"
+msgstr "alternativ för vald sammanslagningsstrategi"
+
+#: builtin/merge.c:207
+msgid "merge commit message (for a non-fast-forward merge)"
+msgstr "incheckningsmeddelande för (icke snabbspolande) sammanslagning"
+
+#: builtin/merge.c:211
+msgid "abort the current in-progress merge"
+msgstr "avbryt den pågående sammanslagningen"
+
 #: builtin/merge.c:240
 msgid "could not run stash."
 msgstr "kunde köra stash."
@@ -3419,55 +5753,51 @@ msgstr "Avslutar SQUASH_MSG"
 msgid "No merge message -- not updating HEAD\n"
 msgstr "Inget sammanslagningsmeddelande -- uppdaterar inte HEAD\n"
 
-#: builtin/merge.c:437
+#: builtin/merge.c:436
 #, c-format
 msgid "'%s' does not point to a commit"
 msgstr "\"%s\" verkar inte peka på en incheckning"
 
-#: builtin/merge.c:536
+#: builtin/merge.c:535
 #, c-format
 msgid "Bad branch.%s.mergeoptions string: %s"
 msgstr "Felaktig branch.%s.mergeoptions-sträng: %s"
 
-#: builtin/merge.c:629
+#: builtin/merge.c:628
 msgid "git write-tree failed to write a tree"
 msgstr "git write-tree misslyckades skriva ett träd"
 
-#: builtin/merge.c:679
+#: builtin/merge.c:678
 msgid "failed to read the cache"
 msgstr "misslyckads läsa cachen"
 
-#: builtin/merge.c:697
-msgid "Unable to write index."
-msgstr "Kunde inte skriva indexet."
-
-#: builtin/merge.c:710
+#: builtin/merge.c:709
 msgid "Not handling anything other than two heads merge."
 msgstr "Hanterar inte något annat än en sammanslagning av två huvuden."
 
-#: builtin/merge.c:724
+#: builtin/merge.c:723
 #, c-format
 msgid "Unknown option for merge-recursive: -X%s"
 msgstr "Felaktig flagga för merge-recursive: -X%s"
 
-#: builtin/merge.c:738
+#: builtin/merge.c:737
 #, c-format
 msgid "unable to write %s"
 msgstr "kunde inte skriva %s"
 
-#: builtin/merge.c:877
+#: builtin/merge.c:876
 #, c-format
 msgid "Could not read from '%s'"
 msgstr "Kunde inte läsa från \"%s\""
 
-#: builtin/merge.c:886
+#: builtin/merge.c:885
 #, 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:892
+#: builtin/merge.c:891
 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"
@@ -3482,53 +5812,53 @@ msgstr ""
 "Rader som inleds med \"#\" kommer ignoreras, och ett tomt meddelande\n"
 "avbryter incheckningen.\n"
 
-#: builtin/merge.c:916
+#: builtin/merge.c:915
 msgid "Empty commit message."
 msgstr "Tomt incheckningsmeddelande."
 
-#: builtin/merge.c:928
+#: builtin/merge.c:927
 #, c-format
 msgid "Wonderful.\n"
 msgstr "Underbart.\n"
 
-#: builtin/merge.c:993
+#: builtin/merge.c:992
 #, 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:1009
+#: builtin/merge.c:1008
 #, c-format
 msgid "'%s' is not a commit"
 msgstr "\"%s\" är inte en incheckning"
 
-#: builtin/merge.c:1050
+#: builtin/merge.c:1049
 msgid "No current branch."
 msgstr "Inte på någon gren."
 
-#: builtin/merge.c:1052
+#: builtin/merge.c:1051
 msgid "No remote for the current branch."
 msgstr "Ingen fjärr för aktuell gren."
 
-#: builtin/merge.c:1054
+#: builtin/merge.c:1053
 msgid "No default upstream defined for the current branch."
 msgstr "Ingen standarduppström angiven för aktuell gren."
 
-#: builtin/merge.c:1059
+#: builtin/merge.c:1058
 #, 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:1146 builtin/merge.c:1303
+#: builtin/merge.c:1145 builtin/merge.c:1302
 #, c-format
 msgid "%s - not something we can merge"
 msgstr "%s - inte något vi kan slå ihop"
 
-#: builtin/merge.c:1214
+#: builtin/merge.c:1213
 msgid "There is no merge to abort (MERGE_HEAD missing)."
 msgstr "Det finns ingen sammanslagning att avbryta (MERGE_HEAD saknas)."
 
-#: builtin/merge.c:1230 git-pull.sh:31
+#: builtin/merge.c:1229 git-pull.sh:31
 msgid ""
 "You have not concluded your merge (MERGE_HEAD exists).\n"
 "Please, commit your changes before you can merge."
@@ -3536,11 +5866,11 @@ msgstr ""
 "Du har inte avslutat sammanslagningen (MERGE_HEAD finns).\n"
 "Checka in dina ändringar innan du kan slå ihop."
 
-#: builtin/merge.c:1233 git-pull.sh:34
+#: builtin/merge.c:1232 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:1237
+#: builtin/merge.c:1236
 msgid ""
 "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
 "Please, commit your changes before you can merge."
@@ -3548,84 +5878,183 @@ 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:1240
+#: builtin/merge.c:1239
 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:1249
+#: builtin/merge.c:1248
 msgid "You cannot combine --squash with --no-ff."
 msgstr "Du kan inte kombinera --squash med --no-ff."
 
-#: builtin/merge.c:1254
+#: builtin/merge.c:1253
 msgid "You cannot combine --no-ff with --ff-only."
 msgstr "Du kan inte kombinera --no-ff med --ff-only."
 
-#: builtin/merge.c:1261
+#: builtin/merge.c:1260
 msgid "No commit specified and merge.defaultToUpstream not set."
 msgstr "Ingen incheckning angiven och merge.defaultToUpstream är ej satt."
 
-#: builtin/merge.c:1293
+#: builtin/merge.c:1292
 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:1296
+#: builtin/merge.c:1295
 msgid "Squash commit into empty head not supported yet"
 msgstr "Stöder inte en tillplattningsincheckning på ett tomt huvud ännu"
 
-#: builtin/merge.c:1298
+#: builtin/merge.c:1297
 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:1413
+#: builtin/merge.c:1412
 #, c-format
 msgid "Updating %s..%s\n"
 msgstr "Uppdaterar %s..%s\n"
 
-#: builtin/merge.c:1451
+#: builtin/merge.c:1450
 #, c-format
 msgid "Trying really trivial in-index merge...\n"
 msgstr "Försöker riktigt enkel sammanslagning i indexet...\n"
 
-#: builtin/merge.c:1458
+#: builtin/merge.c:1457
 #, c-format
 msgid "Nope.\n"
 msgstr "Nej.\n"
 
-#: builtin/merge.c:1490
+#: builtin/merge.c:1489
 msgid "Not possible to fast-forward, aborting."
 msgstr "Kan inte snabbspola, avbryter."
 
-#: builtin/merge.c:1513 builtin/merge.c:1592
+#: builtin/merge.c:1512 builtin/merge.c:1591
 #, c-format
 msgid "Rewinding the tree to pristine...\n"
 msgstr "Återspolar trädet till orört...\n"
 
-#: builtin/merge.c:1517
+#: builtin/merge.c:1516
 #, c-format
 msgid "Trying merge strategy %s...\n"
 msgstr "Försöker sammanslagninsstrategin %s...\n"
 
-#: builtin/merge.c:1583
+#: builtin/merge.c:1582
 #, c-format
 msgid "No merge strategy handled the merge.\n"
 msgstr "Ingen sammanslagningsstrategi hanterade sammanslagningen.\n"
 
-#: builtin/merge.c:1585
+#: builtin/merge.c:1584
 #, c-format
 msgid "Merge with strategy %s failed.\n"
-msgstr "Sammanslaning med strategin %s misslyckades.\n"
+msgstr "Sammanslagning med strategin %s misslyckades.\n"
 
-#: builtin/merge.c:1594
+#: builtin/merge.c:1593
 #, 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:1606
+#: builtin/merge.c:1605
 #, c-format
 msgid "Automatic merge went well; stopped before committing as requested\n"
 msgstr ""
 "Automatisk sammanslagning lyckades; stoppar före incheckning som önskat\n"
 
+#: builtin/merge-base.c:26
+msgid "git merge-base [-a|--all] <commit> <commit>..."
+msgstr "git merge-base [-a|--all] <incheckning> <incheckning>..."
+
+#: builtin/merge-base.c:27
+msgid "git merge-base [-a|--all] --octopus <commit>..."
+msgstr "git merge-base [-a|--all] --octopus <incheckning>..."
+
+#: builtin/merge-base.c:28
+msgid "git merge-base --independent <commit>..."
+msgstr "git merge-base --independent <incheckning>..."
+
+#: builtin/merge-base.c:29
+msgid "git merge-base --is-ancestor <commit> <commit>"
+msgstr "git merge-base --is-ancestor <incheckning> <incheckning>"
+
+#: builtin/merge-base.c:98
+msgid "output all common ancestors"
+msgstr "skriv ut alla gemensamma anfäder"
+
+#: builtin/merge-base.c:99
+msgid "find ancestors for a single n-way merge"
+msgstr "hitta anfader för enkel n-vägssammanslagning"
+
+#: builtin/merge-base.c:100
+msgid "list revs not reachable from others"
+msgstr "visa revisioner som inte kan nås från andra"
+
+#: builtin/merge-base.c:102
+msgid "is the first one ancestor of the other?"
+msgstr "är den första anfader till den andra?"
+
+#: builtin/merge-file.c:8
+msgid ""
+"git merge-file [options] [-L name1 [-L orig [-L name2]]] file1 orig_file "
+"file2"
+msgstr ""
+"git merge-file [alternativ] [-L namn1 [-L orig [-L namn2]]] fil1 origfil fil2"
+
+#: builtin/merge-file.c:33
+msgid "send results to standard output"
+msgstr "sänd resultat till standard ut"
+
+#: builtin/merge-file.c:34
+msgid "use a diff3 based merge"
+msgstr "använd diff3-baserad sammanslagning"
+
+#: builtin/merge-file.c:35
+msgid "for conflicts, use our version"
+msgstr "för konflikter, använd vår version"
+
+#: builtin/merge-file.c:37
+msgid "for conflicts, use their version"
+msgstr "för konflikter, använd deras version"
+
+#: builtin/merge-file.c:39
+msgid "for conflicts, use a union version"
+msgstr "för konflikter, använd en förenad version"
+
+#: builtin/merge-file.c:42
+msgid "for conflicts, use this marker size"
+msgstr "för konflikter, använd denna markörstorlek"
+
+#: builtin/merge-file.c:43
+msgid "do not warn about conflicts"
+msgstr "varna inte om konflikter"
+
+#: builtin/merge-file.c:45
+msgid "set labels for file1/orig_file/file2"
+msgstr "sätt etiketter för fil1/origfil/fil2"
+
+#: 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 "indata är NUL-terminerad"
+
+#: builtin/mktree.c:154 builtin/write-tree.c:24
+msgid "allow missing objects"
+msgstr "tillåt saknade objekt"
+
+#: builtin/mktree.c:155
+msgid "allow creation of more than one tree"
+msgstr "tillåt skapa mer än ett träd"
+
+#: builtin/mv.c:14
+msgid "git mv [options] <source>... <destination>"
+msgstr "git mv [flaggor] <källa>... <mål>"
+
+#: builtin/mv.c:64
+msgid "force move/rename even if target exists"
+msgstr "tvinga flytta/ändra namn även om målet finns"
+
+#: builtin/mv.c:65
+msgid "skip move/rename errors"
+msgstr "hoppa över fel vid flytt/namnändring"
+
 #: builtin/mv.c:108
 #, c-format
 msgid "Checking rename of '%s' to '%s'\n"
@@ -3688,114 +6117,287 @@ msgstr "Byter namn på %s till %s\n"
 msgid "renaming '%s' failed"
 msgstr "misslyckades byta namn på \"%s\""
 
-#: builtin/notes.c:139
+#: builtin/name-rev.c:175
+msgid "git name-rev [options] <commit>..."
+msgstr "git name-rev [flaggor] <incheckning>..."
+
+#: builtin/name-rev.c:176
+msgid "git name-rev [options] --all"
+msgstr "git name-rev [flaggor] --all"
+
+#: builtin/name-rev.c:177
+msgid "git name-rev [options] --stdin"
+msgstr "git name-rev [flaggor] --stdin"
+
+#: builtin/name-rev.c:229
+msgid "print only names (no SHA-1)"
+msgstr "skriv endast namn (ingen SHA-1)"
+
+#: builtin/name-rev.c:230
+msgid "only use tags to name the commits"
+msgstr "använd endast taggar för att namnge incheckningar"
+
+#: builtin/name-rev.c:232
+msgid "only use refs matching <pattern>"
+msgstr "använd endast referenser som motsvarar <mönster>"
+
+#: builtin/name-rev.c:234
+msgid "list all commits reachable from all refs"
+msgstr "lista alla incheckningar som kan nås alla referenser"
+
+#: builtin/name-rev.c:235
+msgid "read from stdin"
+msgstr "läs från standard in"
+
+#: builtin/name-rev.c:236
+msgid "allow to print `undefined` names"
+msgstr "tillåt att skriva \"odefinierade\" namn"
+
+#: builtin/notes.c:26
+msgid "git notes [--ref <notes_ref>] [list [<object>]]"
+msgstr "git notes [--ref <anteckningsref>] [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 <anteckningsref>] add [-f] [-m <medd> | -F <fil> | (-c | -"
+"C) <objekt>] [<objekt>]"
+
+#: builtin/notes.c:28
+msgid "git notes [--ref <notes_ref>] copy [-f] <from-object> <to-object>"
+msgstr ""
+"git notes [--ref <anteckningsref>] copy [-f] <från-objekt> <till-objekt>"
+
+#: builtin/notes.c:29
+msgid ""
+"git notes [--ref <notes_ref>] append [-m <msg> | -F <file> | (-c | -C) "
+"<object>] [<object>]"
+msgstr ""
+"git notes [--ref <anteckningsref>] append [-m <medd> | -F <fil> | (-c | -C) "
+"<objekt>] [<objekt>]"
+
+#: builtin/notes.c:30
+msgid "git notes [--ref <notes_ref>] edit [<object>]"
+msgstr "git notes [--ref <anteckningsref>] edit [<objekt>]"
+
+#: builtin/notes.c:31
+msgid "git notes [--ref <notes_ref>] show [<object>]"
+msgstr "git notes [--ref <anteckningsref>] show [<objekt>]"
+
+#: builtin/notes.c:32
+msgid ""
+"git notes [--ref <notes_ref>] merge [-v | -q] [-s <strategy> ] <notes_ref>"
+msgstr ""
+"git notes [--ref <anteckningsref>] merge [-v | -q] [-s <strategi> ] "
+"<anteckningsref>"
+
+#: 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 <anteckningsref>] remove [<objekt>...]"
+
+#: builtin/notes.c:36
+msgid "git notes [--ref <notes_ref>] prune [-n | -v]"
+msgstr "git notes [--ref <anteckningsref>] prune [-n | -v]"
+
+#: builtin/notes.c:37
+msgid "git notes [--ref <notes_ref>] get-ref"
+msgstr "git notes [--ref <anteckningsref>] 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 [<flaggor>] [<objekt>]"
+
+#: builtin/notes.c:52
+msgid "git notes copy [<options>] <from-object> <to-object>"
+msgstr "git notes copy [<flaggor>] <från-objekt> <till-objekt>"
+
+#: builtin/notes.c:53
+msgid "git notes copy --stdin [<from-object> <to-object>]..."
+msgstr "git notes copy --stdin [<från-objekt> <till-objekt>]..."
+
+#: builtin/notes.c:58
+msgid "git notes append [<options>] [<object>]"
+msgstr "git notes append [<flaggor>] [<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 [<flaggor>] <anteckningsref>"
+
+#: builtin/notes.c:74
+msgid "git notes merge --commit [<options>]"
+msgstr "git notes merge --commit [<flaggor>]"
+
+#: builtin/notes.c:75
+msgid "git notes merge --abort [<options>]"
+msgstr "git notes merge --abort [<flaggor>]"
+
+#: 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 [<flaggor>]"
+
+#: 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 "kunde inte starta \"show\" för objektet \"%s\""
 
-#: builtin/notes.c:145
+#: builtin/notes.c:148
 msgid "can't fdopen 'show' output fd"
 msgstr "kunde inte öppna (fdopen) \"show\"-utdata-filhandtag"
 
-#: builtin/notes.c:155
+#: builtin/notes.c:158
 #, c-format
 msgid "failed to close pipe to 'show' for object '%s'"
 msgstr "kunde inte stänga röret till \"show\" för objektet \"%s\""
 
-#: builtin/notes.c:158
+#: builtin/notes.c:161
 #, c-format
 msgid "failed to finish 'show' for object '%s'"
 msgstr "kunde inte avsluta \"show\" för objektet \"%s\""
 
-#: 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 "kunde inte skapa filen \"%s\""
 
-#: builtin/notes.c:189
+#: builtin/notes.c:192
 msgid "Please supply the note contents using either -m or -F option"
 msgstr "Ange innehåll för anteckningen med antingen -m eller -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 "Tar bort anteckning för objektet %s\n"
 
-#: builtin/notes.c:215
+#: builtin/notes.c:218
 msgid "unable to write note object"
 msgstr "kunde inte skriva anteckningsobjekt"
 
-#: builtin/notes.c:217
+#: builtin/notes.c:220
 #, c-format
 msgid "The note contents has been left in %s"
 msgstr "Anteckningens innehåll har lämnats kvar i %s"
 
-#: builtin/notes.c:251 builtin/tag.c:542
+#: builtin/notes.c:254 builtin/tag.c:542
 #, c-format
 msgid "cannot read '%s'"
 msgstr "kunde inte läsa \"%s\""
 
-#: 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 "kunde inte öppna eller läsa \"%s\""
 
-#: 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 "Kunde inte slå upp \"%s\" som en giltig referens."
 
-#: builtin/notes.c:275
+#: builtin/notes.c:278
 #, c-format
 msgid "Failed to read object '%s'."
 msgstr "Kunde inte läsa objektet \"%s\"."
 
-#: builtin/notes.c:299
+#: builtin/notes.c:302
 msgid "Cannot commit uninitialized/unreferenced notes tree"
 msgstr "Kan inte checka in oinitierat/orefererat anteckningsträd"
 
-#: builtin/notes.c:340
+#: builtin/notes.c:343
 #, c-format
 msgid "Bad notes.rewriteMode value: '%s'"
 msgstr "Felaktigt värde för notes.rewriteMode: '%s'"
 
-#: builtin/notes.c:350
+#: builtin/notes.c:353
 #, c-format
 msgid "Refusing to rewrite notes in %s (outside of refs/notes/)"
 msgstr "Vägrar skriva över anteckningar i %s (utanför 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 "Felaktigt värde på %s: \"%s\""
 
-#: builtin/notes.c:441
+#: builtin/notes.c:444
 #, c-format
 msgid "Malformed input line: '%s'."
 msgstr "Felaktig indatarad: \"%s\"."
 
-#: builtin/notes.c:456
+#: builtin/notes.c:459
 #, c-format
 msgid "Failed to copy notes from '%s' to '%s'"
 msgstr "Misslyckades kopiera anteckningar från \"%s\" till \"%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 "för många parametrar"
 
-#: 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 "Inga anteckningar hittades för objektet %s."
 
-#: builtin/notes.c:580
+#: builtin/notes.c:538 builtin/notes.c:695
+msgid "note contents as a string"
+msgstr "anteckningsinnehåll som sträng"
+
+#: builtin/notes.c:541 builtin/notes.c:698
+msgid "note contents in a file"
+msgstr "anteckningsinnehåll i en fil"
+
+#: 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 "återanvänd och redigera angivet anteckningsobjekt"
+
+#: builtin/notes.c:547 builtin/notes.c:704
+msgid "reuse specified note object"
+msgstr "återanvänd angivet anteckningsobjekt"
+
+#: builtin/notes.c:549 builtin/notes.c:617
+msgid "replace existing notes"
+msgstr "ersätt befintliga anteckningar"
+
+#: builtin/notes.c:583
 #, c-format
 msgid ""
 "Cannot add notes. Found existing notes for object %s. Use '-f' to overwrite "
@@ -3804,16 +6406,24 @@ msgstr ""
 "Kan inte lägga till anteckningar. Hittade befintliga anteckningar för "
 "objektet %s. Använd \"-f\" för att skriva över befintliga anteckningar"
 
-#: 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 "Skriver över befintliga anteckningar för objektet %s\n"
 
-#: builtin/notes.c:635
+#: builtin/notes.c:618
+msgid "read objects from stdin"
+msgstr "läs objekt från standard in"
+
+#: builtin/notes.c:620
+msgid "load rewriting config for <command> (implies --stdin)"
+msgstr "läs omskrivningsinställning för <kommando> (implicerar --stdin)"
+
+#: builtin/notes.c:638
 msgid "too few parameters"
 msgstr "för få parametrar"
 
-#: builtin/notes.c:656
+#: builtin/notes.c:659
 #, c-format
 msgid ""
 "Cannot copy notes. Found existing notes for object %s. Use '-f' to overwrite "
@@ -3822,12 +6432,12 @@ msgstr ""
 "Kan inte kopiera anteckningar. Hittade befintliga anteckningar för objektet "
 "%s. Använd \"-f\" för att skriva över befintliga anteckningar"
 
-#: builtin/notes.c:668
+#: builtin/notes.c:671
 #, c-format
 msgid "Missing notes on source object %s. Cannot copy."
 msgstr "Anteckningar på källobjektet %s saknas. Kan inte kopiera."
 
-#: 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"
@@ -3836,36 +6446,255 @@ msgstr ""
 "Flaggorna -m/-F/-c/-C rekommenderas inte för underkommandot \"edit\".\n"
 "Använd \"git notes add -f -m/-F/-c/-C\" istället.\n"
 
-#: builtin/notes.c:971
+#: builtin/notes.c:867
+msgid "General options"
+msgstr "Allmänna flaggor"
+
+#: builtin/notes.c:869
+msgid "Merge options"
+msgstr "Flaggor för sammanslagning"
+
+#: builtin/notes.c:871
+msgid ""
+"resolve notes conflicts using the given strategy (manual/ours/theirs/union/"
+"cat_sort_uniq)"
+msgstr ""
+"läs konflikter i anteckningar med angiven strategi (manual/ours/theirs/union/"
+"cat_sort_uniq)"
+
+#: builtin/notes.c:873
+msgid "Committing unmerged notes"
+msgstr "Checkar in ej sammanslagna anteckningar"
+
+#: builtin/notes.c:875
+msgid "finalize notes merge by committing unmerged notes"
+msgstr ""
+"färdigställ sammanslagning av anteckningar genom att checka in ej "
+"sammanslagna anteckningar"
+
+#: builtin/notes.c:877
+msgid "Aborting notes merge resolution"
+msgstr "Avbryt lösning av sammanslagning av anteckningar"
+
+#: builtin/notes.c:879
+msgid "abort notes merge"
+msgstr "avbryt sammanslagning av anteckningar"
+
+#: builtin/notes.c:974
 #, c-format
 msgid "Object %s has no note\n"
 msgstr "Objektet %s har ingen anteckning\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 "försök att ta bort icke-existerande anteckningar är inte ett fel"
+
+#: builtin/notes.c:989
+msgid "read object names from the standard input"
+msgstr "läs objektnamn från standard in"
+
+#: builtin/notes.c:1070
+msgid "notes_ref"
+msgstr "anteckningar-ref"
+
+#: builtin/notes.c:1071
+msgid "use notes from <notes_ref>"
+msgstr "använd anteckningar från <anteckningsref>"
+
+#: builtin/notes.c:1106 builtin/remote.c:1598
 #, c-format
 msgid "Unknown subcommand: %s"
 msgstr "Okänt underkommando: %s"
 
-#: builtin/pack-objects.c:2337
+#: builtin/pack-objects.c:23
+msgid "git pack-objects --stdout [options...] [< ref-list | < object-list]"
+msgstr "git pack-objects --stdout [flaggor...] [< reflista | < objektlista]"
+
+#: builtin/pack-objects.c:24
+msgid "git pack-objects [options...] base-name [< ref-list | < object-list]"
+msgstr "git pack-objects [flaggor...] basnamn [< reflista | < objektlista]"
+
+#: builtin/pack-objects.c:183 builtin/pack-objects.c:186
+#, c-format
+msgid "deflate error (%d)"
+msgstr "fel i deflate (%d)"
+
+#: builtin/pack-objects.c:2398
 #, c-format
 msgid "unsupported index version %s"
 msgstr "indexversionen %s stöds ej"
 
-#: builtin/pack-objects.c:2341
+#: builtin/pack-objects.c:2402
 #, c-format
 msgid "bad index version '%s'"
 msgstr "felaktig indexversion \"%s\""
 
-#: builtin/pack-objects.c:2364
+#: builtin/pack-objects.c:2425
 #, c-format
 msgid "option %s does not accept negative form"
 msgstr "flaggan %s godtar inte negativ form"
 
-#: builtin/pack-objects.c:2368
+#: builtin/pack-objects.c:2429
 #, 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
+msgid "do not show progress meter"
+msgstr "visa inte förloppsindikator"
+
+#: builtin/pack-objects.c:2450
+msgid "show progress meter"
+msgstr "visa förloppsindikator"
+
+#: builtin/pack-objects.c:2452
+msgid "show progress meter during object writing phase"
+msgstr "visa förloppsindikator under objektskrivningsfasen"
+
+#: builtin/pack-objects.c:2455
+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
+msgid "version[,offset]"
+msgstr "version[,offset]"
+
+#: builtin/pack-objects.c:2457
+msgid "write the pack index file in the specified idx format version"
+msgstr "skriv paketindexfilen i angiven indexformatversion"
+
+#: builtin/pack-objects.c:2460
+msgid "maximum size of each output pack file"
+msgstr "maximal storlek på varje utdatapaketfil"
+
+#: builtin/pack-objects.c:2462
+msgid "ignore borrowed objects from alternate object store"
+msgstr "ignorera lånade objekt från alternativa objektlager"
+
+#: builtin/pack-objects.c:2464
+msgid "ignore packed objects"
+msgstr "ignorera packade objekt"
+
+#: builtin/pack-objects.c:2466
+msgid "limit pack window by objects"
+msgstr "begränsa paketfönster efter objekt"
+
+#: builtin/pack-objects.c:2468
+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
+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
+msgid "reuse existing deltas"
+msgstr "återanvänd befintliga delta"
+
+#: builtin/pack-objects.c:2474
+msgid "reuse existing objects"
+msgstr "återanvänd befintliga objekt"
+
+#: builtin/pack-objects.c:2476
+msgid "use OFS_DELTA objects"
+msgstr "använd OFS_DELTA-objekt"
+
+#: builtin/pack-objects.c:2478
+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
+msgid "do not create an empty pack output"
+msgstr "försök inte skapa tom paketutdata"
+
+#: builtin/pack-objects.c:2482
+msgid "read revision arguments from standard input"
+msgstr "läs revisionsargument från standard in"
+
+#: builtin/pack-objects.c:2484
+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
+msgid "include objects reachable from any reference"
+msgstr "inkludera objekt som kan nås från någon referens"
+
+#: builtin/pack-objects.c:2490
+msgid "include objects referred by reflog entries"
+msgstr "inkludera objekt som refereras från referensloggposter"
+
+#: builtin/pack-objects.c:2493
+msgid "output pack to stdout"
+msgstr "skriv paket på standard ut"
+
+#: builtin/pack-objects.c:2495
+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
+msgid "keep unreachable objects"
+msgstr "behåll onåbara objekt"
+
+#: builtin/pack-objects.c:2498 parse-options.h:141
+msgid "time"
+msgstr "tid"
+
+#: builtin/pack-objects.c:2499
+msgid "unpack unreachable objects newer than <time>"
+msgstr "packa upp onåbara objekt nyare än <tid>"
+
+#: builtin/pack-objects.c:2502
+msgid "create thin packs"
+msgstr "skapa tunna paket"
+
+#: builtin/pack-objects.c:2504
+msgid "ignore packs that have companion .keep file"
+msgstr "ignorera paket som har tillhörande .keep-fil"
+
+#: builtin/pack-objects.c:2506
+msgid "pack compression level"
+msgstr "komprimeringsgrad för paket"
+
+#: builtin/pack-objects.c:2508
+msgid "do not hide commits by grafts"
+msgstr "göm inte incheckningar med ympningar (\"grafts\")"
+
+#: builtin/pack-refs.c:6
+msgid "git pack-refs [options]"
+msgstr "git pack-refs [flaggor]"
+
+#: builtin/pack-refs.c:14
+msgid "pack everything"
+msgstr "packa allt"
+
+#: builtin/pack-refs.c:15
+msgid "prune loose refs (default)"
+msgstr "ta bort lösa referenser (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 <tid>] [--] [<huvud>...]"
+
+#: builtin/prune.c:132
+msgid "do not remove, show only"
+msgstr "ta inte bort, bara visa"
+
+#: builtin/prune.c:133
+msgid "report pruned objects"
+msgstr "rapportera borttagna objekt"
+
+#: builtin/prune.c:136
+msgid "expire objects older than <time>"
+msgstr "låt tid gå ut för objekt äldre än <tid>"
+
+#: builtin/push.c:14
+msgid "git push [<options>] [<repository> [<refspec>...]]"
+msgstr "git push [<flaggor>] [<arkiv> [<refspec>...]]"
+
 #: builtin/push.c:45
 msgid "tag shorthand without <tag>"
 msgstr "taggförkortning utan <tagg>"
@@ -3952,14 +6781,48 @@ msgstr ""
 "aktuella grenen \"%s\", utan att tala om för mig vad som\n"
 "skall sändas för att uppdatera fjärrgrenen."
 
-#: builtin/push.c:174
+#: builtin/push.c:151
+msgid ""
+"push.default is unset; its implicit value is changing in\n"
+"Git 2.0 from 'matching' to 'simple'. To squelch this message\n"
+"and maintain the current behavior after the default changes, use:\n"
+"\n"
+"  git config --global push.default matching\n"
+"\n"
+"To squelch this message and adopt the new behavior now, use:\n"
+"\n"
+"  git config --global push.default simple\n"
+"\n"
+"See 'git help config' and search for 'push.default' for further "
+"information.\n"
+"(the 'simple' mode was introduced in Git 1.7.11. Use the similar mode\n"
+"'current' instead of 'simple' if you sometimes use older versions of Git)"
+msgstr ""
+"push.default har inte ställts in; dess underförstådda värde\n"
+"ändras i Git 2.0 från \"matching\" till \"simple\". För att\n"
+"undertrycka det här meddelandet och behålla nuvarande beteende\n"
+"efter att förvalet ändras,\n"
+"skriver du:\n"
+"\n"
+"  git config --global push.default matching\n"
+"\n"
+"För att undertrycka meddelandet och välja det nya beteendet nu skriver du:\n"
+"\n"
+"  git config --global push.default simple\n"
+"\n"
+"Se \"git help config\" och sök efter \"push.default\" för ytterligare \n"
+"information. (Läget \"simple\" introducerades i Git 1.7.11. Använd det\n"
+"liknande läget \"current\" istället för \"simple\" om du ibland använder\n"
+"äldre versioner av Git.)"
+
+#: builtin/push.c:199
 msgid ""
 "You didn't specify any refspecs to push, and push.default is \"nothing\"."
 msgstr ""
 "Du angav inga referensspecifikationer att sända, och push.default är "
 "\"nothing\"."
 
-#: builtin/push.c:181
+#: builtin/push.c:206
 msgid ""
 "Updates were rejected because the tip of your current branch is behind\n"
 "its remote counterpart. Merge the remote changes (e.g. 'git pull')\n"
@@ -3971,20 +6834,21 @@ msgstr ""
 "innan du sänder igen.\n"
 "Se avsnittet \"Note about fast-forward\" i \"git push --help\" för detaljer."
 
-#: builtin/push.c:187
+#: builtin/push.c:212
 msgid ""
 "Updates were rejected because a pushed branch tip is behind its remote\n"
 "counterpart. If you did not intend to push that branch, you may want to\n"
-"specify branches to push or set the 'push.default' configuration\n"
-"variable to 'current' or 'upstream' to push only the current branch."
+"specify branches to push or set the 'push.default' configuration variable\n"
+"to 'simple', 'current' or 'upstream' to push only the current branch."
 msgstr ""
 "Uppdateringar avvisades då änden på en insänd gren är bakom dess\n"
 "fjärrmotsvarighet. Om det inte var meningen att sända in grenen, bör\n"
 "du specificera grenar att sända, eller ändra inställningsvariabeln\n"
-"\"push-default\" till \"current\" eller \"upstream\" för att endast sända\n"
-"aktuell gren."
+"\"push-default\" till \"simple\", \"current\" eller \"upstream\" för att "
+"endast\n"
+"sända aktuell gren."
 
-#: builtin/push.c:193
+#: builtin/push.c:218
 msgid ""
 "Updates were rejected because a pushed branch tip is behind its remote\n"
 "counterpart. Check out this branch and merge the remote changes\n"
@@ -3996,22 +6860,22 @@ msgstr ""
 "\"git pull\") innan du sänder igen.\n"
 "Se avsnittet \"Note about fast-forward\" i \"git push --help\" för detaljer."
 
-#: builtin/push.c:233
+#: builtin/push.c:258
 #, c-format
 msgid "Pushing to %s\n"
 msgstr "Sänder till %s\n"
 
-#: builtin/push.c:237
+#: builtin/push.c:262
 #, c-format
 msgid "failed to push some refs to '%s'"
 msgstr "misslyckades sända vissa referenser till \"%s\""
 
-#: builtin/push.c:269
+#: builtin/push.c:294
 #, c-format
 msgid "bad repository '%s'"
 msgstr "felaktigt arkiv \"%s\""
 
-#: builtin/push.c:270
+#: builtin/push.c:295
 msgid ""
 "No configured push destination.\n"
 "Either specify the URL from the command-line or configure a remote "
@@ -4032,34 +6896,238 @@ msgstr ""
 "\n"
 "    git push <namn>\n"
 
-#: builtin/push.c:285
+#: builtin/push.c:310
 msgid "--all and --tags are incompatible"
 msgstr "--all och --tags är inkompatibla"
 
-#: builtin/push.c:286
+#: builtin/push.c:311
 msgid "--all can't be combined with refspecs"
 msgstr "--all kan inte kombineras med referensspecifikationer"
 
-#: builtin/push.c:291
+#: builtin/push.c:316
 msgid "--mirror and --tags are incompatible"
 msgstr "--mirror och --tags är inkompatibla"
 
-#: builtin/push.c:292
+#: builtin/push.c:317
 msgid "--mirror can't be combined with refspecs"
 msgstr "--mirror kan inte kombineras med referensspecifikationer"
 
-#: builtin/push.c:297
+#: builtin/push.c:322
 msgid "--all and --mirror are incompatible"
 msgstr "--all och --mirror är inkompatibla"
 
-#: builtin/push.c:385
+#: builtin/push.c:382
+msgid "repository"
+msgstr "arkiv"
+
+#: builtin/push.c:383
+msgid "push all refs"
+msgstr "sänd alla referenser"
+
+#: builtin/push.c:384
+msgid "mirror all refs"
+msgstr "spegla alla referenser"
+
+#: builtin/push.c:386
+msgid "delete refs"
+msgstr "ta bort referenser"
+
+#: builtin/push.c:387
+msgid "push tags (can't be used with --all or --mirror)"
+msgstr "sänd taggar (kan inte användas med --all eller --mirror)"
+
+#: builtin/push.c:390
+msgid "force updates"
+msgstr "tvinga uppdateringar"
+
+#: builtin/push.c:391
+msgid "check"
+msgstr "kontrollera"
+
+#: builtin/push.c:392
+msgid "control recursive pushing of submodules"
+msgstr "styr rekursiv insändning av undermoduler"
+
+#: builtin/push.c:394
+msgid "use thin pack"
+msgstr "använd tunna paket"
+
+#: builtin/push.c:395 builtin/push.c:396
+msgid "receive pack program"
+msgstr "program för att ta emot paket"
+
+#: builtin/push.c:397
+msgid "set upstream for git pull/status"
+msgstr "ställ in uppström för git pull/status"
+
+#: builtin/push.c:400
+msgid "prune locally removed refs"
+msgstr "ta bort lokalt borttagna referenser"
+
+#: builtin/push.c:410
 msgid "--delete is incompatible with --all, --mirror and --tags"
 msgstr "--delete är imkompatibel med --all, --mirror och --tags"
 
-#: builtin/push.c:387
+#: builtin/push.c:412
 msgid "--delete doesn't make sense without any refs"
 msgstr "--delete kan inte användas utan referenser"
 
+#: 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=<fil>] (--empty | <träd-igt1> [<träd-igt2> [<träd-igt3>]])"
+
+#: builtin/read-tree.c:108
+msgid "write resulting index to <file>"
+msgstr "skriv resulterande index till <fil>"
+
+#: builtin/read-tree.c:111
+msgid "only empty the index"
+msgstr "töm bara indexet"
+
+#: builtin/read-tree.c:113
+msgid "Merging"
+msgstr "Sammanslagning"
+
+#: builtin/read-tree.c:115
+msgid "perform a merge in addition to a read"
+msgstr "utför en sammanslagning i tillägg till en läsning"
+
+#: builtin/read-tree.c:117
+msgid "3-way merge if no file level merging required"
+msgstr "3-vägssammanslagning om sammanslagning på filnivå ej krävs"
+
+#: builtin/read-tree.c:119
+msgid "3-way merge in presence of adds and removes"
+msgstr "3-vägssammanslagning när det finns tillägg och borttagningar"
+
+#: builtin/read-tree.c:121
+msgid "same as -m, but discard unmerged entries"
+msgstr "som -m, men kasta bort ej sammanslagna poster"
+
+#: builtin/read-tree.c:122
+msgid "<subdirectory>/"
+msgstr "<underkatalog>/"
+
+#: builtin/read-tree.c:123
+msgid "read the tree into the index under <subdirectory>/"
+msgstr "läs in trädet i indexet under <underkatalog>/"
+
+#: builtin/read-tree.c:126
+msgid "update working tree with merge result"
+msgstr "uppdatera arbetskatalogen med resultatet från sammanslagningen"
+
+#: builtin/read-tree.c:128
+msgid "gitignore"
+msgstr "gitignore"
+
+#: builtin/read-tree.c:129
+msgid "allow explicitly ignored files to be overwritten"
+msgstr "tillåt explicit ignorerade filer att skrivas över"
+
+#: builtin/read-tree.c:132
+msgid "don't check the working tree after merging"
+msgstr "kontrollera inte arbetskatalogen efter sammanslagning"
+
+#: builtin/read-tree.c:133
+msgid "don't update the index or the work tree"
+msgstr "uppdatera inte indexet eller arbetskatalogen"
+
+#: builtin/read-tree.c:135
+msgid "skip applying sparse checkout filter"
+msgstr "hoppa över att applicera filter för gles utcheckning"
+
+#: builtin/read-tree.c:137
+msgid "debug unpack-trees"
+msgstr "felsök unpack-trees"
+
+#: 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 <gren>] [-m <master>] [-f] [--tags|--no-tags] [--"
+"mirror=<fetch|push>] <namn> <url>"
+
+#: builtin/remote.c:13 builtin/remote.c:32
+msgid "git remote rename <old> <new>"
+msgstr "git remote rename <gammal> <ny>"
+
+#: builtin/remote.c:14 builtin/remote.c:37
+msgid "git remote remove <name>"
+msgstr "git remote remove <namn>"
+
+#: builtin/remote.c:15
+msgid "git remote set-head <name> (-a | -d | <branch>)"
+msgstr "git remote set-head <namn> (-a | -d | <gren>)"
+
+#: builtin/remote.c:16
+msgid "git remote [-v | --verbose] show [-n] <name>"
+msgstr "git remote [-v | --verbose] show [-n] <namn>"
+
+#: builtin/remote.c:17
+msgid "git remote prune [-n | --dry-run] <name>"
+msgstr "git remote prune [-n | --dry-run] <namn>"
+
+#: builtin/remote.c:18
+msgid ""
+"git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]"
+msgstr ""
+"git remote [-v | --verbose] update [-p | --prune] [(<grupp> | <fjärr>)...]"
+
+#: builtin/remote.c:19
+msgid "git remote set-branches [--add] <name> <branch>..."
+msgstr "git remote set-branches [--add] <namn> <gren>..."
+
+#: builtin/remote.c:20 builtin/remote.c:68
+msgid "git remote set-url [--push] <name> <newurl> [<oldurl>]"
+msgstr "git remote set-url [--push] <namn> <nyurl> [<gammalurl>]"
+
+#: builtin/remote.c:21 builtin/remote.c:69
+msgid "git remote set-url --add <name> <newurl>"
+msgstr "git remote set-url --add <namn> <nyurl>"
+
+#: builtin/remote.c:22 builtin/remote.c:70
+msgid "git remote set-url --delete <name> <url>"
+msgstr "git remote set-url --delete <namn> <url>"
+
+#: builtin/remote.c:27
+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>..."
+
+#: builtin/remote.c:48
+msgid "git remote set-branches --add <name> <branch>..."
+msgstr "git remote set-branches --add <namn> <gren>..."
+
+#: builtin/remote.c:53
+msgid "git remote show [<options>] <name>"
+msgstr "git remote show [<flaggor>] <namn>"
+
+#: builtin/remote.c:58
+msgid "git remote prune [<options>] <name>"
+msgstr "git remote prune [<flaggor>] <namn>"
+
+#: builtin/remote.c:63
+msgid "git remote update [<options>] [<group> | <remote>]..."
+msgstr "git remote update [<flaggor>] [<grupp> | <fjärr>]..."
+
 #: builtin/remote.c:98
 #, c-format
 msgid "Updating %s"
@@ -4078,6 +7146,34 @@ msgstr ""
 msgid "unknown mirror argument: %s"
 msgstr "okänt argument till mirror: %s"
 
+#: builtin/remote.c:163
+msgid "fetch the remote branches"
+msgstr "hämta fjärrgrenarna"
+
+#: builtin/remote.c:165
+msgid "import all tags and associated objects when fetching"
+msgstr "importera alla taggar och associerade objekt vid hämtning"
+
+#: builtin/remote.c:168
+msgid "or do not fetch any tag at all (--no-tags)"
+msgstr "eller hämta inte några taggar alls (--no-tags)"
+
+#: builtin/remote.c:170
+msgid "branch(es) to track"
+msgstr "gren(ar) att spåra"
+
+#: builtin/remote.c:171
+msgid "master branch"
+msgstr "huvudgren"
+
+#: 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 "ställ in arkiv som spegel att sända eller ta emot från"
+
 #: builtin/remote.c:185
 msgid "specifying a master branch makes no sense with --mirror"
 msgstr "att ange en master-gren ger ingen mening med --mirror"
@@ -4274,6 +7370,10 @@ msgstr "    %-*s tvingar till %s"
 msgid "    %-*s pushes to %s"
 msgstr "    %-*s sänder till %s"
 
+#: builtin/remote.c:1091
+msgid "do not query remotes"
+msgstr "fråga inte fjärrar"
+
 #: builtin/remote.c:1118
 #, c-format
 msgid "* remote %s"
@@ -4332,6 +7432,14 @@ msgid_plural "  Local refs configured for 'git push'%s:"
 msgstr[0] "  Lokal referens konfigurerad för \"git push\"%s:"
 msgstr[1] "  Lokala referenser konfigurerade för \"git push\"%s:"
 
+#: builtin/remote.c:1199
+msgid "set refs/remotes/<name>/HEAD according to remote"
+msgstr "sätt refs/remotes/<namn>/HEAD enligt fjärren"
+
+#: builtin/remote.c:1201
+msgid "delete refs/remotes/<name>/HEAD"
+msgstr "ta bort refs/remotes/<namn>/HEAD"
+
 #: builtin/remote.c:1216
 msgid "Cannot determine remote HEAD"
 msgstr "Kan inte bestämma HEAD på fjärren"
@@ -4385,15 +7493,35 @@ msgstr " * [skulle rensa] %s"
 msgid " * [pruned] %s"
 msgstr " * [rensad] %s"
 
+#: builtin/remote.c:1321
+msgid "prune remotes after fetching"
+msgstr "rensa fjärrar efter hämtning"
+
 #: builtin/remote.c:1387 builtin/remote.c:1461
 #, c-format
 msgid "No such remote '%s'"
 msgstr "Ingen sådan fjärr \"%s\""
 
+#: builtin/remote.c:1407
+msgid "add branch"
+msgstr "lägg till gren"
+
 #: builtin/remote.c:1414
 msgid "no remote specified"
 msgstr "ingen fjärr angavs"
 
+#: builtin/remote.c:1436
+msgid "manipulate push URLs"
+msgstr "manipulera URL:ar för sändning"
+
+#: builtin/remote.c:1438
+msgid "add URL"
+msgstr "lägg till URL"
+
+#: builtin/remote.c:1440
+msgid "delete URLs"
+msgstr "ta bort URL:ar"
+
 #: builtin/remote.c:1447
 msgid "--add --delete doesn't make sense"
 msgstr "--add --delete ger ingen mening"
@@ -4412,6 +7540,56 @@ msgstr "Ingen sådan URL hittades: %s"
 msgid "Will not delete all non-push URLs"
 msgstr "Kommer inte ta bort alla icke-sänd-URL:er"
 
+#: builtin/remote.c:1569
+msgid "be verbose; must be placed before a subcommand"
+msgstr "var pratsam; måste skrivas före ett underkommando"
+
+#: builtin/replace.c:17
+msgid "git replace [-f] <object> <replacement>"
+msgstr "git replace [-f] <objekt> <ersättning>"
+
+#: 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 [<mönster>]"
+
+#: builtin/replace.c:118
+msgid "list replace refs"
+msgstr "visa ersättningsreferenser"
+
+#: builtin/replace.c:119
+msgid "delete replace refs"
+msgstr "ta bort ersättningsreferenser"
+
+#: builtin/replace.c:120
+msgid "replace the ref if it exists"
+msgstr "ersätt referensen om den finns"
+
+#: builtin/rerere.c:11
+msgid "git rerere [clear | forget path... | status | remaining | diff | gc]"
+msgstr "git rerere [clear | forget path... | status | remaining | diff | gc]"
+
+#: builtin/rerere.c:56
+msgid "register clean resolutions in index"
+msgstr "registrera rena lösningar i indexet"
+
+#: builtin/reset.c:25
+msgid ""
+"git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]"
+msgstr ""
+"git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<incheckning>]"
+
+#: builtin/reset.c:26
+msgid "git reset [-q] <commit> [--] <paths>..."
+msgstr "git reset [-q] <incheckning> [--] <sökvägar>..."
+
+#: builtin/reset.c:27
+msgid "git reset --patch [<commit>] [--] [<paths>...]"
+msgstr "git reset --patch [<incheckning>] [--] [<sökvägar>...]"
+
 #: builtin/reset.c:33
 msgid "mixed"
 msgstr "blandad"
@@ -4467,52 +7645,175 @@ msgstr "Oköade ändringar efter återställning:"
 msgid "Cannot do a %s reset in the middle of a merge."
 msgstr "Kan inte utföra en %s återställning mitt i en sammanslagning."
 
-#: builtin/reset.c:297
+#: builtin/reset.c:238
+msgid "be quiet, only report errors"
+msgstr "var tyst, rapportera endast fel"
+
+#: builtin/reset.c:240
+msgid "reset HEAD and index"
+msgstr "återställ HEAD och index"
+
+#: builtin/reset.c:241
+msgid "reset only HEAD"
+msgstr "återställ endast HEAD"
+
+#: builtin/reset.c:243 builtin/reset.c:245
+msgid "reset HEAD, index and working tree"
+msgstr "återställ HEAD, index och arbetskatalog"
+
+#: builtin/reset.c:247
+msgid "reset HEAD but keep local changes"
+msgstr "återställ HEAD men behåll lokala ändringar"
+
+#: builtin/reset.c:303
 #, c-format
 msgid "Could not parse object '%s'."
 msgstr "Kan inte tolka objektet \"%s\""
 
-#: builtin/reset.c:302
+#: builtin/reset.c:308
 msgid "--patch is incompatible with --{hard,mixed,soft}"
 msgstr "--patch är inkompatibel med --{hard,mixed,soft}"
 
-#: builtin/reset.c:311
+#: builtin/reset.c:317
 msgid "--mixed with paths is deprecated; use 'git reset -- <paths>' instead."
 msgstr ""
 "--mixed rekommenderas inte med sökvägar; använd \"git reset -- <sökvägar>\"."
 
-#: builtin/reset.c:313
+#: builtin/reset.c:319
 #, c-format
 msgid "Cannot do %s reset with paths."
 msgstr "Kan inte göra %s återställning med sökvägar."
 
-#: builtin/reset.c:325
+#: builtin/reset.c:331
 #, c-format
 msgid "%s reset is not allowed in a bare repository"
 msgstr "%s återställning tillåts inte i ett naket arkiv"
 
-#: builtin/reset.c:341
+#: builtin/reset.c:347
 #, c-format
 msgid "Could not reset index file to revision '%s'."
 msgstr "Kunde inte återställa indexfilen till versionen \"%s\"."
 
+#: builtin/rev-parse.c:339
+msgid "git rev-parse --parseopt [options] -- [<args>...]"
+msgstr "git rev-parse --parseopt [options] -- [<argument>...]"
+
+#: builtin/rev-parse.c:344
+msgid "keep the `--` passed as an arg"
+msgstr "behåll \"--\" sänt som argument"
+
+#: builtin/rev-parse.c:346
+msgid "stop parsing after the first non-option argument"
+msgstr "sluta tolka efter första argument som inte är flagga"
+
+#: 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 [flaggor] -- [<argument>...]\n"
+"     eller: git rev-parse --sq-quote [<argument>...]\n"
+"     eller: git rev-parse [flaggor] [<argument>...]\n"
+"\n"
+"Kör \"git rev-parse --parseopt -h\" för mer information om den första "
+"varianten."
+
+#: builtin/revert.c:22
+msgid "git revert [options] <commit-ish>"
+msgstr "git revert [flaggor] <incheckning-igt>"
+
+#: builtin/revert.c:23
+msgid "git revert <subcommand>"
+msgstr "git revert <underkommando>"
+
+#: builtin/revert.c:28
+msgid "git cherry-pick [options] <commit-ish>"
+msgstr "git cherry-pick [flaggor] <incheckning-igt>"
+
+#: builtin/revert.c:29
+msgid "git cherry-pick <subcommand>"
+msgstr "git cherry-pick <underkommando>"
+
 #: builtin/revert.c:70 builtin/revert.c:92
 #, c-format
 msgid "%s: %s cannot be used with %s"
 msgstr "%s: %s kan inte användas med %s"
 
-#: builtin/revert.c:131
+#: builtin/revert.c:103
+msgid "end revert or cherry-pick sequence"
+msgstr "avsluta revert- eller cherry-pick-sekvens"
+
+#: builtin/revert.c:104
+msgid "resume revert or cherry-pick sequence"
+msgstr "återuppta revert- eller cherry-pick-sekvens"
+
+#: builtin/revert.c:105
+msgid "cancel revert or cherry-pick sequence"
+msgstr "avbryt revert- eller cherry-pick-sekvens"
+
+#: builtin/revert.c:106
+msgid "don't automatically commit"
+msgstr "checka inte in automatiskt"
+
+#: builtin/revert.c:107
+msgid "edit the commit message"
+msgstr "redigera incheckningsmeddelandet"
+
+#: builtin/revert.c:110
+msgid "parent number"
+msgstr "nummer på förälder"
+
+#: builtin/revert.c:112
+msgid "merge strategy"
+msgstr "sammanslagninsstrategi"
+
+#: builtin/revert.c:113
+msgid "option"
+msgstr "alternativ"
+
+#: builtin/revert.c:114
+msgid "option for merge strategy"
+msgstr "alternativ för sammanslagningsstrategi"
+
+#: builtin/revert.c:125
+msgid "append commit name"
+msgstr "lägg till incheckningsnamn"
+
+#: builtin/revert.c:126
+msgid "allow fast-forward"
+msgstr "tillåt snabbspolning"
+
+#: builtin/revert.c:127
+msgid "preserve initially empty commits"
+msgstr "behåll incheckningar som börjar som tomma"
+
+#: builtin/revert.c:128
+msgid "allow commits with empty messages"
+msgstr "tillåt incheckningar med tomt meddelande"
+
+#: builtin/revert.c:129
+msgid "keep redundant, empty commits"
+msgstr "behåll redundanta, tomma incheckningar"
+
+#: builtin/revert.c:133
 msgid "program error"
 msgstr "programfel"
 
-#: builtin/revert.c:221
+#: builtin/revert.c:223
 msgid "revert failed"
 msgstr "\"revert\" misslyckades"
 
-#: builtin/revert.c:236
+#: builtin/revert.c:238
 msgid "cherry-pick failed"
 msgstr "\"cherry-pick\" misslyckades"
 
+#: builtin/rm.c:14
+msgid "git rm [options] [--] <file>..."
+msgstr "git rm [flaggor] [--] <fil>..."
+
 #: builtin/rm.c:109
 #, c-format
 msgid ""
@@ -4540,6 +7841,26 @@ 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
+msgid "do not list removed files"
+msgstr "lista inte borttagna filer"
+
+#: builtin/rm.c:135
+msgid "only remove from the index"
+msgstr "ta bara bort från indexet"
+
+#: builtin/rm.c:136
+msgid "override the up-to-date check"
+msgstr "överstyr àjour-testet"
+
+#: builtin/rm.c:137
+msgid "allow recursive removal"
+msgstr "tillåt rekursiv borttagning"
+
+#: builtin/rm.c:139
+msgid "exit with a zero status even if nothing matched"
+msgstr "avsluta med nollstatus även om inget träffades"
+
 #: builtin/rm.c:194
 #, c-format
 msgid "not removing '%s' recursively without -r"
@@ -4550,11 +7871,203 @@ msgstr "tar inte bort \"%s\" rekursivt utan -r"
 msgid "git rm: unable to remove %s"
 msgstr "git rm: kan inte ta bort %s"
 
+#: builtin/shortlog.c:13
+msgid "git shortlog [-n] [-s] [-e] [-w] [rev-opts] [--] [<commit-id>... ]"
+msgstr ""
+"git shortlog [-n] [-s] [-e] [-w] [rev-flaggor] [--] [<incheckning-id>... ]"
+
 #: builtin/shortlog.c:157
 #, c-format
 msgid "Missing author: %s"
 msgstr "Författare saknas: %s"
 
+#: builtin/shortlog.c:253
+msgid "sort output according to the number of commits per author"
+msgstr "sortera utdata enligt antal incheckningar per författare"
+
+#: builtin/shortlog.c:255
+msgid "Suppress commit descriptions, only provides commit count"
+msgstr "Undertryck beskrivningar, visa bara antal incheckningar"
+
+#: builtin/shortlog.c:257
+msgid "Show the email address of each author"
+msgstr "Visa e-postadress för varje författare"
+
+#: builtin/shortlog.c:258
+msgid "w[,i1[,i2]]"
+msgstr "w[,i1[,i2]]"
+
+#: builtin/shortlog.c:259
+msgid "Linewrap output"
+msgstr "Radbryt utdata"
+
+#: 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[=<när>] | --no-color] [--sparse] [--more=<n> | --list | --"
+"independent | --merge-base] [--no-name | --sha1-name] [--topics] [(<rev> | "
+"<mönster>)...]"
+
+#: builtin/show-branch.c:10
+msgid "git show-branch (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]"
+msgstr "git show-branch (-g|--reflog)[=<n>[,<bas>]] [--list] [<ref>]"
+
+#: builtin/show-branch.c:651
+msgid "show remote-tracking and local branches"
+msgstr "visa fjärrspårande och lokala grenar"
+
+#: builtin/show-branch.c:653
+msgid "show remote-tracking branches"
+msgstr "visa fjärrspårande grenar"
+
+#: builtin/show-branch.c:655
+msgid "color '*!+-' corresponding to the branch"
+msgstr "färga \"*!+-\" enligt grenen"
+
+#: builtin/show-branch.c:657
+msgid "show <n> more commits after the common ancestor"
+msgstr "visa <n> ytterligare incheckningar efter gemensam anfader"
+
+#: builtin/show-branch.c:659
+msgid "synonym to more=-1"
+msgstr "synonym till more=-1"
+
+#: builtin/show-branch.c:660
+msgid "suppress naming strings"
+msgstr "undertyck namnsträngar"
+
+#: builtin/show-branch.c:662
+msgid "include the current branch"
+msgstr "inkludera aktuell gren"
+
+#: builtin/show-branch.c:664
+msgid "name commits with their object names"
+msgstr "namnge incheckningar med deras objektnamn"
+
+#: builtin/show-branch.c:666
+msgid "show possible merge bases"
+msgstr "visa möjliga sammanslaningsbaser"
+
+#: builtin/show-branch.c:668
+msgid "show refs unreachable from any other ref"
+msgstr "visa referenser som inte kan nås från någon annan referens"
+
+#: builtin/show-branch.c:670
+msgid "show commits in topological order"
+msgstr "visa incheckningar i topologisk ordning"
+
+#: builtin/show-branch.c:672
+msgid "show only commits not on the first branch"
+msgstr "visa endast incheckningar inte på den första grenen"
+
+#: builtin/show-branch.c:674
+msgid "show merges reachable from only one tip"
+msgstr "visa sammanslagningar som endast kan nås från en spets"
+
+#: builtin/show-branch.c:676
+msgid "show commits where no parent comes before its children"
+msgstr "visa incheckningar där ingen förälder kommer före dess barn"
+
+#: builtin/show-branch.c:678
+msgid "<n>[,<base>]"
+msgstr "<n>[,<bas>]"
+
+#: builtin/show-branch.c:679
+msgid "show <n> most recent ref-log entries starting at base"
+msgstr "visa <n> nyaste refloggposter med början på bas"
+
+#: 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] [--] [mönster*] "
+
+#: builtin/show-ref.c:11
+msgid "git show-ref --exclude-existing[=pattern] < ref-list"
+msgstr "git show-ref --exclude-existing[=mönster] < reflista"
+
+#: builtin/show-ref.c:182
+msgid "only show tags (can be combined with heads)"
+msgstr "visa endast taggar (kan kombineras med huvuden)"
+
+#: builtin/show-ref.c:183
+msgid "only show heads (can be combined with tags)"
+msgstr "visa endast huvuden (kan kombineras med taggar)"
+
+#: builtin/show-ref.c:184
+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
+msgid "show the HEAD reference"
+msgstr "visa HEAD-referensen"
+
+#: builtin/show-ref.c:191
+msgid "dereference tags into object IDs"
+msgstr "avreferera taggar till objekt-id"
+
+#: builtin/show-ref.c:193
+msgid "only show SHA1 hash using <n> digits"
+msgstr "visa SHA1-hash endast med <n> siffror"
+
+#: builtin/show-ref.c:197
+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
+msgid "show refs from stdin that aren't in local repository"
+msgstr "visa referenser från standard in som inte finns i lokalt arkiv"
+
+#: builtin/symbolic-ref.c:7
+msgid "git symbolic-ref [options] name [ref]"
+msgstr "git symbolic-ref [flaggor] namn [ref]"
+
+#: builtin/symbolic-ref.c:38
+msgid "suppress error message for non-symbolic (detached) refs"
+msgstr ""
+"undertryck felmeddelanden för icke-symboliska (frånkopplade) referenser"
+
+#: builtin/symbolic-ref.c:39
+msgid "shorten ref output"
+msgstr "förkorta ref-utdata"
+
+#: builtin/symbolic-ref.c:40 builtin/update-ref.c:18
+msgid "reason"
+msgstr "skäl"
+
+#: builtin/symbolic-ref.c:40 builtin/update-ref.c:18
+msgid "reason of the update"
+msgstr "skäl till uppdateringen"
+
+#: 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 <nyckel-id>] [-f] [-m <medd>|-F <fil>] <taggnamn> [<huvud>]"
+
+#: builtin/tag.c:23
+msgid "git tag -d <tagname>..."
+msgstr "git tag -d <taggnamn>..."
+
+#: builtin/tag.c:24
+msgid ""
+"git tag -l [-n[<num>]] [--contains <commit>] [--points-at <object>] \n"
+"\t\t[<pattern>...]"
+msgstr ""
+"git tag -l [-n[<antal>]] [--contains <incheckning>] [--points-at <objekt>] \n"
+"\t\t[<mönster>...]"
+
+#: builtin/tag.c:26
+msgid "git tag -v <tagname>..."
+msgstr "git tag -v <taggnamn>..."
+
 #: builtin/tag.c:60
 #, c-format
 msgid "malformed object at '%s'"
@@ -4644,6 +8157,62 @@ msgstr "flaggan \"points-at\" behöver ett object"
 msgid "malformed object name '%s'"
 msgstr "felformat objektnamn \"%s\""
 
+#: builtin/tag.c:447
+msgid "list tag names"
+msgstr "lista taggnamn"
+
+#: builtin/tag.c:449
+msgid "print <n> lines of each tag message"
+msgstr "visa <n> rader från varje taggmeddelande"
+
+#: builtin/tag.c:451
+msgid "delete tags"
+msgstr "ta bort taggar"
+
+#: builtin/tag.c:452
+msgid "verify tags"
+msgstr "verifiera taggar"
+
+#: builtin/tag.c:454
+msgid "Tag creation options"
+msgstr "Alternativ för att skapa taggar"
+
+#: builtin/tag.c:456
+msgid "annotated tag, needs a message"
+msgstr "annoterad tagg, behöver meddelande"
+
+#: builtin/tag.c:458
+msgid "tag message"
+msgstr "taggmeddelande"
+
+#: builtin/tag.c:460
+msgid "annotated and GPG-signed tag"
+msgstr "annoterad och GPG-signerad tagg"
+
+#: builtin/tag.c:464
+msgid "use another key to sign the tag"
+msgstr "använd annan nyckel för att signera taggen"
+
+#: builtin/tag.c:465
+msgid "replace the tag if exists"
+msgstr "ersätt taggen om den finns"
+
+#: builtin/tag.c:466
+msgid "show tag list in columns"
+msgstr "lista taggar i spalter"
+
+#: builtin/tag.c:468
+msgid "Tag listing options"
+msgstr "Alternativ för listning av taggar"
+
+#: builtin/tag.c:471
+msgid "print only tags that contain the commit"
+msgstr "visa endast taggar som innehåller incheckningen"
+
+#: builtin/tag.c:477
+msgid "print only tags of the object"
+msgstr "visa endast taggar för objektet"
+
 #: builtin/tag.c:506
 msgid "--column and -n are incompatible"
 msgstr "--column och -n är inkompatibla"
@@ -4693,27 +8262,182 @@ msgstr "%s: kan inte uppdatera referensen"
 msgid "Updated tag '%s' (was %s)\n"
 msgstr "Uppdaterad tagg \"%s\" (var %s)\n"
 
-#: git.c:16
-msgid "See 'git help <command>' for more information on a specific command."
-msgstr ""
-"Se \"git help <kommando>\" för mer information om ett specifikt kommando."
+#: builtin/update-index.c:401
+msgid "git update-index [options] [--] [<file>...]"
+msgstr "git update-index [flaggor] [--] [<fil>...]"
 
-#: parse-options.h:133 parse-options.h:235
-msgid "n"
-msgstr "n"
+#: builtin/update-index.c:717
+msgid "continue refresh even when index needs update"
+msgstr "fortsätt uppdatera även när index inte är àjour"
 
-#: parse-options.h:141
-msgid "time"
-msgstr "tid"
+#: builtin/update-index.c:720
+msgid "refresh: ignore submodules"
+msgstr "refresh: ignorera undermoduler"
 
-# %s är ett verb ("Untracked"/"Ignored"); lägg till ett -e.
-#: parse-options.h:149
-msgid "file"
-msgstr "fil"
+#: builtin/update-index.c:723
+msgid "do not ignore new files"
+msgstr "ignorera inte nya filer"
 
-#: parse-options.h:151
-msgid "when"
-msgstr "när"
+#: builtin/update-index.c:725
+msgid "let files replace directories and vice-versa"
+msgstr "låt filer ersätta kataloger och omvänt"
+
+#: builtin/update-index.c:727
+msgid "notice files missing from worktree"
+msgstr "lägg märke till filer som saknas i arbetskatalogen"
+
+#: builtin/update-index.c:729
+msgid "refresh even if index contains unmerged entries"
+msgstr "uppdatera även om indexet innehåller ej sammanslagna poster"
+
+#: builtin/update-index.c:732
+msgid "refresh stat information"
+msgstr "uppdatera statusinformation"
+
+#: builtin/update-index.c:736
+msgid "like --refresh, but ignore assume-unchanged setting"
+msgstr "som --refresh, men ignorera assume-unchanged-inställning"
+
+#: builtin/update-index.c:740
+msgid "<mode> <object> <path>"
+msgstr "<läge> <objekt> <sökväg>"
+
+#: builtin/update-index.c:741
+msgid "add the specified entry to the index"
+msgstr "lägg till angiven post i indexet"
+
+#: builtin/update-index.c:745
+msgid "(+/-)x"
+msgstr "(+/-)x"
+
+#: builtin/update-index.c:746
+msgid "override the executable bit of the listed files"
+msgstr "överstyr exekveringsbiten för angivna filer"
+
+#: builtin/update-index.c:750
+msgid "mark files as \"not changing\""
+msgstr "markera filer som \"ändras inte\""
+
+#: builtin/update-index.c:753
+msgid "clear assumed-unchanged bit"
+msgstr "rensa \"assume-unchanged\"-biten"
+
+#: builtin/update-index.c:756
+msgid "mark files as \"index-only\""
+msgstr "markera filer som \"endast index\""
+
+#: builtin/update-index.c:759
+msgid "clear skip-worktree bit"
+msgstr "töm \"skip-worktree\"-biten"
+
+#: builtin/update-index.c:762
+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
+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
+msgid "with --stdin: input lines are terminated by null bytes"
+msgstr "med --stdin: indatarader termineras med null-byte"
+
+#: builtin/update-index.c:768
+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
+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
+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
+msgid "only update entries that differ from HEAD"
+msgstr "uppdatera endast poster som skiljer sig från HEAD"
+
+#: builtin/update-index.c:784
+msgid "ignore files missing from worktree"
+msgstr "ignorera filer som saknas i arbetskatalogen"
+
+#: builtin/update-index.c:787
+msgid "report actions to standard output"
+msgstr "raportera åtgärder på standard ut"
+
+#: builtin/update-index.c:789
+msgid "(for porcelains) forget saved unresolved conflicts"
+msgstr "(för porslin) glöm sparade olösta konflikter"
+
+#: builtin/update-index.c:793
+msgid "write index in this format"
+msgstr "skriv index i detta format"
+
+#: builtin/update-ref.c:7
+msgid "git update-ref [options] -d <refname> [<oldval>]"
+msgstr "git update-ref [flaggor] -d <refnamn> [<gammaltvärde>]"
+
+#: builtin/update-ref.c:8
+msgid "git update-ref [options]    <refname> <newval> [<oldval>]"
+msgstr "git update-ref [flaggor]    <refnamn> <gammaltvärde> [<nyttvärde>]"
+
+#: builtin/update-ref.c:19
+msgid "delete the reference"
+msgstr "ta bort referensen"
+
+#: builtin/update-ref.c:21
+msgid "update <refname> not the one it points to"
+msgstr "uppdatera <refnamn> inte det den pekar på"
+
+#: 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 "uppdatera informationsfilerna från grunden"
+
+#: 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 "pratsam"
+
+#: builtin/verify-pack.c:68
+msgid "show statistics only"
+msgstr "visa endast statistik"
+
+#: builtin/verify-tag.c:17
+msgid "git verify-tag [-v|--verbose] <tag>..."
+msgstr "git verify-tag [-v|--verbose] <tagg>..."
+
+#: builtin/verify-tag.c:73
+msgid "print tag contents"
+msgstr "visa innehåll för tag"
+
+#: 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 "visa trädobjekt för underkatalogen <prefix>"
+
+#: builtin/write-tree.c:30
+msgid "only useful for debugging"
+msgstr "endast användbart vid felsökning"
+
+#: git.c:16
+msgid "See 'git help <command>' for more information on a specific command."
+msgstr ""
+"Se \"git help <kommando>\" för mer information om ett specifikt kommando."
 
 #: parse-options.h:156
 msgid "no-op (backward compatibility)"
@@ -4813,7 +8537,7 @@ msgstr "Visa status för arbetskatalogen"
 
 #: common-cmds.h:28
 msgid "Create, list, delete or verify a tag object signed with GPG"
-msgstr "Skapa, visa, ta bort eller verifiera ett taggobjekt signerat med GPG"
+msgstr "Skapa, visa, ta bort eller verifiera GPG-signerat taggobjekt"
 
 #: git-am.sh:50
 msgid "You need to set your committer info first"
@@ -4830,9 +8554,9 @@ msgstr ""
 #: git-am.sh:105
 #, sh-format
 msgid ""
-"When you have resolved this problem run \"$cmdline --resolved\".\n"
-"If you would prefer to skip this patch, instead run \"$cmdline --skip\".\n"
-"To restore the original branch and stop patching run \"$cmdline --abort\"."
+"When you have resolved this problem, run \"$cmdline --resolved\".\n"
+"If you prefer to skip this patch, run \"$cmdline --skip\" instead.\n"
+"To restore the original branch and stop patching, run \"$cmdline --abort\"."
 msgstr ""
 "När du har löst problemet kör du \"$cmdline --resolved\".\n"
 "Om du vill hoppa över patchen kör du istället \"$cmdline --skip\".\n"
@@ -4848,6 +8572,10 @@ msgstr ""
 "Arkivet saknar objekt som behövs för att falla tillbaka på 3-"
 "vägssammanslagning."
 
+#: git-am.sh:139
+msgid "Using index info to reconstruct a base tree..."
+msgstr "Använder indexinfo för att åteskapa ett basträd..."
+
 #: git-am.sh:154
 msgid ""
 "Did you hand edit your patch?\n"
@@ -4861,42 +8589,50 @@ msgid "Falling back to patching base and 3-way merge..."
 msgstr ""
 "Faller tillbaka på att pacha grundversionen och trevägssammanslagning..."
 
-#: git-am.sh:275
+#: git-am.sh:179
+msgid "Failed to merge in the changes."
+msgstr "Misslyckads slå ihop ändringarna."
+
+#: git-am.sh:274
 msgid "Only one StGIT patch series can be applied at once"
 msgstr "Endast en StGIT-patchserie kan tillämpas åt gången"
 
-#: git-am.sh:362
+#: git-am.sh:361
 #, sh-format
 msgid "Patch format $patch_format is not supported."
 msgstr "Patchformatet $patch_format stöds inte."
 
-#: git-am.sh:364
+#: git-am.sh:363
 msgid "Patch format detection failed."
 msgstr "Misslyckades detektera patchformat."
 
-#: git-am.sh:418
-msgid "-d option is no longer supported.  Do not use."
-msgstr "Flaggan -d stöds inte lägre. Använd inte."
+#: git-am.sh:389
+msgid ""
+"The -b/--binary option has been a no-op for long time, and\n"
+"it will be removed. Please do not use it anymore."
+msgstr ""
+"Flaggan -b/--binary har varit utan funktion länge, och\n"
+"kommer tas bort. Vi ber dig att inte använda den längre."
 
-#: git-am.sh:481
+#: git-am.sh:477
 #, sh-format
 msgid "previous rebase directory $dotest still exists but mbox given."
 msgstr "tidigare rebase-katalog $dotest finns fortfarande, men mbox angavs."
 
-#: git-am.sh:486
+#: git-am.sh:482
 msgid "Please make up your mind. --skip or --abort?"
 msgstr "Bestäm dig. --skip eller --abort?"
 
-#: git-am.sh:513
+#: git-am.sh:509
 msgid "Resolve operation not in progress, we are not resuming."
 msgstr "Lösningsoperation pågår inte, vi återupptar inte."
 
-#: git-am.sh:579
+#: git-am.sh:575
 #, sh-format
 msgid "Dirty index: cannot apply patches (dirty: $files)"
 msgstr "Smutsigt index: kan inte tillämpa patchar (smutsiga: $files)"
 
-#: git-am.sh:671
+#: git-am.sh:679
 #, sh-format
 msgid ""
 "Patch is empty.  Was it split wrong?\n"
@@ -4907,32 +8643,32 @@ msgstr ""
 "Om du vill hoppa över patchen kör du istället \"$cmdline --skip\".\n"
 "För att återställa originalgrenen och avbryta kör du \"$cmdline --abort\"."
 
-#: git-am.sh:708
+#: git-am.sh:706
 msgid "Patch does not have a valid e-mail address."
 msgstr "Patchen har inte någon giltig e-postadress."
 
-#: git-am.sh:755
+#: git-am.sh:753
 msgid "cannot be interactive without stdin connected to a terminal."
 msgstr ""
 "kan inte vara interaktiv om standard in inte är ansluten till en terminal."
 
-#: git-am.sh:759
+#: git-am.sh:757
 msgid "Commit Body is:"
 msgstr "Incheckningskroppen är:"
 
 #. TRANSLATORS: Make sure to include [y], [n], [e], [v] and [a]
 #. in your translation. The program will only accept English
 #. input at this point.
-#: git-am.sh:766
+#: git-am.sh:764
 msgid "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all "
 msgstr "Tillämpa? Y=ja/N=nej/E=redigera/V=visa patch/A=godta alla "
 
-#: git-am.sh:802
+#: git-am.sh:800
 #, sh-format
 msgid "Applying: $FIRSTLINE"
 msgstr "Tillämpar: $FIRSTLINE"
 
-#: git-am.sh:823
+#: git-am.sh:821
 msgid ""
 "No changes - did you forget to use 'git add'?\n"
 "If there is nothing left to stage, chances are that something else\n"
@@ -4942,7 +8678,7 @@ msgstr ""
 "Om det inte är något kvar att köa kan det hända att något annat redan\n"
 "introducerat samma ändringar; kanske du bör hoppa över patchen."
 
-#: git-am.sh:831
+#: git-am.sh:829
 msgid ""
 "You still have unmerged paths in your index\n"
 "did you forget to use 'git add'?"
@@ -4950,16 +8686,25 @@ msgstr ""
 "Du har fortfarande sökvägar som inte slagits samman i ditt index\n"
 "glömde du använda \"git add\"?"
 
-#: git-am.sh:847
+#: git-am.sh:845
 msgid "No changes -- Patch already applied."
 msgstr "Inga ändringar -- Patchen har redan tillämpats."
 
-#: git-am.sh:857
+#: git-am.sh:855
 #, sh-format
 msgid "Patch failed at $msgnum $FIRSTLINE"
 msgstr "Patchen misslyckades vid $msgnum $FIRSTLINE"
 
-#: git-am.sh:873
+#: git-am.sh:858
+#, sh-format
+msgid ""
+"The copy of the patch that failed is found in:\n"
+"   $dotest/patch"
+msgstr ""
+"En kopia av patchen som misslyckades finns i:\n"
+"   $dotest/patch"
+
+#: git-am.sh:876
 msgid "applying to an empty history"
 msgstr "tillämpar på en tom historik"
 
@@ -5162,6 +8907,130 @@ msgstr "Kan inte slå ihop flera grenar i ett tomt huvud."
 msgid "Cannot rebase onto multiple branches"
 msgstr "Kan inte utföra en \"rebase\" ovanpå flera grenar"
 
+#: 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"
+"To check out the original branch and stop rebasing, run \"git rebase --abort"
+"\"."
+msgstr ""
+"När du har löst problemet kör du \"git rebase --continue\".\n"
+"Om du vill hoppa över patchen kör du istället \"git rebase --skip\".\n"
+"För att återställa originalgrenen och avbryta kör du \"git rebase --abort\"."
+
+#: git-rebase.sh:160
+msgid "The pre-rebase hook refused to rebase."
+msgstr "Kroken pre-rebase vägrade ombaseringen."
+
+#: git-rebase.sh:165
+msgid "It looks like git-am is in progress. Cannot rebase."
+msgstr "Det verkar som en git-am körs. Kan inte ombasera."
+
+#: git-rebase.sh:296
+msgid "The --exec option must be used with the --interactive option"
+msgstr "Flaggan --exec måste användas tillsammans med flaggan --interactive"
+
+#: git-rebase.sh:301
+msgid "No rebase in progress?"
+msgstr "Ingen ombasering pågår?"
+
+#: git-rebase.sh:312
+msgid "The --edit-todo action can only be used during interactive rebase."
+msgstr "Åtgärden --edit-todo kan endast användas under interaktiv ombasering."
+
+#: git-rebase.sh:319
+msgid "Cannot read HEAD"
+msgstr "Kan inte läsa HEAD"
+
+#: git-rebase.sh:322
+msgid ""
+"You must edit all merge conflicts and then\n"
+"mark them as resolved using git add"
+msgstr ""
+"Du måste redigera alla sammanslagningskonflikter och\n"
+"därefter markera dem som lösta med git add"
+
+#: git-rebase.sh:340
+#, sh-format
+msgid "Could not move back to $head_name"
+msgstr "Kunde inte flytta tillbaka till $head_name"
+
+#: git-rebase.sh:359
+#, sh-format
+msgid ""
+"It seems that there is already a $state_dir_base directory, and\n"
+"I wonder if you are in the middle of another rebase.  If that is the\n"
+"case, please try\n"
+"\t$cmd_live_rebase\n"
+"If that is not the case, please\n"
+"\t$cmd_clear_stale_rebase\n"
+"and run me again.  I am stopping in case you still have something\n"
+"valuable there."
+msgstr ""
+"Det verkar som katalogen $state_dir_base redan existerar, och\n"
+"jag undrar om du redan är mitt i en annan ombasering. Om så är\n"
+"fallet, försök\n"
+"\t$cmd_live_rebase\n"
+"Om så inte är fallet, kör\n"
+"\t$cmd_clear_stale_rebase\n"
+"och kör programmet igen. Jag avslutar ifall du fortfarande har\n"
+"något av värde där."
+
+#: git-rebase.sh:404
+#, sh-format
+msgid "invalid upstream $upstream_name"
+msgstr "ogiltig uppström $upstream_name"
+
+#: git-rebase.sh:428
+#, sh-format
+msgid "$onto_name: there are more than one merge bases"
+msgstr "$onto_name: mer än en sammanslagningsbas finns"
+
+#: git-rebase.sh:431 git-rebase.sh:435
+#, sh-format
+msgid "$onto_name: there is no merge base"
+msgstr "$onto_name: ingen sammanslagningsbas finns"
+
+#: git-rebase.sh:440
+#, sh-format
+msgid "Does not point to a valid commit: $onto_name"
+msgstr "Peka på en giltig incheckning: $onto_name"
+
+#: git-rebase.sh:463
+#, sh-format
+msgid "fatal: no such branch: $branch_name"
+msgstr "ödesdigert: ingen sådan gren: $branch_name"
+
+#: git-rebase.sh:483
+msgid "Please commit or stash them."
+msgstr "Checka in eller använd \"stash\" på dem."
+
+#: git-rebase.sh:501
+#, sh-format
+msgid "Current branch $branch_name is up to date."
+msgstr "Aktuell gren $branch_name är à jour."
+
+#: git-rebase.sh:504
+#, sh-format
+msgid "Current branch $branch_name is up to date, rebase forced."
+msgstr "Aktuell gren $branch_name är à jour, ombasering framtvingad."
+
+#: git-rebase.sh:515
+#, sh-format
+msgid "Changes from $mb to $onto:"
+msgstr "Ändringar från $mb till $onto:"
+
+#. Detach HEAD and reset the tree
+#: git-rebase.sh:524
+msgid "First, rewinding head to replay your work on top of it..."
+msgstr ""
+"Först, spolar tillbaka huvudet för att spela av ditt arbete ovanpå det..."
+
+#: git-rebase.sh:532
+#, sh-format
+msgid "Fast-forwarded $branch_name to $onto_name."
+msgstr "Snabbspolade $branch_name till $onto_name."
+
 #: git-stash.sh:51
 msgid "git stash clear with parameters is unimplemented"
 msgstr "\"git stash clear\" med parametrar har inte implementerats"
@@ -5269,60 +9138,60 @@ msgstr "Kunde inte spara indexträd"
 msgid "Cannot unstage modified files"
 msgstr "Kan inte ta bort ändrade filer ur kön"
 
-#: git-stash.sh:474
+#: git-stash.sh:475
 msgid "Index was not unstashed."
 msgstr "Indexet har inte tagits ur kön."
 
-#: git-stash.sh:491
+#: git-stash.sh:492
 #, sh-format
 msgid "Dropped ${REV} ($s)"
 msgstr "Kastade ${REV} ($s)"
 
-#: git-stash.sh:492
+#: git-stash.sh:493
 #, sh-format
 msgid "${REV}: Could not drop stash entry"
 msgstr "${REV}: Kunde inte kasta \"stash\"-post"
 
-#: git-stash.sh:499
+#: git-stash.sh:500
 msgid "No branch name specified"
 msgstr "Inget grennamn angavs"
 
-#: git-stash.sh:570
+#: git-stash.sh:571
 msgid "(To restore them type \"git stash apply\")"
 msgstr "(För att återställa dem, skriv \"git stash apply\")"
 
-#: git-submodule.sh:56
+#: git-submodule.sh:88
 #, 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:109
+#: git-submodule.sh:167
 #, sh-format
 msgid "No submodule mapping found in .gitmodules for path '$sm_path'"
 msgstr ""
 "Hittade ingen undermodulmappning i .gitmodules för sökvägen \"$sm_path\""
 
-#: git-submodule.sh:150
+#: git-submodule.sh:211
 #, sh-format
 msgid "Clone of '$url' into submodule path '$sm_path' failed"
 msgstr "Misslyckades klona \"$url\" till undermodulsökvägen \"$sm_path\""
 
-#: git-submodule.sh:160
+#: git-submodule.sh:223
 #, sh-format
 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:249
+#: git-submodule.sh:312
 #, 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:266
+#: git-submodule.sh:329
 #, sh-format
 msgid "'$sm_path' already exists in the index"
 msgstr "\"$sm_path\" finns redan i indexet"
 
-#: git-submodule.sh:270
+#: git-submodule.sh:333
 #, sh-format
 msgid ""
 "The following path is ignored by one of your .gitignore files:\n"
@@ -5333,64 +9202,64 @@ msgstr ""
 "$sm_path\n"
 "Använd -f om du verkligen vill lägga till den"
 
-#: git-submodule.sh:281
+#: git-submodule.sh:344
 #, 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:283
+#: git-submodule.sh:346
 #, 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:297
+#: git-submodule.sh:360
 #, sh-format
 msgid "Unable to checkout submodule '$sm_path'"
 msgstr "Kan inte checka ut undermodulen \"$sm_path\""
 
-#: git-submodule.sh:302
+#: git-submodule.sh:365
 #, sh-format
 msgid "Failed to add submodule '$sm_path'"
 msgstr "Misslyckades lägga till undermodulen \"$sm_path\""
 
-#: git-submodule.sh:307
+#: git-submodule.sh:370
 #, sh-format
 msgid "Failed to register submodule '$sm_path'"
 msgstr "Misslyckades registrera undermodulen \"$sm_path\""
 
-#: git-submodule.sh:349
+#: git-submodule.sh:413
 #, sh-format
 msgid "Entering '$prefix$sm_path'"
 msgstr "Går in i \"$prefix$sm_path\""
 
-#: git-submodule.sh:363
+#: git-submodule.sh:427
 #, 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:406
+#: git-submodule.sh:471
 #, 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:415
+#: git-submodule.sh:480
 #, 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:417
+#: git-submodule.sh:482
 #, 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:425
+#: git-submodule.sh:490
 #, 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:524
+#: git-submodule.sh:590
 #, sh-format
 msgid ""
 "Submodule path '$sm_path' not initialized\n"
@@ -5399,97 +9268,161 @@ msgstr ""
 "Undermodulen \"$sm_path\" har inte initierats\n"
 "Kanske du vill köra \"update --init\"?"
 
-#: git-submodule.sh:537
+#: git-submodule.sh:603
 #, 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:556
+#: git-submodule.sh:622
 #, 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:570
+#: git-submodule.sh:636
 #, 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:571
+#: git-submodule.sh:637
 #, sh-format
 msgid "Submodule path '$sm_path': rebased into '$sha1'"
 msgstr "Undermodulsökvägen \"$sm_path\": ombaserade in i \"$sha1\""
 
-#: git-submodule.sh:576
+#: git-submodule.sh:642
 #, 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:577
+#: git-submodule.sh:643
 #, sh-format
 msgid "Submodule path '$sm_path': merged in '$sha1'"
 msgstr "Undermodulsökvägen \"$sm_path\": sammanslagen i \"$sha1\""
 
-#: git-submodule.sh:582
+#: git-submodule.sh:648
 #, 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:583
+#: git-submodule.sh:649
 #, sh-format
 msgid "Submodule path '$sm_path': checked out '$sha1'"
 msgstr "Undermodulsökvägen \"$sm_path\": checkade ut \"$sha1\""
 
-#: git-submodule.sh:605 git-submodule.sh:928
+#: git-submodule.sh:671 git-submodule.sh:995
 #, sh-format
 msgid "Failed to recurse into submodule path '$sm_path'"
 msgstr "Misslyckades rekursera in i undermodulsökvägen \"$sm_path\""
 
-#: git-submodule.sh:713
-msgid "--cached cannot be used with --files"
-msgstr "--cached kan inte användas med --files"
+#: git-submodule.sh:779
+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:753
+#: git-submodule.sh:819
 #, sh-format
 msgid "unexpected mode $mod_dst"
 msgstr "oväntat läge $mod_dst"
 
-#: git-submodule.sh:771
+#: git-submodule.sh:837
 #, sh-format
 msgid "  Warn: $name doesn't contain commit $sha1_src"
 msgstr "  Varning: $name innehåller inte incheckning $sha1_src"
 
-#: git-submodule.sh:774
+#: git-submodule.sh:840
 #, sh-format
 msgid "  Warn: $name doesn't contain commit $sha1_dst"
 msgstr "  Varning: $name innehåller inte incheckning $sha1_dst"
 
-#: git-submodule.sh:777
+#: git-submodule.sh:843
 #, 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:802
+#: git-submodule.sh:868
 msgid "blob"
 msgstr "blob"
 
-#: git-submodule.sh:803
-msgid "submodule"
-msgstr "undermodul"
-
-#: git-submodule.sh:840
+#: git-submodule.sh:906
 msgid "# Submodules changed but not updated:"
 msgstr "# Undermoduler ändrade men inte uppdaterade:"
 
-#: git-submodule.sh:842
+#: git-submodule.sh:908
 msgid "# Submodule changes to be committed:"
 msgstr "# Undermodulers ändringar att checka in:"
 
-#: git-submodule.sh:974
+#: git-submodule.sh:1054
 #, sh-format
 msgid "Synchronizing submodule url for '$name'"
 msgstr "Synkroniserar undermodul-url för \"$name\""
 
+#~ msgid " 0 files changed"
+#~ msgstr " 0 filer ändrade"
+
+#~ msgid " %d file changed"
+#~ msgid_plural " %d files changed"
+#~ msgstr[0] " %d fil ändrad"
+#~ msgstr[1] " %d filer ändrade"
+
+#~ msgid ", %d insertion(+)"
+#~ msgid_plural ", %d insertions(+)"
+#~ msgstr[0] ", %d tillägg(+)"
+#~ msgstr[1] ", %d tillägg(+)"
+
+#~ msgid ", %d deletion(-)"
+#~ msgid_plural ", %d deletions(-)"
+#~ msgstr[0] ", %d borttagning(-)"
+#~ msgstr[1] ", %d borttagningar(-)"
+
+#~ msgid "Auto packing the repository for optimum performance.\n"
+#~ msgstr "Packar arkivet automatiskt för optimal prestanda.\n"
+
+#~ msgid " (use \"git add\" to track)"
+#~ msgstr " (spåra med \"git add\")"
+
+#~ msgid "-B cannot be used with -b"
+#~ msgstr "-B kan inte användas med -b"
+
+#~ msgid "--patch is incompatible with all other options"
+#~ msgstr "--patch är inkompatibel med alla andra flaggor"
+
+#~ msgid "--detach cannot be used with -b/-B/--orphan"
+#~ msgstr "--detcah kan inte användas med -b/-B/--orphan"
+
+#~ msgid "--detach cannot be used with -t"
+#~ msgstr "--detach kan inte användas med -t"
+
+#~ msgid "--orphan and -b|-B are mutually exclusive"
+#~ msgstr "--orphan och -b|-B kan inte användas samtidigt"
+
+#~ msgid "--orphan cannot be used with -t"
+#~ msgstr "--orphan kan inte användas med -t"
+
+#~ msgid "git checkout: -f and -m are incompatible"
+#~ msgstr "git checkout: -f och -m är inkompatibla"
+
+#~ msgid ""
+#~ "git checkout: updating paths is incompatible with switching branches."
+#~ msgstr ""
+#~ "git checkout: uppdatera sökvägar är inkompatibelt med att växla gren."
+
+#~ msgid "diff setup failed"
+#~ msgstr "misslyckades sätta upp för diff"
+
+#~ msgid "merge-recursive: disk full?"
+#~ msgstr "merge-recursive: disk full?"
+
+#~ msgid "diff_setup_done failed"
+#~ msgstr "diff_setup_done misslyckades"
+
+#~ msgid "%s: has been deleted/renamed"
+#~ msgstr "%s: har tagits bort/ändrat namn"
+
+#~ msgid "'%s': not a documentation directory."
+#~ msgstr "\"%s\": inte en dokumentationskatalog."
+
+#~ msgid "-d option is no longer supported.  Do not use."
+#~ msgstr "Flaggan -d stöds inte lägre. Använd inte."
+
 #~ msgid "cherry-pick"
 #~ msgstr "cherry-pick"
 
@@ -5502,9 +9435,6 @@ msgstr "Synkroniserar undermodul-url för \"$name\""
 #~ msgid "--"
 #~ msgstr "--"
 
-#~ msgid "Too many options specified"
-#~ msgstr "För många flaggor angavs"
-
 #~ msgid "# Changed but not updated:"
 #~ msgstr "# Ändrade men inte uppdaterade:"
 
@@ -5529,26 +9459,17 @@ msgstr "Synkroniserar undermodul-url för \"$name\""
 #~ msgid "cannot mix --fixed-strings and regexp"
 #~ msgstr "kan inte blanda --fixed-strings och reguljära uttryck"
 
-#~ msgid "invalid --decorate option: %s"
-#~ msgstr "felaktigt värde till --decorate: %s"
-
 #~ msgid "%s; will overwrite!"
 #~ msgstr "%s; kommer skriva över!"
 
 #~ msgid "Failed to write current notes tree to database"
 #~ msgstr "Kunde inte skriva aktuellt anteckningsträd till databasen"
 
-#~ msgid "Failed to commit notes tree to database"
-#~ msgstr "Kunde inte checka in anteckningsträd i databasen"
-
 # FIXME: Untranslatable!
 #
 #~ msgid "Refusing to %s notes in %s (outside of refs/notes/)"
 #~ msgstr "Vägrar %s anteckningar i %s (utanför refs/notes/)"
 
-#~ msgid "list"
-#~ msgstr "list"
-
 #~ msgid "add"
 #~ msgstr "add"
 
index f0529f407a15669156777455395a480165ee5162..ca617a3ca087db1cde72adf060b24c71dbef11cf 100644 (file)
--- a/po/vi.po
+++ b/po/vi.po
@@ -2,23 +2,22 @@
 # Copyright (C) 2012, Trần Ngọc Quân.
 # This file is distributed under the same license as the git-core package.
 # First translated by Trần Ngọc Quân <vnwildman@gmail.com>, 2012.
+# Nguyễn Thái Ngọc Duy <pclouds@gmail.com>, 2012.
 #
 msgid ""
 msgstr ""
-"Project-Id-Version: git-1.7.11.rc2.2.gb694fbb\n"
+"Project-Id-Version: git-v1.8.0-rc2-4-g42e55\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2012-06-08 10:20+0800\n"
-"PO-Revision-Date: 2012-06-09 14:08+0700\n"
+"POT-Creation-Date: 2012-10-16 08:38+0800\n"
+"PO-Revision-Date: 2012-10-17 08:09+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"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"Language: \n"
 "Plural-Forms: nplurals=2; plural=1;\n"
-"X-Poedit-Language: Vietnamese\n"
-"X-Poedit-Country: VIET NAM\n"
-"X-Poedit-SourceCharset: utf-8\n"
+"X-Poedit-SourceCharset: UTF-8\n"
 "X-Poedit-Basepath: ../\n"
 
 #: advice.c:40
@@ -38,38 +37,118 @@ msgid ""
 "or use 'git commit -a'."
 msgstr ""
 "Sửa chúng trong cây làm việc,\n"
-"và sau đó sử dụng lệnh 'git add/rm <tập-tin>'\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à sử dụng lệnh 'git commit -a'."
+"hoặc là dùng lệnh `git commit -a'."
+
+#: archive.c:10
+msgid "git archive [options] <tree-ish> [<path>...]"
+msgstr "git archive [các-tùy-chọn] <tree-ish> [<đường-dẫn>...]"
+
+#: 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 <kho> [--exec <lệnh>] [các-tùy-chọn] <tree-ish> [<đường-"
+"dẫn>...]"
+
+#: archive.c:13
+msgid "git archive --remote <repo> [--exec <cmd>] --list"
+msgstr "git archive --remote <kho> [--exec <lệnh>] --list"
+
+#: archive.c:322
+msgid "fmt"
+msgstr "fmt"
+
+#: archive.c:322
+msgid "archive format"
+msgstr "định dạng lưu trữ"
+
+#: archive.c:323 builtin/log.c:1079
+msgid "prefix"
+msgstr "tiền tố"
+
+#: archive.c:324
+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
+#: 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 "tập-tin"
+
+#: archive.c:326 builtin/archive.c:92
+msgid "write the archive to this file"
+msgstr "ghi kho lưu vào tập tin này"
+
+#: archive.c:328
+msgid "read .gitattributes in working directory"
+msgstr "đọc .gitattributes trong thư mục làm việc"
+
+#: archive.c:329
+msgid "report archived files on stderr"
+msgstr "liệt kê các tập tin được lưu trữ vào stderr (đầu ra lỗi chuẩn)"
+
+#: archive.c:330
+msgid "store only"
+msgstr "chỉ lưu"
+
+#: archive.c:331
+msgid "compress faster"
+msgstr "nén nhanh hơn"
+
+#: archive.c:339
+msgid "compress better"
+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ợ"
+
+#: archive.c:344 builtin/archive.c:93 builtin/clone.c:85
+msgid "repo"
+msgstr "kho"
+
+#: archive.c:345 builtin/archive.c:94
+msgid "retrieve the archive from remote repository <repo>"
+msgstr "nhận kho lưu từ kho chứa <kho> trên máy chủ"
+
+#: archive.c:346 builtin/archive.c:95 builtin/notes.c:619
+msgid "command"
+msgstr "lệnh"
+
+#: archive.c:347 builtin/archive.c:96
+msgid "path to the remote git-upload-archive command"
+msgstr "đường dẫn đến lệnh git-upload-pack trên máy chủ"
 
 #: 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 (cụm)"
 
 #: 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:696
+#: bundle.c:89 builtin/commit.c:672
 #, 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:550
-#: sequencer.c:982
-#: builtin/log.c:289
-#: builtin/log.c:720
-#: builtin/log.c:1309
-#: builtin/log.c:1528
-#: builtin/merge.c:347
+#: 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/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"
@@ -82,67 +161,68 @@ msgstr[0] "Bundle chứa %d tham chiếu (refs)"
 msgstr[1] "Bundle chứa %d tham chiếu (refs)"
 
 #: bundle.c:192
+msgid "The bundle records a complete history."
+msgstr "Lệnh bundle ghi lại toàn bộ lịch sử."
+
+#: bundle.c:195
 #, c-format
 msgid "The bundle requires this ref"
 msgid_plural "The bundle requires these %d refs"
 msgstr[0] "Lệnh bundle yêu cầu tham chiếu (refs) này"
 msgstr[1] "Lệnh bundle yêu cầu %d tham chiếu (refs) này"
 
-#: bundle.c:290
+#: bundle.c:294
 msgid "rev-list died"
 msgstr "rev-list bị chết"
 
-#: bundle.c:296
-#: builtin/log.c:1205
-#: builtin/shortlog.c:284
+#: bundle.c:300 builtin/log.c:1209 builtin/shortlog.c:284
 #, c-format
 msgid "unrecognized argument: %s"
 msgstr "đối số không được thừa nhận: %s"
 
-#: bundle.c:331
+#: 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 "tham chiếu `%s' bị loại trừ bởi các tùy chọn rev-list"
 
-#: bundle.c:376
+#: bundle.c:380
 msgid "Refusing to create empty bundle."
 msgstr "Từ chối tạo một bundle trống rỗng."
 
-#: bundle.c:394
+#: bundle.c:398
 msgid "Could not spawn pack-objects"
 msgstr "Không thể sản sinh pack-objects"
 
-#: bundle.c:412
+#: bundle.c:416
 msgid "pack-objects died"
 msgstr "pack-objects đã chết"
 
-#: bundle.c:415
+#: 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:437
+#: bundle.c:441
 msgid "index-pack died"
 msgstr "index-pack đã chết"
 
-#: commit.c:48
+#: commit.c:50
 #, c-format
 msgid "could not parse %s"
 msgstr "không thể phân tích %s"
 
-#: commit.c:50
+#: commit.c:52
 #, c-format
 msgid "%s %s is not a commit!"
 msgstr "%s %s không phải là một lần commit!"
 
-#: compat/obstack.c:406
-#: compat/obstack.c:408
+#: compat/obstack.c:406 compat/obstack.c:408
 msgid "memory exhausted"
 msgstr "cạn 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
@@ -214,8 +294,7 @@ msgid_plural "%s, %lu months ago"
 msgstr[0] "%s, %lu tháng trước"
 msgstr[1] "%s, %lu tháng trước"
 
-#: date.c:154
-#: date.c:159
+#: date.c:154 date.c:159
 #, c-format
 msgid "%lu year ago"
 msgid_plural "%lu years ago"
@@ -225,12 +304,12 @@ msgstr[1] "%lu năm trước"
 #: diff.c:105
 #, 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"
+msgstr "  Gặp lỗi khi phân tích dirstat cắt bỏ phần trăm `%.*s'\n"
 
 #: diff.c:110
 #, c-format
 msgid "  Unknown dirstat parameter '%.*s'\n"
-msgstr "  Không hiểu đối số dirstat '%.*s'\n"
+msgstr "  Không hiểu đối số dirstat `%.*s'\n"
 
 #: diff.c:210
 #, c-format
@@ -241,32 +320,7 @@ msgstr ""
 "Tìm thấy các lỗi trong biến cấu hình 'diff.dirstat':\n"
 "%s"
 
-#: diff.c:1400
-msgid " 0 files changed\n"
-msgstr " 0 tập tin nào bị thay đổi\n"
-
-#: diff.c:1404
-#, c-format
-msgid " %d file changed"
-msgid_plural " %d files changed"
-msgstr[0] " %d tập tin đã bị thay đổi"
-msgstr[1] " %d tập tin đã bị thay đổi"
-
-#: diff.c:1421
-#, c-format
-msgid ", %d insertion(+)"
-msgid_plural ", %d insertions(+)"
-msgstr[0] ", %d được thêm vào(+)"
-msgstr[1] ", %d được thêm vào(+)"
-
-#: diff.c:1432
-#, c-format
-msgid ", %d deletion(-)"
-msgid_plural ", %d deletions(-)"
-msgstr[0] ", %d bị xóa(-)"
-msgstr[1] ", %d bị xóa(-)"
-
-#: diff.c:3478
+#: diff.c:3458
 #, c-format
 msgid ""
 "Failed to parse --dirstat/-X option parameter:\n"
@@ -287,63 +341,63 @@ 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:1320
+#: grep.c:1441
 #, c-format
 msgid "'%s': unable to read %s"
-msgstr "'%s': không thể đọc %s"
+msgstr "`%s': không thể đọc %s"
 
-#: grep.c:1337
+#: grep.c:1458
 #, c-format
 msgid "'%s': %s"
-msgstr "'%s': %s"
+msgstr "`%s': %s"
 
-#: grep.c:1348
+#: grep.c:1469
 #, c-format
 msgid "'%s': short read %s"
-msgstr "'%s': đọc ngắn %s"
+msgstr "`%s': đọc ngắn %s"
 
-#: help.c:207
+#: 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:214
+#: help.c:219
 msgid "git commands available from elsewhere on your $PATH"
 msgstr "các lệnh git sẵn sàng để dùng từ một nơi khác trong $PATH của bạn"
 
-#: help.c:270
+#: help.c:275
 #, c-format
 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:327
+#: help.c:332
 msgid "Uh oh. Your system reports no Git commands at all."
 msgstr "Ối chà. Hệ thống của bạn báo rằng chẳng có lệnh Git nào cả."
 
-#: help.c:349
+#: help.c:354
 #, c-format
 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 sẵn có.\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:354
+#: help.c:359
 #, c-format
 msgid "in %0.1f seconds automatically..."
 msgstr "trong %0.1f giây một cách tự động..."
 
-#: help.c:361
+#: 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 thêm 'git --help'."
+msgstr "git: `%s' không phải là một lệnh của git. Xem `git --help'."
 
-#: help.c:365
+#: help.c:370
 msgid ""
 "\n"
 "Did you mean this?"
@@ -357,42 +411,303 @@ msgstr[1] ""
 "\n"
 "Có phải ý bạn là một trong số những cái này không?"
 
-#: parse-options.c:493
+#: merge-recursive.c:190
+#, c-format
+msgid "(bad commit)\n"
+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'"
+
+#: merge-recursive.c:268
+msgid "error building trees"
+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"
+
+#: merge-recursive.c:683
+#, c-format
+msgid "Removing %s to make room for subdirectory\n"
+msgstr "Gỡ bỏ %s để tạo chỗ (room) cho thư mục con\n"
+
+#. something else exists
+#. .. but not some other error (who really cares what?)
+#: merge-recursive.c:697 merge-recursive.c:718
+msgid ": perhaps a D/F conflict?"
+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'"
+
+#: merge-recursive.c:748
+#, c-format
+msgid "cannot read object %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'"
+
+#: merge-recursive.c:773 builtin/clone.c:302
+#, c-format
+msgid "failed to open '%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'"
+
+#: 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'"
+
+#: merge-recursive.c:922
+msgid "Failed to execute internal merge"
+msgstr "Gặp lỗi khi thực hiện trộn nội bộ"
+
+#: merge-recursive.c:926
+#, c-format
+msgid "Unable to add %s to database"
+msgstr "Không thể thêm %s vào cơ sở dữ liệu"
+
+#: merge-recursive.c:942
+msgid "unsupported object type in the tree"
+msgstr "kiểu đối tượng không được hỗ trợ trong cây (tree)"
+
+#: 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 "
+"in tree."
+msgstr ""
+"XUNG ĐỘT (%s/xóa): %s bị xóa trong %s và %s trong %s. Phiên bản %s của %s "
+"còn lại trong cây (tree)."
+
+#: 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 "
+"in tree at %s."
+msgstr ""
+"XUNG ĐỘT (%s/xóa): %s bị xóa trong %s và %s trong %s. Phiên bản %s của %s "
+"còn lại trong cây (tree) tại %s."
+
+#: merge-recursive.c:1081
+msgid "rename"
+msgstr "đổi tên"
+
+#: merge-recursive.c:1081
+msgid "renamed"
+msgstr "đã đổi tên"
+
+#: merge-recursive.c:1137
+#, c-format
+msgid "%s is a directory in %s adding as %s instead"
+msgstr "%s là một thư mục trong %s thay vào đó thêm vào như là %s"
+
+#: merge-recursive.c:1159
+#, c-format
+msgid ""
+"CONFLICT (rename/rename): Rename \"%s\"->\"%s\" in branch \"%s\" rename \"%s"
+"\"->\"%s\" in \"%s\"%s"
+msgstr ""
+"XUNG ĐỘT (đổi-tên/đổi-tên): Đổi tên \"%s\"->\"%s\" trong nhánh \"%s\" đổi "
+"tên \"%s\"->\"%s\" trong \"%s\"%s"
+
+#: merge-recursive.c:1164
+msgid " (left unresolved)"
+msgstr " (cần giải quyết)"
+
+#: merge-recursive.c:1218
+#, c-format
+msgid "CONFLICT (rename/rename): Rename %s->%s in %s. Rename %s->%s in %s"
+msgstr ""
+"XUNG ĐỘT (đổi-tên/đổi-tên): Đổi tên %s->%s trong %s. Đổi tên %s->%s trong %s"
+
+#: merge-recursive.c:1248
+#, c-format
+msgid "Renaming %s to %s and %s to %s instead"
+msgstr "Đang đổi tên %s thành %s thay vì %s thành %s"
+
+#: merge-recursive.c:1447
+#, c-format
+msgid "CONFLICT (rename/add): Rename %s->%s in %s. %s added in %s"
+msgstr ""
+"XUNG ĐỘT (đổi-tên/thêm): Đổi tên %s->%s trong %s. %s được thêm vào trong %s"
+
+#: merge-recursive.c:1457
+#, c-format
+msgid "Adding merged %s"
+msgstr "Thêm hòa trộn %s"
+
+#: merge-recursive.c:1462 merge-recursive.c:1660
+#, c-format
+msgid "Adding as %s instead"
+msgstr "Thay vào đó thêm vào %s"
+
+#: merge-recursive.c:1513
+#, c-format
+msgid "cannot read object %s"
+msgstr "không thể đọc đối tượng %s"
+
+#: merge-recursive.c:1516
+#, c-format
+msgid "object %s is not a blob"
+msgstr "đối tượng %s không phải là một blob"
+
+#: merge-recursive.c:1564
+msgid "modify"
+msgstr "sửa đổi"
+
+#: merge-recursive.c:1564
+msgid "modified"
+msgstr "đã sửa"
+
+#: merge-recursive.c:1574
+msgid "content"
+msgstr "nội dung"
+
+#: merge-recursive.c:1581
+msgid "add/add"
+msgstr "thêm/thêm"
+
+#: merge-recursive.c:1615
+#, c-format
+msgid "Skipped %s (merged same as existing)"
+msgstr "Đã bỏ qua %s (đã có sẵn lần hòa trộn này)"
+
+#: merge-recursive.c:1629
+#, c-format
+msgid "Auto-merging %s"
+msgstr "Tự-động-hòa-trộn %s"
+
+#: merge-recursive.c:1633 git-submodule.sh:869
+msgid "submodule"
+msgstr "mô-đun-con"
+
+#: merge-recursive.c:1634
+#, c-format
+msgid "CONFLICT (%s): Merge conflict in %s"
+msgstr "XUNG ĐỘT (%s): Xung đột hòa trộn trong %s"
+
+#: merge-recursive.c:1724
+#, c-format
+msgid "Removing %s"
+msgstr "Đang xóa %s"
+
+#: merge-recursive.c:1749
+msgid "file/directory"
+msgstr "tập-tin/thư-mục"
+
+#: merge-recursive.c:1755
+msgid "directory/file"
+msgstr "thư-mục/tập tin"
+
+#: merge-recursive.c:1760
+#, c-format
+msgid "CONFLICT (%s): There is a directory with name %s in %s. Adding %s as %s"
+msgstr ""
+"XUNG ĐỘT (%s): Ở đây không có thư mục nào có tên %s trong %s. Thêm %s như là "
+"%s"
+
+#: merge-recursive.c:1770
+#, c-format
+msgid "Adding %s"
+msgstr "Thêm \"%s\""
+
+#: merge-recursive.c:1787
+msgid "Fatal merge failure, shouldn't happen."
+msgstr "Việc hòa trộn hỏng nghiêm trọng, không nên để xảy ra."
+
+#: merge-recursive.c:1806
+msgid "Already up-to-date!"
+msgstr "Đã cập nhật rồi!"
+
+#: merge-recursive.c:1815
+#, c-format
+msgid "merging of trees %s and %s failed"
+msgstr "hòa trộn cây (tree) %s và %s gặp lỗi"
+
+#: merge-recursive.c:1845
+#, c-format
+msgid "Unprocessed path??? %s"
+msgstr "Đường dẫn chưa được xử lý??? %s"
+
+#: merge-recursive.c:1890
+msgid "Merging:"
+msgstr "Đang trộn:"
+
+#: merge-recursive.c:1903
+#, c-format
+msgid "found %u common ancestor:"
+msgid_plural "found %u common ancestors:"
+msgstr[0] "tìm thấy %u tổ tiên chung:"
+msgstr[1] "tìm thấy %u tổ tiên chung:"
+
+#: merge-recursive.c:1940
+msgid "merge returned no commit"
+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'"
+
+#: merge-recursive.c:2009 builtin/merge.c:696
+msgid "Unable to write index."
+msgstr "Không thể ghi bảng mục lục"
+
+#: parse-options.c:494
 msgid "..."
 msgstr "..."
 
-#: parse-options.c:511
+#: parse-options.c:512
 #, c-format
 msgid "usage: %s"
-msgstr "cách sử dụng: %s"
+msgstr "cách ng: %s"
 
 #. TRANSLATORS: the colon here should align with the
 #. one in "usage: %s" translation
-#: parse-options.c:515
+#: parse-options.c:516
 #, c-format
 msgid "   or: %s"
-msgstr "   hoặc: %s"
+msgstr "     hoặc: %s"
 
-#: parse-options.c:518
+#: parse-options.c:519
 #, c-format
 msgid "    %s"
 msgstr "    %s"
 
-#: remote.c:1629
+#: remote.c:1632
 #, 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:1635
+#: remote.c:1638
 #, 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ể đượ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ể được fast-forward.\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ể "
+"đượ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ể "
+"được fast-forward.\n"
 
-#: remote.c:1643
+#: remote.c:1646
 #, c-format
 msgid ""
 "Your branch and '%s' have diverged,\n"
@@ -401,561 +716,697 @@ 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:121
-#: builtin/merge.c:865
-#: builtin/merge.c:978
-#: builtin/merge.c:1088
-#: builtin/merge.c:1098
+#: sequencer.c:123 builtin/merge.c:864 builtin/merge.c:977
+#: builtin/merge.c:1087 builtin/merge.c:1097
 #, c-format
 msgid "Could not open '%s' for writing"
 msgstr "Không thể mở %s' để ghi"
 
-#: sequencer.c:123
-#: builtin/merge.c:333
-#: builtin/merge.c:868
-#: builtin/merge.c:1090
-#: builtin/merge.c:1103
+#: sequencer.c:125 builtin/merge.c:333 builtin/merge.c:867
+#: builtin/merge.c:1089 builtin/merge.c:1102
 #, 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:144
+#: sequencer.c:146
 msgid ""
 "after resolving the conflicts, mark the corrected paths\n"
 "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:147
+#: sequencer.c:149
 msgid ""
 "after resolving the conflicts, mark the corrected paths\n"
 "with 'git add <paths>' or 'git rm <paths>'\n"
 "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: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 "Không thể ghi vào %s"
 
-#: sequencer.c:163
+#: sequencer.c:165
 #, c-format
 msgid "Error wrapping up %s"
 msgstr "Lỗi bao bọc %s"
 
-#: sequencer.c:178
+#: sequencer.c:180
 msgid "Your local changes would be overwritten by cherry-pick."
 msgstr "Các thay đổi nội bộ của bạn có thể bị ghi đè bởi lệnh cherry-pick."
 
-#: sequencer.c:180
+#: sequencer.c:182
 msgid "Your local changes would be overwritten by revert."
 msgstr "Các thay đổi nội bộ của bạn có thể bị ghi đè bởi lệnh revert."
 
-#: sequencer.c:183
+#: sequencer.c:185
 msgid "Commit your changes or stash them to proceed."
-msgstr "Chuyển giao (commit) các thay đổi hay stash chúng để tiến hành."
+msgstr "Chuyển giao (commit) các thay đổi của bạn hay stash chúng để xử lý."
 
 #. 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: Không thể ghi tập tin lưu bảng mục lục mới"
 
-#: sequencer.c:261
+#: sequencer.c:266
 msgid "Could not resolve HEAD commit\n"
 msgstr "Không thể phân giải commit (lần chuyển giao) HEAD\n"
 
-#: sequencer.c:282
+#: sequencer.c:287
 msgid "Unable to update cache tree\n"
 msgstr "Không thể cập nhật cây bộ nhớ đệm\n"
 
-#: sequencer.c:324
+#: sequencer.c:332
 #, c-format
 msgid "Could not parse commit %s\n"
 msgstr "Không thể phân tích commit (lần chuyển giao) %s\n"
 
-#: sequencer.c:329
+#: sequencer.c:337
 #, c-format
 msgid "Could not parse parent commit %s\n"
 msgstr "Không thể phân tích commit (lần chuyển giao) cha mẹ %s\n"
 
-#: sequencer.c:395
+#: sequencer.c:403
 msgid "Your index file is unmerged."
 msgstr "Tập tin lưu mục lục của bạn không được hòa trộn."
 
-#: sequencer.c:398
+#: sequencer.c:406
 msgid "You do not have a valid HEAD"
 msgstr "Bạn không có HEAD nào hợp lệ"
 
-#: sequencer.c:413
+#: sequencer.c:421
 #, c-format
 msgid "Commit %s is a merge but no -m option was given."
-msgstr "Lần chuyển giao (commit) %s là một lần hòa trộn nhưng không đưa ra tùy chọn  -m."
+msgstr ""
+"Lần chuyển giao (commit) %s là một lần hòa trộn nhưng không đưa ra tùy chọn -"
+"m."
 
-#: sequencer.c:421
+#: sequencer.c:429
 #, c-format
 msgid "Commit %s does not have parent %d"
 msgstr "Lần chuyển giao (commit) %s không có cha mẹ %d"
 
-#: sequencer.c:425
+#: sequencer.c:433
 #, c-format
 msgid "Mainline was specified but commit %s is not a merge."
-msgstr "Luồng chính được chỉ định nhưng lần chuyển giao (commit) %s không phải là một lần hòa trộn."
+msgstr ""
+"Luồng chính được chỉ ra nhưng lần chuyển giao (commit) %s không phải là một "
+"lần hòa trộn."
 
 #. 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: không thể phân tích lần chuyển giao mẹ của %s"
 
-#: sequencer.c:440
+#: sequencer.c:448
 #, c-format
 msgid "Cannot get commit message for %s"
 msgstr "Không thể lấy thông điệp lần chuyển giao (commit) cho %s"
 
-#: sequencer.c:524
+#: sequencer.c:532
 #, c-format
 msgid "could not revert %s... %s"
 msgstr "không thể revert %s... %s"
 
-#: sequencer.c:525
+#: sequencer.c:533
 #, c-format
 msgid "could not apply %s... %s"
 msgstr "không thể apply (áp dụng miếng vá) %s... %s"
 
-#: sequencer.c:553
+#: sequencer.c:565
 msgid "empty commit set passed"
 msgstr "lần chuyển giao (commit) trống rỗng đặt là hợp quy cách"
 
-#: sequencer.c:561
+#: sequencer.c:573
 #, c-format
 msgid "git %s: failed to read the index"
 msgstr "git %s: gặp lỗi đọc bảng mục lục"
 
-#: sequencer.c:566
+#: sequencer.c:578
 #, c-format
 msgid "git %s: failed to refresh the index"
 msgstr "git %s: gặp lỗi khi làm tươi mới bảng mục lục"
 
-#: sequencer.c:624
+#: sequencer.c:636
 #, c-format
 msgid "Cannot %s during a %s"
 msgstr "Không thể %s trong khi %s"
 
-#: sequencer.c:646
+#: sequencer.c:658
 #, c-format
 msgid "Could not parse line %d."
 msgstr "Không phân tích được dòng %d."
 
-#: sequencer.c:651
+#: sequencer.c:663
 msgid "No commits parsed."
 msgstr "Không có lần chuyển giao (commit) nào được phân tích."
 
-#: sequencer.c:664
+#: sequencer.c:676
 #, c-format
 msgid "Could not open %s"
 msgstr "Không thể mở %s"
 
-#: sequencer.c:668
+#: sequencer.c:680
 #, c-format
 msgid "Could not read %s."
 msgstr "Không thể đọc %s."
 
-#: sequencer.c:675
+#: sequencer.c:687
 #, c-format
 msgid "Unusable instruction sheet: %s"
 msgstr "Bảng chỉ thị không thể dùng được: %s"
 
-#: sequencer.c:703
+#: sequencer.c:715
 #, c-format
 msgid "Invalid key: %s"
 msgstr "Khóa không đúng: %s"
 
-#: sequencer.c:706
+#: sequencer.c:718
 #, c-format
 msgid "Invalid value for %s: %s"
 msgstr "Giá trị không hợp lệ %s: %s"
 
-#: sequencer.c:718
+#: sequencer.c:730
 #, c-format
 msgid "Malformed options sheet: %s"
 msgstr "Bảng tùy chọn dị hình: %s"
 
-#: sequencer.c:739
+#: sequencer.c:751
 msgid "a cherry-pick or revert is already in progress"
 msgstr "một thao tác cherry-pick hoặc revert đang được thực hiện"
 
-#: sequencer.c:740
+#: sequencer.c:752
 msgid "try \"git cherry-pick (--continue | --quit | --abort)\""
 msgstr "hãy thử \"git cherry-pick (--continue | --quit | --abort)\""
 
-#: sequencer.c:744
+#: sequencer.c:756
 #, c-format
 msgid "Could not create sequencer directory %s"
 msgstr "Không thể tạo thư mục xếp dãy %s"
 
-#: sequencer.c:760
-#: sequencer.c:845
+#: sequencer.c:772 sequencer.c:857
 #, c-format
 msgid "Error wrapping up %s."
 msgstr "Lỗi bao bọc %s."
 
-#: sequencer.c:779
-#: sequencer.c:913
+#: sequencer.c:791 sequencer.c:925
 msgid "no cherry-pick or revert in progress"
 msgstr "không cherry-pick hay revert trong tiến trình"
 
-#: sequencer.c:781
+#: sequencer.c:793
 msgid "cannot resolve HEAD"
 msgstr "không thể phân giải HEAD"
 
-#: sequencer.c:783
+#: sequencer.c:795
 msgid "cannot abort from a branch yet to be born"
 msgstr "không thể hủy bỏ từ một nhánh mà nó còn chưa được tạo ra"
 
-#: sequencer.c:805
-#: builtin/apply.c:3697
+#: sequencer.c:817 builtin/apply.c:4005
 #, c-format
 msgid "cannot open %s: %s"
 msgstr "không thể mở %s: %s"
 
-#: sequencer.c:808
+#: sequencer.c:820
 #, c-format
 msgid "cannot read %s: %s"
 msgstr "không thể đọc %s: %s"
 
-#: sequencer.c:809
+#: sequencer.c:821
 msgid "unexpected end of file"
 msgstr "kết thúc tập tin đột xuất"
 
-#: sequencer.c:815
+#: 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:838
+#: sequencer.c:850
 #, c-format
 msgid "Could not format %s."
 msgstr "Không thể định dạng %s."
 
-#: sequencer.c:1000
+#: sequencer.c:1012
 msgid "Can't revert as initial commit"
 msgstr "Không thể revert một lần chuyển giao (commit) khởi tạo"
 
-#: sequencer.c:1001
+#: sequencer.c:1013
 msgid "Can't cherry-pick into empty head"
 msgstr "Không thể cherry-pick vào một đầu (head) trống rỗng"
 
-#: sha1_name.c:864
+#: sha1_name.c:1044
 msgid "HEAD does not point to a branch"
 msgstr "HEAD không chỉ đến một nhánh nào cả"
 
-#: sha1_name.c:867
+#: 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:869
+#: sha1_name.c:1049
 #, c-format
 msgid "No upstream configured for branch '%s'"
-msgstr "Không có dòng ngược (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:872
+#: sha1_name.c:1052
 #, c-format
 msgid "Upstream branch '%s' not stored as a remote-tracking branch"
-msgstr "Nhánh dòng ngược (upstream) '%s' không được lưu lại như là một nhánh 'remote-tracking'"
+msgstr ""
+"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:413
+#: wrapper.c:408
+#, c-format
+msgid "unable to access '%s': %s"
+msgstr "không thể truy cập `%s': %s"
+
+#: wrapper.c:426
 #, c-format
 msgid "unable to look up current user in the passwd file: %s"
 msgstr "không tìm thấy người dùng hiện tại trong tập tin passwd: %s"
 
-#: wrapper.c:414
+#: wrapper.c:427
 msgid "no such user"
 msgstr "không có người dùng như vậy"
 
-#: wt-status.c:135
+#: wt-status.c:140
 msgid "Unmerged paths:"
 msgstr "Những đường dẫn chưa được hòa trộn:"
 
-#: wt-status.c:141
-#: wt-status.c:158
+#: wt-status.c:167 wt-status.c:194
 #, c-format
 msgid "  (use \"git reset %s <file>...\" to unstage)"
-msgstr "  (sử dụng \"git reset %s <tập-tin>...\" để bỏ một stage (trạng thái))"
+msgstr "  (ng \"git reset %s <tập-tin>...\" để bỏ một stage (trạng thái))"
 
-#: wt-status.c:143
-#: wt-status.c:160
+#: wt-status.c:169 wt-status.c:196
 msgid "  (use \"git rm --cached <file>...\" to unstage)"
-msgstr "  (sử dụng \"git rm --cached <tập-tin>...\" để bỏ trạng thái (stage))"
+msgstr "  (ng \"git rm --cached <tập-tin>...\" để bỏ trạng thái (stage))"
 
-#: wt-status.c:144
+#: wt-status.c:173
+msgid "  (use \"git add <file>...\" to mark resolution)"
+msgstr "  (dùng \"git add <tập-tin>...\" để đánh dấu là cần giải quyết)"
+
+#: wt-status.c:175 wt-status.c:179
 msgid "  (use \"git add/rm <file>...\" as appropriate to mark resolution)"
-msgstr "  (sử dụng \"git add/rm <tập-tin>...\" như là một cách  thích hợp để đánh dấu là cần được giải quyết)"
+msgstr ""
+"  (dùng \"git add/rm <tập-tin>...\" như là một cách  thích hợp để đánh dấu "
+"là cần được giải quyết)"
 
-#: wt-status.c:152
+#: wt-status.c:177
+msgid "  (use \"git rm <file>...\" to mark resolution)"
+msgstr "  (dùng \"git rm <tập-tin>...\" để đánh dấu là cần giải quyết)"
+
+#: wt-status.c:188
 msgid "Changes to be committed:"
 msgstr "Những thay đổi sẽ được chuyển giao:"
 
-#: wt-status.c:170
+#: wt-status.c:206
 msgid "Changes not staged for commit:"
-msgstr "Các thay đổi không được đặt trạng thái (stage) cho lần chuyển giao (commit):"
+msgstr ""
+"Các thay đổi không được đặt trạng thái (stage) cho lần chuyển giao (commit):"
 
-#: wt-status.c:174
+#: wt-status.c:210
 msgid "  (use \"git add <file>...\" to update what will be committed)"
-msgstr "  (sử dụng \"git add <tập-tin>...\" để cập nhật những gì cần chuyển giao (commit))"
+msgstr ""
+"  (dùng \"git add <tập-tin>...\" để cập nhật những gì cần chuyển giao "
+"(commit))"
 
-#: wt-status.c:176
+#: wt-status.c:212
 msgid "  (use \"git add/rm <file>...\" to update what will be committed)"
-msgstr "  (sử dụng \"git add/rm <tập_tin>...\" để cập nhật những gì sẽ được chuyển giao)"
+msgstr ""
+"  (dùng \"git add/rm <tập-tin>...\" để cập nhật những gì sẽ được chuyển giao)"
 
-#: wt-status.c:177
-msgid "  (use \"git checkout -- <file>...\" to discard changes in working directory)"
-msgstr "  (sử dụng \"git checkout -- <tập_tin>...\" để loại bỏ những thay đổi trong thư mục làm việc)"
+#: wt-status.c:213
+msgid ""
+"  (use \"git checkout -- <file>...\" to discard changes in working directory)"
+msgstr ""
+"  (dùng \"git checkout -- <tập-tin>...\" để bỏ thay đổi trong thư mục làm "
+"việc)"
 
-#: wt-status.c:179
+#: wt-status.c:215
 msgid "  (commit or discard the untracked or modified content in submodules)"
-msgstr "  (chuyển giao (commit) hoặc là loại bỏ các nội dung không-bị-theo-vết hay đã bị chỉnh sửa trong mô-đun-con)"
-
-#: wt-status.c:188
-#, c-format
-msgid "%s files:"
-msgstr "%s tệp tin:"
+msgstr ""
+"  (chuyển giao (commit) hoặc là loại bỏ các nội dung không-bị-theo-vết hay "
+"đã bị chỉnh sửa trong mô-đun-con)"
 
-#: wt-status.c:191
+#: wt-status.c:227
 #, c-format
 msgid "  (use \"git %s <file>...\" to include in what will be committed)"
-msgstr "  (sử dụng \"git %s <tập-tin>...\" để bao gồm thêm vào những gì cần chuyển giao (commit))"
+msgstr ""
+"  (dùng \"git %s <tập-tin>...\" để thêm vào những gì cần chuyển giao "
+"(commit))"
 
-#: wt-status.c:208
+#: wt-status.c:244
 msgid "bug"
 msgstr "lỗi"
 
-#: wt-status.c:213
+#: wt-status.c:249
 msgid "both deleted:"
 msgstr "bị xóa bởi cả hai:"
 
-#: wt-status.c:214
+#: wt-status.c:250
 msgid "added by us:"
 msgstr "được thêm vào bởi chúng tôi:"
 
-#: wt-status.c:215
+#: wt-status.c:251
 msgid "deleted by them:"
 msgstr "bị xóa đi bởi họ:"
 
-#: wt-status.c:216
+#: wt-status.c:252
 msgid "added by them:"
 msgstr "được thêm vào bởi họ:"
 
-#: wt-status.c:217
+#: wt-status.c:253
 msgid "deleted by us:"
 msgstr "bị xóa bởi chúng tôi:"
 
-#: wt-status.c:218
+#: wt-status.c:254
 msgid "both added:"
 msgstr "được thêm vào bởi cả hai:"
 
-#: wt-status.c:219
+#: wt-status.c:255
 msgid "both modified:"
 msgstr "bị sửa bởi cả hai:"
 
-#: wt-status.c:249
+#: wt-status.c:285
 msgid "new commits, "
-msgstr " lần chuyển giao (commit) mới, "
+msgstr "lần chuyển giao (commit) mới, "
 
-#: wt-status.c:251
+#: wt-status.c:287
 msgid "modified content, "
-msgstr "nội dung được sửa đổi,"
+msgstr "nội dung được sửa đổi, "
 
-#: wt-status.c:253
+#: wt-status.c:289
 msgid "untracked content, "
-msgstr "nội dung chưa được theo dõi"
+msgstr "nội dung chưa được theo dõi"
 
-#: wt-status.c:267
+#: wt-status.c:303
 #, c-format
 msgid "new file:   %s"
 msgstr "tập tin mới:   %s"
 
-#: wt-status.c:270
+#: wt-status.c:306
 #, c-format
 msgid "copied:     %s -> %s"
 msgstr "đã sao chép:     %s -> %s"
 
-#: wt-status.c:273
+#: wt-status.c:309
 #, c-format
 msgid "deleted:    %s"
-msgstr "bị xóa:    %s"
+msgstr "đã xóa:    %s"
 
-#: wt-status.c:276
+#: wt-status.c:312
 #, c-format
 msgid "modified:   %s"
-msgstr "bị sửa đổi:   %s"
+msgstr "đã sửa đổi:   %s"
 
-#: wt-status.c:279
+#: wt-status.c:315
 #, c-format
 msgid "renamed:    %s -> %s"
 msgstr "đã đổi tên:    %s -> %s"
 
-#: wt-status.c:282
+#: wt-status.c:318
 #, c-format
 msgid "typechange: %s"
 msgstr "đổi-kiểu: %s"
 
-#: wt-status.c:285
+#: wt-status.c:321
 #, c-format
 msgid "unknown:    %s"
-msgstr "không :    %s"
+msgstr "không hiểu:    %s"
 
-#: wt-status.c:288
+#: wt-status.c:324
 #, c-format
 msgid "unmerged:   %s"
 msgstr "chưa hòa trộn:   %s"
 
-#: wt-status.c:291
+#: wt-status.c:327
 #, c-format
 msgid "bug: unhandled diff status %c"
 msgstr "lỗi: không lấy được trạng thái lệnh diff %c"
 
-#: wt-status.c:737
+#: wt-status.c:785
+msgid "You have unmerged paths."
+msgstr "Bạn có những đường dẫn chưa được hòa trộn."
+
+#: wt-status.c:788 wt-status.c:912
+msgid "  (fix conflicts and run \"git commit\")"
+msgstr "  (sửa các xung đột sau đó chạy \"git commit\")"
+
+#: wt-status.c:791
+msgid "All conflicts fixed but you are still merging."
+msgstr "Tất cả các xung đột đã được giải quyết nhưng bạn vẫn đang hòa trộn."
+
+#: wt-status.c:794
+msgid "  (use \"git commit\" to conclude merge)"
+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'."
+
+#: wt-status.c:807
+msgid "The current patch is empty."
+msgstr "Miếng vá hiện tại bị trống rỗng."
+
+#: wt-status.c:811
+msgid "  (fix conflicts and then run \"git am --resolved\")"
+msgstr "  (sửa các xung đột và sau đó chạy lệnh \"git am --resolved\")"
+
+#: wt-status.c:813
+msgid "  (use \"git am --skip\" to skip this patch)"
+msgstr "  (dùng \"git am --skip\" để bỏ qua lần vá này)"
+
+#: wt-status.c:815
+msgid "  (use \"git am --abort\" to restore the original branch)"
+msgstr "  (dùng \"git am --abort\" để phục hồi lại nhánh nguyên thủy)"
+
+#: wt-status.c:873 wt-status.c:883
+msgid "You are currently rebasing."
+msgstr "Bạn hiện nay đang thực hiện việc rebase (tái cấu trúc)."
+
+#: wt-status.c:876
+msgid "  (fix conflicts and then run \"git rebase --continue\")"
+msgstr "  (sửa các xung đột và sau đó chạy lệnh \"git rebase --continue\")"
+
+#: wt-status.c:878
+msgid "  (use \"git rebase --skip\" to skip this patch)"
+msgstr "  (dùng \"git rebase --skip\" để bỏ qua lần vá này)"
+
+#: wt-status.c:880
+msgid "  (use \"git rebase --abort\" to check out the original branch)"
+msgstr "  (dùng \"git rebase --abort\" để check-out nhánh nguyên thủy)"
+
+#: wt-status.c:886
+msgid "  (all conflicts fixed: run \"git rebase --continue\")"
+msgstr ""
+"  (khi tất cả các xung đột đã sửa xong: chạy lệnh \"git rebase --continue\")"
+
+#: wt-status.c:888
+msgid "You are currently splitting a commit during a rebase."
+msgstr ""
+"Bạn hiện tại đang cắt đôi một lần chuyển giao trong khi đang thực hiện việc "
+"rebase."
+
+#: wt-status.c:891
+msgid "  (Once your working directory is clean, run \"git rebase --continue\")"
+msgstr ""
+"  (Một khi thư mục làm việc của bạn đã gọn gàng, chạy \"git rebase --continue"
+"\")"
+
+#: wt-status.c:893
+msgid "You are currently editing a commit during a rebase."
+msgstr "Bạn hiện đang sửa một lần chuyển giao trong khi bạn thực hiện rebase."
+
+#: wt-status.c:896
+msgid "  (use \"git commit --amend\" to amend the current commit)"
+msgstr ""
+"  (dùng \"git commit --amend\" để tu bổ lần chuyển giao (commit) hiện tại)"
+
+#: wt-status.c:898
+msgid ""
+"  (use \"git rebase --continue\" once you are satisfied with your changes)"
+msgstr ""
+"  (dùng \"git rebase --continue\" một khi bạn cảm thấy hài lòng về những "
+"thay đổi của mình)"
+
+#: wt-status.c:908
+msgid "You are currently cherry-picking."
+msgstr "Bạn hiện nay đang thực hiện việc cherry-pick."
+
+#: wt-status.c:915
+msgid "  (all conflicts fixed: run \"git commit\")"
+msgstr "  (khi tất cả các xung đột đã sửa xong: chạy lệnh \"git commit\")"
+
+#: wt-status.c:924
+msgid "You are currently bisecting."
+msgstr "Bạn hiện tại đang thực hiện việc bisect (chia đôi)."
+
+#: wt-status.c:927
+msgid "  (use \"git bisect reset\" to get back to the original branch)"
+msgstr "  (dùng \"git bisect reset\" để quay trở lại nhánh nguyên thủy)"
+
+#: wt-status.c:978
 msgid "On branch "
-msgstr "Trên nhánh"
+msgstr "Trên nhánh "
 
-#: wt-status.c:744
+#: wt-status.c:985
 msgid "Not currently on any branch."
 msgstr "Hiện tại chẳng ở nhánh nào cả."
 
-#: wt-status.c:755
+#: wt-status.c:997
 msgid "Initial commit"
 msgstr "Lần chuyển giao (commit) khởi đầu"
 
-#: wt-status.c:769
-msgid "Untracked"
-msgstr "Không được theo vết"
+#: wt-status.c:1011
+msgid "Untracked files"
+msgstr "Những tập tin chưa được theo dõi"
 
-#: wt-status.c:771
-msgid "Ignored"
-msgstr "Bị bỏ qua"
+#: wt-status.c:1013
+msgid "Ignored files"
+msgstr "Những tập tin bị lờ đi"
 
-#: wt-status.c:773
+#: wt-status.c:1015
 #, c-format
 msgid "Untracked files not listed%s"
 msgstr "Những tập tin không bị theo vết không được liệt kê ra %s"
 
-#: wt-status.c:775
+#: wt-status.c:1017
 msgid " (use -u option to show untracked files)"
-msgstr " (sử dụng tùy chọn -u để hiển thị các tập tin chưa được theo dõi)"
+msgstr " (ng tùy chọn -u để hiển thị các tập tin chưa được theo dõi)"
 
-#: wt-status.c:781
+#: wt-status.c:1023
 msgid "No changes"
 msgstr "Không có thay đổi nào"
 
-#: wt-status.c:785
+#: wt-status.c:1028
 #, c-format
-msgid "no changes added to commit%s\n"
-msgstr "không có thay đổi nào được thêm vào lần chuyển giao (commit)%s\n"
+msgid "no changes added to commit (use \"git add\" and/or \"git commit -a\")\n"
+msgstr ""
+"không có thay đổi nào được thêm vào commit (dùng \"git add\" và/hoặc \"git "
+"commit -a\")\n"
 
-#: wt-status.c:787
-msgid " (use \"git add\" and/or \"git commit -a\")"
-msgstr " (sử dụng \"git add\" và/hoặc \"git commit -a\")"
+#: wt-status.c:1031
+#, c-format
+msgid "no changes added to commit\n"
+msgstr "không có thay đổi nào được thêm vào lần chuyển giao (commit)\n"
 
-#: wt-status.c:789
+#: wt-status.c:1034
 #, c-format
-msgid "nothing added to commit but untracked files present%s\n"
-msgstr "không có gì được thêm vào lần chuyển giao (commit) nhưng có những tập tin không được theo dấu vết hiện diện%s\n"
+msgid ""
+"nothing added to commit but untracked files present (use \"git add\" to "
+"track)\n"
+msgstr ""
+"không có gì được thêm vào lần chuyển giao (commit) nhưng có những tập tin "
+"không được theo dấu vết hiện diện (dùng \"git add\" để đưa vào theo dõi)\n"
 
-#: wt-status.c:791
-msgid " (use \"git add\" to track)"
-msgstr " (sử dụng \"git add\" để theo dõi dấu vết)"
+#: wt-status.c:1037
+#, c-format
+msgid "nothing added to commit but untracked files present\n"
+msgstr ""
+"không có gì được thêm vào lần chuyển giao (commit) nhưng có những tập tin "
+"không được theo dấu vết hiện diện\n"
 
-#: wt-status.c:793
-#: wt-status.c:796
-#: wt-status.c:799
+#: wt-status.c:1040
 #, c-format
-msgid "nothing to commit%s\n"
-msgstr "không có gì để chuyển giao (commit) %s\n"
+msgid "nothing to commit (create/copy files and use \"git add\" to track)\n"
+msgstr ""
+" không có gì để commit (tạo/sao-chép các tập tin và dùng \"git add\" để theo "
+"dõi dấu vết)\n"
 
-#: wt-status.c:794
-msgid " (create/copy files and use \"git add\" to track)"
-msgstr " (tạo/sao-chép các tập tin và sử dụng \"git add\" để theo dõi dấu vết)"
+#: wt-status.c:1043 wt-status.c:1048
+#, c-format
+msgid "nothing to commit\n"
+msgstr "không có gì để chuyển giao (commit)\n"
 
-#: wt-status.c:797
-msgid " (use -u to show untracked files)"
-msgstr " (sử dụng tùy chọn -u để hiển thị các tập tin chưa được theo dõi)"
+#: wt-status.c:1046
+#, c-format
+msgid "nothing to commit (use -u to show untracked files)\n"
+msgstr ""
+"không có gì để chuyển giao (commit) (dùng -u để bỏ các tập tin cần theo dấu "
+"vết)\n"
 
-#: wt-status.c:800
-msgid " (working directory clean)"
-msgstr " (thư mục làm việc sạch sẽ)"
+#: wt-status.c:1050
+#, c-format
+msgid "nothing to commit, working directory clean\n"
+msgstr "không có gì để chuyển giao (commit), thư mục làm việc sạch sẽ\n"
 
-#: wt-status.c:908
+#: wt-status.c:1158
 msgid "HEAD (no branch)"
-msgstr "HEAD (chưa có nhánh nào)"
+msgstr "HEAD (không nhánh)"
 
-#: wt-status.c:914
+#: wt-status.c:1164
 msgid "Initial commit on "
-msgstr "Lần chuyển giao (commit)  khởi tạo trên"
+msgstr "Lần chuyển giao (commit) khởi tạo trên "
 
-#: wt-status.c:929
+#: wt-status.c:1179
 msgid "behind "
-msgstr "đằng sau"
+msgstr "đằng sau "
 
-#: wt-status.c:932
-#: wt-status.c:935
+#: wt-status.c:1182 wt-status.c:1185
 msgid "ahead "
-msgstr "phía trước"
+msgstr "phía trước "
 
-#: wt-status.c:937
+#: wt-status.c:1187
 msgid ", behind "
-msgstr ", đằng sau"
+msgstr ", đằng sau "
+
+#: compat/precompose_utf8.c:58 builtin/clone.c:341
+#, c-format
+msgid "failed to unlink '%s'"
+msgstr "bỏ liên kết (unlink) %s không thành công"
+
+#: builtin/add.c:19
+msgid "git add [options] [--] <filepattern>..."
+msgstr "git add [các-tùy-chọn] [--] <mẫu-tập-tin>..."
 
 #: builtin/add.c:62
 #, c-format
 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:226
+#: builtin/add.c:67 builtin/commit.c:230
 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:"
+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:456
-#: builtin/rm.c:186
+#: builtin/add.c:195 builtin/add.c:460 builtin/rm.c:186
 #, 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"
@@ -964,7 +1415,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"
@@ -973,7 +1424,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."
@@ -982,200 +1433,261 @@ 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:312
+#: builtin/add.c:313
 msgid "The following paths are ignored by one of your .gitignore files:\n"
-msgstr "Các đường dẫn theo sau đây sẽ bị lờ đi bởi một trong các tập tin .gitignore của bạn:\n"
+msgstr ""
+"Các đường dẫn theo sau đây sẽ bị lờ đi bởi một trong các tập tin .gitignore "
+"của bạn:\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
+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/mv.c:62 builtin/read-tree.c:112
+msgid "be verbose"
+msgstr "chi tiết"
+
+#: builtin/add.c:322
+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
+msgid "select hunks interactively"
+msgstr "chọn `hunks' một cách tương tác"
+
+#: builtin/add.c:324
+msgid "edit current diff and apply"
+msgstr "sửa diff hiện nay và áp dụng nó"
+
+#: builtin/add.c:325
+msgid "allow adding otherwise ignored files"
+msgstr "cho phép thêm các tập tin bị bỏ qua khác"
+
+#: builtin/add.c:326
+msgid "update tracked files"
+msgstr "cập nhật các tập tin được theo vết"
 
-#: builtin/add.c:352
+#: builtin/add.c:327
+msgid "record only the fact that the path will be added later"
+msgstr "chỉ ghi lại sự việc mà đường dẫn sẽ được thêm vào sau"
+
+#: builtin/add.c:328
+msgid "add changes from all tracked and untracked files"
+msgstr ""
+"thêm các thay đổi từ tất cả các tập tin có cũng như không được theo dõi dấu "
+"vết"
+
+#: builtin/add.c:329
+msgid "don't add, only refresh the index"
+msgstr "không thêm, chỉ làm tươi mới bảng mục lục"
+
+#: builtin/add.c:330
+msgid "just skip files which cannot be added because of errors"
+msgstr "chie bỏ qua những tập tin mà nó không thể được thêm vào bởi vì gặp lỗi"
+
+#: builtin/add.c:331
+msgid "check if - even missing - files are ignored in dry run"
+msgstr ""
+"kiểm tra xem - thậm chí thiếu - tập tin bị bỏ qua trong quá trình chạy thử"
+
+#: builtin/add.c:353
 #, c-format
 msgid "Use -f if you really want to add them.\n"
 msgstr "Sử dụng tùy chọn -f nếu bạn thực sự muốn thêm chúng vào.\n"
 
-#: builtin/add.c:353
+#: builtin/add.c:354
 msgid "no files added"
 msgstr "chưa có tập tin nào được thêm vào"
 
-#: builtin/add.c:359
+#: builtin/add.c:360
 msgid "adding files failed"
 msgstr "thêm tập tin gặp lỗi"
 
-#: builtin/add.c:391
+#: builtin/add.c:392
 msgid "-A and -u are mutually incompatible"
 msgstr "-A và -u xung khắc nhau"
 
-#: builtin/add.c:393
+#: builtin/add.c:394
 msgid "Option --ignore-missing can only be used together with --dry-run"
-msgstr "Tùy chọn --ignore-missing chỉ có thể được sử dụng cùng với --dry-run"
+msgstr "Tùy chọn --ignore-missing chỉ có thể được ng cùng với --dry-run"
 
-#: builtin/add.c:413
+#: builtin/add.c:414
 #, c-format
 msgid "Nothing specified, nothing added.\n"
 msgstr "Không có gì được chỉ ra, không có gì được thêm vào.\n"
 
-#: builtin/add.c:414
+#: builtin/add.c:415
 #, c-format
 msgid "Maybe you wanted to say 'git add .'?\n"
-msgstr "Có lẽ bạn muốn nói 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:420
-#: builtin/clean.c:95
-#: builtin/commit.c:286
-#: builtin/mv.c:82
+#: builtin/add.c:421 builtin/clean.c:95 builtin/commit.c:290 builtin/mv.c:82
 #: builtin/rm.c:162
 msgid "index file corrupt"
 msgstr "tập tin ghi bảng mục lục bị hỏng"
 
-#: builtin/add.c:476
-#: builtin/apply.c:4108
-#: builtin/mv.c:229
-#: builtin/rm.c:260
+#: builtin/add.c:481 builtin/apply.c:4450 builtin/mv.c:229 builtin/rm.c:260
 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"
 
-#: builtin/apply.c:53
+#: builtin/apply.c:57
 msgid "git apply [options] [<patch>...]"
 msgstr "git apply [các-tùy-chọn] [<miếng-vá>...]"
 
-#: builtin/apply.c:106
+#: 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:121
+#: 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:815
+#: builtin/apply.c:823
 #, c-format
 msgid "Cannot prepare timestamp regexp %s"
-msgstr "Không thể chuẩn bị biểu thức chính qui dấu vết thời gian (timestamp regexp) %s"
+msgstr ""
+"Không thể chuẩn bị biểu thức chính qui dấu vết thời gian (timestamp regexp) "
+"%s"
 
-#: builtin/apply.c:824
+#: builtin/apply.c:832
 #, c-format
 msgid "regexec returned %d for input: %s"
 msgstr "thi hành biểu thức chính quy trả về %d cho kết xuất: %s"
 
-#: builtin/apply.c:905
+#: builtin/apply.c:913
 #, c-format
 msgid "unable to find filename in patch at line %d"
 msgstr "không thể tìm thấy tên tập tin trong miếng vá tại dòng %d"
 
-#: builtin/apply.c:937
+#: builtin/apply.c:945
 #, c-format
 msgid "git apply: bad git-diff - expected /dev/null, got %s on line %d"
 msgstr "git apply: git-diff sai - mong đợi /dev/null, đã nhận %s trên dòng %d"
 
-#: builtin/apply.c:941
+#: builtin/apply.c:949
 #, c-format
 msgid "git apply: bad git-diff - inconsistent new filename on line %d"
 msgstr "git apply: git-diff sai - tên tập tin mới mâu thuấn trên dòng %d"
 
-#: builtin/apply.c:942
+#: builtin/apply.c:950
 #, c-format
 msgid "git apply: bad git-diff - inconsistent old filename on line %d"
 msgstr "git apply: git-diff sai - tên tập tin cũ mâu thuấn trên dòng %d"
 
-#: builtin/apply.c:949
+#: builtin/apply.c:957
 #, c-format
 msgid "git apply: bad git-diff - expected /dev/null on line %d"
 msgstr "git apply: git-diff sai - mong đợi /dev/null trên dòng %d"
 
-#: builtin/apply.c:1394
+#: builtin/apply.c:1420
 #, c-format
 msgid "recount: unexpected line: %.*s"
 msgstr "chi tiết: dòng không được mong đợi: %.*s"
 
-#: builtin/apply.c:1451
+#: builtin/apply.c:1477
 #, c-format
 msgid "patch fragment without header at line %d: %.*s"
 msgstr "miếng vá phân mảnh mà không có phần đầu tại dòng %d: %.*s"
 
-#: builtin/apply.c:1468
+#: builtin/apply.c:1494
 #, c-format
-msgid "git diff header lacks filename information when removing %d leading pathname component (line %d)"
-msgid_plural "git diff header lacks filename information when removing %d leading pathname components (line %d)"
-msgstr[0] "phần đầu diff cho git  thiếu thông tin tên tập tin khi gỡ bỏ đi %d trong thành phần dẫn đầu tên của đường dẫn (dòng %d)"
-msgstr[1] "phần đầu diff cho git  thiếu thông tin tên tập tin khi gỡ bỏ đi %d trong thành phần dẫn đầu tên của đường dẫn (dòng %d)"
+msgid ""
+"git diff header lacks filename information when removing %d leading pathname "
+"component (line %d)"
+msgid_plural ""
+"git diff header lacks filename information when removing %d leading pathname "
+"components (line %d)"
+msgstr[0] ""
+"phần đầu diff cho git  thiếu thông tin tên tập tin khi gỡ bỏ đi %d trong "
+"thành phần dẫn đầu tên của đường dẫn (dòng %d)"
+msgstr[1] ""
+"phần đầu diff cho git  thiếu thông tin tên tập tin khi gỡ bỏ đi %d trong "
+"thành phần dẫn đầu tên của đường dẫn (dòng %d)"
 
-#: builtin/apply.c:1628
+#: builtin/apply.c:1654
 msgid "new file depends on old contents"
 msgstr "tập tin mới phụ thuộc vào nội dung cũ"
 
-#: builtin/apply.c:1630
+#: builtin/apply.c:1656
 msgid "deleted file still has contents"
 msgstr "tập tin đã xóa vẫn còn nội dung"
 
-#: builtin/apply.c:1656
+#: builtin/apply.c:1682
 #, c-format
 msgid "corrupt patch at line %d"
 msgstr "miếng vá hỏng tại dòng %d"
 
-#: builtin/apply.c:1692
+#: builtin/apply.c:1718
 #, c-format
 msgid "new file %s depends on old contents"
 msgstr "tập tin mới %s phụ thuộc vào nội dung cũ"
 
-#: builtin/apply.c:1694
+#: builtin/apply.c:1720
 #, c-format
 msgid "deleted file %s still has contents"
 msgstr "tập tin đã xóa %s vẫn còn nội dung"
 
-#: builtin/apply.c:1697
+#: builtin/apply.c:1723
 #, c-format
 msgid "** warning: file %s becomes empty but is not deleted"
 msgstr "** cảnh báo: tập tin %s trở nên trống rỗng nhưng không bị xóa"
 
-#: builtin/apply.c:1843
+#: builtin/apply.c:1869
 #, c-format
 msgid "corrupt binary patch at line %d: %.*s"
 msgstr "miếng vá định dạng nhị phân sai hỏng tại dòng %d: %.*s"
 
 #. there has to be one hunk (forward hunk)
-#: builtin/apply.c:1872
+#: builtin/apply.c:1898
 #, c-format
 msgid "unrecognized binary patch at line %d"
 msgstr "miếng vá định dạng nhị phân không được nhận ra tại dòng %d"
 
-#: builtin/apply.c:1958
+#: 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"
 
-#: builtin/apply.c:2048
+#: builtin/apply.c:2074
 #, c-format
 msgid "unable to read symlink %s"
 msgstr "không thể đọc liên kết tượng trưng %s"
 
-#: builtin/apply.c:2052
+#: builtin/apply.c:2078
 #, c-format
 msgid "unable to open or read %s"
 msgstr "không thể mở để đọc hay ghi %s"
 
-#: builtin/apply.c:2123
+#: builtin/apply.c:2149
 msgid "oops"
 msgstr "ôi?"
 
-#: builtin/apply.c:2645
+#: 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:2763
+#: 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)."
 msgstr[0] "Khối dữ liệu #%d thành công tại %d (offset %d dòng)."
 msgstr[1] "Khối dữ liệu #%d thành công tại %d (offset %d dòng)."
 
-#: builtin/apply.c:2775
+#: builtin/apply.c:2801
 #, c-format
 msgid "Context reduced to (%ld/%ld) to apply fragment at %d"
-msgstr "Nội dung được giảm xuống (%ld/%ld) để áp dụng mảnh dữ liệu tại %d"
+msgstr "Nội dung bị giảm xuống (%ld/%ld) để áp dụng mảnh dữ liệu tại %d"
 
-#: builtin/apply.c:2781
+#: builtin/apply.c:2807
 #, c-format
 msgid ""
 "while searching for:\n"
@@ -1184,320 +1696,325 @@ msgstr ""
 "Trong khi đang tìm kiếm cho:\n"
 "%.*s"
 
-#: builtin/apply.c:2800
+#: 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:2903
+#: 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:2909
+#: 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 (đang chờ %s, đã nhận %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 "
+"%s)"
 
-#: builtin/apply.c:2930
+#: builtin/apply.c:2956
 #, c-format
 msgid "patch failed: %s:%ld"
 msgstr "vá gặp lỗi: %s:%ld"
 
-#: builtin/apply.c:3045
+#: builtin/apply.c:3078
 #, c-format
-msgid "patch %s has been renamed/deleted"
-msgstr "miếng vá %s đã bị xóa/đổi tên"
+msgid "cannot checkout %s"
+msgstr "không thể \"checkout\" %s"
 
-#: builtin/apply.c:3052
-#: builtin/apply.c:3069
+#: builtin/apply.c:3123 builtin/apply.c:3132 builtin/apply.c:3176
 #, c-format
 msgid "read of %s failed"
 msgstr "đọc %s gặp lỗi"
 
-#: builtin/apply.c:3084
-msgid "removal patch leaves file contents"
-msgstr "loại bỏ miếng vá để lại nội dung tập tin"
-
-#: builtin/apply.c:3105
+#: builtin/apply.c:3156 builtin/apply.c:3378
 #, c-format
-msgid "%s: already exists in working directory"
-msgstr "%s: đã sẵn có trong thư mục đang làm việc"
+msgid "path %s has been renamed/deleted"
+msgstr "đường dẫn %s đã bị xóa/đổi tên"
 
-#: builtin/apply.c:3143
+#: builtin/apply.c:3237 builtin/apply.c:3392
 #, c-format
-msgid "%s: has been deleted/renamed"
-msgstr "%s: đã được xóa/thay-tên"
+msgid "%s: does not exist in index"
+msgstr "%s: không tồn tại trong bảng mục lục"
 
-#: builtin/apply.c:3148
-#: builtin/apply.c:3179
+#: builtin/apply.c:3241 builtin/apply.c:3384 builtin/apply.c:3406
 #, c-format
 msgid "%s: %s"
 msgstr "%s: %s"
 
-#: builtin/apply.c:3159
-#, c-format
-msgid "%s: does not exist in index"
-msgstr "%s: không tồn tại trong bảng mục lục"
-
-#: builtin/apply.c:3173
+#: builtin/apply.c:3246 builtin/apply.c:3400
 #, c-format
 msgid "%s: does not match index"
 msgstr "%s: không khớp trong mục lục"
 
-#: builtin/apply.c:3190
+#: builtin/apply.c:3348
+msgid "removal patch leaves file contents"
+msgstr "loại bỏ miếng vá để lại nội dung tập tin"
+
+#: builtin/apply.c:3417
 #, c-format
 msgid "%s: wrong type"
 msgstr "%s: sai kiểu"
 
-#: builtin/apply.c:3192
+#: builtin/apply.c:3419
 #, c-format
 msgid "%s has type %o, expected %o"
 msgstr "%s có kiểu %o, mong chờ %o"
 
-#: builtin/apply.c:3247
+#: builtin/apply.c:3520
 #, c-format
 msgid "%s: already exists in index"
 msgstr "%s: đã có từ trước trong bảng mục lục"
 
-#: builtin/apply.c:3267
+#: builtin/apply.c:3523
+#, c-format
+msgid "%s: already exists in working directory"
+msgstr "%s: đã sẵn có trong thư mục đang làm việc"
+
+#: builtin/apply.c:3543
 #, c-format
 msgid "new mode (%o) of %s does not match old mode (%o)"
 msgstr "chế độ mới (%o) của %s không khớp với chế độ cũ (%o)"
 
-#: builtin/apply.c:3272
+#: builtin/apply.c:3548
 #, c-format
 msgid "new mode (%o) of %s does not match old mode (%o) of %s"
 msgstr "chế độ mới (%o) của %s không khớp với chế độ cũ (%o) của %s"
 
-#: builtin/apply.c:3280
+#: builtin/apply.c:3556
 #, c-format
 msgid "%s: patch does not apply"
 msgstr "%s: miếng vá không được áp dụng"
 
-#: builtin/apply.c:3293
+#: builtin/apply.c:3569
 #, c-format
 msgid "Checking patch %s..."
 msgstr "Đang kiểm tra miếng vá %s..."
 
-#: builtin/apply.c:3348
-#: builtin/checkout.c:212
-#: 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 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:3491
+#: builtin/apply.c:3767
 #, c-format
 msgid "unable to remove %s from index"
 msgstr "không thể gỡ bỏ %s từ mục lục"
 
-#: builtin/apply.c:3518
+#: builtin/apply.c:3795
 #, c-format
 msgid "corrupt patch for subproject %s"
 msgstr "miếng vá sai hỏng cho dự án con (subproject) %s"
 
-#: builtin/apply.c:3522
+#: builtin/apply.c:3799
 #, c-format
 msgid "unable to stat newly created file '%s'"
 msgstr "không thể lấy trạng thái về tập tin %s mới hơn đã được tạo"
 
-#: builtin/apply.c:3527
+#: 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"
 
-#: builtin/apply.c:3530
+#: builtin/apply.c:3807 builtin/apply.c:3915
 #, c-format
 msgid "unable to add cache entry for %s"
 msgstr "không thể thêm mục nhớ tạm cho %s"
 
-#: builtin/apply.c:3563
+#: 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:3612
+#: 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:3668
+#: builtin/apply.c:3976
 #, c-format
 msgid "Applied patch %s cleanly."
 msgstr "Đã áp dụng miếng và %s một cách sạch sẽ."
 
-#: builtin/apply.c:3676
+#: builtin/apply.c:3984
 msgid "internal error"
 msgstr "lỗi nội bộ"
 
 #. Say this even without --verbose
-#: builtin/apply.c:3679
+#: builtin/apply.c:3987
 #, c-format
 msgid "Applying patch %%s with %d reject..."
 msgid_plural "Applying patch %%s with %d rejects..."
 msgstr[0] "Đang áp dụng miếng vá %%s với %d lần từ chối..."
 msgstr[1] "Đang áp dụng miếng vá %%s với %d lần từ chối..."
 
-#: builtin/apply.c:3689
+#: builtin/apply.c:3997
 #, c-format
 msgid "truncating .rej filename to %.*s.rej"
 msgstr "đang cắt cụt tên tập tin .rej thành %.*s.rej"
 
-#: builtin/apply.c:3710
+#: builtin/apply.c:4018
 #, c-format
 msgid "Hunk #%d applied cleanly."
 msgstr "Khối nhớ #%d được áp dụng gọn gàng."
 
-#: builtin/apply.c:3713
+#: builtin/apply.c:4021
 #, c-format
 msgid "Rejected hunk #%d."
 msgstr "hunk #%d bị từ chối."
 
-#: builtin/apply.c:3844
+#: builtin/apply.c:4171
 msgid "unrecognized input"
 msgstr "không thừa nhận đầu vào"
 
-#: builtin/apply.c:3855
+#: builtin/apply.c:4182
 msgid "unable to read index file"
 msgstr "không thể đọc tập tin lưu bảng mục lục"
 
-#: builtin/apply.c:3970
-#: builtin/apply.c:3973
+#: builtin/apply.c:4301 builtin/apply.c:4304 builtin/clone.c:91
+#: builtin/fetch.c:63
 msgid "path"
 msgstr "đường-dẫn"
 
-#: builtin/apply.c:3971
+#: builtin/apply.c:4302
 msgid "don't apply changes matching the given path"
 msgstr "không áp dụng các thay đổi khớp với đường dẫn đã cho"
 
-#: builtin/apply.c:3974
+#: builtin/apply.c:4305
 msgid "apply changes matching the given path"
 msgstr "áp dụng các thay đổi khớp với đường dẫn đã cho"
 
-#: builtin/apply.c:3976
+#: builtin/apply.c:4307
 msgid "num"
 msgstr "số"
 
-#: builtin/apply.c:3977
+#: builtin/apply.c:4308
 msgid "remove <num> leading slashes from traditional diff paths"
 msgstr "gỡ bỏ <số> phần dẫn đầu (slashe) từ đường dẫn diff cổ điển"
 
-#: builtin/apply.c:3980
+#: builtin/apply.c:4311
 msgid "ignore additions made by the patch"
 msgstr "lờ đi phần phụ thêm tạo ra bởi miếng vá"
 
-#: builtin/apply.c:3982
+#: builtin/apply.c:4313
 msgid "instead of applying the patch, output diffstat for the input"
-msgstr "thay vì áp dụng một miếng vá, kết xuất kết quả từ lệnh diffstat cho đầu ra"
+msgstr ""
+"thay vì áp dụng một miếng vá, kết xuất kết quả từ lệnh diffstat cho đầu ra"
 
-#: builtin/apply.c:3986
-msgid "shows number of added and deleted lines in decimal notation"
-msgstr "hiển thị số lượng các dòng được thêm vào và xóa đi theo ký hiệu thập phân"
+#: builtin/apply.c:4317
+msgid "show number of added and deleted lines in decimal notation"
+msgstr ""
+"hiển thị số lượng các dòng được thêm vào và xóa đi theo ký hiệu thập phân"
 
-#: builtin/apply.c:3988
+#: builtin/apply.c:4319
 msgid "instead of applying the patch, output a summary for the input"
 msgstr "thay vì áp dụng một miếng vá, kết xuất kết quả cho đầu vào"
 
-#: builtin/apply.c:3990
+#: builtin/apply.c:4321
 msgid "instead of applying the patch, see if the patch is applicable"
 msgstr "thay vì áp dụng miếng vá, hãy xem xem miếng vá có thích hợp không"
 
-#: builtin/apply.c:3992
+#: builtin/apply.c:4323
 msgid "make sure the patch is applicable to the current index"
 msgstr "hãy chắc chắn là miếng vá thích hợp với bảng mục lục hiện hành"
 
-#: builtin/apply.c:3994
+#: builtin/apply.c:4325
 msgid "apply a patch without touching the working tree"
 msgstr "áp dụng một miếng vá mà không động chạm đến cây làm việc"
 
-#: builtin/apply.c:3996
+#: builtin/apply.c:4327
 msgid "also apply the patch (use with --stat/--summary/--check)"
-msgstr "đồng thời áp dụng miếng vá (sử dụng với tùy chọn --stat/--summary/--check)"
+msgstr ""
+"đồng thời áp dụng miếng vá (dùng với tùy chọn --stat/--summary/--check)"
 
-#: builtin/apply.c:3998
+#: builtin/apply.c:4329
+msgid "attempt three-way merge if a patch does not apply"
+msgstr "thử hòa trộn kiểu three-way nếu việc vá không thể thực hiện được"
+
+#: builtin/apply.c:4331
 msgid "build a temporary index based on embedded index information"
-msgstr "xây dựng bảng mục lục tạm thời trên cơ sở thông tin bảng mục lục được nhúng"
+msgstr ""
+"xây dựng bảng mục lục tạm thời trên cơ sở thông tin bảng mục lục được nhúng"
 
-#: builtin/apply.c:4000
+#: builtin/apply.c:4333 builtin/checkout-index.c:197 builtin/ls-files.c:460
 msgid "paths are separated with NUL character"
 msgstr "các đường dẫn bị ngăn cách bởi ký tự NULL"
 
-#: builtin/apply.c:4003
+#: builtin/apply.c:4336
 msgid "ensure at least <n> lines of context match"
 msgstr "đảm bảo rằng có ít nhất <n> dòng nội dung khớp"
 
-#: builtin/apply.c:4004
+#: builtin/apply.c:4337
 msgid "action"
 msgstr "hành động"
 
-#: builtin/apply.c:4005
+#: builtin/apply.c:4338
 msgid "detect new or modified lines that have whitespace errors"
 msgstr "tìm thấy một dòng mới hoặc bị sửa đổi mà nó có lỗi do khoảng trắng"
 
-#: builtin/apply.c:4008
-#: builtin/apply.c:4011
+#: builtin/apply.c:4341 builtin/apply.c:4344
 msgid "ignore changes in whitespace when finding context"
 msgstr "lờ đi sự thay đổi do khoảng trắng khi quét nội dung"
 
-#: builtin/apply.c:4014
+#: builtin/apply.c:4347
 msgid "apply the patch in reverse"
 msgstr "áp dụng miếng vá theo chiều ngược"
 
-#: builtin/apply.c:4016
+#: builtin/apply.c:4349
 msgid "don't expect at least one line of context"
 msgstr "đừng hy vọng có ít nhất một dòng nội dung"
 
-#: builtin/apply.c:4018
+#: builtin/apply.c:4351
 msgid "leave the rejected hunks in corresponding *.rej files"
 msgstr "để lại khối dữ liệu bị từ chối trong các tập tin *.rej tương ứng"
 
-#: builtin/apply.c:4020
+#: builtin/apply.c:4353
 msgid "allow overlapping hunks"
 msgstr "cho phép chồng khối nhớ"
 
-#: builtin/apply.c:4021
-msgid "be verbose"
-msgstr "chi tiết"
-
-#: builtin/apply.c:4023
+#: builtin/apply.c:4356
 msgid "tolerate incorrectly detected missing new-line at the end of file"
-msgstr "dung sai không chính xác đã tìm thấy thiếu dòng mới tại cuối tập tin"
+msgstr ""
+"đã dò tìm thấy dung sai không chính xác thiếu dòng mới tại cuối tập tin"
 
-#: builtin/apply.c:4026
+#: builtin/apply.c:4359
 msgid "do not trust the line counts in the hunk headers"
 msgstr "không tin số lượng dòng trong phần đầu khối dữ liệu"
 
-#: builtin/apply.c:4028
+#: builtin/apply.c:4361
 msgid "root"
 msgstr "root"
 
-#: builtin/apply.c:4029
+#: builtin/apply.c:4362
 msgid "prepend <root> to all filenames"
 msgstr "treo thêm <root> vào tất cả các tên tập tin"
 
-#: builtin/apply.c:4050
+#: builtin/apply.c:4384
+msgid "--3way outside a repository"
+msgstr "--3way ở ngoài một kho chứa"
+
+#: builtin/apply.c:4392
 msgid "--index outside a repository"
 msgstr "--index ở ngoài một kho chứa"
 
-#: builtin/apply.c:4053
+#: builtin/apply.c:4395
 msgid "--cached outside a repository"
 msgstr "--cached ở ngoài một kho chứa"
 
-#: builtin/apply.c:4069
+#: 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:4083
+#: builtin/apply.c:4425
 #, c-format
 msgid "squelched %d whitespace error"
 msgid_plural "squelched %d whitespace errors"
 msgstr[0] "đã chấm dứt %d lỗi khoảng trắng"
 msgstr[1] "đã chấm dứt %d lỗi khoảng trắng"
 
-#: builtin/apply.c:4089
-#: builtin/apply.c:4099
+#: builtin/apply.c:4431 builtin/apply.c:4441
 #, c-format
 msgid "%d line adds whitespace errors."
 msgid_plural "%d lines add whitespace errors."
@@ -1507,7 +2024,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"
@@ -1539,186 +2056,449 @@ msgstr "git archive: lỗi giao thức"
 msgid "git archive: expected a flush"
 msgstr "git archive: đã mong chờ một 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 "thực hiện `git bisect next'"
+
+#: builtin/bisect--helper.c:19
+msgid "update BISECT_HEAD instead of checking out the current commit"
+msgstr ""
+"cập nhật BISECT_HEAD thay vì lấy ra (checking out) lần chuyển giao (commit) "
+"hiện hành"
+
+#: builtin/blame.c:25
+msgid "git blame [options] [rev-opts] [rev] [--] file"
+msgstr "git blame [các-tùy-chọn] [rev-opts] [rev] [--] tập-tin"
+
+#: builtin/blame.c:30 builtin/shortlog.c:15
+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
+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"
+
+#: builtin/blame.c:2374
+msgid "Show blank SHA-1 for boundary commits (Default: off)"
+msgstr ""
+"Hiển thị SHA-1 trống cho những lần chuyển giao biên giới (Mặc định: off)"
+
+#: builtin/blame.c:2375
+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
+msgid "Show work cost statistics"
+msgstr "Hiển thị thống kê công sức làm việc"
+
+#: builtin/blame.c:2377
+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'"
+
+#: builtin/blame.c:2378
+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
+msgid "Show original linenumber (Default: off)"
+msgstr "Hiển thị số dòng gốc (Mặc định: off)"
+
+#: builtin/blame.c:2380
+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
+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"
+
+#: builtin/blame.c:2382
+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
+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
+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
+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
+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
+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
+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
+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'"
+
+#: builtin/blame.c:2390
+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
+msgid "score"
+msgstr "điểm số"
+
+#: builtin/blame.c:2391
+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
+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
+msgid "n,m"
+msgstr "n,m"
+
+#: builtin/blame.c:2393
+msgid "Process only line range n,m, counting from 1"
+msgstr "Xử lý chỉ dòng vùng n,m, tính từ 1"
+
+#: builtin/branch.c:23
+msgid "git branch [options] [-r | -a] [--merged | --no-merged]"
+msgstr "git branch [các-tùy-chọn] [-r | -a] [--merged | --no-merged]"
+
+#: builtin/branch.c:24
+msgid "git branch [options] [-l] [-f] <branchname> [<start-point>]"
+msgstr "git branch [các-tùy-chọn] [-l] [-f] <tên-nhánh> [<điểm-đầu>]"
+
+#: builtin/branch.c:25
+msgid "git branch [options] [-r] (-d | -D) <branchname>..."
+msgstr "git branch [các-tùy-chọn] [-r] (-d | -D) <tên-nhánh> ..."
+
+#: builtin/branch.c:26
+msgid "git branch [options] (-m | -M) [<oldbranch>] <newbranch>"
+msgstr "git branch [các-tùy-chọn] (-m | -M) [<nhánh-cũ>] <nhánh-mới>"
+
+#: builtin/branch.c:145
 #, c-format
 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:148
+#: builtin/branch.c:149
 #, c-format
 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ộng vào\n"
+"         `%s', cho dù là nó đã được hòa trộn vào HEAD."
 
-#: builtin/branch.c:180
+#: builtin/branch.c:181
 msgid "cannot use -a with -d"
-msgstr "không thể sử dụng -a với -d"
+msgstr "không thể dùng tùy chọn -a với -d"
 
-#: builtin/branch.c:186
+#: builtin/branch.c:187
 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:191
+#: builtin/branch.c:192
 #, 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:202
+#: builtin/branch.c:203
 #, c-format
 msgid "remote branch '%s' not found."
-msgstr "nhánh máy chủ '%s' không tìm thấy."
+msgstr "không tìm thấy nhánh máy chủ `%s'."
 
-#: builtin/branch.c:203
+#: builtin/branch.c:204
 #, 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:210
+#: 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'"
+msgstr "Không thể tìm kiếm đối tượng chuyển giao (commit) cho `%s'"
 
-#: builtin/branch.c:216
+#: 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'."
+"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:225
+#: builtin/branch.c:226
 #, 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:226
+#: builtin/branch.c:227
 #, 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:233
+#: builtin/branch.c:234
 #, c-format
 msgid "Deleted remote branch %s (was %s).\n"
-msgstr "Nhánh máy chủ đã xóa %s (trước là %s).\n"
+msgstr "Nhánh máy chủ \"%s\" đã bị xóa (từng là %s).\n"
 
-#: builtin/branch.c:234
+#: builtin/branch.c:235
 #, c-format
 msgid "Deleted branch %s (was %s).\n"
-msgstr "Nhánh đã bị xóa '%s' (trước là %s)\n"
+msgstr "Nhánh `%s' đã bị xóa (từng là %s)\n"
 
-#: builtin/branch.c:239
+#: builtin/branch.c:240
 msgid "Update of config-file failed"
-msgstr "Cập nhật tá»\87p tin cấu hình gặp lỗi"
+msgstr "Cập nhật tập tin cấu hình gặp lỗi"
 
-#: builtin/branch.c:337
+#: builtin/branch.c:338
 #, 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:409
+#: builtin/branch.c:410
 #, c-format
 msgid "[%s: behind %d]"
 msgstr "[%s: đằng sau %d]"
 
-#: builtin/branch.c:411
+#: builtin/branch.c:412
 #, c-format
 msgid "[behind %d]"
 msgstr "[đằng sau %d]"
 
-#: builtin/branch.c:415
+#: builtin/branch.c:416
 #, c-format
 msgid "[%s: ahead %d]"
 msgstr "[%s: phía trước %d]"
 
-#: builtin/branch.c:417
+#: builtin/branch.c:418
 #, c-format
 msgid "[ahead %d]"
 msgstr "[phía trước %d]"
 
-#: builtin/branch.c:420
+#: builtin/branch.c:421
 #, c-format
 msgid "[%s: ahead %d, behind %d]"
-msgstr "[%s: phía trước %d, phía sau %d]"
+msgstr "[%s: trước %d, sau %d]"
 
-#: builtin/branch.c:423
+#: builtin/branch.c:424
 #, c-format
 msgid "[ahead %d, behind %d]"
-msgstr "[phía trước %d, phía sau %d]"
+msgstr "[trước %d, sau %d]"
 
-#: builtin/branch.c:535
+#: builtin/branch.c:537
 msgid "(no branch)"
-msgstr "(không có nhánh nào)"
+msgstr "(không nhánh)"
 
-#: builtin/branch.c:600
+#: builtin/branch.c:602
 msgid "some refs could not be read"
 msgstr "một số tham chiếu đã không thể đọc được"
 
-#: builtin/branch.c:613
+#: builtin/branch.c:615
 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:623
+#: builtin/branch.c:625
 #, c-format
 msgid "Invalid branch name: '%s'"
-msgstr "tên nhánh sai: '%s'"
+msgstr "Sai tên nhánh: `%s'"
 
-#: builtin/branch.c:638
+#: builtin/branch.c:640
 msgid "Branch rename failed"
 msgstr "Đổi tên nhánh gặp lỗi"
 
-#: builtin/branch.c:642
+#: builtin/branch.c:644
 #, 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:646
+#: builtin/branch.c:648
 #, 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:653
+#: builtin/branch.c:655
 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:668
+#: builtin/branch.c:670
 #, c-format
 msgid "malformed object name %s"
 msgstr "tên đối tượng dị hình %s"
 
-#: builtin/branch.c:692
+#: builtin/branch.c:694
 #, 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:783
+#: builtin/branch.c:724
+msgid "Generic options"
+msgstr "Tùy chọn chung"
+
+#: builtin/branch.c:726
+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
+msgid "suppress informational messages"
+msgstr "Thu hồi các thông điệp thông tin"
+
+#: builtin/branch.c:728
+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
+msgid "change upstream info"
+msgstr "thay đổi thông tin thượng nguồn (upstream)"
+
+#: builtin/branch.c:734
+msgid "use colored output"
+msgstr "sử dụng kết xuất có tô màu"
+
+#: builtin/branch.c:735
+msgid "act on remote-tracking branches"
+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
+msgid "commit"
+msgstr "commit"
+
+#: builtin/branch.c:739 builtin/branch.c:745
+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
+msgid "Specific git-branch actions:"
+msgstr "Hành động git-branch:"
+
+#: builtin/branch.c:752
+msgid "list both remote-tracking and local branches"
+msgstr "liệt kê cả nhánh `remote-tracking' và nội bộ"
+
+#: builtin/branch.c:754
+msgid "delete fully merged branch"
+msgstr "xóa một cách đầy đủ nhánh đã hòa trộn"
+
+#: builtin/branch.c:755
+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
+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
+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"
+
+#: builtin/branch.c:758
+msgid "list branch names"
+msgstr "liệt kê các tên nhánh"
+
+#: builtin/branch.c:759
+msgid "create the branch's reflog"
+msgstr "tạo reflog của nhánh"
+
+#: builtin/branch.c:761
+msgid "edit the description for the branch"
+msgstr "sửa mô tả cho nhánh"
+
+#: builtin/branch.c:762
+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
+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
+msgid "print only merged branches"
+msgstr "chỉ hiển thị các nhánh được hòa trộn"
+
+#: builtin/branch.c:775
+msgid "list branches in columns"
+msgstr "liệt kê các nhánh trong các cột"
+
+#: builtin/branch.c:788
 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:788
-#: builtin/clone.c:558
+#: builtin/branch.c:793 builtin/clone.c:561
 msgid "HEAD not found below refs/heads!"
-msgstr "HEAD không tìm thấy ở dưới refs/heads!"
+msgstr "không tìm thấy HEAD ở dưới refs/heads!"
 
-#: builtin/branch.c:808
+#: builtin/branch.c:813
 msgid "--column and --verbose are incompatible"
 msgstr "--column và --verbose xung khắc nhau"
 
-#: builtin/branch.c:857
+#: builtin/branch.c:864
+#, c-format
+msgid "branch '%s' does not exist"
+msgstr "nhánh `%s' chưa sẵn có"
+
+#: builtin/branch.c:876
+#, c-format
+msgid "Branch '%s' has no upstream information"
+msgstr "Nhánh `%s' không có thông tin thượng nguồn (upstream)"
+
+#: builtin/branch.c:891
 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 nhánh"
+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 "
+"nhánh"
+
+#: builtin/branch.c:894
+#, c-format
+msgid ""
+"The --set-upstream flag is deprecated and will be removed. Consider using --"
+"track or --set-upstream-to\n"
+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
+#, c-format
+msgid ""
+"\n"
+"If you wanted to make '%s' track '%s', do this:\n"
+"\n"
+msgstr ""
+"\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
+#, c-format
+msgid "    git branch -d %s\n"
+msgstr "    git branch -d %s\n"
+
+#: builtin/branch.c:913
+#, 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"
-msgstr "'%s' tốt\n"
+msgstr "`%s' tốt\n"
 
 #: builtin/bundle.c:56
 msgid "Need a repository to create a bundle."
@@ -1728,107 +2508,231 @@ msgstr "Cần một kho chứa để mà tạo một bundle."
 msgid "Need a repository to unbundle."
 msgstr "Cần một kho chứa để mà bung một bundle."
 
-#: builtin/checkout.c:113
-#: builtin/checkout.c:146
+#: builtin/cat-file.c:247
+msgid "git cat-file (-t|-s|-e|-p|<type>|--textconv) <object>"
+msgstr "git cat-file (-t|-s|-e|-p|<kiểu>|--textconv) <đối tượng>"
+
+#: builtin/cat-file.c:248
+msgid "git cat-file (--batch|--batch-check) < <list_of_objects>"
+msgstr "git cat-file (--batch|--batch-check) < <danh-sách-đối-tượng>"
+
+#: builtin/cat-file.c:266
+msgid "<type> can be one of: blob, tree, commit, tag"
+msgstr "<kiểu> là một trong số: blob, tree, commit, tag"
+
+#: builtin/cat-file.c:267
+msgid "show object type"
+msgstr "hiển thị kiểu đối tượng"
+
+#: builtin/cat-file.c:268
+msgid "show object size"
+msgstr "hiển thị kích thước đối tượng"
+
+#: builtin/cat-file.c:270
+msgid "exit with zero when there's no error"
+msgstr "thoát với 0 khi không có lỗi"
+
+#: builtin/cat-file.c:271
+msgid "pretty-print object's content"
+msgstr "in nội dung đối tượng dạng dễ đọc"
+
+#: builtin/cat-file.c:273
+msgid "for blob objects, run textconv on object's content"
+msgstr "với đối tượng blob, chạy lệnh textconv trên nội dung của đối tượng"
+
+#: builtin/cat-file.c:275
+msgid "show info and content of objects fed from the standard input"
+msgstr ""
+"hiển thị thông tin và nội dung của các đối tượng lấy từ đầu vào tiêu chuẩn"
+
+#: builtin/cat-file.c:278
+msgid "show info about objects fed from the standard input"
+msgstr "hiển thị các thông tin về đối tượng fed  từ đầu vào tiêu chuẩn"
+
+#: builtin/check-attr.c:11
+msgid "git check-attr [-a | --all | attr...] [--] pathname..."
+msgstr "git check-attr [-a | --all | attr...] [--] tên-đường-dẫn..."
+
+#: 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 | attr...] < <danh-sách-đường-dẫn>"
+
+#: builtin/check-attr.c:19
+msgid "report all attributes set on file"
+msgstr "báo cáo tất cả các thuộc tính đặt trên tập tin"
+
+#: builtin/check-attr.c:20
+msgid "use .gitattributes only from the index"
+msgstr "chỉ sử dụng .gitattributes từ bảng mục lục"
+
+#: builtin/check-attr.c:21 builtin/hash-object.c:75
+msgid "read file names from stdin"
+msgstr "đọc tên tập tin từ đầu vào tiêu chuẩn"
+
+#: builtin/check-attr.c:23
+msgid "input paths are terminated by a null character"
+msgstr "các đường dẫn được  ngăn cách bởi ký tự null"
+
+#: builtin/checkout-index.c:126
+msgid "git checkout-index [options] [--] [<file>...]"
+msgstr "git checkout-index [các-tùy-chọn] [--] [<tập-tin>...]"
+
+#: builtin/checkout-index.c:187
+msgid "check out all files in the index"
+msgstr "lấy ra toàn bộ các tập tin trong bảng mục lục"
+
+#: builtin/checkout-index.c:188
+msgid "force overwrite of existing files"
+msgstr "ép buộc ghi đè lên tập tin đã sẵn có từ trước"
+
+#: builtin/checkout-index.c:190
+msgid "no warning for existing files and files not in index"
+msgstr ""
+"không cảnh báo cho những tập tin tồn tại và không có trong bảng mục lục"
+
+#: builtin/checkout-index.c:192
+msgid "don't checkout new files"
+msgstr "không checkout các tập tin mới"
+
+#: builtin/checkout-index.c:194
+msgid "update stat information in the index file"
+msgstr "cập nhật thông tin thống kê trong tập tin lưu bảng mục lục mới"
+
+#: builtin/checkout-index.c:200
+msgid "read list of paths from the standard input"
+msgstr " đọc danh sách đường dẫn từ thiết bị nhập chuẩn"
+
+#: builtin/checkout-index.c:202
+msgid "write the content to temporary files"
+msgstr "ghi nội dung vào tập tin tạm"
+
+#: builtin/checkout-index.c:203 builtin/column.c:30
+msgid "string"
+msgstr "chuỗi"
+
+#: builtin/checkout-index.c:204
+msgid "when creating files, prepend <string>"
+msgstr "khi tạo các tập tin, nối thêm <chuỗi>"
+
+#: builtin/checkout-index.c:207
+msgid "copy out the files from named stage"
+msgstr "sao chép ra các tập tin từ trạng thái được đặt tên"
+
+#: builtin/checkout.c:25
+msgid "git checkout [options] <branch>"
+msgstr "git checkout [các-tùy-chọn] <nhánh>"
+
+#: builtin/checkout.c:26
+msgid "git checkout [options] [<branch>] -- <file>..."
+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:115
-#: builtin/checkout.c:148
+#: 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:131
+#: 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:175
+#: 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:192
+#: 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:209
+#: 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"
+
+#: 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"
+
+#: 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."
 
-#: builtin/checkout.c:234
-#: builtin/checkout.c:392
+#: builtin/checkout.c:265 builtin/checkout.c:426
 msgid "corrupt index file"
 msgstr "tập tin ghi bảng mục lục bị hỏng"
 
-#: builtin/checkout.c:264
-#: builtin/checkout.c:271
+#: 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"
+msgstr "đường dẫn `%s' không được hòa trộn"
 
-#: builtin/checkout.c:302
-#: builtin/checkout.c:498
-#: builtin/clone.c:583
-#: builtin/merge.c:812
+#: 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"
 
-#: builtin/checkout.c:319
-#: builtin/diff.c:302
-#: builtin/merge.c:408
-msgid "diff_setup_done failed"
-msgstr "diff_setup_done gặp lỗi"
-
-#: builtin/checkout.c:414
+#: builtin/checkout.c:448
 msgid "you need to resolve your current index first"
 msgstr "bạn cần phải giải quyết bảng mục lục hiện tại của bạn trước đã!"
 
-#: builtin/checkout.c:533
+#: 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:566
+#: builtin/checkout.c:602
 msgid "HEAD is now at"
 msgstr "HEAD hiện giờ tại"
 
-#: builtin/checkout.c:573
+#: 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:576
+#: 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:580
+#: 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:582
+#: builtin/checkout.c:618
 #, 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:584
+#: 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:640
+#: builtin/checkout.c:676
 #, c-format
 msgid " ... and %d more.\n"
 msgstr " ... và nhiều hơn %d.\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"
@@ -1841,17 +2745,19 @@ msgid_plural ""
 "\n"
 "%s\n"
 msgstr[0] ""
-"Cảnh báo: bạn đã rời bở %d lần chuyển giao (commit) lại đằng sau, không được kết nối đến\n"
+"Cảnh báo: bạn đã rời bỏ %d lần chuyển giao (commit) lại đằng sau, không được "
+"kết nối đến\n"
 "bất kỳ nhánh nào của bạn:\n"
 "\n"
 "%s\n"
 msgstr[1] ""
-"Cảnh báo: bạn đã rời bở %d lần chuyển giao (commit) lại đằng sau, không được kết nối đến\n"
+"Cảnh báo: bạn đã rời bỏ %d lần chuyển giao (commit) lại đằng sau, không được "
+"kết nối đến\n"
 "bất kỳ nhánh nào của bạn:\n"
 "\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"
@@ -1860,135 +2766,230 @@ msgid ""
 " git branch new_branch_name %s\n"
 "\n"
 msgstr ""
-"Nếu bạn muốn giữ chúng bằng cách tạo ra một nhánh mới, đây có lẽ là một thời điểm thích hợp\n"
+"Nếu bạn muốn giữ chúng bằng cách tạo ra một nhánh mới, đây có lẽ là một thời "
+"điểm thích hợp\n"
 "để làm thế bằng lệnh:\n"
 "\n"
 " git branch tên_nhánh_mới %s\n"
 "\n"
 
-#: builtin/checkout.c:694
+#: builtin/checkout.c:730
 msgid "internal error in revision walk"
 msgstr "lỗi nội bộ trong khi di chuyển qua các điểm xét lại"
 
-#: builtin/checkout.c:698
+#: builtin/checkout.c:734
 msgid "Previous HEAD position was"
 msgstr "Vị trí kế trước của HEAD là"
 
-#: builtin/checkout.c:724
+#: builtin/checkout.c:761 builtin/checkout.c:950
 msgid "You are on a branch yet to be born"
 msgstr "Bạn tại nhánh mà nó chưa hề được sinh ra"
 
 #. case (1)
-#: builtin/checkout.c:855
+#: builtin/checkout.c:886
 #, c-format
 msgid "invalid reference: %s"
 msgstr "tham chiếu sai: %s"
 
 #. case (1): want a tree
-#: builtin/checkout.c:894
+#: builtin/checkout.c:925
 #, c-format
 msgid "reference is not a tree: %s"
-msgstr "tham chiếu không phải là cây:%s"
+msgstr "tham chiếu không phải là một cây (tree):%s"
 
-#: builtin/checkout.c:974
-msgid "-B cannot be used with -b"
-msgstr "-B không thể được sử dụng với -b"
+#: builtin/checkout.c:961
+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:983
-msgid "--patch is incompatible with all other options"
-msgstr "--patch xung khắc với tất cả các tùy chọn khác"
+#: builtin/checkout.c:964 builtin/checkout.c:968
+#, 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"
 
-#: builtin/checkout.c:986
-msgid "--detach cannot be used with -b/-B/--orphan"
-msgstr "--detach không thể được sử dụng với -b/-B/--orphan"
+#: builtin/checkout.c:972 builtin/checkout.c:975 builtin/checkout.c:980
+#: builtin/checkout.c:983
+#, c-format
+msgid "'%s' cannot be used with '%s'"
+msgstr "`%s' không thể được sử dụng với `%s'"
 
 #: builtin/checkout.c:988
-msgid "--detach cannot be used with -t"
-msgstr "--detach không thể được sử dụng với tùy chọn -t"
+#, 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'"
 
-#: builtin/checkout.c:994
-msgid "--track needs a branch name"
-msgstr "--track cần tên một nhánh"
+#: builtin/checkout.c:1009 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:1001
-msgid "Missing branch name; try -b"
-msgstr "Thiếu tên nhánh; hãy thử -b"
+#: builtin/checkout.c:1010 builtin/checkout.c:1012 builtin/clone.c:89
+#: builtin/remote.c:169 builtin/remote.c:171
+msgid "branch"
+msgstr "nhánh"
+
+#: builtin/checkout.c:1011
+msgid "create and checkout a new branch"
+msgstr "tạo và checkout một nhánh mới"
+
+#: builtin/checkout.c:1013
+msgid "create/reset and checkout a branch"
+msgstr "create/reset và checkout một nhánh"
+
+#: builtin/checkout.c:1014
+msgid "create reflog for new branch"
+msgstr "tạo reflog cho nhánh mới"
+
+#: builtin/checkout.c:1015
+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
+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:1007
-msgid "--orphan and -b|-B are mutually exclusive"
-msgstr "Tùy chọn --orphan và -b|-B loại từ lẫn nhau"
+#: builtin/checkout.c:1018
+msgid "new branch"
+msgstr "nhánh mới"
 
-#: builtin/checkout.c:1009
-msgid "--orphan cannot be used with -t"
-msgstr "--orphan không thể được sử dụng với tùy chọn -t"
+#: builtin/checkout.c:1018
+msgid "new unparented branch"
+msgstr "nhánh mồ côi mới"
 
 #: builtin/checkout.c:1019
-msgid "git checkout: -f and -m are incompatible"
-msgstr "git checkout: -f và -m xung khắc nhau"
+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
+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
+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
+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
+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
+msgid "style"
+msgstr "kiểu"
+
+#: builtin/checkout.c:1027
+msgid "conflict style (merge or diff3)"
+msgstr "xung đột kiểu (hòa trộn hay diff3)"
+
+#: builtin/checkout.c:1030
+msgid "second guess 'git checkout no-such-branch'"
+msgstr "gợi ý thứ hai `git checkout không-nhánh-nào-như-vậy'"
+
+#: builtin/checkout.c:1054
+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
+msgid "--track needs a branch name"
+msgstr "--track cần tên một nhánh"
+
+#: builtin/checkout.c:1078
+msgid "Missing branch name; try -b"
+msgstr "Thiếu tên nhánh; hãy thử -b"
 
-#: builtin/checkout.c:1053
+#: builtin/checkout.c:1113
 msgid "invalid path specification"
 msgstr "đường dẫn đã cho không hợp lệ"
 
-#: builtin/checkout.c:1061
+#: builtin/checkout.c:1120
 #, 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: việc cập nhật các đường dẫn là xung khắc với việc chuyển đổi các nhánh..\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:1063
-msgid "git checkout: updating paths is incompatible with switching branches."
-msgstr "git checkout: việc cập nhật các đường dẫn là xung khắc với việc chuyển đổi các nhánh."
+"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:1068
-msgid "git checkout: --detach does not take a path argument"
-msgstr "git checkout: --detach không nhận một đối số đường dẫn"
+#: builtin/checkout.c:1125
+#, 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'"
 
-#: builtin/checkout.c:1071
+#: builtin/checkout.c:1129
 msgid ""
 "git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
 "checking out of the index."
 msgstr ""
 "git checkout: --ours/--theirs, --force và --merge là xung khắc với nhau khi\n"
-"checkout."
+"checkout bảng mục lục (index)."
+
+#: builtin/clean.c:19
+msgid "git clean [-d] [-f] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>..."
+msgstr "git clean [-d] [-f] [-n] [-q] [-e <mẫu>] [-x | -X] [--] <đường-dẫn>..."
+
+#: builtin/clean.c:51
+msgid "do not print names of files removed"
+msgstr "không hiển thị tên của các tập tin đã gỡ bỏ"
+
+#: builtin/clean.c:53
+msgid "force"
+msgstr "ép buộc"
+
+#: builtin/clean.c:55
+msgid "remove whole directories"
+msgstr "gỡ bỏ toàn bộ thư mục"
 
-#: builtin/checkout.c:1090
-msgid "Cannot switch branch to a non-commit."
-msgstr "Không thể chuyển đến một non-commit."
+#: 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
+msgid "pattern"
+msgstr "mẫu"
 
-#: builtin/checkout.c:1093
-msgid "--ours/--theirs is incompatible with switching branches."
-msgstr "--ours/--theirs là xung khắc nhau khi chuyển đổi các nhánh."
+#: builtin/clean.c:57
+msgid "add <pattern> to ignore rules"
+msgstr "thêm <mẫu> vào trong qui tắc bỏ qua"
+
+#: builtin/clean.c:58
+msgid "remove ignored files, too"
+msgstr "đồng thời gỡ bỏ cả các tập tin bị bỏ qua"
+
+#: builtin/clean.c:60
+msgid "remove only ignored files"
+msgstr "chỉ gỡ bỏ những tập tin bị bỏ qua"
 
 #: builtin/clean.c:78
 msgid "-x and -X cannot be used together"
 msgstr "-x và -X không thể dùng cùng một lúc với nhau"
 
 #: builtin/clean.c:82
-msgid "clean.requireForce set to true and neither -n nor -f given; refusing to clean"
-msgstr "clean.requireForce được đặt thành true và không đưa ra tùy chọn  -n mà cũng không -f; từ chối lệnh dọn dẹp (clean)"
+msgid ""
+"clean.requireForce set to true and neither -n nor -f given; refusing to clean"
+msgstr ""
+"clean.requireForce được đặt thành true và không đưa ra tùy chọn  -n mà cũng "
+"không -f; từ chối lệnh dọn dẹp (clean)"
 
 #: builtin/clean.c:85
-msgid "clean.requireForce defaults to true and neither -n nor -f given; refusing to clean"
-msgstr "clean.requireForce mặc định được đặt thành true và không đưa ra tùy chọn  -n mà cũng không -f; từ chối lệnh dọn dẹp (clean)"
+msgid ""
+"clean.requireForce defaults to true and neither -n nor -f given; refusing to "
+"clean"
+msgstr ""
+"clean.requireForce mặc định được đặt thành true và không đưa ra tùy chọn  -n "
+"mà cũng không -f; từ chối lệnh dọn dẹp (clean)"
 
-#: builtin/clean.c:155
-#: builtin/clean.c:176
+#: builtin/clean.c:155 builtin/clean.c:176
 #, c-format
 msgid "Would remove %s\n"
 msgstr "Có thể gỡ bỏ %s\n"
 
-#: builtin/clean.c:159
-#: builtin/clean.c:179
+#: builtin/clean.c:159 builtin/clean.c:179
 #, c-format
 msgid "Removing %s\n"
 msgstr "Đang gỡ bỏ %s\n"
 
-#: builtin/clean.c:162
-#: builtin/clean.c:182
+#: builtin/clean.c:162 builtin/clean.c:182
 #, c-format
 msgid "failed to remove %s"
 msgstr "gặp lỗi khi gỡ bỏ %s"
@@ -2003,26 +3004,113 @@ msgstr "Không thể gỡ bỏ %s\n"
 msgid "Not removing %s\n"
 msgstr "Không xóa %s\n"
 
+#: builtin/clone.c:36
+msgid "git clone [options] [--] <repo> [<dir>]"
+msgstr "git clone [các-tùy-chọn] [--] <kho> [<t.mục>]"
+
+#: builtin/clone.c:64 builtin/fetch.c:82 builtin/merge.c:212
+#: builtin/push.c:399
+msgid "force progress reporting"
+msgstr "ép buộc báo cáo tiến trình"
+
+#: builtin/clone.c:66
+msgid "don't create a checkout"
+msgstr "không tạo một checkout"
+
+#: builtin/clone.c:67 builtin/clone.c:69 builtin/init-db.c:488
+msgid "create a bare repository"
+msgstr "tạo kho chứa bare"
+
+#: builtin/clone.c:72
+msgid "create a mirror repository (implies bare)"
+msgstr "tạo kho bản sao (mirror) (ngụ ý là bare)"
+
+#: builtin/clone.c:74
+msgid "to clone from a local repository"
+msgstr "để nhân bản từ kho nội bộ"
+
+#: builtin/clone.c:76
+msgid "don't use local hardlinks, always copy"
+msgstr "không sử dụng liên kết cứng nội bộ, luôn sao chép"
+
+#: builtin/clone.c:78
+msgid "setup as shared repository"
+msgstr "cài đặt đây là kho chia sẻ"
+
+#: builtin/clone.c:80 builtin/clone.c:82
+msgid "initialize submodules in the clone"
+msgstr "khởi tạo mô-đun-con trong bản sao"
+
+#: builtin/clone.c:83 builtin/init-db.c:485
+msgid "template-directory"
+msgstr "thư-mục-tạm"
+
+#: builtin/clone.c:84 builtin/init-db.c:486
+msgid "directory from which templates will be used"
+msgstr "thư mục mà tại đó các mẫu sẽ được dùng"
+
+#: builtin/clone.c:86
+msgid "reference repository"
+msgstr "kho tham chiếu"
+
+#: builtin/clone.c:87 builtin/column.c:26 builtin/merge-file.c:44
+msgid "name"
+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)"
+
+#: builtin/clone.c:90
+msgid "checkout <branch> instead of the remote's HEAD"
+msgstr "lấy ra nhánh (checkout <nhánh>) thay vì HEAD của máy chủ"
+
+#: builtin/clone.c:92
+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
+msgid "depth"
+msgstr "độ sâu"
+
+#: builtin/clone.c:94
+msgid "create a shallow clone of that depth"
+msgstr "tạo bản sao không đầy đủ cho mức sâu đã cho"
+
+#: builtin/clone.c:96
+msgid "clone only one branch, HEAD or --branch"
+msgstr "nhân bản (clone) chỉ một nhánh, HEAD hoặc --branch"
+
+#: builtin/clone.c:97 builtin/init-db.c:494
+msgid "gitdir"
+msgstr "gitdir"
+
+#: builtin/clone.c:98 builtin/init-db.c:495
+msgid "separate git dir from working tree"
+msgstr "không dùng chung thư mục dành riêng cho git và thư mục làm việc"
+
+#: builtin/clone.c:99
+msgid "key=value"
+msgstr "khóa=giá trị"
+
+#: builtin/clone.c:100
+msgid "set config inside the new repository"
+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ộ."
-
-#: builtin/clone.c:302
-#, c-format
-msgid "failed to open '%s'"
-msgstr "gặp lỗi khi mở '%s'"
+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
 msgid "failed to create directory '%s'"
 msgstr "tạo thư mục \"%s\" gặp lỗi"
 
-#: builtin/clone.c:308
-#: builtin/diff.c:75
+#: 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
@@ -2034,107 +3122,137 @@ msgstr "%s tồn tại nhưng không phải là một thư mục"
 msgid "failed to stat %s\n"
 msgstr "lỗi stat (lấy trạng thái về) %s\n"
 
-#: builtin/clone.c:341
-#, c-format
-msgid "failed to unlink '%s'"
-msgstr "bỏ liên kết (unlink) %s không thành công"
-
 #: builtin/clone.c:346
 #, c-format
 msgid "failed to create link '%s'"
-msgstr "tạo được liên kết mềm tới %s gặp lỗi"
+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 "sao chép tệp tin tới '%s' gặp lỗi"
+msgstr "gặp lỗi khi chép tập tin tới `%s'"
 
 #: builtin/clone.c:373
 #, c-format
 msgid "done.\n"
 msgstr "hoàn tất.\n"
 
-#: builtin/clone.c:440
+#: builtin/clone.c:443
 #, c-format
 msgid "Could not find remote branch %s to clone."
 msgstr "Không tìm thấy nhánh máy chủ %s để nhân bản (clone)."
 
-#: builtin/clone.c:549
+#: builtin/clone.c:552
 msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n"
 msgstr "refers HEAD máy chủ  chỉ đến ref không tồn tại, không thể checkout.\n"
 
-#: builtin/clone.c:639
+#: builtin/clone.c:690
 msgid "Too many arguments."
 msgstr "Có quá nhiều đối số."
 
-#: builtin/clone.c:643
+#: builtin/clone.c:694
 msgid "You must specify a repository to clone."
 msgstr "Bạn phải chỉ định một kho để mà nhân bản (clone)."
 
-#: builtin/clone.c:654
+#: builtin/clone.c:705
 #, c-format
 msgid "--bare and --origin %s options are incompatible."
 msgstr "tùy chọn --bare và --origin %s xung khắc nhau."
 
-#: builtin/clone.c:668
+#: 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:673
+#: builtin/clone.c:724
 msgid "--depth is ignored in local clones; use file:// instead."
 msgstr "--depth bị lờ đi khi nhân bản nội bộ; hãy sử dụng file:// để thay thế."
 
-#: builtin/clone.c:683
+#: 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:693
+#: 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:706
-#: builtin/clone.c:720
+#: 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:709
+#: 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:728
+#: 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:730
+#: 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:786
+#: builtin/clone.c:823
 #, c-format
 msgid "Don't know how to clone %s"
 msgstr "Không biết làm cách nào để nhân bản (clone) %s"
 
-#: builtin/clone.c:835
+#: builtin/clone.c:872
 #, c-format
 msgid "Remote branch %s not found in upstream %s"
-msgstr "Nhánh máy chủ %s không tìm thấy trong dòng ngược (upstream) %s"
+msgstr "Nhánh máy chủ %s không tìm thấy trong thượng nguồn (upstream) %s"
 
-#: builtin/clone.c:842
+#: builtin/clone.c:879
 msgid "You appear to have cloned an empty repository."
 msgstr "Bạn hình như là đã nhân bản một kho trống rỗng."
 
+#: builtin/column.c:9
+msgid "git column [options]"
+msgstr "git column [các-tùy-chọn]"
+
+#: builtin/column.c:26
+msgid "lookup config vars"
+msgstr "tìm kiếm biến cấu hình"
+
+#: builtin/column.c:27 builtin/column.c:28
+msgid "layout to use"
+msgstr "bố cục để dùng"
+
+#: builtin/column.c:29
+msgid "Maximum width"
+msgstr "Độ rộng tối đa"
+
+#: builtin/column.c:30
+msgid "Padding space on left border"
+msgstr "Chèn thêm khoảng trống vào bờ bên trái"
+
+#: builtin/column.c:31
+msgid "Padding space on right border"
+msgstr "Chèn thêm khoảng trắng vào tiếp giáp bên phải"
+
+#: builtin/column.c:32
+msgid "Padding space between columns"
+msgstr "Chèn thêm khoảng trắng giữa các cột"
+
 #: builtin/column.c:51
 msgid "--command must be the first argument"
 msgstr "--command phải là đối số đầu tiên"
 
-#: builtin/commit.c:43
+#: builtin/commit.c:34
+msgid "git commit [options] [--] <filepattern>..."
+msgstr "git commit [các-tùy-chọn] [--] <mẫu-tập-tin>..."
+
+#: builtin/commit.c:39
+msgid "git status [options] [--] <filepattern>..."
+msgstr "git status [các-tùy-chọn] [--] <mẫu-tập-tin>..."
+
+#: 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"
@@ -2147,29 +3265,35 @@ msgid ""
 "\n"
 "    git commit --amend --reset-author\n"
 msgstr ""
-"Tên và địa chỉ thư điện tử của bạn được cấu hình một cách tự động trên cơ sở\n"
-"tài khoản và địa chỉ máy chủ của bạn. Xin hãy kiểm tra xem chúng có chính xác không.\n"
-"Bạn có thể chặn những thông báo kiểu này bằng cách cài đặt các thông tin trên một cách rõ ràng:\n"
+"Tên và địa chỉ thư điện tử của bạn được cấu hình một cách tự động trên cơ "
+"sở\n"
+"tài khoản và địa chỉ máy chủ của bạn. Xin hãy kiểm tra xem chúng có chính "
+"xác không.\n"
+"Bạn có thể chặn những thông báo kiểu này bằng cách cài đặt các thông tin "
+"trên một cách rõ ràng:\n"
 "\n"
 "    git config --global user.name \"Tên của bạn\"\n"
 "    git config --global user.email you@example.com\n"
 "\n"
-"Sau khi thực hiện xong, bạn có thể sửa chữa định danh được sử dụng cho lần chuyển giao (commit) này với lệnh:\n"
+"Sau khi thực hiện xong, bạn có thể sửa chữa định danh được sử dụng cho lần "
+"chuyển giao (commit) này với lệnh:\n"
 "\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"
 "remove the commit entirely with \"git reset HEAD^\".\n"
 msgstr ""
-"Bạn đã yêu cầu amend (tu bổ) phần lớn các lần chuyển giao (commit) gần đây, nhưng làm như thế\n"
-"có thể làm cho nó trở nên trống rỗng. Bạn có thể lặp lại lệnh của mình bằng --allow-empty,\n"
+"Bạn đã yêu cầu amend (tu bổ) phần lớn các lần chuyển giao (commit) gần đây, "
+"nhưng làm như thế\n"
+"có thể làm cho nó trở nên trống rỗng. Bạn có thể lặp lại lệnh của mình bằng "
+"--allow-empty,\n"
 "hoặc là bạn gỡ bỏ các lần chuyển giao một cách hoàn toàn bằng lệnh:\n"
 "\"git reset HEAD^\".\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"
@@ -2178,106 +3302,105 @@ msgid ""
 "\n"
 "Otherwise, please use 'git reset'\n"
 msgstr ""
-"Lần cherry-pick trước hiện nay trống rỗng, có lẽ là bởi vì sự phân giải xung đột.\n"
+"Lần cherry-pick trước hiện nay trống rỗng, có lẽ là bởi vì sự phân giải xung "
+"đột.\n"
 "Nếu bạn muốn chuyển giao nó cho dù thế nào đi nữa, sử dụng:\n"
 "\n"
 "    git commit --allow-empty\n"
 "\n"
-"Nếu không, hãy thử sử dụng 'git reset'\n"
+"Nếu không, hãy thử dùng `git reset'\n"
 
-#: builtin/commit.c:253
+#: builtin/commit.c:257
 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:295
+#: builtin/commit.c:299
 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:301
+#: builtin/commit.c:305
 msgid "interactive add failed"
 msgstr "việc thêm tương tác gặp lỗi"
 
-#: builtin/commit.c:334
-#: builtin/commit.c:355
-#: builtin/commit.c:405
+#: builtin/commit.c:338 builtin/commit.c:359 builtin/commit.c:409
 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:386
+#: builtin/commit.c:390
 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."
+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:388
+#: builtin/commit.c:392
 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."
+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:398
+#: builtin/commit.c:402
 msgid "cannot read the index"
 msgstr "không đọc được bảng mục lục"
 
-#: builtin/commit.c:418
+#: builtin/commit.c:422
 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:493
-#: builtin/commit.c:499
+#: builtin/commit.c:509 builtin/commit.c:515
 #, c-format
 msgid "invalid commit: %s"
 msgstr "lần chuyển giao (commit) không hợp lệ: %s"
 
-#: builtin/commit.c:522
+#: builtin/commit.c:538
 msgid "malformed --author parameter"
 msgstr "đối số --author bị dị hình"
 
-#: builtin/commit.c:582
+#: builtin/commit.c:558
 #, 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:620
-#: builtin/commit.c:653
-#: builtin/commit.c:967
+#: builtin/commit.c:596 builtin/commit.c:629 builtin/commit.c:952
 #, 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:632
-#: builtin/shortlog.c:296
+#: builtin/commit.c:608 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:634
+#: builtin/commit.c:610
 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:638
+#: builtin/commit.c:614
 #, 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:644
+#: builtin/commit.c:620
 msgid "commit has empty message"
 msgstr "lần chuyển giao (commit) có ghi chú trống rỗng"
 
-#: builtin/commit.c:660
+#: builtin/commit.c:636
 msgid "could not read MERGE_MSG"
 msgstr "không thể đọc MERGE_MSG"
 
-#: builtin/commit.c:664
+#: builtin/commit.c:640
 msgid "could not read SQUASH_MSG"
 msgstr "không thể đọc SQUASH_MSG"
 
-#: builtin/commit.c:668
+#: builtin/commit.c:644
 #, c-format
 msgid "could not read '%s'"
-msgstr "Không thể đọc '%s'."
+msgstr "Không thể đọc `%s'."
 
-#: builtin/commit.c:720
+#: builtin/commit.c:705
 msgid "could not write commit template"
 msgstr "không thể ghi mẫu commit"
 
-#: builtin/commit.c:731
+#: builtin/commit.c:716
 #, c-format
 msgid ""
 "\n"
@@ -2292,7 +3415,7 @@ msgstr ""
 "\t%s\n"
 "và thử lại.\n"
 
-#: builtin/commit.c:736
+#: builtin/commit.c:721
 #, c-format
 msgid ""
 "\n"
@@ -2307,182 +3430,385 @@ msgstr ""
 "\t%s\n"
 "và thử lại.\n"
 
-#: builtin/commit.c:748
+#: builtin/commit.c:733
 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ỏ lần chuyển giao (commit).\n"
+"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ỏ "
+"lần chuyển giao (commit).\n"
 
-#: builtin/commit.c:753
+#: builtin/commit.c:738
 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 ""
-"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"
+"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"
 "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:766
+#: builtin/commit.c:751
 #, c-format
 msgid "%sAuthor:    %s"
 msgstr "%sTác giả:    %s"
 
-#: builtin/commit.c:773
+#: builtin/commit.c:758
 #, c-format
 msgid "%sCommitter: %s"
 msgstr "%sNgười chuyển giao (commit): %s"
 
-#: builtin/commit.c:793
+#: builtin/commit.c:778
 msgid "Cannot read index"
 msgstr "không đọc được bảng mục lục"
 
-#: builtin/commit.c:830
+#: builtin/commit.c:815
 msgid "Error building trees"
 msgstr "Gặp lỗi khi xây dựng cây"
 
-#: builtin/commit.c:845
-#: builtin/tag.c:361
+#: builtin/commit.c:830 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:942
+#: builtin/commit.c:927
 #, c-format
 msgid "No existing author found with '%s'"
-msgstr "Không tìm thấy tác giả đã sẵn có với '%s'"
+msgstr "Không tìm thấy tác giả có sẵn với `%s'"
 
-#: builtin/commit.c:957
-#: builtin/commit.c:1157
+#: builtin/commit.c:942 builtin/commit.c:1142
 #, 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:997
+#: builtin/commit.c:982
 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:1008
+#: builtin/commit.c:993
 msgid "You have nothing to amend."
 msgstr "Không có gì để amend (tu bổ) cả."
 
-#: builtin/commit.c:1011
+#: builtin/commit.c:996
 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ổ)."
+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:1013
+#: builtin/commit.c:998
 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ổ)."
+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:1016
+#: builtin/commit.c:1001
 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:1026
+#: builtin/commit.c:1011
 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:1028
+#: builtin/commit.c:1013
 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:1036
+#: builtin/commit.c:1021
 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."
+msgstr ""
+"--reset-author chỉ có thể được sử dụng với tùy chọn -C, -c hay --amend."
 
-#: builtin/commit.c:1053
+#: builtin/commit.c:1038
 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."
+msgstr ""
+"Chỉ một trong các tùy chọn --include/--only/--all/--interactive/--patch được "
+"sử dụng."
 
-#: builtin/commit.c:1055
+#: builtin/commit.c:1040
 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:1057
+#: builtin/commit.c:1042
 msgid "Clever... amending the last one with dirty index."
-msgstr "Giỏi... đang tu bổ cái cuối với bảng mục lục phi nghĩa."
+msgstr "Giỏi...  tu bổ cái cuối với bảng mục lục phi nghĩa."
 
-#: builtin/commit.c:1059
+#: builtin/commit.c:1044
 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..."
+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:1069
-#: builtin/tag.c:577
+#: builtin/commit.c:1054 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:1074
+#: builtin/commit.c:1059
 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:1257
+#: builtin/commit.c:1156 builtin/commit.c:1384
+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
+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
+msgid "machine-readable output"
+msgstr "kết xuất dạng máy-có-thể-đọc"
+
+#: builtin/commit.c:1163 builtin/commit.c:1390
+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/fast-export.c:639 builtin/tag.c:461
+msgid "mode"
+msgstr "chế độ"
+
+#: builtin/commit.c:1166 builtin/commit.c:1393
+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
+msgid "show ignored files"
+msgstr "hiển thị các tập tin ẩn"
+
+#: builtin/commit.c:1170 parse-options.h:151
+msgid "when"
+msgstr "khi"
+
+#: builtin/commit.c:1171
+msgid ""
+"ignore changes to submodules, optional when: all, dirty, untracked. "
+"(Default: all)"
+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
+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
 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:1259
+#: builtin/commit.c:1244
 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"
+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:1300
+#: builtin/commit.c:1285
 msgid "detached HEAD"
 msgstr "đã rời khỏi HEAD"
 
-#: builtin/commit.c:1302
+#: builtin/commit.c:1287
 msgid " (root-commit)"
 msgstr " (root-commit)"
 
-#: builtin/commit.c:1446
+#: builtin/commit.c:1354
+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
+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
+msgid "Commit message options"
+msgstr "Các tùy chọn ghi chú commit"
+
+#: builtin/commit.c:1358 builtin/tag.c:459
+msgid "read message from file"
+msgstr "đọc chú thích từ tập tin"
+
+#: builtin/commit.c:1359
+msgid "author"
+msgstr "tác giả"
+
+#: builtin/commit.c:1359
+msgid "override author for commit"
+msgstr "ghi đè tác giả cho commit"
+
+#: builtin/commit.c:1360 builtin/gc.c:178
+msgid "date"
+msgstr "ngày tháng"
+
+#: builtin/commit.c:1360
+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/notes.c:694 builtin/tag.c:457
+msgid "message"
+msgstr "thông điệp"
+
+#: builtin/commit.c:1361
+msgid "commit message"
+msgstr "chú thích của lần commit"
+
+#: builtin/commit.c:1362
+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
+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
+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
+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
+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
+msgid "add Signed-off-by:"
+msgstr "thêm dòng Signed-off-by:"
+
+#: builtin/commit.c:1368
+msgid "use specified template file"
+msgstr "sử dụng tập tin mẫu đã cho"
+
+#: builtin/commit.c:1369
+msgid "force edit of commit"
+msgstr "ép buộc sửa lần commit"
+
+#: builtin/commit.c:1370
+msgid "default"
+msgstr "mặc định"
+
+#: builtin/commit.c:1370 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
+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
+msgid "key id"
+msgstr "id khóa"
+
+#: builtin/commit.c:1373 builtin/merge.c:214
+msgid "GPG sign commit"
+msgstr "ký lần commit dùng GPG"
+
+#. end commit message options
+#: builtin/commit.c:1376
+msgid "Commit contents options"
+msgstr "Các tùy nội dung ghi chú commit"
+
+#: builtin/commit.c:1377
+msgid "commit all changed files"
+msgstr "chuyển giao tất cả các tập tin có thay đổi"
+
+#: builtin/commit.c:1378
+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
+msgid "interactively add files"
+msgstr "thêm các tập-tin bằng tương tác"
+
+#: builtin/commit.c:1380
+msgid "interactively add changes"
+msgstr "thêm các thay đổi bằng tương tác"
+
+#: builtin/commit.c:1381
+msgid "commit only specified files"
+msgstr "chỉ chuyển giao các tập tin đã chỉ ra"
+
+#: builtin/commit.c:1382
+msgid "bypass pre-commit hook"
+msgstr "vòng qua móc (hook) pre-commit"
+
+#: builtin/commit.c:1383
+msgid "show what would be committed"
+msgstr "hiển thị xem cái gì có thể được chuyển giao"
+
+#: builtin/commit.c:1391
+msgid "amend previous commit"
+msgstr "tu bổ (amend) lần commit trước"
+
+#: builtin/commit.c:1392
+msgid "bypass post-rewrite hook"
+msgstr "vòng qua móc (hook) post-rewrite"
+
+#: builtin/commit.c:1397
+msgid "ok to record an empty change"
+msgstr "ok để ghi lại một thay đổi trống rỗng"
+
+#: builtin/commit.c:1400
+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
 msgid "could not parse HEAD commit"
 msgstr "không thể phân tích commit (lần chuyển giao) HEAD"
 
-#: builtin/commit.c:1484
-#: builtin/merge.c:509
+#: builtin/commit.c:1470 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:1491
+#: builtin/commit.c:1477
 #, c-format
 msgid "Corrupt MERGE_HEAD file (%s)"
 msgstr "Tập tin MERGE_HEAD sai hỏng (%s)"
 
-#: builtin/commit.c:1498
+#: builtin/commit.c:1484
 msgid "could not read MERGE_MODE"
 msgstr "không thể đọc MERGE_MODE"
 
-#: builtin/commit.c:1517
+#: builtin/commit.c:1503
 #, 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:1531
+#: builtin/commit.c:1517
 #, 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"
+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:1536
+#: builtin/commit.c:1522
 #, 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"
+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:1551
-#: builtin/merge.c:936
-#: builtin/merge.c:961
+#: builtin/commit.c:1537 builtin/merge.c:935 builtin/merge.c:960
 msgid "failed to write commit object"
 msgstr "gặp lỗi khi ghi đối tượng chuyển giao (commit)"
 
-#: builtin/commit.c:1572
+#: builtin/commit.c:1558
 msgid "cannot lock HEAD ref"
 msgstr "không thể khóa HEAD ref (tham chiếu)"
 
-#: builtin/commit.c:1576
+#: builtin/commit.c:1562
 msgid "cannot update HEAD ref"
-msgstr "không thể cập nhật HEAD ref (tham chiếu)"
+msgstr "không thể cập nhật ref (tham chiếu) HEAD"
 
-#: builtin/commit.c:1587
+#: builtin/commit.c:1573
 msgid ""
 "Repository has been updated, but unable to write\n"
 "new_index file. Check that disk is not full or quota is\n"
@@ -2490,7 +3816,136 @@ msgid ""
 msgstr ""
 "Kho chứa đã hoàn tất việc cập nhật, nhưng không thể ghi vào\n"
 "tập tin new_index (bảng mục lục mới). Hãy kiểm tra xem đĩa có bị đầy quá\n"
-"hay quota (hạn nghạch đĩa cứng) bị vượt quá, và sau đó \"git reset HEAD\" để khắc phục."
+"hay quota (hạn nghạch đĩa cứng) bị vượt quá, và sau đó \"git reset HEAD\" để "
+"khắc phục."
+
+#: builtin/config.c:7
+msgid "git config [options]"
+msgstr "git config [các-tùy-chọn]"
+
+#: builtin/config.c:52
+msgid "Config file location"
+msgstr "Vị trí tập tin cấu hình"
+
+#: builtin/config.c:53
+msgid "use global config file"
+msgstr "đặt tập tin cấu hình cần toàn cục"
+
+#: builtin/config.c:54
+msgid "use system config file"
+msgstr "sử dụng tập tin cấu hình hệ thống"
+
+#: builtin/config.c:55
+msgid "use repository config file"
+msgstr "dùng tập tin cấu hình của kho"
+
+#: builtin/config.c:56
+msgid "use given config file"
+msgstr "sử dụng tập tin cấu hình đã cho"
+
+#: builtin/config.c:57
+msgid "Action"
+msgstr "Hành động"
+
+#: builtin/config.c:58
+msgid "get value: name [value-regex]"
+msgstr "lấy giá-trị: tên [value-regex]"
+
+#: builtin/config.c:59
+msgid "get all values: key [value-regex]"
+msgstr "lấy tất cả giá-trị: khóa [value-regex]"
+
+#: builtin/config.c:60
+msgid "get values for regexp: name-regex [value-regex]"
+msgstr "lấy giá trị cho regexp: name-regex [value-regex]"
+
+#: builtin/config.c:61
+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
+msgid "add a new variable: name value"
+msgstr "thêm biến mới: tên giá-trị"
+
+#: builtin/config.c:63
+msgid "remove a variable: name [value-regex]"
+msgstr "gỡ bỏ biến: tên [value-regex]"
+
+#: builtin/config.c:64
+msgid "remove all matches: name [value-regex]"
+msgstr "gỡ bỏ mọi cái khớp: tên [value-regex]"
+
+#: builtin/config.c:65
+msgid "rename section: old-name new-name"
+msgstr "đổi tên chương: tên-cũ tên-mới"
+
+#: builtin/config.c:66
+msgid "remove a section: name"
+msgstr "gỡ bỏ chương: tên"
+
+#: builtin/config.c:67
+msgid "list all"
+msgstr "liệt kê tất"
+
+#: builtin/config.c:68
+msgid "open an editor"
+msgstr "mở một trình biên soạn"
+
+#: builtin/config.c:69 builtin/config.c:70
+msgid "slot"
+msgstr "khe"
+
+#: builtin/config.c:69
+msgid "find the color configured: [default]"
+msgstr "tìm cấu hình màu sắc: [mặc định]"
+
+#: builtin/config.c:70
+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
+msgid "Type"
+msgstr "Kiểu"
+
+#: builtin/config.c:72
+msgid "value is \"true\" or \"false\""
+msgstr "giá trị là \"true\" hoặc \"false\""
+
+#: builtin/config.c:73
+msgid "value is decimal number"
+msgstr "giá trị ở dạng số thập phân"
+
+#: builtin/config.c:74
+msgid "value is --bool or --int"
+msgstr "giá trị là --bool hoặc --int"
+
+#: builtin/config.c:75
+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
+msgid "Other"
+msgstr "Khác"
+
+#: builtin/config.c:77
+msgid "terminate values with NUL byte"
+msgstr "chấm dứt giá trị với byte NUL"
+
+#: builtin/config.c:78
+msgid "respect include directives on lookup"
+msgstr "tôn trọng kể cà các hướng trong tìm kiếm"
+
+#: 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 [các-tùy-chọn] <committish>*"
+
+#: builtin/describe.c:16
+msgid "git describe [options] --dirty"
+msgstr "git describe [các-tùy-chọn] --dirty"
 
 #: builtin/describe.c:234
 #, c-format
@@ -2505,7 +3960,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
@@ -2515,12 +3970,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
@@ -2538,7 +3993,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
@@ -2547,7 +4002,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
@@ -2564,6 +4019,50 @@ msgstr ""
 "tìm thấy nhiều hơn %i thẻ (tag); đã liệt kê %i gần đây nhất\n"
 "bỏ đi tìm kiếm tại %s\n"
 
+#: builtin/describe.c:403
+msgid "find the tag that comes after the commit"
+msgstr "tìm các thẻ mà nó đến trước lần chuyển giao"
+
+#: builtin/describe.c:404
+msgid "debug search strategy on stderr"
+msgstr "chiến lược tìm kiếm trên đầu ra lỗi chuẩn stderr"
+
+#: builtin/describe.c:405
+msgid "use any ref in .git/refs"
+msgstr "sử dụng bất kỳ ref nào trong .git/refs"
+
+#: builtin/describe.c:406
+msgid "use any tag in .git/refs/tags"
+msgstr "sử dụng bất kỳ thẻ nào trong .git/refs/tags"
+
+#: builtin/describe.c:407
+msgid "always use long format"
+msgstr "luôn dùng định dạng dài"
+
+#: builtin/describe.c:410
+msgid "only output exact matches"
+msgstr "chỉ xuất những gì khớp chính xác"
+
+#: builtin/describe.c:412
+msgid "consider <n> most recent tags (default: 10)"
+msgstr "coi như  <n> thẻ gần đây nhất (mặc định: 10)"
+
+#: builtin/describe.c:414
+msgid "only consider tags matching <pattern>"
+msgstr "chỉ cân nhắc đến những thẻ khớp với  <mẫu>"
+
+#: builtin/describe.c:416 builtin/name-rev.c:238
+msgid "show abbreviated commit object as fallback"
+msgstr "hiển thị đối tượng chuyển giao vắn tắt như là fallback"
+
+#: builtin/describe.c:417
+msgid "mark"
+msgstr "dấu"
+
+#: builtin/describe.c:418
+msgid "append <mark> on dirty working tree (default: \"-dirty\")"
+msgstr "thêm <dấu> trên cây thư mục làm việc bẩn (mặc định \"-dirty\")"
+
 #: builtin/describe.c:436
 msgid "--long is incompatible with --abbrev=0"
 msgstr "--long là xung khắc với tùy chọn --abbrev=0"
@@ -2576,45 +4075,167 @@ msgstr "Không tìm thấy các tên, không thể mô tả gì cả."
 msgid "--dirty is incompatible with committishes"
 msgstr "--dirty là xung khắc với các tùy chọn dành cho chuyển giao (commit)"
 
-#: builtin/diff.c:77
+#: 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:220
+#: builtin/diff.c:224
 #, c-format
 msgid "invalid option: %s"
 msgstr "tùy chọn sai: %s"
 
-#: builtin/diff.c:297
+#: builtin/diff.c:301
 msgid "Not a git repository"
 msgstr "Không phải là kho git"
 
-#: builtin/diff.c:347
+#: builtin/diff.c:344
 #, 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:352
+#: builtin/diff.c:349
 #, 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:362
+#: builtin/diff.c:359
 #, 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:370
+#: builtin/diff.c:367
 #, 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]"
+msgstr "git fast-export [rev-list-opts]"
+
+#: builtin/fast-export.c:635
+msgid "show progress after <n> objects"
+msgstr "hiển thị tiến triển sau <n> đối tượng"
+
+#: builtin/fast-export.c:637
+msgid "select handling of signed tags"
+msgstr "chọn điều khiển của thẻ đã ký"
+
+#: builtin/fast-export.c:640
+msgid "select handling of tags that tag filtered objects"
+msgstr "chọn sự xử lý của các thẻ, cái mà đánh thẻ các đối tượng được lọc ra"
+
+#: builtin/fast-export.c:643
+msgid "Dump marks to this file"
+msgstr "Đổ các đánh dấu này vào tập-tin"
+
+#: builtin/fast-export.c:645
+msgid "Import marks from this file"
+msgstr "nhập vào đánh dấu từ tập tin này"
+
+#: builtin/fast-export.c:647
+msgid "Fake a tagger when tags lack one"
+msgstr "Làm giả một cái thẻ khi thẻ bị thiếu một cái"
+
+#: builtin/fast-export.c:649
+msgid "Output full tree for each commit"
+msgstr "Xuất ra toàn bộ cây cho mỗi lần chuyển giao"
 
-#: builtin/fetch.c:200
+#: builtin/fast-export.c:651
+msgid "Use the done feature to terminate the stream"
+msgstr "Sử dụng tính năng done để chấm dứt luồng dữ liệu"
+
+#: builtin/fast-export.c:652
+msgid "Skip output of blob data"
+msgstr "Bỏ qua kết xuất của dữ liệu blob"
+
+#: builtin/fetch.c:20
+msgid "git fetch [<options>] [<repository> [<refspec>...]]"
+msgstr "git fetch [<các-tùy-chọn>] [<kho-chứa> [<refspec>...]]"
+
+#: builtin/fetch.c:21
+msgid "git fetch [<options>] <group>"
+msgstr "git fetch [<các-tùy-chọn>] [<nhóm>"
+
+#: builtin/fetch.c:22
+msgid "git fetch --multiple [<options>] [(<repository> | <group>)...]"
+msgstr "git fetch --multiple [<các-tùy-chọn>] [(<kho> | <nhóm>)...]"
+
+#: builtin/fetch.c:23
+msgid "git fetch --all [<options>]"
+msgstr "git fetch --all [<các-tùy-chọn>]"
+
+#: builtin/fetch.c:60
+msgid "fetch from all remotes"
+msgstr "fetch từ tất cả các máy chủ"
+
+#: builtin/fetch.c:62
+msgid "append to .git/FETCH_HEAD instead of overwriting"
+msgstr "nối thêm vào .git/FETCH_HEAD thay vì ghi đè lên nó"
+
+#: builtin/fetch.c:64
+msgid "path to upload pack on remote end"
+msgstr "đường dẫn đến gói (pack) tải lên trên máy chủ cuối"
+
+#: builtin/fetch.c:65
+msgid "force overwrite of local branch"
+msgstr "ép buộc ghi đè lên nhánh nội bộ"
+
+#: builtin/fetch.c:67
+msgid "fetch from multiple remotes"
+msgstr "fetch từ nhiều máy chủ cùng lúc"
+
+#: builtin/fetch.c:69
+msgid "fetch all tags and associated objects"
+msgstr "lấy (fetch) tất cả các thẻ cùng với các đối tượng liên quan đến nó"
+
+#: builtin/fetch.c:71
+msgid "do not fetch all tags (--no-tags)"
+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ủ "
+"nữa"
+
+#: builtin/fetch.c:74
+msgid "on-demand"
+msgstr "khi-cần"
+
+#: builtin/fetch.c:75
+msgid "control recursive fetching of submodules"
+msgstr "điều khiển việc lấy về (fetch) đệ quy trong các mô-đun-con"
+
+#: builtin/fetch.c:79
+msgid "keep downloaded pack"
+msgstr "giữ các gói đã tải về"
+
+#: builtin/fetch.c:81
+msgid "allow updating of HEAD ref"
+msgstr "cho phép cập nhật ref (tham chiếu) HEAD"
+
+#: builtin/fetch.c:84
+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
+msgid "dir"
+msgstr "tmục"
+
+#: builtin/fetch.c:86
+msgid "prepend this to submodule path output"
+msgstr "soạn sẵn cái này cho kết xuất đường dẫn mô-đun-con"
+
+#: builtin/fetch.c:89
+msgid "default mode for recursion"
+msgstr "chế độ mặc định cho đệ qui"
+
+#: builtin/fetch.c:201
 msgid "Couldn't find remote ref HEAD"
 msgstr "Không thể tìm thấy máy chủ cho tham chiếu HEAD"
 
-#: builtin/fetch.c:253
+#: builtin/fetch.c:254
 #, c-format
 msgid "object %s not found"
 msgstr "Không tìm thấy đối tượng %s"
@@ -2626,10 +4247,9 @@ msgstr "[đã cập nhật]"
 #: builtin/fetch.c:273
 #, c-format
 msgid "! %-*s %-*s -> %s  (can't fetch in current branch)"
-msgstr "! %-*s %-*s -> %s  (không thể fetch (lấy về) trong nhánh hiện hành)"
+msgstr "! %-*s %-*s -> %s  (không thể fetch (lấy) về nhánh hiện hành)"
 
-#: builtin/fetch.c:274
-#: builtin/fetch.c:360
+#: builtin/fetch.c:274 builtin/fetch.c:360
 msgid "[rejected]"
 msgstr "[Bị từ chối]"
 
@@ -2637,9 +4257,7 @@ msgstr "[Bị từ chối]"
 msgid "[tag update]"
 msgstr "[cập nhật thẻ]"
 
-#: builtin/fetch.c:287
-#: builtin/fetch.c:322
-#: builtin/fetch.c:340
+#: builtin/fetch.c:287 builtin/fetch.c:322 builtin/fetch.c:340
 msgid "  (unable to update local ref)"
 msgstr "  (không thể cập nhật tham chiếu (ref) nội bộ)"
 
@@ -2667,8 +4285,7 @@ msgstr "cưỡng bức cập nhật"
 msgid "(non-fast-forward)"
 msgstr "(non-fast-forward)"
 
-#: builtin/fetch.c:393
-#: builtin/fetch.c:685
+#: builtin/fetch.c:393 builtin/fetch.c:685
 #, c-format
 msgid "cannot open %s: %s\n"
 msgstr "không thể mở %s: %s\n"
@@ -2690,31 +4307,32 @@ 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
 msgid "   (%s will become dangling)"
-msgstr "   (%s sẽ trở thành lủng lẳng (không được quản lý))"
+msgstr "   (%s sẽ trở thành không đầu (không được quản lý))"
 
 #: builtin/fetch.c:550
 #, c-format
 msgid "   (%s has become dangling)"
-msgstr "   (%s phải trở thành lủng lẳng (không được quản lý))"
+msgstr "   (%s đã trở thành không đầu (không được quản lý))"
 
 #: builtin/fetch.c:557
 msgid "[deleted]"
 msgstr "[đã xóa]"
 
-#: builtin/fetch.c:558
-#: builtin/remote.c:1055
+#: builtin/fetch.c:558 builtin/remote.c:1055
 msgid "(none)"
 msgstr "(không)"
 
 #: builtin/fetch.c:675
 #, c-format
 msgid "Refusing to fetch into current branch %s of non-bare repository"
-msgstr "Từ chối việc lấy (fetch) vào trong nhánh hiện tại %s của một kho chứa không phải kho trần (bare)"
+msgstr ""
+"Từ chối việc lấy (fetch) vào trong nhánh hiện tại %s của một kho chứa không "
+"phải kho trần (bare)"
 
 #: builtin/fetch.c:709
 #, c-format
@@ -2731,18 +4349,17 @@ msgstr "Tùy chọn \"%s\" có giá trị \"%s\" là không hợp lệ cho %s"
 msgid "Option \"%s\" is ignored for %s\n"
 msgstr "Tùy chọn \"%s\" bị bỏ qua với %s\n"
 
-#: builtin/fetch.c:888
+#: builtin/fetch.c:891
 #, c-format
 msgid "Fetching %s\n"
 msgstr "Đang lấy (fetch) %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 "không thể fetch (lấy) %s"
 
-#: 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."
@@ -2750,424 +4367,817 @@ msgstr ""
 "Chưa chỉ ra kho chứa máy chủ.  Xin hãy chỉ định hoặc là URL hoặc\n"
 "tên máy chủ từ cái mà những điểm xét duyệt mới có thể được fetch (lấy về)."
 
-#: builtin/fetch.c:927
+#: builtin/fetch.c:932
 msgid "You need to specify a tag name."
 msgstr "Bạn phải định rõ tên thẻ."
 
-#: builtin/fetch.c:979
+#: builtin/fetch.c:984
 msgid "fetch --all does not take a repository argument"
-msgstr "lệnh lấy về sử dụng tùy chọn --all sẽ không lấy đối số kho chứa"
+msgstr "lệnh lấy về \"fetch --all\" không lấy đối số kho chứa"
 
-#: builtin/fetch.c:981
+#: builtin/fetch.c:986
 msgid "fetch --all does not make sense with refspecs"
-msgstr "lệnh lấy về fetch sử dụng tùy chọn --all không hợp lý với refspecs"
+msgstr "lệnh lấy về \"fetch --all\" không hợp lý với refspecs"
 
-#: builtin/fetch.c:992
+#: builtin/fetch.c:997
 #, c-format
 msgid "No such remote or remote group: %s"
 msgstr "không có nhóm máy chủ hay máy chủ như thế: %s"
 
-#: builtin/fetch.c:1000
+#: builtin/fetch.c:1005
 msgid "Fetching a group and specifying refspecs does not make sense"
 msgstr "Việc lấy về cả một nhóm và chỉ định refspecs không hợp lý"
 
+#: 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 <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/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'"
+
+#: builtin/fmt-merge-msg.c:657
+msgid "alias for --log (deprecated)"
+msgstr "bí danh cho --log (không được dùng)"
+
+#: builtin/fmt-merge-msg.c:660
+msgid "text"
+msgstr "văn bản"
+
+#: builtin/fmt-merge-msg.c:661
+msgid "use <text> as start of message"
+msgstr "dùng <văn bản thường> để bắt đầu ghi chú"
+
+#: builtin/fmt-merge-msg.c:662
+msgid "file to read from"
+msgstr "tập tin để đọc dữ liệu từ đó"
+
+#: builtin/for-each-ref.c:979
+msgid "git for-each-ref [options] [<pattern>]"
+msgstr "git for-each-ref [các-tùy-chọn] [<mẫu>]"
+
+#: builtin/for-each-ref.c:994
+msgid "quote placeholders suitably for shells"
+msgstr "trích dẫn để phù hợp cho hệ vỏ (shell)"
+
+#: builtin/for-each-ref.c:996
+msgid "quote placeholders suitably for perl"
+msgstr "trích dẫn để phù hợp cho perl"
+
+#: builtin/for-each-ref.c:998
+msgid "quote placeholders suitably for python"
+msgstr "trích dẫn để phù hợp cho python"
+
+#: builtin/for-each-ref.c:1000
+msgid "quote placeholders suitably for tcl"
+msgstr "trích dẫn để phù hợp cho tcl"
+
+#: builtin/for-each-ref.c:1003
+msgid "show only <n> matched refs"
+msgstr "hiển thị chỉ <n> tham chiếu khớp"
+
+#: builtin/for-each-ref.c:1004
+msgid "format"
+msgstr "định dạng"
+
+#: builtin/for-each-ref.c:1004
+msgid "format to use for the output"
+msgstr "định dạng sẽ dùng cho đầu ra"
+
+#: builtin/for-each-ref.c:1005
+msgid "key"
+msgstr "khóa"
+
+#: builtin/for-each-ref.c:1006
+msgid "field name to sort on"
+msgstr "tên trường cần sắp xếp"
+
+#: builtin/fsck.c:608
+msgid "git fsck [options] [<object>...]"
+msgstr "git fsck [các-tùy-chọn] [<đối-tượng>...]"
+
+#: builtin/fsck.c:614
+msgid "show unreachable objects"
+msgstr "hiển thị các đối tượng không thể đọc được"
+
+#: builtin/fsck.c:615
+msgid "show dangling objects"
+msgstr "hiển thị các đối tượng không được quản lý"
+
+#: builtin/fsck.c:616
+msgid "report tags"
+msgstr "báo cáo các thẻ"
+
+#: builtin/fsck.c:617
+msgid "report root nodes"
+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'"
+
+#: builtin/fsck.c:619
+msgid "make reflogs head nodes (default)"
+msgstr "tạo  reflogs head nodes (mặc định)"
+
+#: builtin/fsck.c:620
+msgid "also consider packs and alternate objects"
+msgstr "cũng cân nhắc đến các đối tượng gói và thay thế"
+
+#: builtin/fsck.c:621
+msgid "enable more strict checking"
+msgstr "cho phép kiểm tra hạn chế hơn"
+
+#: builtin/fsck.c:623
+msgid "write dangling objects in .git/lost-found"
+msgstr "ghi các đối tượng không được quản lý trong .git/lost-found"
+
+#: builtin/fsck.c:624 builtin/prune.c:134
+msgid "show progress"
+msgstr "hiển thị quá trình"
+
+#: builtin/gc.c:22
+msgid "git gc [options]"
+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
 msgid "insanely long object directory %.*s"
 msgstr "thư mục đối tượng dài một cách điên rồ  %.*s"
 
-#: builtin/gc.c:221
-#, c-format
-msgid "Auto packing the repository for optimum performance.\n"
-msgstr "Tự động đóng gói kho chứa để tối ưu hóa hiệu suất làm việc.\n"
+#: builtin/gc.c:179
+msgid "prune unreferenced objects"
+msgstr "xóa bỏ các đối tượng không được tham chiếu"
+
+#: builtin/gc.c:181
+msgid "be more thorough (increased runtime)"
+msgstr "cẩn thận hơn nữa (tăng thời gian chạy)"
+
+#: builtin/gc.c:182
+msgid "enable auto-gc mode"
+msgstr "bật chế độ auto-gc"
 
-#: builtin/gc.c:224
+#: builtin/gc.c:222
 #, c-format
 msgid ""
 "Auto packing the repository for optimum performance. You may also\n"
 "run \"git gc\" manually. See \"git help gc\" for more information.\n"
 msgstr ""
 "Tự động đóng gói kho chứa để tối ưu hóa hiệu suất làm việc.\n"
-"chạy lệnh \"git gc\" một cách thủ công. Hãy xem \"git help gc\" để biết thêm chi tiết.\n"
+"chạy lệnh \"git gc\" một cách thủ công. Hãy xem \"git help gc\" để biết thêm "
+"chi tiết.\n"
 
-#: builtin/gc.c:251
-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' để xóa bỏ chúng đi."
+#: builtin/gc.c:249
+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' "
+"để xóa bỏ chúng đi."
 
-#: builtin/grep.c:216
+#: builtin/grep.c:22
+msgid "git grep [options] [-e] <pattern> [<rev>...] [[--] <path>...]"
+msgstr "git grep [các-tùy-chọn] [-e] <mẫu> [<rev>...] [[--] <đường-dẫn>...]"
+
+#: builtin/grep.c:217
 #, c-format
 msgid "grep: failed to create thread: %s"
 msgstr "grep: gặp lỗi tạo tuyến (thread): %s"
 
-#: builtin/grep.c:402
+#: builtin/grep.c:455
 #, c-format
 msgid "Failed to chdir: %s"
 msgstr "Gặp lỗi với lệnh chdir: %s"
 
-#: builtin/grep.c:478
-#: builtin/grep.c:512
+#: builtin/grep.c:531 builtin/grep.c:565
 #, c-format
 msgid "unable to read tree (%s)"
 msgstr "không thể đọc cây (%s)"
 
-#: builtin/grep.c:526
+#: builtin/grep.c:579
 #, 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:584
+#: builtin/grep.c:637
 #, c-format
 msgid "switch `%c' expects a numerical value"
 msgstr "chuyển đến `%c' mong chờ một giá trị bằng số"
 
-#: builtin/grep.c:601
+#: builtin/grep.c:654
 #, c-format
 msgid "cannot open '%s'"
-msgstr "không mở được '%s'"
+msgstr "không mở được `%s'"
+
+#: builtin/grep.c:729
+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
+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
+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
+msgid "search also in ignored files"
+msgstr "tìm cả trong các tập tin đã bị lờ đi"
+
+#: builtin/grep.c:738
+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
+msgid "case insensitive matching"
+msgstr "phân biệt chữ hoa/thường"
+
+#: builtin/grep.c:742
+msgid "match patterns only at word boundaries"
+msgstr "chỉ khớp mẫu tại đường ranh giới từ"
+
+#: builtin/grep.c:744
+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
+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
+msgid "descend at most <depth> levels"
+msgstr "giảm xuống ít nhất mức <sâu>"
+
+#: builtin/grep.c:753
+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
+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
+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
+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
+msgid "show line numbers"
+msgstr "hiển thị số của dòng"
+
+#: builtin/grep.c:766
+msgid "don't show filenames"
+msgstr "không hiển thị tên tập tin"
+
+#: builtin/grep.c:767
+msgid "show filenames"
+msgstr "hiển thị các tên tập tin"
+
+#: builtin/grep.c:769
+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
+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
+msgid "synonym for --files-with-matches"
+msgstr "đồng nghĩa với --files-with-matches"
+
+#: builtin/grep.c:776
+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
+msgid "print NUL after filenames"
+msgstr "thêm NUL vào sau tên tập tin"
+
+#: builtin/grep.c:780
+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
+msgid "highlight matches"
+msgstr "tô sáng cái khớp"
+
+#: builtin/grep.c:783
+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
+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:885
+#: builtin/grep.c:788
+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
+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
+msgid "show <n> context lines after matches"
+msgstr "hiển thị <n> dòng nội dung sau khớp"
+
+#: builtin/grep.c:794
+msgid "shortcut for -C NUM"
+msgstr "Dạng tắt cho -C SỐ"
+
+#: builtin/grep.c:797
+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
+msgid "show the surrounding function"
+msgstr "hiển thị hàm bao quanh"
+
+#: builtin/grep.c:802
+msgid "read patterns from file"
+msgstr "đọc mẫu từ tập-tin"
+
+#: builtin/grep.c:804
+msgid "match <pattern>"
+msgstr "match <mẫu>"
+
+#: builtin/grep.c:806
+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
+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
+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
+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)"
+
+#: builtin/grep.c:826
+msgid "pager"
+msgstr "trang giấy"
+
+#: builtin/grep.c:826
+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
+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
+msgid "show usage"
+msgstr "hiển thị cách dùng"
+
+#: builtin/grep.c:921
 msgid "no pattern given."
 msgstr "chưa chỉ ra mẫu."
 
-#: builtin/grep.c:899
+#: builtin/grep.c:935
 #, c-format
 msgid "bad object %s"
 msgstr "đối tượng sai %s"
 
-#: builtin/grep.c:940
+#: builtin/grep.c:976
 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:963
+#: builtin/grep.c:999
 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:968
+#: builtin/grep.c:1004
 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."
+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:971
+#: builtin/grep.c:1007
 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:979
+#: builtin/grep.c:1015
 msgid "both --cached and trees are given."
 msgstr "cả hai --cached và các cây phải được chỉ ra."
 
-#: builtin/help.c:59
+#: builtin/hash-object.c:60
+msgid ""
+"git hash-object [-t <type>] [-w] [--path=<file>|--no-filters] [--stdin] [--] "
+"<file>..."
+msgstr ""
+"git hash-object [-t <kiểu>] [-w] [--path=<tập-tin>|--no-filters] [--stdin] "
+"[--] <tập-tin>..."
+
+#: builtin/hash-object.c:61
+msgid "git hash-object  --stdin-paths < <list-of-paths>"
+msgstr "git hash-object  --stdin-paths < <danh-sách-đường-dẫn>"
+
+#: builtin/hash-object.c:72
+msgid "type"
+msgstr "kiểu"
+
+#: builtin/hash-object.c:72
+msgid "object type"
+msgstr "kiểu đối tượng"
+
+#: builtin/hash-object.c:73
+msgid "write the object into the object database"
+msgstr "ghi đối tượng vào dữ liệu đối tượng"
+
+#: builtin/hash-object.c:74
+msgid "read the object from stdin"
+msgstr "đọc đối tượng từ đầu vào tiêu chuẩn stdin"
+
+#: builtin/hash-object.c:76
+msgid "store file as is without filters"
+msgstr "lưu các tập tin mà nó không có các bộ lọc"
+
+#: builtin/hash-object.c:77
+msgid "process file as it were from this path"
+msgstr "xử lý tập tin như là nó đang ở thư mục này"
+
+#: builtin/help.c:43
+msgid "print all available commands"
+msgstr "hiển thị danh sách các câu lệnh người dùng có thể sử dụng"
+
+#: builtin/help.c:44
+msgid "show man page"
+msgstr "hiển thị trang man"
+
+#: builtin/help.c:45
+msgid "show manual in web browser"
+msgstr "hiển thị hướng dẫn sử dụng trong trình duyệt web"
+
+#: builtin/help.c:47
+msgid "show info page"
+msgstr "hiện trang info"
+
+#: builtin/help.c:53
+msgid "git help [--all] [--man|--web|--info] [command]"
+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:87
+#: builtin/help.c:93
 msgid "Failed to start emacsclient."
 msgstr "Lỗi khởi chạy emacsclient."
 
-#: builtin/help.c:100
+#: builtin/help.c:106
 msgid "Failed to parse emacsclient version."
 msgstr "Gặp lỗi khi phân tích phiên bản emacsclient."
 
-#: builtin/help.c:108
+#: 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:126
-#: builtin/help.c:154
-#: builtin/help.c:163
-#: builtin/help.c:171
+#: 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:211
+#: builtin/help.c:217
 #, c-format
 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"
+"`%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:223
+#: builtin/help.c:229
 #, c-format
 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"
+"`%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:287
+#: builtin/help.c:299
 msgid "The most commonly used git commands are:"
 msgstr "Những lệnh git hay được sử dụng nhất là:"
 
-#: builtin/help.c:355
+#: 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:372
+#: builtin/help.c:384
 msgid "no man viewer handled the request"
 msgstr "không có trình xem trợ giúp dạng manpage tiếp hợp với yêu cầu"
 
-#: builtin/help.c:380
+#: builtin/help.c:392
 msgid "no info viewer handled the request"
 msgstr "không có trình xem trợ giúp dạng info tiếp hợp với yêu cầu"
 
-#: builtin/help.c:391
-#, c-format
-msgid "'%s': not a documentation directory."
-msgstr "'%s': không phải là một thư mục tài liệu."
-
-#: builtin/help.c:432
-#: builtin/help.c:439
+#: builtin/help.c:447 builtin/help.c:454
 #, c-format
 msgid "usage: %s%s"
 msgstr "cách sử dụng: %s%s"
 
-#: builtin/help.c:453
+#: builtin/help.c:470
 #, c-format
 msgid "`git %s' is aliased to `%s'"
 msgstr "`git %s' được đặt bí danh thành `%s'"
 
-#: builtin/index-pack.c:169
+#: builtin/index-pack.c:170
 #, c-format
 msgid "object type mismatch at %s"
 msgstr "kiểu đối tượng không khớp tại %s"
 
-#: builtin/index-pack.c:189
+#: builtin/index-pack.c:190
 msgid "object of unexpected type"
 msgstr "đối tượng của kiểu không mong đợi"
 
-#: builtin/index-pack.c:226
+#: builtin/index-pack.c:227
 #, c-format
 msgid "cannot fill %d byte"
 msgid_plural "cannot fill %d bytes"
 msgstr[0] "không thể điền vào %d byte"
 msgstr[1] "không thể điền vào %d byte"
 
-#: builtin/index-pack.c:236
+#: builtin/index-pack.c:237
 msgid "early EOF"
 msgstr "vừa đúng lúc EOF"
 
-#: builtin/index-pack.c:237
+#: builtin/index-pack.c:238
 msgid "read error on input"
 msgstr "lỗi đọc ở đầu vào"
 
-#: builtin/index-pack.c:249
+#: builtin/index-pack.c:250
 msgid "used more bytes than were available"
 msgstr "sử dụng nhiều hơn số lượng byte mà nó sẵn có"
 
-#: builtin/index-pack.c:256
+#: builtin/index-pack.c:257
 msgid "pack too large for current definition of off_t"
 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:272
+#: 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:277
+#: 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:291
+#: builtin/index-pack.c:292
 msgid "pack signature mismatch"
 msgstr "chữ ký cho pack không khớp"
 
-#: builtin/index-pack.c:311
+#: builtin/index-pack.c:294
+#, c-format
+msgid "pack version %<PRIu32> unsupported"
+msgstr "không hỗ trợ phiên bản pack %<PRIu32>"
+
+#: builtin/index-pack.c:312
 #, c-format
 msgid "pack has bad object at offset %lu: %s"
 msgstr "pack có đối tượng sai khoảng bù (offset) %lu: %s"
 
-#: builtin/index-pack.c:405
+#: builtin/index-pack.c:434
 #, c-format
 msgid "inflate returned %d"
 msgstr "xả nén trả về %d"
 
-#: builtin/index-pack.c:450
+#: builtin/index-pack.c:483
 msgid "offset value overflow for delta base object"
 msgstr "tràn giá trị khoảng bù cho đối tượng delta cơ sở"
 
-#: builtin/index-pack.c:458
+#: builtin/index-pack.c:491
 msgid "delta base offset is out of bound"
 msgstr "khoảng bù cơ sở cho delta nằm ngoài phạm vi"
 
-#: builtin/index-pack.c:466
+#: builtin/index-pack.c:499
 #, c-format
 msgid "unknown object type %d"
 msgstr "không hiểu kiểu đối tượng %d"
 
-#: builtin/index-pack.c:495
+#: builtin/index-pack.c:530
 msgid "cannot pread pack file"
 msgstr "không thể chạy hàm pread cho tập tin pack"
 
-#: builtin/index-pack.c:497
+#: builtin/index-pack.c:532
 #, c-format
 msgid "premature end of pack file, %lu byte missing"
 msgid_plural "premature end of pack file, %lu bytes missing"
 msgstr[0] "tập tin pack bị kết thúc sớm, %lu byte bị thiếu"
 msgstr[1] "tập tin pack bị kết thúc sớm, %lu byte bị thiếu"
 
-#: builtin/index-pack.c:510
+#: builtin/index-pack.c:558
 msgid "serious inflate inconsistency"
 msgstr "sự mâu thuẫn xả nén nghiêm trọng"
 
-#: builtin/index-pack.c:583
-#, c-format
-msgid "cannot read existing object %s"
-msgstr "không thể đọc đối tượng đã tồn tại %s"
-
-#: builtin/index-pack.c:586
+#: builtin/index-pack.c:649 builtin/index-pack.c:655 builtin/index-pack.c:678
+#: builtin/index-pack.c:712 builtin/index-pack.c:721
 #, c-format
 msgid "SHA1 COLLISION FOUND WITH %s !"
 msgstr "SỰ VA CHẠM SHA1 ĐàXẢY RA VỚI %s!"
 
-#: builtin/index-pack.c:598
+#: builtin/index-pack.c:652 builtin/pack-objects.c:170
+#: builtin/pack-objects.c:262
+#, c-format
+msgid "unable to read %s"
+msgstr "không thể đọc %s"
+
+#: builtin/index-pack.c:718
+#, c-format
+msgid "cannot read existing object %s"
+msgstr "không thể đọc đối tượng đã tồn tại %s"
+
+#: builtin/index-pack.c:732
 #, c-format
 msgid "invalid blob object %s"
 msgstr "đối tượng blob không hợp lệ %s"
 
-#: builtin/index-pack.c:610
+#: builtin/index-pack.c:747
 #, c-format
 msgid "invalid %s"
 msgstr "%s không hợp lệ"
 
-#: builtin/index-pack.c:612
+#: builtin/index-pack.c:749
 msgid "Error in object"
 msgstr "Lỗi trong đối tượng"
 
-#: builtin/index-pack.c:614
+#: builtin/index-pack.c:751
 #, c-format
 msgid "Not all child objects of %s are reachable"
 msgstr "Không phải tất cả các đối tượng con của %s là có thể với tới được"
 
-#: builtin/index-pack.c:687
-#: builtin/index-pack.c:713
+#: builtin/index-pack.c:821 builtin/index-pack.c:847
 msgid "failed to apply delta"
 msgstr "gặp lỗi khi áp dụng delta"
 
-#: builtin/index-pack.c:850
+#: builtin/index-pack.c:986
 msgid "Receiving objects"
 msgstr "Đang nhận về các đối tượng"
 
-#: builtin/index-pack.c:850
+#: builtin/index-pack.c:986
 msgid "Indexing objects"
 msgstr "Các đối tượng bảng mục lục"
 
-#: builtin/index-pack.c:872
+#: builtin/index-pack.c:1012
 msgid "pack is corrupted (SHA1 mismatch)"
 msgstr "pack bị sai hỏng (SHA1 không khớp)"
 
-#: builtin/index-pack.c:877
+#: builtin/index-pack.c:1017
 msgid "cannot fstat packfile"
 msgstr "không thể fstat packfile"
 
-#: builtin/index-pack.c:880
+#: builtin/index-pack.c:1020
 msgid "pack has junk at the end"
 msgstr "pack có phần thừa ở cuối"
 
-#: builtin/index-pack.c:903
+#: builtin/index-pack.c:1031
+msgid "confusion beyond insanity in parse_pack_objects()"
+msgstr "lộn xộn hơn cả điên rồ khi chạy hàm parse_pack_objects()"
+
+#: builtin/index-pack.c:1054
 msgid "Resolving deltas"
 msgstr "Đang phân giải các delta"
 
-#: builtin/index-pack.c:954
+#: builtin/index-pack.c:1064
+#, c-format
+msgid "unable to create thread: %s"
+msgstr "không thể tạo tuyến: %s"
+
+#: builtin/index-pack.c:1106
 msgid "confusion beyond insanity"
 msgstr "lộn xộn hơn cả điên rồ"
 
-#: builtin/index-pack.c:973
+#: builtin/index-pack.c:1112
+#, c-format
+msgid "completed with %d local objects"
+msgstr "đầy đủ với %d đối tượng nội bộ"
+
+#: builtin/index-pack.c:1121
+#, c-format
+msgid "Unexpected tail checksum for %s (disk corruption?)"
+msgstr "Tổng kiểm tra tail không như mong đợi cho %s (đĩa hỏng?)"
+
+#: builtin/index-pack.c:1125
 #, c-format
 msgid "pack has %d unresolved delta"
 msgid_plural "pack has %d unresolved deltas"
 msgstr[0] "pack có %d delta chưa được giải quyết"
 msgstr[1] "pack có %d delta chưa được giải quyết"
 
-#: builtin/index-pack.c:998
+#: builtin/index-pack.c:1150
 #, c-format
 msgid "unable to deflate appended object (%d)"
 msgstr "không thể xả đối tượng nối thêm (%d)"
 
-#: builtin/index-pack.c:1077
+#: builtin/index-pack.c:1229
 #, c-format
 msgid "local object %s is corrupt"
 msgstr "đối tượng nội bộ %s bị hỏng"
 
-#: builtin/index-pack.c:1101
+#: builtin/index-pack.c:1253
 msgid "error while closing pack file"
 msgstr "gặp lỗi trong khi đóng tập tin pack"
 
-#: builtin/index-pack.c:1114
+#: 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:1122
+#: 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:1135
+#: builtin/index-pack.c:1287
 msgid "cannot store pack file"
 msgstr "không thể lưu tập tin pack"
 
-#: builtin/index-pack.c:1146
+#: builtin/index-pack.c:1298
 msgid "cannot store index file"
 msgstr "không thể lưu trữ tập tin ghi mục lục"
 
-#: builtin/index-pack.c:1247
+#: builtin/index-pack.c:1331
+#, c-format
+msgid "bad pack.indexversion=%<PRIu32>"
+msgstr "sai pack.indexversion=%<PRIu32>"
+
+#: builtin/index-pack.c:1337
+#, c-format
+msgid "invalid number of threads specified (%d)"
+msgstr "số tuyến chỉ ra không hợp lệ (%d)"
+
+#: builtin/index-pack.c:1341 builtin/index-pack.c:1514
+#, c-format
+msgid "no threads support, ignoring %s"
+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:1249
+#: 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:1296
+#: builtin/index-pack.c:1448
 #, c-format
 msgid "non delta: %d object"
 msgid_plural "non delta: %d objects"
 msgstr[0] "không delta: %d đối tượng"
 msgstr[1] "không delta: %d đối tượng"
 
-#: builtin/index-pack.c:1303
+#: builtin/index-pack.c:1455
 #, c-format
 msgid "chain length = %d: %lu object"
 msgid_plural "chain length = %d: %lu objects"
 msgstr[0] "chiều dài xích = %d: %lu đối tượng"
 msgstr[1] "chiều dài xích = %d: %lu đối tượng"
 
-#: builtin/index-pack.c:1330
+#: builtin/index-pack.c:1482
 msgid "Cannot come back to cwd"
 msgstr "Không thể quay lại cwd"
 
-#: builtin/index-pack.c:1374
-#: builtin/index-pack.c:1377
-#: builtin/index-pack.c:1389
-#: builtin/index-pack.c:1393
+#: 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 sai"
 
-#: builtin/index-pack.c:1407
+#: builtin/index-pack.c:1559
 msgid "--fix-thin cannot be used without --stdin"
 msgstr "--fix-thin không thể được dùng mà không có --stdin"
 
-#: builtin/index-pack.c:1411
-#: builtin/index-pack.c:1421
+#: 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:1430
+#: builtin/index-pack.c:1582
 msgid "--verify with no packfile name given"
 msgstr "dùng tùy chọn --verify mà không đưa ra tên packfile"
 
@@ -3184,22 +5194,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
@@ -3209,7 +5219,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
@@ -3234,185 +5244,494 @@ 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
 msgid "insane git directory %s"
 msgstr "thư mục git điên rồ %s"
 
-#: builtin/init-db.c:322
-#: builtin/init-db.c:325
+#: builtin/init-db.c:323 builtin/init-db.c:326
 #, c-format
 msgid "%s already exists"
-msgstr "%s đã tồn tại rồi"
+msgstr "%s đã có từ trước rồi"
 
-#: builtin/init-db.c:354
+#: builtin/init-db.c:355
 #, c-format
 msgid "unable to handle file type %d"
-msgstr "không thể handle tệp tin kiểu %d"
+msgstr "không thể nắm (handle) tập tin kiểu %d"
 
-#: builtin/init-db.c:357
+#: builtin/init-db.c:358
 #, c-format
 msgid "unable to move %s to %s"
 msgstr "không di chuyển được %s vào %s"
 
-#: builtin/init-db.c:362
+#: 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
 #. * existing" or "Initialized empty", the second " shared" or
 #. * "", and the last '%s%s' is the verbatim directory name.
 #.
-#: builtin/init-db.c:419
+#: builtin/init-db.c:420
 #, c-format
 msgid "%s%s Git repository in %s%s\n"
 msgstr "%s%s kho Git trong %s%s\n"
 
-#: builtin/init-db.c:420
+#: builtin/init-db.c:421
 msgid "Reinitialized existing"
 msgstr "Khởi tạo lại đã sẵn có rồi"
 
-#: builtin/init-db.c:420
+#: builtin/init-db.c:421
 msgid "Initialized empty"
 msgstr "Khởi tạo trống rỗng"
 
-#: builtin/init-db.c:421
+#: builtin/init-db.c:422
 msgid " shared"
 msgstr " đã chia sẻ"
 
-#: builtin/init-db.c:440
+#: builtin/init-db.c:441
 msgid "cannot tell cwd"
 msgstr "không nói chuyện được với lệnh cwd"
 
-#: builtin/init-db.c:521
-#: builtin/init-db.c:528
+#: builtin/init-db.c:467
+msgid ""
+"git init [-q | --quiet] [--bare] [--template=<template-directory>] [--shared"
+"[=<permissions>]] [directory]"
+msgstr ""
+"git init [-q | --quiet] [--bare] [--template=<thư-mục-tạm>] [--shared[=<các-"
+"quyền>]] [thư-mục]"
+
+#: builtin/init-db.c:490
+msgid "permissions"
+msgstr "các quyền"
+
+#: builtin/init-db.c:491
+msgid "specify that the git repository is to be shared amongst several users"
+msgstr "chỉ ra cái mà kho git được chia sẻ giữa nhiều người dùng"
+
+#: builtin/init-db.c:493 builtin/prune-packed.c:77
+msgid "be quiet"
+msgstr "im lặng"
+
+#: builtin/init-db.c:522 builtin/init-db.c:529
 #, c-format
 msgid "cannot mkdir %s"
 msgstr "không thể mkdir (tạo thư mục): %s"
 
-#: builtin/init-db.c:532
+#: builtin/init-db.c:533
 #, c-format
 msgid "cannot chdir to %s"
 msgstr "không thể chdir (chuyển đổi thư mục) sang %s"
 
-#: builtin/init-db.c:554
+#: builtin/init-db.c:555
 #, c-format
-msgid "%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-dir=<directory>)"
-msgstr "%s (hoặc --work-tree=<thư-mục>) không cho phép không chỉ định %s (hoặc --git-dir=<thư-mục>)"
+msgid ""
+"%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-"
+"dir=<directory>)"
+msgstr ""
+"%s (hoặc --work-tree=<thư-mục>) không cho phép không chỉ định %s (hoặc --git-"
+"dir=<thư-mục>)"
 
-#: builtin/init-db.c:578
+#: builtin/init-db.c:579
 msgid "Cannot access current working directory"
 msgstr "Không thể truy cập thư mục làm việc hiện hành"
 
-#: builtin/init-db.c:585
+#: 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"
+msgstr "git log [<các-tùy-chọn>] [<kể-từ>..<cho-đến>] [[--] <đường-dẫn>...]\n"
+
+#: builtin/log.c:38
+msgid "   or: git show [options] <object>..."
+msgstr "   or: git show [các-tùy-chọn] <đối-tượng>..."
+
+#: builtin/log.c:100
+msgid "suppress diff output"
+msgstr "chặn mọi kết xuất từ diff"
 
-#: builtin/log.c:188
+#: builtin/log.c:101
+msgid "show source"
+msgstr "hiển thị mã nguồn"
+
+#: builtin/log.c:102
+msgid "decorate options"
+msgstr "các tùy chọn trang trí"
+
+#: builtin/log.c:189
 #, c-format
 msgid "Final output: %d %s\n"
 msgstr "Kết xuất cuối cùng: %d %s\n"
 
-#: builtin/log.c:401
-#: builtin/log.c:489
+#: builtin/log.c:403 builtin/log.c:494
 #, c-format
 msgid "Could not read object %s"
 msgstr "Không thể đọc đối tượng %s"
 
-#: builtin/log.c:513
+#: builtin/log.c:518
 #, c-format
 msgid "Unknown type: %d"
 msgstr "Không nhận ra kiểu: %d"
 
-#: builtin/log.c:602
+#: builtin/log.c:608
 msgid "format.headers without value"
 msgstr "format.headers không có giá trị cụ thể"
 
-#: builtin/log.c:676
+#: builtin/log.c:682
 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:687
+#: builtin/log.c:693
 #, c-format
 msgid "Cannot open patch file %s"
 msgstr "Không thể mở tập tin miếng vá: %s"
 
-#: builtin/log.c:701
+#: builtin/log.c:707
 msgid "Need exactly one range."
 msgstr "Cần chính xác một vùng."
 
-#: builtin/log.c:709
+#: builtin/log.c:715
 msgid "Not a range."
 msgstr "Không phải là một vùng."
 
-#: builtin/log.c:786
+#: builtin/log.c:789
 msgid "Cover letter needs email format"
 msgstr "'Cover letter' cần cho định dạng thư"
 
-#: builtin/log.c:859
+#: builtin/log.c:862
 #, c-format
 msgid "insane in-reply-to: %s"
 msgstr "in-reply-to điên rồ: %s"
 
-#: builtin/log.c:932
+#: builtin/log.c:890
+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
 msgid "Two output directories?"
 msgstr "Hai thư mục kết xuất?"
 
-#: builtin/log.c:1153
+#: builtin/log.c:1063
+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
+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
+msgid "print patches to standard out"
+msgstr "hiển thị miếng vá ra đầu ra chuẩn"
+
+#: builtin/log.c:1072
+msgid "generate a cover letter"
+msgstr "tạo bì thư"
+
+#: builtin/log.c:1074
+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
+msgid "sfx"
+msgstr "sfx"
+
+#: builtin/log.c:1076
+msgid "use <sfx> instead of '.patch'"
+msgstr "sử dụng <sfx> thay cho '.patch'"
+
+#: builtin/log.c:1078
+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
+msgid "Use [<prefix>] instead of [PATCH]"
+msgstr "Dùng [<tiền-tố>] thay cho [VÁ]"
+
+#: builtin/log.c:1083
+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
+msgid "don't strip/add [PATCH]"
+msgstr "không strip/add [VÁ]"
+
+#: builtin/log.c:1089
+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
+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
+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
+msgid "Messaging"
+msgstr "Lời nhắn"
+
+#: builtin/log.c:1096
+msgid "header"
+msgstr "đầu đề thư"
+
+#: builtin/log.c:1097
+msgid "add email header"
+msgstr "thêm đầu đề thư"
+
+#: builtin/log.c:1098 builtin/log.c:1100
+msgid "email"
+msgstr "thư điện tử"
+
+#: builtin/log.c:1098
+msgid "add To: header"
+msgstr "thêm To: đầu đề thư"
+
+#: builtin/log.c:1100
+msgid "add Cc: header"
+msgstr "thêm Cc: đầu đề thư"
+
+#: builtin/log.c:1102
+msgid "message-id"
+msgstr "message-id"
+
+#: builtin/log.c:1103
+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
+msgid "boundary"
+msgstr "ranh giới"
+
+#: builtin/log.c:1105
+msgid "attach the patch"
+msgstr "đính kèm miếng vá"
+
+#: builtin/log.c:1108
+msgid "inline the patch"
+msgstr "dùng miếng vá làm nội dung"
+
+#: builtin/log.c:1112
+msgid "enable message threading, styles: shallow, deep"
+msgstr "cho phép luồng lời nhắn, kiểu: `shallow', `deep'"
+
+#: builtin/log.c:1114
+msgid "signature"
+msgstr "chữ ký"
+
+#: builtin/log.c:1115
+msgid "add a signature"
+msgstr "thêm chữ ký"
+
+#: builtin/log.c:1117
+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
 #, 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:1198
+#: builtin/log.c:1202
 msgid "-n and -k are mutually exclusive."
 msgstr "-n và  -k loại từ lẫn nhau."
 
-#: builtin/log.c:1200
+#: builtin/log.c:1204
 msgid "--subject-prefix and -k are mutually exclusive."
 msgstr "--subject-prefix và -k xung khắc nhau."
 
-#: builtin/log.c:1208
+#: builtin/log.c:1212
 msgid "--name-only does not make sense"
 msgstr "--name-only không hợp lý"
 
-#: builtin/log.c:1210
+#: builtin/log.c:1214
 msgid "--name-status does not make sense"
 msgstr "--name-status không hợp lý"
 
-#: builtin/log.c:1212
+#: builtin/log.c:1216
 msgid "--check does not make sense"
 msgstr "--check không hợp lý"
 
-#: builtin/log.c:1235
+#: builtin/log.c:1239
 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:1237
+#: builtin/log.c:1241
 #, 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:1390
+#: builtin/log.c:1394
 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:1494
+#: builtin/log.c:1443
+msgid "git cherry [-v] [<upstream> [<head> [<limit>]]]"
+msgstr "git cherry [-v] [<thượng-nguồn> [<head> [<giới-hạn>]]]"
+
+#: builtin/log.c:1498
 #, c-format
-msgid "Could not find a tracked remote branch, please specify <upstream> manually.\n"
-msgstr "Không tìm thấy nhánh mạng bị theo vết, hãy chỉ định <dòng-ngược> một cách thủ công.\n"
+msgid ""
+"Could not find a tracked remote branch, please specify <upstream> manually.\n"
+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:1510
-#: builtin/log.c:1512
-#: builtin/log.c:1524
+#: builtin/log.c:1511 builtin/log.c:1513 builtin/log.c:1525
 #, c-format
 msgid "Unknown commit %s"
 msgstr "Không hiểu lần chuyển giao (commit) %s"
 
+#: builtin/ls-files.c:408
+msgid "git ls-files [options] [<file>...]"
+msgstr "git ls-files [các-tùy-chọn] [<tập-tin>...]"
+
+#: builtin/ls-files.c:463
+msgid "identify the file status with tags"
+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 "
+"thay đổi)"
+
+#: builtin/ls-files.c:467
+msgid "show cached files in the output (default)"
+msgstr "hiển thị các tập tin được nhớ tạm vào đầu ra (mặc định)"
+
+#: builtin/ls-files.c:469
+msgid "show deleted files in the output"
+msgstr "hiển thị các tập tin đã xóa trong kết xuất"
+
+#: builtin/ls-files.c:471
+msgid "show modified files in the output"
+msgstr "hiển thị các tập tin đã bị sửa đổi ra kết xuất"
+
+#: builtin/ls-files.c:473
+msgid "show other files in the output"
+msgstr "hiển thị các tập tin khác trong kết xuất"
+
+#: builtin/ls-files.c:475
+msgid "show ignored files in the output"
+msgstr "hiển thị các tập tin bị bỏ qua trong kết xuất"
+
+#: builtin/ls-files.c:478
+msgid "show staged contents' object name in the output"
+msgstr "hiển thị tên đối tượng của nội dung được lưu trạng thái ở kết xuất"
+
+#: builtin/ls-files.c:480
+msgid "show files on the filesystem that need to be removed"
+msgstr "hiển thị các tập tin trên hệ thống tập tin mà nó cần được gỡ bỏ"
+
+#: 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'"
+
+#: builtin/ls-files.c:485
+msgid "don't show empty directories"
+msgstr "không hiển thị thư mục rỗng"
+
+#: builtin/ls-files.c:488
+msgid "show unmerged files in the output"
+msgstr "hiển thị các tập tin chưa hòa trộn trong kết xuất"
+
+#: builtin/ls-files.c:490
+msgid "show resolve-undo information"
+msgstr "hiển thị thông tin resolve-undo"
+
+#: builtin/ls-files.c:492
+msgid "skip files matching pattern"
+msgstr "bỏ qua những tập tin khớp với một mẫu"
+
+#: builtin/ls-files.c:495
+msgid "exclude patterns are read from <file>"
+msgstr "mẫu loại trừ được đọc từ <tập tin>"
+
+#: builtin/ls-files.c:498
+msgid "read additional per-directory exclude patterns in <file>"
+msgstr "đọc thêm các mẫu ngoại trừ mỗi thư mục trong <tập tin>"
+
+#: builtin/ls-files.c:500
+msgid "add the standard git exclusions"
+msgstr "thêm loại trừ tiêu chuẩn kiểu git"
+
+#: builtin/ls-files.c:503
+msgid "make the output relative to the project top directory"
+msgstr "làm cho kết xuất liên quan đến thư mục ở mức cao nhất (gốc) của dự án"
+
+#: builtin/ls-files.c:506
+msgid "if any <file> is not in the index, treat this as an error"
+msgstr "nếu <tập tin> bất kỳ không ở trong bảng mục lục, xử lý nó như một lỗi"
+
+#: builtin/ls-files.c:507
+msgid "tree-ish"
+msgstr "tree-ish"
+
+#: builtin/ls-files.c:508
+msgid "pretend that paths removed since <tree-ish> are still present"
+msgstr ""
+"giả định rằng các đường dẫn đã bị gỡ bỏ kể từ <tree-ish> nay vẫn hiện diện"
+
+#: builtin/ls-files.c:510
+msgid "show debugging data"
+msgstr "hiển thị dữ liệu gỡ lỗi"
+
+#: builtin/ls-tree.c:27
+msgid "git ls-tree [<options>] <tree-ish> [<path>...]"
+msgstr "git ls-tree [<các-tùy-chọn>] <tree-ish> [<đường-dẫn>...]"
+
+#: builtin/ls-tree.c:125
+msgid "only show trees"
+msgstr "chỉ hiển thị các tree"
+
+#: builtin/ls-tree.c:127
+msgid "recurse into subtrees"
+msgstr "đệ quy vào các thư mục con"
+
+#: builtin/ls-tree.c:129
+msgid "show trees when recursing"
+msgstr "hiển thị cây khi đệ quy"
+
+#: builtin/ls-tree.c:132
+msgid "terminate entries with NUL byte"
+msgstr "chấm dứt mục tin với byte NUL"
+
+#: builtin/ls-tree.c:133
+msgid "include object size"
+msgstr "gồm cả kích thước đối tượng"
+
+#: builtin/ls-tree.c:135 builtin/ls-tree.c:137
+msgid "list only filenames"
+msgstr "chỉ liệt kê tên tập tin"
+
+#: builtin/ls-tree.c:140
+msgid "use full path names"
+msgstr "dùng tên đường dẫn đầy đủ"
+
+#: builtin/ls-tree.c:142
+msgid "list entire tree; not just current directory (implies --full-name)"
+msgstr "liệt kê cây mục tin; không chỉ thư mục hiện hành (ngụ ý --full-name)"
+
+#: builtin/merge.c:43
+msgid "git merge [options] [<commit>...]"
+msgstr "git merge [các-tùy-chọn] [<commit>...]"
+
+#: builtin/merge.c:44
+msgid "git merge [options] <msg> HEAD <commit>"
+msgstr "git merge [các-tùy-chọn] <tin-nhắn> HEAD <commit>"
+
+#: builtin/merge.c:45
+msgid "git merge --abort"
+msgstr "git merge --abort"
+
 #: builtin/merge.c:90
 msgid "switch `m' requires a value"
 msgstr "switch `m' yêu cầu một giá trị"
@@ -3420,7 +5739,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
@@ -3432,6 +5751,67 @@ msgstr "Các chiến lược sẵn sàng là:"
 msgid "Available custom strategies are:"
 msgstr "Các chiến lược tùy chỉnh sẵn sàng là:"
 
+#: builtin/merge.c:183
+msgid "do not show a diffstat at the end of the merge"
+msgstr "không hiển thị thống kê khác biệt tại cuối của lần hòa trộn"
+
+#: builtin/merge.c:186
+msgid "show a diffstat at the end of the merge"
+msgstr "hiển thị thống kê khác biệt tại cuối của hòa trộn"
+
+#: builtin/merge.c:187
+msgid "(synonym to --stat)"
+msgstr "(đồng nghĩa với --stat)"
+
+#: builtin/merge.c:189
+msgid "add (at most <n>) entries from shortlog to merge commit message"
+msgstr "thêm (ít nhất <n>) mục từ shortlog cho ghi chú chuyển giao hòa trộn"
+
+#: builtin/merge.c:192
+msgid "create a single commit instead of doing a merge"
+msgstr "tạo một lần chuyển giao (commit) đưon thay vì thực hiện việc hòa trộn"
+
+#: builtin/merge.c:194
+msgid "perform a commit if the merge succeeds (default)"
+msgstr "thực hiện chuyển giao nếu hòa trộn thành công (mặc định)"
+
+#: builtin/merge.c:196
+msgid "edit message before committing"
+msgstr "sửa chú thích trước khi chuyển giao (commit)"
+
+#: builtin/merge.c:198
+msgid "allow fast-forward (default)"
+msgstr "cho phép fast-forward (mặc định)"
+
+#: builtin/merge.c:200
+msgid "abort if fast-forward is not possible"
+msgstr "bỏ qua nếu fast-forward không thể được"
+
+#: builtin/merge.c:202 builtin/notes.c:870 builtin/revert.c:112
+msgid "strategy"
+msgstr "chiến lược"
+
+#: builtin/merge.c:203
+msgid "merge strategy to use"
+msgstr "chiến lược hòa trộn sẽ dùng"
+
+#: builtin/merge.c:204
+msgid "option=value"
+msgstr "tùy_chọn=giá_trị"
+
+#: builtin/merge.c:205
+msgid "option for selected merge strategy"
+msgstr "tùy chọn cho chiến lược hòa trộn đã chọn"
+
+#: builtin/merge.c:207
+msgid "merge commit message (for a non-fast-forward merge)"
+msgstr ""
+"hòa trộn ghi chú của lần chuyển giao (dành cho hòa trộn non-fast-forward)"
+
+#: builtin/merge.c:211
+msgid "abort the current in-progress merge"
+msgstr "bãi bỏ quá trình hòa trộn hiện tại đang thực hiện"
+
 #: builtin/merge.c:240
 msgid "could not run stash."
 msgstr "không thể chạy stash."
@@ -3445,14 +5825,13 @@ msgstr "stash gặp lỗi"
 msgid "not a valid object: %s"
 msgstr "không phải là một đối tượng hợp lệ: %s"
 
-#: builtin/merge.c:269
-#: builtin/merge.c:286
+#: builtin/merge.c:269 builtin/merge.c:286
 msgid "read-tree failed"
 msgstr "read-tree gặp lỗi"
 
 #: builtin/merge.c:316
 msgid " (nothing to squash)"
-msgstr " (không có ghì để squash)"
+msgstr " (không có gì để squash)"
 
 #: builtin/merge.c:329
 #, c-format
@@ -3472,53 +5851,51 @@ msgstr "Hoàn thành SQUASH_MSG"
 msgid "No merge message -- not updating HEAD\n"
 msgstr "Không thông điệp hòa trộn -- không cập nhật HEAD\n"
 
-#: builtin/merge.c:437
+#: 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:536
+#: builtin/merge.c:535
 #, c-format
 msgid "Bad branch.%s.mergeoptions string: %s"
 msgstr "Chuỗi branch.%s.mergeoptions sai: %s"
 
-#: builtin/merge.c:629
+#: builtin/merge.c:628
 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:679
+#: builtin/merge.c:678
 msgid "failed to read the cache"
 msgstr "gặp lỗi khi đọc bộ nhớ tạm"
 
-#: builtin/merge.c:697
-msgid "Unable to write index."
-msgstr "Không thể ghi bảng mục lục"
-
-#: builtin/merge.c:710
+#: builtin/merge.c:709
 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:724
+#: builtin/merge.c:723
 #, 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:738
+#: builtin/merge.c:737
 #, c-format
 msgid "unable to write %s"
-msgstr "không ghi được %s"
+msgstr "không thể ghi %s"
 
-#: builtin/merge.c:877
+#: builtin/merge.c:876
 #, 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:886
+#: builtin/merge.c:885
 #, 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' để hoàn tất việc hòa trộn.\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' để "
+"hoàn tất việc hòa trộn.\n"
 
-#: builtin/merge.c:892
+#: builtin/merge.c:891
 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"
@@ -3526,60 +5903,64 @@ msgid ""
 "Lines starting with '#' will be ignored, and an empty message aborts\n"
 "the commit.\n"
 msgstr ""
-"Hãy nhập vào các thông tin để giải thích tại sao sự hòa trộn này là cần thiết,\n"
-"đặc biệt là khi nó hòa trộn dòng ngược đã cập nhật vào trong một nhánh topic.\n"
+"Hãy nhập vào các thông tin để giải thích tại sao sự hòa trộn này là cần "
+"thiết,\n"
+"đặ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 rỗng\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 "
+"rỗng\n"
 "sẽ làm hủy bỏ lần chuyển giao (commit).\n"
 
-#: builtin/merge.c:916
+#: builtin/merge.c:915
 msgid "Empty commit message."
 msgstr "Chú thích của lần commit (chuyển giao) bị trống rỗng."
 
-#: builtin/merge.c:928
+#: builtin/merge.c:927
 #, c-format
 msgid "Wonderful.\n"
 msgstr "Thần kỳ.\n"
 
-#: builtin/merge.c:993
+#: builtin/merge.c:992
 #, 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"
+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:1009
+#: builtin/merge.c:1008
 #, 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:1050
+#: builtin/merge.c:1049
 msgid "No current branch."
 msgstr "không phải nhánh hiện hành"
 
-#: builtin/merge.c:1052
+#: builtin/merge.c:1051
 msgid "No remote for the current branch."
 msgstr "Không có máy chủ cho nhánh hiện hành."
 
-#: builtin/merge.c:1054
+#: builtin/merge.c:1053
 msgid "No default upstream defined for the current branch."
-msgstr "Không có dòng ngược mặc định được định nghĩa cho nhánh hiện hành."
+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:1059
+#: builtin/merge.c:1058
 #, 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:1146
-#: builtin/merge.c:1303
+#: builtin/merge.c:1145 builtin/merge.c:1302
 #, 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:1214
+#: builtin/merge.c:1213
 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ả (không thấy MERGE_HEAD)."
+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:1230
-#: git-pull.sh:31
+#: builtin/merge.c:1229 git-pull.sh:31
 msgid ""
 "You have not concluded your merge (MERGE_HEAD exists).\n"
 "Please, commit your changes before you can merge."
@@ -3587,12 +5968,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:1233
-#: git-pull.sh:34
+#: builtin/merge.c:1232 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:1237
+#: builtin/merge.c:1236
 msgid ""
 "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
 "Please, commit your changes before you can merge."
@@ -3600,88 +5980,195 @@ 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:1240
+#: builtin/merge.c:1239
 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:1249
+#: builtin/merge.c:1248
 msgid "You cannot combine --squash with --no-ff."
-msgstr "Bạn không thể tổ hợp --squash với --no-ff."
+msgstr "Bạn không thể kết hợp --squash với --no-ff."
 
-#: builtin/merge.c:1254
+#: builtin/merge.c:1253
 msgid "You cannot combine --no-ff with --ff-only."
-msgstr "Bạn không thể tổ hợp --no-ff với --ff-only."
+msgstr "Bạn không thể kết hợp --no-ff với --ff-only."
 
-#: builtin/merge.c:1261
+#: builtin/merge.c:1260
 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."
+msgstr ""
+"Không chỉ ra lần chuyển giao (commit) và merge.defaultToUpstream chưa được "
+"đặt."
 
-#: builtin/merge.c:1293
+#: builtin/merge.c:1292
 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"
+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:1296
+#: builtin/merge.c:1295
 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:1298
+#: builtin/merge.c:1297
 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"
+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:1413
+#: builtin/merge.c:1412
 #, c-format
 msgid "Updating %s..%s\n"
 msgstr "Đang cập nhật %s..%s\n"
 
-#: builtin/merge.c:1451
+#: builtin/merge.c:1450
 #, c-format
 msgid "Trying really trivial in-index merge...\n"
 msgstr "Đang thử hòa trộn kiểu 'trivial in-index'...\n"
 
-#: builtin/merge.c:1458
+#: builtin/merge.c:1457
 #, c-format
 msgid "Nope.\n"
 msgstr "Không.\n"
 
-#: builtin/merge.c:1490
+#: builtin/merge.c:1489
 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:1513
-#: builtin/merge.c:1592
+#: builtin/merge.c:1512 builtin/merge.c:1591
 #, 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:1517
+#: builtin/merge.c:1516
 #, c-format
 msgid "Trying merge strategy %s...\n"
 msgstr "Đang thử chiến lược hòa trộn %s...\n"
 
-#: builtin/merge.c:1583
+#: builtin/merge.c:1582
 #, 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:1585
+#: builtin/merge.c:1584
 #, 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:1594
+#: builtin/merge.c:1593
 #, 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:1606
+#: builtin/merge.c:1605
 #, c-format
 msgid "Automatic merge went well; stopped before committing as requested\n"
-msgstr "Hòa trộn tự động đã trở nên tốt; bị dừng trước khi việc chuyển giao được yêu cầu\n"
+msgstr ""
+"Hòa trộn tự động đã trở nên tốt; bị dừng trước khi việc chuyển giao được yêu "
+"cầu\n"
+
+#: builtin/merge-base.c:26
+msgid "git merge-base [-a|--all] <commit> <commit>..."
+msgstr "git merge-base [-a|--all] <commit> <commit>..."
+
+#: builtin/merge-base.c:27
+msgid "git merge-base [-a|--all] --octopus <commit>..."
+msgstr "git merge-base [-a|--all] --octopus <lần commit>..."
+
+#: builtin/merge-base.c:28
+msgid "git merge-base --independent <commit>..."
+msgstr "git merge-base --independent <lần commit>..."
+
+#: builtin/merge-base.c:29
+msgid "git merge-base --is-ancestor <commit> <commit>"
+msgstr "git merge-base --is-ancestor <commit> <commit>"
+
+#: builtin/merge-base.c:98
+msgid "output all common ancestors"
+msgstr "xuất ra tất cả các ông bà, tổ tiên chung"
+
+#: builtin/merge-base.c:99
+msgid "find ancestors for a single n-way merge"
+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"
+
+#: builtin/merge-base.c:102
+msgid "is the first one ancestor of the other?"
+msgstr "là cha mẹ đầu tiên của cái khác?"
+
+#: builtin/merge-file.c:8
+msgid ""
+"git merge-file [options] [-L name1 [-L orig [-L name2]]] file1 orig_file "
+"file2"
+msgstr ""
+"git merge-file [các-tùy-chọn] [-L tên1 [-L gốc [-L tên2]]] tập-tin1 tập-tin-"
+"gốc tập-tin2"
+
+#: builtin/merge-file.c:33
+msgid "send results to standard output"
+msgstr "gửi kết quả vào đầu ra tiêu chuẩn"
+
+#: builtin/merge-file.c:34
+msgid "use a diff3 based merge"
+msgstr "dùng kiểu  hòa dựa trên diff3"
+
+#: builtin/merge-file.c:35
+msgid "for conflicts, use our version"
+msgstr "để tránh xung đột, sử dụng phiên bản của chúng ta"
+
+#: builtin/merge-file.c:37
+msgid "for conflicts, use their version"
+msgstr "để tránh xung đột, sử dụng phiên bản của họ"
+
+#: builtin/merge-file.c:39
+msgid "for conflicts, use a union version"
+msgstr "để tránh xung đột, sử dụng phiên bản kết hợp"
+
+#: builtin/merge-file.c:42
+msgid "for conflicts, use this marker size"
+msgstr "để tránh xung đột, hãy sử dụng kích thước bộ tạo này"
+
+#: builtin/merge-file.c:43
+msgid "do not warn about conflicts"
+msgstr "không cảnh báo về các xung đột xảy ra"
+
+#: builtin/merge-file.c:45
+msgid "set labels for file1/orig_file/file2"
+msgstr "đặt nhãn cho tập-tin-1/tập-tin-gốc/tập-tin-2"
+
+#: 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 "đầu vào được chấm dứt bởi NUL"
+
+#: builtin/mktree.c:154 builtin/write-tree.c:24
+msgid "allow missing objects"
+msgstr "cho phép thiếu đối tượng"
+
+#: builtin/mktree.c:155
+msgid "allow creation of more than one tree"
+msgstr "cho phép tạo nhiều hơn một cây"
+
+#: builtin/mv.c:14
+msgid "git mv [options] <source>... <destination>"
+msgstr "git mv [các-tùy-chọn] <nguồn>... <đích>"
+
+#: builtin/mv.c:64
+msgid "force move/rename even if target exists"
+msgstr "ép buộc di chuyển hay đổi tên thậm chí cả khi đích đã tồn tại"
+
+#: builtin/mv.c:65
+msgid "skip move/rename errors"
+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"
@@ -3708,227 +6195,622 @@ msgstr "thư mục nguồn là trống rỗng"
 msgid "not under version control"
 msgstr "không nằm dưới sự quản lý mã nguồn"
 
-#: builtin/mv.c:173
-msgid "destination exists"
-msgstr "đích đã tồn tại sẵn rồi"
+#: builtin/mv.c:173
+msgid "destination exists"
+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'"
+
+#: builtin/mv.c:184
+msgid "Cannot overwrite"
+msgstr "Không thể ghi đè"
+
+#: builtin/mv.c:187
+msgid "multiple sources for the same target"
+msgstr "Nhiều nguồn cho cùng một đích"
+
+#: builtin/mv.c:202
+#, c-format
+msgid "%s, source=%s, destination=%s"
+msgstr "%s, nguồn=%s, đích=%s"
+
+#: builtin/mv.c:212
+#, c-format
+msgid "Renaming %s to %s\n"
+msgstr "Đổi tên %s thành %s\n"
+
+#: builtin/mv.c:215 builtin/remote.c:731
+#, c-format
+msgid "renaming '%s' failed"
+msgstr "đổi tên %s gặp lỗi"
+
+#: builtin/name-rev.c:175
+msgid "git name-rev [options] <commit>..."
+msgstr "git name-rev [các-tùy-chọn] <commit>..."
+
+#: builtin/name-rev.c:176
+msgid "git name-rev [options] --all"
+msgstr "git name-rev [các-tùy-chọn] --all"
+
+#: builtin/name-rev.c:177
+msgid "git name-rev [options] --stdin"
+msgstr "git name-rev [các-tùy-chọn] --stdin"
+
+#: builtin/name-rev.c:229
+msgid "print only names (no SHA-1)"
+msgstr "chỉ hiển thị tên (không SHA-1)"
+
+#: builtin/name-rev.c:230
+msgid "only use tags to name the commits"
+msgstr "chỉ dùng các thẻ để đặt tên cho các lần chuyển giao"
+
+#: builtin/name-rev.c:232
+msgid "only use refs matching <pattern>"
+msgstr "chỉ sử dụng các tham chiếu (refs) khớp với <mẫu>"
+
+#: builtin/name-rev.c:234
+msgid "list all commits reachable from all refs"
+msgstr ""
+"liệt kê tất cả các lần chuyển giao có thể đọc được từ tất cả các tham chiếu"
+
+#: builtin/name-rev.c:235
+msgid "read from stdin"
+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'"
+
+#: builtin/notes.c:26
+msgid "git notes [--ref <notes_ref>] [list [<object>]]"
+msgstr "git notes [--ref <notes_ref>] [list [<đối-tượng>]]"
+
+#: builtin/notes.c:27
+msgid ""
+"git notes [--ref <notes_ref>] add [-f] [-m <msg> | -F <file> | (-c | -C) "
+"<object>] [<object>]"
+msgstr ""
+"git notes [--ref <notes_ref>] add [-f] [-m <lời-nhắn> | -F <tập-tin> | (-c | "
+"-C) <đối-tượng>] [<đối-tượng>]"
+
+#: builtin/notes.c:28
+msgid "git notes [--ref <notes_ref>] copy [-f] <from-object> <to-object>"
+msgstr "git notes [--ref <notes_ref>] copy [-f] <từ-đối-tượng> <đến-đối-tượng>"
+
+#: builtin/notes.c:29
+msgid ""
+"git notes [--ref <notes_ref>] append [-m <msg> | -F <file> | (-c | -C) "
+"<object>] [<object>]"
+msgstr ""
+"git notes [--ref <notes_ref>] append [-m <lời-nhắn> | -F <tập-tin> | (-c | -"
+"C) <đối-tượng>] [<đối-tượng>]"
+
+#: builtin/notes.c:30
+msgid "git notes [--ref <notes_ref>] edit [<object>]"
+msgstr "git notes [--ref <notes_ref>] edit [<đối-tượng>]"
+
+#: builtin/notes.c:31
+msgid "git notes [--ref <notes_ref>] show [<object>]"
+msgstr "git notes [--ref <notes_ref>] show [<đối-tượng>]"
+
+#: builtin/notes.c:32
+msgid ""
+"git notes [--ref <notes_ref>] merge [-v | -q] [-s <strategy> ] <notes_ref>"
+msgstr ""
+"git notes [--ref <notes_ref>] merge [-v | -q] [-s <chiến-lược> ] <notes_ref>"
+
+#: 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 <notes_ref>] remove [<đối-tượng>...]"
+
+#: builtin/notes.c:36
+msgid "git notes [--ref <notes_ref>] prune [-n | -v]"
+msgstr "git notes [--ref <notes_ref>] prune [-n | -v]"
+
+#: builtin/notes.c:37
+msgid "git notes [--ref <notes_ref>] get-ref"
+msgstr "git notes [--ref <notes_ref>] get-ref"
+
+#: builtin/notes.c:42
+msgid "git notes [list [<object>]]"
+msgstr "git notes [list [<đối tượng>]]"
+
+#: builtin/notes.c:47
+msgid "git notes add [<options>] [<object>]"
+msgstr "git notes add [<các-tùy-chọn>] [<đối-tượng>]"
+
+#: builtin/notes.c:52
+msgid "git notes copy [<options>] <from-object> <to-object>"
+msgstr "git notes copy [<các-tùy-chọn>] <từ-đối-tượng> <đến-đối-tượng>"
+
+#: builtin/notes.c:53
+msgid "git notes copy --stdin [<from-object> <to-object>]..."
+msgstr "git notes copy --stdin [<từ-đối-tượng> <đến-đối-tượng>]..."
+
+#: builtin/notes.c:58
+msgid "git notes append [<options>] [<object>]"
+msgstr "git notes append [<các-tùy-chọn>] [<đối-tượng>]"
 
-#: builtin/mv.c:181
-#, c-format
-msgid "overwriting '%s'"
-msgstr "đang ghi đè lên '%s'"
+#: builtin/notes.c:63
+msgid "git notes edit [<object>]"
+msgstr "git notes edit [<đối tượng>]"
 
-#: builtin/mv.c:184
-msgid "Cannot overwrite"
-msgstr "Không thể ghi chèn"
+#: builtin/notes.c:68
+msgid "git notes show [<object>]"
+msgstr "git notes show [<đối tượng>]"
 
-#: builtin/mv.c:187
-msgid "multiple sources for the same target"
-msgstr "Nhiều nguồn cho cùng một đích"
+#: builtin/notes.c:73
+msgid "git notes merge [<options>] <notes_ref>"
+msgstr "git notes merge [<các-tùy-chọn>] <notes_ref>"
 
-#: builtin/mv.c:202
-#, c-format
-msgid "%s, source=%s, destination=%s"
-msgstr "%s, nguồn=%s, đích=%s"
+#: builtin/notes.c:74
+msgid "git notes merge --commit [<options>]"
+msgstr "git notes merge --commit [<các-tùy-chọn>]"
 
-#: builtin/mv.c:212
-#, c-format
-msgid "Renaming %s to %s\n"
-msgstr "Đang thay đổi tên %s thành %s\n"
+#: builtin/notes.c:75
+msgid "git notes merge --abort [<options>]"
+msgstr "git notes merge --abort [<các-tùy-chọn>]"
 
-#: builtin/mv.c:215
-#: builtin/remote.c:731
-#, c-format
-msgid "renaming '%s' failed"
-msgstr "đổi tên %s gặp lỗi"
+#: builtin/notes.c:80
+msgid "git notes remove [<object>]"
+msgstr "git notes remove [<đối tượng>]"
+
+#: builtin/notes.c:85
+msgid "git notes prune [<options>]"
+msgstr "git notes prune [<các-tùy-chọn>]"
 
-#: builtin/notes.c:139
+#: 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 "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:145
+#: 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"
 
-#: builtin/notes.c:155
+#: 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:158
+#: 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:175
-#: builtin/tag.c:347
+#: 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:189
+#: builtin/notes.c:192
 msgid "Please supply the note contents using either -m or -F option"
-msgstr "Xin hãy áp dụng nội dung của ghi chú sử dụng hoặc là tùy chọn -m hoặc là -F"
+msgstr ""
+"Xin hãy áp dụng nội dung của ghi chú sử dụng hoặc là tùy chọn -m hoặc là -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 "Đang gỡ bỏ ghi chú (note) cho đối tượng %s\n"
 
-#: builtin/notes.c:215
+#: builtin/notes.c:218
 msgid "unable to write note object"
 msgstr "không thể ghi đối tượng ghi chú (note)"
 
-#: builtin/notes.c:217
+#: builtin/notes.c:220
 #, c-format
 msgid "The note contents has been left in %s"
 msgstr "Nội dung ghi chú còn lại %s"
 
-#: builtin/notes.c:251
-#: builtin/tag.c:542
+#: 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:253
-#: builtin/tag.c:545
+#: 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'"
-
-#: 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
+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
+#: 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 "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:275
+#: 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:299
+#: builtin/notes.c:302
 msgid "Cannot commit uninitialized/unreferenced notes tree"
-msgstr "Không thể chuyển giao (commit) chưa được khởi tạo hoặc không được tham chiếu cây ghi chú"
+msgstr ""
+"Không thể chuyển giao (commit) chưa được khởi tạo hoặc không được tham chiếu "
+"cây ghi chú"
 
-#: builtin/notes.c:340
+#: 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:350
+#: builtin/notes.c:353
 #, c-format
 msgid "Refusing to rewrite notes in %s (outside of refs/notes/)"
 msgstr "Từ chối ghi đè ghi chú trong %s (nằm ngoài của 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 "Giá trị %s sai: '%s'"
+msgstr "Giá trị %s sai: `%s'"
 
-#: builtin/notes.c:441
+#: 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:456
+#: 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'"
-
-#: 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
+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
+#: builtin/notes.c:1036
 msgid "too many parameters"
 msgstr "quá nhiều đối số"
 
-#: 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 "không ghi chú được tìm thấy cho đối tượng %s."
+msgstr "không tìm thấy ghi chú cho đối tượng %s."
+
+#: builtin/notes.c:538 builtin/notes.c:695
+msgid "note contents as a string"
+msgstr "nội dung ghi chú (note) nằm trong một chuỗi"
+
+#: builtin/notes.c:541 builtin/notes.c:698
+msgid "note contents in a file"
+msgstr "nội dung ghi chú (note) nằm trong một tập tin"
+
+#: builtin/notes.c:543 builtin/notes.c:546 builtin/notes.c:700
+#: builtin/notes.c:703 builtin/tag.c:476
+msgid "object"
+msgstr "đối tượng"
 
-#: builtin/notes.c:580
+#: builtin/notes.c:544 builtin/notes.c:701
+msgid "reuse and edit specified note object"
+msgstr "dùng lại nhưng có sửa chữa đối tượng note đã chỉ ra"
+
+#: builtin/notes.c:547 builtin/notes.c:704
+msgid "reuse specified note object"
+msgstr "dùng lại đối tượng ghi chú (note) đã chỉ ra"
+
+#: builtin/notes.c:549 builtin/notes.c:617
+msgid "replace existing notes"
+msgstr "thay thế ghi chú trước"
+
+#: builtin/notes.c:583
 #, c-format
-msgid "Cannot add notes. Found existing notes for object %s. Use '-f' to overwrite existing notes"
-msgstr "Không thể thêm các ghi chú. Đã tìm thấy các ghi chú đã sẵn có cho đối tượng %s. Sử dụng tùy chọn '-f' để ghi đè lên các ghi chú cũ"
+msgid ""
+"Cannot add notes. Found existing notes for object %s. Use '-f' to overwrite "
+"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ũ"
 
-#: 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 "Đang ghi đè lên ghi chú cũ cho đối tượng %s\n"
 
-#: builtin/notes.c:635
+#: builtin/notes.c:618
+msgid "read objects from stdin"
+msgstr "đọc các đối tượng từ đầu vào tiêu chuẩn"
+
+#: builtin/notes.c:620
+msgid "load rewriting config for <command> (implies --stdin)"
+msgstr "tải cấu hình chép lại cho <lệnh> (ngầm định là --stdin)"
+
+#: builtin/notes.c:638
 msgid "too few parameters"
 msgstr "quá ít đối số"
 
-#: builtin/notes.c:656
+#: builtin/notes.c:659
 #, c-format
-msgid "Cannot copy notes. Found existing notes for object %s. Use '-f' to overwrite existing notes"
-msgstr "Không thể sao chép các ghi chú. Đã tìm thấy các ghi chú đã sẵn có cho đối tượng %s. Sử dụng tùy chọn '-f' để ghi đè lên các ghi chú cũ"
+msgid ""
+"Cannot copy notes. Found existing notes for object %s. Use '-f' to overwrite "
+"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ũ"
 
-#: builtin/notes.c:668
+#: builtin/notes.c:671
 #, c-format
 msgid "Missing notes on source object %s. Cannot copy."
 msgstr "Thiếu ghi chú trên đối tượng nguốn %s. Không thể sao chép."
 
-#: 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"
 "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"
+msgstr "Tùy chọn chung"
+
+#: builtin/notes.c:869
+msgid "Merge options"
+msgstr "Tùy chọn về hòa trộn"
+
+#: builtin/notes.c:871
+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/"
+"theirs/union/cat_sort_uniq)"
+
+#: builtin/notes.c:873
+msgid "Committing unmerged notes"
+msgstr "Chuyển giao các note chưa được hòa trộn"
+
+#: builtin/notes.c:875
+msgid "finalize notes merge by committing unmerged notes"
+msgstr ""
+"các note cuối cùng được hòa trộn bởi các note chưa hòa trộn của lần chuyển "
+"giao"
+
+#: builtin/notes.c:877
+msgid "Aborting notes merge resolution"
+msgstr "Hủy bỏ phân giải ghi chú (note) hòa trộn"
 
-#: builtin/notes.c:971
+#: builtin/notes.c:879
+msgid "abort notes merge"
+msgstr "bỏ qua hòa trộn các ghi chú (note)"
+
+#: builtin/notes.c:974
 #, c-format
 msgid "Object %s has no note\n"
 msgstr "Đối tượng %s không có ghi chú (note)\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 "cố gắng gỡ bỏ một note chưa từng tồn tại không phải là một lỗi"
+
+#: builtin/notes.c:989
+msgid "read object names from the standard input"
+msgstr "đọc tên đối tượng từ thiết bị nhập chuẩn"
+
+#: builtin/notes.c:1070
+msgid "notes_ref"
+msgstr "notes_ref"
+
+#: builtin/notes.c:1071
+msgid "use notes from <notes_ref>"
+msgstr "dùng `notes' từ <notes_ref>"
+
+#: builtin/notes.c:1106 builtin/remote.c:1598
 #, c-format
 msgid "Unknown subcommand: %s"
 msgstr "Không hiểu câu lệnh con: %s"
 
-#: builtin/pack-objects.c:2337
+#: builtin/pack-objects.c:23
+msgid "git pack-objects --stdout [options...] [< ref-list | < object-list]"
+msgstr ""
+"git pack-objects --stdout [các-tùy-chọn...] [< danh-sách-ref | < danh-sách-"
+"đối-tượng]"
+
+#: builtin/pack-objects.c:24
+msgid "git pack-objects [options...] base-name [< ref-list | < object-list]"
+msgstr ""
+"git pack-objects [các-tùy-chọn...] base-name [< danh-sách-ref | < danh-sách-"
+"đối-tượng]"
+
+#: builtin/pack-objects.c:183 builtin/pack-objects.c:186
+#, c-format
+msgid "deflate error (%d)"
+msgstr "lỗi giải nén (%d)"
+
+#: builtin/pack-objects.c:2398
 #, 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:2341
+#: builtin/pack-objects.c:2402
 #, 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:2364
+#: builtin/pack-objects.c:2425
 #, 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:2368
+#: builtin/pack-objects.c:2429
 #, 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
+msgid "do not show progress meter"
+msgstr "không hiển thị bộ đo tiến trình"
+
+#: builtin/pack-objects.c:2450
+msgid "show progress meter"
+msgstr "hiển thị bộ đo tiến trình"
+
+#: builtin/pack-objects.c:2452
+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
+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
+msgid "version[,offset]"
+msgstr "phiên bản[,offset]"
+
+#: builtin/pack-objects.c:2457
+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
+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
+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
+msgid "ignore packed objects"
+msgstr "bỏ qua các đối tượng đóng gói"
+
+#: builtin/pack-objects.c:2466
+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
+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
+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ả"
+
+#: builtin/pack-objects.c:2472
+msgid "reuse existing deltas"
+msgstr "dùng lại các delta sẵn có"
+
+#: builtin/pack-objects.c:2474
+msgid "reuse existing objects"
+msgstr "dùng lại các đối tượng sẵn có"
+
+#: builtin/pack-objects.c:2476
+msgid "use OFS_DELTA objects"
+msgstr "dùng các đối tượng OFS_DELTA"
+
+#: builtin/pack-objects.c:2478
+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
+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
+msgid "read revision arguments from standard input"
+msgstr " đọc tham số `revision' từ thiết bị nhập chuẩn"
+
+#: builtin/pack-objects.c:2484
+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
+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
+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
+msgid "output pack to stdout"
+msgstr "xuất gói ra đầu ra tiêu chuẩn"
+
+#: builtin/pack-objects.c:2495
+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
+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
+msgid "time"
+msgstr "thời-gian"
+
+#: builtin/pack-objects.c:2499
+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
+msgid "create thin packs"
+msgstr "tạo gói nhẹ"
+
+#: builtin/pack-objects.c:2504
+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
+msgid "pack compression level"
+msgstr "mức nén gói"
+
+#: builtin/pack-objects.c:2508
+msgid "do not hide commits by 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]"
+msgstr "git pack-refs [các-tùy-chọn]"
+
+#: builtin/pack-refs.c:14
+msgid "pack everything"
+msgstr "đóng gói mọi thứ"
+
+#: builtin/pack-refs.c:15
+msgid "prune loose refs (default)"
+msgstr "prune (cắt cụt) những tham chiếu (refs) bị mất (mặc định)"
+
+#: 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 <thời-gian>] [--] [<head>...]"
+
+#: builtin/prune.c:132
+msgid "do not remove, show only"
+msgstr "không gỡ bỏ, chỉ hiển thị"
+
+#: builtin/prune.c:133
+msgid "report pruned objects"
+msgstr "báo cáo các đối tượng đã prune"
+
+#: builtin/prune.c:136
+msgid "expire objects older than <time>"
+msgstr "các đối tượng hết hạn cũ hơn khoảng <thời gian>"
+
+#: builtin/push.c:14
+msgid "git push [<options>] [<repository> [<refspec>...]]"
+msgstr "git push [<các-tùy-chọn>] [<kho-chứa> [<refspec>...]]"
 
 #: builtin/push.c:45
 msgid "tag shorthand without <tag>"
@@ -3944,7 +6826,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
@@ -3960,8 +6843,8 @@ msgid ""
 "    git push %s %s\n"
 "%s"
 msgstr ""
-"Nhánh dòng ngược (upstream) của nhánh hiện tại của bạn không khớp\n"
-"với tên của nhánh hiện tại của bạn.  Để push đến nhánh dòng ngược\n"
+"Nhánh thượng nguồn (upstream) của nhánh hiện tại của bạn không khớp\n"
+"với tên của nhánh hiện tại của bạn.  Để push đến nhánh thượng nguồn\n"
 "trên máy chủ, sử dụng\n"
 "\n"
 "    git push %s HEAD:%s\n"
@@ -3994,15 +6877,16 @@ msgid ""
 "\n"
 "    git push --set-upstream %s %s\n"
 msgstr ""
-"Nhánh hiện tại %s không có nhánh dòng ngược (upstream) nào.\n"
-"Để push (đẩy lên) nhánh hiện tại và đặt máy chủ như là dòng ngược (upstream), sử dụng\n"
+"Nhánh hiện tại %s không có nhánh thượng nguồn (upstream) nào.\n"
+"Để push (đẩy lên) nhánh hiện tại và đặt máy chủ như là thượng nguồn "
+"(upstream), sử dụng\n"
 "\n"
 "    git push --set-upstream %s %s\n"
 
 #: builtin/push.c:136
 #, c-format
 msgid "The current branch %s has multiple upstream branches, refusing to push."
-msgstr "Nhánh hiện tại %s có đa nhánh dòng ngược (upstream), từ chối push."
+msgstr "Nhánh hiện tại %s có đa nhánh thượng nguồn (upstream), từ chối push."
 
 #: builtin/push.c:139
 #, c-format
@@ -4011,15 +6895,52 @@ 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à dòng ngược (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"
+"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"
 "để cập nhật nhánh máy chủ nào."
 
-#: builtin/push.c:174
-msgid "You didn't specify any refspecs to push, and push.default is \"nothing\"."
-msgstr "Bạn đã không chỉ ra một refspecs nào để push, và push.default là \"không là gì cả\"."
+#: builtin/push.c:151
+msgid ""
+"push.default is unset; its implicit value is changing in\n"
+"Git 2.0 from 'matching' to 'simple'. To squelch this message\n"
+"and maintain the current behavior after the default changes, use:\n"
+"\n"
+"  git config --global push.default matching\n"
+"\n"
+"To squelch this message and adopt the new behavior now, use:\n"
+"\n"
+"  git config --global push.default simple\n"
+"\n"
+"See 'git help config' and search for 'push.default' for further "
+"information.\n"
+"(the 'simple' mode was introduced in Git 1.7.11. Use the similar mode\n"
+"'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"
+"Để 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"
+"  git config --global push.default matching\n"
+"\n"
+"Để không hiển thị nhắc nhở này và áp dụng cách xử lý mới, hãy chạy lệnh:\n"
+"\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 "
+"tự\n"
+"`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 ""
+"You didn't specify any refspecs to push, and push.default is \"nothing\"."
+msgstr ""
+"Bạn đã không chỉ ra một refspecs nào để push, và push.default là \"không là "
+"gì cả\"."
 
-#: builtin/push.c:181
+#: builtin/push.c:206
 msgid ""
 "Updates were rejected because the tip of your current branch is behind\n"
 "its remote counterpart. Merge the remote changes (e.g. 'git pull')\n"
@@ -4027,23 +6948,28 @@ 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' trong nội dung từ lệnh 'git push --help'."
+"Xem trong phần 'Note about fast-forwards' từ lệnh `git push --help' để có "
+"thông tin chi tiết."
 
-#: builtin/push.c:187
+#: builtin/push.c:212
 msgid ""
 "Updates were rejected because a pushed branch tip is behind its remote\n"
 "counterpart. If you did not intend to push that branch, you may want to\n"
-"specify branches to push or set the 'push.default' configuration\n"
-"variable to 'current' or 'upstream' to push only the current branch."
+"specify branches to push or set the 'push.default' configuration variable\n"
+"to 'simple', 'current' or 'upstream' to push only the current branch."
 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 'current' hoặc 'upstream' để push chỉ nhánh hiện hành mà thôi."
-
-#: builtin/push.c:193
+"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à "
+"thôi."
+
+#: builtin/push.c:218
 msgid ""
 "Updates were rejected because a pushed branch tip is behind its remote\n"
 "counterpart. Check out this branch and merge the remote changes\n"
@@ -4051,29 +6977,32 @@ 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ủ. 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' trong nội dung từ lệnh 'git push --help'."
+"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ó "
+"thông tin chi tiết."
 
-#: builtin/push.c:233
+#: builtin/push.c:258
 #, c-format
 msgid "Pushing to %s\n"
 msgstr "Đang push (đẩy) lên %s\n"
 
-#: builtin/push.c:237
+#: 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:269
+#: builtin/push.c:294
 #, c-format
 msgid "bad repository '%s'"
-msgstr "repository (kho) sai '%s'"
+msgstr "repository (kho) sai `%s'"
 
-#: builtin/push.c:270
+#: builtin/push.c:295
 msgid ""
 "No configured push destination.\n"
-"Either specify the URL from the command-line or configure a remote repository using\n"
+"Either specify the URL from the command-line or configure a remote "
+"repository using\n"
 "\n"
 "    git remote add <name> <url>\n"
 "\n"
@@ -4090,34 +7019,241 @@ msgstr ""
 "\n"
 "    git push <tên>\n"
 
-#: builtin/push.c:285
+#: builtin/push.c:310
 msgid "--all and --tags are incompatible"
 msgstr "--all và --tags xung khắc nhau"
 
-#: builtin/push.c:286
+#: builtin/push.c:311
 msgid "--all can't be combined with refspecs"
 msgstr "--all không thể được tổ hợp cùng với refspecs"
 
-#: builtin/push.c:291
+#: builtin/push.c:316
 msgid "--mirror and --tags are incompatible"
 msgstr "--mirror và --tags xung khắc nhau"
 
-#: builtin/push.c:292
+#: builtin/push.c:317
 msgid "--mirror can't be combined with refspecs"
 msgstr "--mirror không thể được tổ hợp cùng với refspecs"
 
-#: builtin/push.c:297
+#: builtin/push.c:322
 msgid "--all and --mirror are incompatible"
 msgstr "--all và --mirror xung khắc nhau"
 
-#: builtin/push.c:385
+#: builtin/push.c:382
+msgid "repository"
+msgstr "kho"
+
+#: builtin/push.c:383
+msgid "push all refs"
+msgstr "push tất cả refs"
+
+#: builtin/push.c:384
+msgid "mirror all refs"
+msgstr "mirror tất cả refs"
+
+#: builtin/push.c:386
+msgid "delete refs"
+msgstr "xóa refs"
+
+#: builtin/push.c:387
+msgid "push tags (can't be used with --all or --mirror)"
+msgstr ""
+"các thẻ push (không thể sử dụng cùng với các tùy chọn --all hay --mirror)"
+
+#: builtin/push.c:390
+msgid "force updates"
+msgstr "ép buộc cập nhật"
+
+#: builtin/push.c:391
+msgid "check"
+msgstr "kiểm tra"
+
+#: builtin/push.c:392
+msgid "control recursive pushing of submodules"
+msgstr "điều khiển việc đẩy lên (push) đệ qui của mô-đun-con"
+
+#: builtin/push.c:394
+msgid "use thin pack"
+msgstr "tạo gói nhẹ"
+
+#: builtin/push.c:395 builtin/push.c:396
+msgid "receive pack program"
+msgstr "nhận về chương trình pack"
+
+#: builtin/push.c:397
+msgid "set upstream for git pull/status"
+msgstr "đặt thượng nguồn (upstream) cho git pull/status"
+
+#: builtin/push.c:400
+msgid "prune locally removed refs"
+msgstr "prune (cắt cụt) những tham chiếu (refs) bị gỡ bỏ"
+
+#: builtin/push.c:410
 msgid "--delete is incompatible with --all, --mirror and --tags"
 msgstr "--delete là xung khắc với các tùy chọn --all, --mirror và --tags"
 
-#: builtin/push.c:387
+#: builtin/push.c:412
 msgid "--delete doesn't make sense without any refs"
 msgstr "--delete không hợp lý nếu không có bất kỳ tham chiếu (refs) nào"
 
+#: 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=<tiền-"
+"tố>] [-u [--exclude-per-directory=<gitignore>] | -i]] [--no-sparse-checkout] "
+"[--index-output=<tập-tin>] (--empty | <tree-ish1> [<tree-ish2> [<tree-"
+"ish3>]])"
+
+#: builtin/read-tree.c:108
+msgid "write resulting index to <file>"
+msgstr "ghi mục lục kết quả vào <tập-tin>"
+
+#: builtin/read-tree.c:111
+msgid "only empty the index"
+msgstr "chỉ với bảng mục lục trống rỗng"
+
+#: builtin/read-tree.c:113
+msgid "Merging"
+msgstr "Hòa trộn"
+
+#: builtin/read-tree.c:115
+msgid "perform a merge in addition to a read"
+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 "
+
+#: 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'"
+
+#: builtin/read-tree.c:121
+msgid "same as -m, but discard unmerged entries"
+msgstr "giống với -m, nhưng bỏ qua các mục chưa được hòa trộn"
+
+#: builtin/read-tree.c:122
+msgid "<subdirectory>/"
+msgstr "<thư-mục-con>/"
+
+#: builtin/read-tree.c:123
+msgid "read the tree into the index under <subdirectory>/"
+msgstr "đọc cây vào trong bảng mục lục dưới <thư_mục_con>/"
+
+#: builtin/read-tree.c:126
+msgid "update working tree with merge result"
+msgstr "cập nhật cây làm việc với kết quả hòa trộn"
+
+#: builtin/read-tree.c:128
+msgid "gitignore"
+msgstr "gitignore"
+
+#: builtin/read-tree.c:129
+msgid "allow explicitly ignored files to be overwritten"
+msgstr "cho phép các tập tin rõ ràng bị lờ đi được ghi đè"
+
+#: builtin/read-tree.c:132
+msgid "don't check the working tree after merging"
+msgstr "không kiểm tra cây làm việc sau hòa trộn"
+
+#: builtin/read-tree.c:133
+msgid "don't update the index or the work tree"
+msgstr "không cập nhật bảng mục lục hay cây làm việc"
+
+#: builtin/read-tree.c:135
+msgid "skip applying sparse checkout filter"
+msgstr "bỏ qua áp dụng bộ lọc lấy ra (checkout) thưa thớt"
+
+#: builtin/read-tree.c:137
+msgid "debug unpack-trees"
+msgstr "gỡ lỗi unpack-trees"
+
+#: 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 <nhánh>] [-m <master>] [-f] [--tags|--no-tags] [--"
+"mirror=<fetch|push>] <tên> <url>"
+
+#: builtin/remote.c:13 builtin/remote.c:32
+msgid "git remote rename <old> <new>"
+msgstr "git remote rename <tên-cũ> <tên-mới>"
+
+#: builtin/remote.c:14 builtin/remote.c:37
+msgid "git remote remove <name>"
+msgstr "git remote remove <tên>"
+
+#: builtin/remote.c:15
+msgid "git remote set-head <name> (-a | -d | <branch>)"
+msgstr "git remote set-head <tên> (-a | -d | <nhánh>)"
+
+#: builtin/remote.c:16
+msgid "git remote [-v | --verbose] show [-n] <name>"
+msgstr "git remote [-v | --verbose] show [-n] <tên>"
+
+#: builtin/remote.c:17
+msgid "git remote prune [-n | --dry-run] <name>"
+msgstr "git remote prune [-n | --dry-run] <tên>"
+
+#: builtin/remote.c:18
+msgid ""
+"git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]"
+msgstr ""
+"git remote [-v | --verbose] update [-p | --prune] [(<nhóm> | <máy-chủ>)...]"
+
+#: builtin/remote.c:19
+msgid "git remote set-branches [--add] <name> <branch>..."
+msgstr "git remote set-branches [--add] <tên> <nhánh>..."
+
+#: builtin/remote.c:20 builtin/remote.c:68
+msgid "git remote set-url [--push] <name> <newurl> [<oldurl>]"
+msgstr "git remote set-url [--push] <tên> <url-mới> [<url-cũ>]"
+
+#: builtin/remote.c:21 builtin/remote.c:69
+msgid "git remote set-url --add <name> <newurl>"
+msgstr "git remote set-url --add <tên> <url-mới>"
+
+#: builtin/remote.c:22 builtin/remote.c:70
+msgid "git remote set-url --delete <name> <url>"
+msgstr "git remote set-url --delete <tên> <url>"
+
+#: builtin/remote.c:27
+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>..."
+
+#: builtin/remote.c:48
+msgid "git remote set-branches --add <name> <branch>..."
+msgstr "git remote set-branches --add <tên> <nhánh>..."
+
+#: builtin/remote.c:53
+msgid "git remote show [<options>] <name>"
+msgstr "git remote show [<các-tùy-chọn>] <tên>"
+
+#: builtin/remote.c:58
+msgid "git remote prune [<options>] <name>"
+msgstr "git remote prune [<các-tùy-chọn>] <tên>"
+
+#: builtin/remote.c:63
+msgid "git remote update [<options>] [<group> | <remote>]..."
+msgstr "git remote update [<các-tùy-chọn>] [<nhóm> | <máy-chủ>]..."
+
 #: builtin/remote.c:98
 #, c-format
 msgid "Updating %s"
@@ -4136,30 +7272,57 @@ msgstr ""
 msgid "unknown mirror argument: %s"
 msgstr "không hiểu tham số máy bản sao (mirror): %s"
 
+#: builtin/remote.c:163
+msgid "fetch the remote branches"
+msgstr "lấy về (fetch) các nhánh từ máy chủ"
+
+#: builtin/remote.c:165
+msgid "import all tags and associated objects when fetching"
+msgstr ""
+"nhập vào tất cả các đối tượng thẻ và thành phần liên quan khi lấy về (fetch)"
+
+#: builtin/remote.c:168
+msgid "or do not fetch any tag at all (--no-tags)"
+msgstr "hoặc không lấy về (fetch) bất kỳ thẻ nào (--no-tags)"
+
+#: builtin/remote.c:170
+msgid "branch(es) to track"
+msgstr "các nhánh theo vết"
+
+#: builtin/remote.c:171
+msgid "master branch"
+msgstr "nhánh master"
+
+#: 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 "đặt máy chủ (remote) như là một máy bản sao để push hay fetch từ đó"
+
 #: builtin/remote.c:185
 msgid "specifying a master branch makes no sense with --mirror"
-msgstr "đang chỉ định một nhánh master không phân biệt HOA/thường với tùy chọn --mirror"
+msgstr "đang chỉ định một nhánh master không hợp lý với tùy chọn --mirror"
 
 #: 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'"
 
-#: builtin/remote.c:195
-#: builtin/remote.c:646
+#: builtin/remote.c:195 builtin/remote.c:646
 #, c-format
 msgid "remote %s already exists."
 msgstr "máy chủ %s đã tồn tại rồi."
 
-#: builtin/remote.c:199
-#: builtin/remote.c:650
+#: 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
@@ -4171,8 +7334,7 @@ msgstr "nhiều hơn một %s"
 msgid "Could not get fetch map for refspec %s"
 msgstr "Không thể lấy ánh xạ (map) fetch cho refspec %s"
 
-#: builtin/remote.c:440
-#: builtin/remote.c:448
+#: builtin/remote.c:440 builtin/remote.c:448
 msgid "(matching)"
 msgstr "(mẫu)"
 
@@ -4180,16 +7342,12 @@ msgstr "(mẫu)"
 msgid "(delete)"
 msgstr "(xoá)"
 
-#: builtin/remote.c:595
-#: builtin/remote.c:601
-#: builtin/remote.c:607
+#: 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
+#: builtin/remote.c:639 builtin/remote.c:792 builtin/remote.c:890
 #, c-format
 msgid "No such remote: %s"
 msgstr "Không có máy chủ nào như thế: %s"
@@ -4197,13 +7355,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
+#: 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
@@ -4219,12 +7376,12 @@ msgstr ""
 #: 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
@@ -4239,7 +7396,7 @@ msgstr "tạo %s gặp lỗi"
 #: builtin/remote.c:764
 #, c-format
 msgid "Could not remove branch %s"
-msgstr "Không thể gỡ nhánh %s"
+msgstr "Không thể gỡ bỏ nhánh %s"
 
 #: builtin/remote.c:834
 msgid ""
@@ -4252,7 +7409,8 @@ msgstr[0] ""
 "Chú ý: Một nhánh nằm ngoài hệ thống refs/remotes/ đã không được gỡ bỏ đi;\n"
 "để xóa đi, sử dụng:"
 msgstr[1] ""
-"Chú ý: Một số nhánh nằm ngoài hệ thống refs/remotes/ đã không được gỡ bỏ đi;\n"
+"Chú ý: Một số nhánh nằm ngoài hệ thống refs/remotes/ đã không được gỡ bỏ "
+"đi;\n"
 "để xóa đi, sử dụng:"
 
 #: builtin/remote.c:943
@@ -4262,11 +7420,11 @@ msgstr " mới (lần lấy về tiếp theo sẽ lưu trong remotes/%s)"
 
 #: builtin/remote.c:946
 msgid " tracked"
-msgstr " bị theo vết"
+msgstr " được theo vết"
 
 #: builtin/remote.c:948
 msgid " stale (use 'git remote prune' to remove)"
-msgstr " cũ (sử dụng 'git remote prune' để gỡ bỏ)"
+msgstr " cũ (dùng `git remote prune' để gỡ bỏ)"
 
 #: builtin/remote.c:950
 msgid " ???"
@@ -4294,7 +7452,7 @@ msgstr "    và với máy chủ"
 #: builtin/remote.c:1004
 #, c-format
 msgid "merges with remote %s"
-msgstr "hòa trộn với máy chủ  %s"
+msgstr "hòa trộn với máy chủ %s"
 
 #: builtin/remote.c:1005
 msgid "   and with remote"
@@ -4340,6 +7498,10 @@ msgstr "    %-*s ép buộc thành %s"
 msgid "    %-*s pushes to %s"
 msgstr "    %-*s push tới %s"
 
+#: builtin/remote.c:1091
+msgid "do not query remotes"
+msgstr "không truy vấn các máy chủ"
+
 #: builtin/remote.c:1118
 #, c-format
 msgid "* remote %s"
@@ -4350,28 +7512,25 @@ msgstr "* máy chủ %s"
 msgid "  Fetch URL: %s"
 msgstr "  URL để lấy về (fetch): %s"
 
-#: builtin/remote.c:1120
-#: builtin/remote.c:1285
+#: builtin/remote.c:1120 builtin/remote.c:1285
 msgid "(no URL)"
-msgstr "(không có URL nào)"
+msgstr "(không có URL)"
 
-#: builtin/remote.c:1129
-#: builtin/remote.c:1131
+#: builtin/remote.c:1129 builtin/remote.c:1131
 #, c-format
 msgid "  Push  URL: %s"
-msgstr "  URL để đẩy lên (push)  : %s"
+msgstr "  URL để đẩy lên (push): %s"
 
-#: builtin/remote.c:1133
-#: builtin/remote.c:1135
-#: builtin/remote.c:1137
+#: builtin/remote.c:1133 builtin/remote.c:1135 builtin/remote.c:1137
 #, c-format
 msgid "  HEAD branch: %s"
 msgstr "  Nhánh HEAD: %s"
 
 #: builtin/remote.c:1139
 #, c-format
-msgid "  HEAD branch (remote HEAD is ambiguous, may be one of the following):\n"
-msgstr "  nhánh HEAD (HEAD máy chủ là không rõ ràng, có lẽ là một trong số sau):\n"
+msgid ""
+"  HEAD branch (remote HEAD is ambiguous, may be one of the following):\n"
+msgstr "  nhánh HEAD (HEAD máy chủ chưa rõ ràng, có lẽ là một trong số sau):\n"
 
 #: builtin/remote.c:1151
 #, c-format
@@ -4380,27 +7539,34 @@ msgid_plural "  Remote branches:%s"
 msgstr[0] "  Nhánh trên máy chủ:%s"
 msgstr[1] "  Những nhánh trên máy chủ:%s"
 
-#: builtin/remote.c:1154
-#: builtin/remote.c:1181
+#: builtin/remote.c:1154 builtin/remote.c:1181
 msgid " (status not queried)"
 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"
+msgstr "đặt refs/remotes/<tên>/HEAD cho phù hợp với máy chủ"
+
+#: builtin/remote.c:1201
+msgid "delete refs/remotes/<name>/HEAD"
+msgstr "xóa refs/remotes/<tên>/HEAD"
 
 #: builtin/remote.c:1216
 msgid "Cannot determine remote HEAD"
@@ -4428,12 +7594,12 @@ msgstr "Không thể cài đặt %s"
 #: builtin/remote.c:1274
 #, c-format
 msgid " %s will become dangling!"
-msgstr " %s sẽ trở thành lủng lẳng (không được quản lý)!"
+msgstr " %s sẽ trở thành không đầu (không được quản lý)!"
 
 #: builtin/remote.c:1275
 #, c-format
 msgid " %s has become dangling!"
-msgstr " %s phải trở thành lủng lẳng (không được quản lý)!"
+msgstr " %s đã trở thành không đầu (không được quản lý)!"
 
 #: builtin/remote.c:1281
 #, c-format
@@ -4455,16 +7621,35 @@ msgstr " * [nên xén bớt] %s"
 msgid " * [pruned] %s"
 msgstr " *[đã xén bớ] %s"
 
-#: builtin/remote.c:1387
-#: builtin/remote.c:1461
+#: builtin/remote.c:1321
+msgid "prune remotes after fetching"
+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"
+msgstr "thêm nhánh"
 
 #: builtin/remote.c:1414
 msgid "no remote specified"
 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"
+
+#: builtin/remote.c:1438
+msgid "add URL"
+msgstr "thêm URL"
+
+#: builtin/remote.c:1440
+msgid "delete URLs"
+msgstr "xóa URLs"
+
 #: builtin/remote.c:1447
 msgid "--add --delete doesn't make sense"
 msgstr "--add --delete không hợp lý"
@@ -4483,6 +7668,56 @@ msgstr "Không tìm thấy URL như vậy: %s"
 msgid "Will not delete all non-push URLs"
 msgstr "Sẽ không xóa những địa chỉ URL không-push"
 
+#: builtin/remote.c:1569
+msgid "be verbose; must be placed before a subcommand"
+msgstr "chi tiết; phải được đặt trước một lệnh-con"
+
+#: builtin/replace.c:17
+msgid "git replace [-f] <object> <replacement>"
+msgstr "git replace [-f] <đối-tượng> <thay-thế>"
+
+#: builtin/replace.c:18
+msgid "git replace -d <object>..."
+msgstr "git replace -d <đối tượng>..."
+
+#: builtin/replace.c:19
+msgid "git replace -l [<pattern>]"
+msgstr "git replace -l [<mẫu>]"
+
+#: builtin/replace.c:118
+msgid "list replace refs"
+msgstr "liệt kê các refs thay thế"
+
+#: builtin/replace.c:119
+msgid "delete replace refs"
+msgstr "xóa tham chiếu (refs) thay thế"
+
+#: builtin/replace.c:120
+msgid "replace the ref if it exists"
+msgstr "thay thế tham chiếu (ref) nếu nó đã sẵn có"
+
+#: builtin/rerere.c:11
+msgid "git rerere [clear | forget path... | status | remaining | diff | gc]"
+msgstr "git rerere [clear | forget path... | status | remaining | diff | gc]"
+
+#: builtin/rerere.c:56
+msgid "register clean resolutions in index"
+msgstr "sổ ghi dọn sạch các phân giải trong bản mục lục"
+
+#: builtin/reset.c:25
+msgid ""
+"git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]"
+msgstr ""
+"git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]"
+
+#: builtin/reset.c:26
+msgid "git reset [-q] <commit> [--] <paths>..."
+msgstr "git reset [-q] <commit> [--] <các-đường-dẫn>..."
+
+#: builtin/reset.c:27
+msgid "git reset --patch [<commit>] [--] [<paths>...]"
+msgstr "git reset --patch [<commit>] [--] [<các-đường-dẫn>...]"
+
 #: builtin/reset.c:33
 msgid "mixed"
 msgstr "pha trộn"
@@ -4533,65 +7768,188 @@ msgstr "Không thể đọc bảng mục lục"
 msgid "Unstaged changes after reset:"
 msgstr "Những thay đổi bị bỏ trạng thái (stage) sau khi reset:"
 
-#: builtin/reset.c:223
-#, c-format
-msgid "Cannot do a %s reset in the middle of a merge."
-msgstr "Không thể thực hiện một %s reset ở giữa của quá trình hòa trộn."
+#: builtin/reset.c:223
+#, c-format
+msgid "Cannot do a %s reset in the middle of a merge."
+msgstr "Không thể thực hiện một %s reset ở giữa của quá trình hòa trộn."
+
+#: builtin/reset.c:238
+msgid "be quiet, only report errors"
+msgstr "làm việc ở chế độ im lặng, chỉ hiển thị khi có lỗi"
+
+#: builtin/reset.c:240
+msgid "reset HEAD and index"
+msgstr "đặt lại (reset) HEAD và bảng mục lục"
+
+#: builtin/reset.c:241
+msgid "reset only HEAD"
+msgstr "chỉ đặt lại (reset) HEAD"
+
+#: builtin/reset.c:243 builtin/reset.c:245
+msgid "reset HEAD, index and working tree"
+msgstr "đặt lại HEAD, bảng mục lục và cây làm việc"
+
+#: builtin/reset.c:247
+msgid "reset HEAD but keep local changes"
+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'."
+
+#: builtin/reset.c:308
+msgid "--patch is incompatible with --{hard,mixed,soft}"
+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>'."
+
+#: builtin/reset.c:319
+#, c-format
+msgid "Cannot do %s reset with paths."
+msgstr "Không thể thực hiện lệnh %s reset với các đường dẫn."
+
+#: builtin/reset.c:331
+#, c-format
+msgid "%s reset is not allowed in a bare repository"
+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'."
+
+#: builtin/rev-parse.c:339
+msgid "git rev-parse --parseopt [options] -- [<args>...]"
+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ố"
+
+#: builtin/rev-parse.c:346
+msgid "stop parsing after the first non-option argument"
+msgstr "dừng phân tích sau đối số đầu tiên không có tùy chọn"
+
+#: 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 [các-tùy-chọn] -- [<đ.số>...]\n"
+"   or: git rev-parse --sq-quote [<đ.số>...]\n"
+"   or: git rev-parse [các-tùy-chọn] [<đ.số>...]\n"
+"\n"
+"Chạy lệnh \"git rev-parse --parseopt -h\" để có thêm thông tin về cách dùng."
+
+#: builtin/revert.c:22
+msgid "git revert [options] <commit-ish>"
+msgstr "git revert [các-tùy-chọn] <commit-ish>"
+
+#: builtin/revert.c:23
+msgid "git revert <subcommand>"
+msgstr "git revert <lệnh-con>"
+
+#: builtin/revert.c:28
+msgid "git cherry-pick [options] <commit-ish>"
+msgstr "git cherry-pick [các-tùy-chọn] <commit-ish>"
+
+#: builtin/revert.c:29
+msgid "git cherry-pick <subcommand>"
+msgstr "git cherry-pick <lệnh-con>"
+
+#: builtin/revert.c:70 builtin/revert.c:92
+#, c-format
+msgid "%s: %s cannot be used with %s"
+msgstr "%s: %s không thể được sử dụng với %s"
+
+#: builtin/revert.c:103
+msgid "end revert or cherry-pick sequence"
+msgstr "kết thúc cherry-pick hay revert liên tiếp nhau"
+
+#: builtin/revert.c:104
+msgid "resume revert or cherry-pick sequence"
+msgstr "phục hồi lại cherry-pick hay revert liên tiếp nhau"
+
+#: builtin/revert.c:105
+msgid "cancel revert or cherry-pick sequence"
+msgstr "không cherry-pick hay revert liên tiếp nhau"
+
+#: builtin/revert.c:106
+msgid "don't automatically commit"
+msgstr "không commit một cách tự động."
+
+#: builtin/revert.c:107
+msgid "edit the commit message"
+msgstr "sửa lại chú thích cho commit"
 
-#: builtin/reset.c:297
-#, c-format
-msgid "Could not parse object '%s'."
-msgstr "không thể phân tích đối tượng '%s'."
+#: builtin/revert.c:110
+msgid "parent number"
+msgstr "số của cha mẹ"
 
-#: builtin/reset.c:302
-msgid "--patch is incompatible with --{hard,mixed,soft}"
-msgstr "--patch xung khắc với --{hard,mixed,soft}"
+#: builtin/revert.c:112
+msgid "merge strategy"
+msgstr "chiến lược hòa trộn"
 
-#: builtin/reset.c:311
-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>'."
+#: builtin/revert.c:113
+msgid "option"
+msgstr "tùy chọn"
 
-#: builtin/reset.c:313
-#, c-format
-msgid "Cannot do %s reset with paths."
-msgstr "Không thể thực hiện lệnh %s reset với các đường dẫn."
+#: builtin/revert.c:114
+msgid "option for merge strategy"
+msgstr "tùy chọn cho chiến lược hòa trộn"
 
-#: builtin/reset.c:325
-#, c-format
-msgid "%s reset is not allowed in a bare repository"
-msgstr "%s reset không được phép trên kho bare (trên máy chủ)"
+#: builtin/revert.c:125
+msgid "append commit name"
+msgstr "nối thêm tên lần chuyển giao (commit)"
 
-#: builtin/reset.c:341
-#, 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'."
+#: builtin/revert.c:126
+msgid "allow fast-forward"
+msgstr "cho phép fast-forward"
 
-#: builtin/revert.c:70
-#: builtin/revert.c:92
-#, c-format
-msgid "%s: %s cannot be used with %s"
-msgstr "%s: %s không thể được sử dụng với %s"
+#: builtin/revert.c:127
+msgid "preserve initially empty commits"
+msgstr "cấm khởi tạo lần chuyển giao trống rỗng"
 
-#: builtin/revert.c:131
+#: builtin/revert.c:128
+msgid "allow commits with empty messages"
+msgstr "chấp nhận chuyển giao (commit) mà không ghi chú gì"
+
+#: builtin/revert.c:129
+msgid "keep redundant, empty commits"
+msgstr "giữ lại các lần chuyển giao dư thừa, rỗng"
+
+#: builtin/revert.c:133
 msgid "program error"
 msgstr "lỗi chương trình"
 
-#: builtin/revert.c:221
+#: builtin/revert.c:223
 msgid "revert failed"
 msgstr "revert gặp lỗi"
 
-#: builtin/revert.c:236
+#: builtin/revert.c:238
 msgid "cherry-pick failed"
 msgstr "cherry-pick gặp lỗi"
 
+#: builtin/rm.c:14
+msgid "git rm [options] [--] <file>..."
+msgstr "git rm [các-tùy-chọn] [--] <tập-tin>..."
+
 #: builtin/rm.c:109
 #, 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ử dụng -f để ép buộc gỡ bỏ)"
+"`%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
 #, c-format
@@ -4599,8 +7957,8 @@ 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ử dụng --cached để giữ tập tin, hoặc -f để ép buộc gỡ bỏ)"
+"`%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
 #, c-format
@@ -4608,28 +7966,244 @@ 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ử dụng --cached để giữ tập tin, hoặc -f để ép buộc gỡ bỏ)"
+"`%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
+msgid "do not list removed files"
+msgstr "không liệt kê các tập tin đã gỡ bỏ"
+
+#: builtin/rm.c:135
+msgid "only remove from the index"
+msgstr "chỉ gỡ bỏ từ mục lục"
+
+#: builtin/rm.c:136
+msgid "override the up-to-date check"
+msgstr "ghi đè lên kiểm tra cập nhật"
+
+#: builtin/rm.c:137
+msgid "allow recursive removal"
+msgstr "cho phép gỡ bỏ đệ qui"
+
+#: builtin/rm.c:139
+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
 #, 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
 #, c-format
 msgid "git rm: unable to remove %s"
 msgstr "git rm: không thể gỡ bỏ %s"
 
+#: builtin/shortlog.c:13
+msgid "git shortlog [-n] [-s] [-e] [-w] [rev-opts] [--] [<commit-id>... ]"
+msgstr "git shortlog [-n] [-s] [-e] [-w] [rev-opts] [--] [<commit-id>... ]"
+
 #: builtin/shortlog.c:157
 #, c-format
 msgid "Missing author: %s"
 msgstr "Thiếu tên tác giả: %s"
 
+#: builtin/shortlog.c:253
+msgid "sort output according to the number of commits per author"
+msgstr "sắp xếp kết xuất tuân theo số lượng chuyển giao trên mỗi tác giả"
+
+#: builtin/shortlog.c:255
+msgid "Suppress commit descriptions, only provides commit count"
+msgstr "Chặn mọi mô tả lần chuyển giao, chỉ đưa ra số lượng lần chuyển giao"
+
+#: builtin/shortlog.c:257
+msgid "Show the email address of each author"
+msgstr "Hiển thị thư điện tử cho từng tác giả"
+
+#: builtin/shortlog.c:258
+msgid "w[,i1[,i2]]"
+msgstr "w[,i1[,i2]]"
+
+#: builtin/shortlog.c:259
+msgid "Linewrap output"
+msgstr "Ngắt dòng khi quá dài"
+
+#: 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[=<khi>] | --no-color] [--sparse] [--more=<n> | --list | --"
+"independent | --merge-base] [--no-name | --sha1-name] [--topics] [(<rev> | "
+"<glob>)...]"
+
+#: builtin/show-branch.c:10
+msgid "git show-branch (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]"
+msgstr "git show-branch (-g|--reflog)[=<n>[,<nền>]] [--list] [<ref>]"
+
+#: builtin/show-branch.c:651
+msgid "show remote-tracking and local branches"
+msgstr "hiển thị các nhánh remote-tracking và nội bộ"
+
+#: builtin/show-branch.c:653
+msgid "show remote-tracking branches"
+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"
+
+#: builtin/show-branch.c:657
+msgid "show <n> more commits after the common ancestor"
+msgstr "hiển thị thêm <n> lần chuyển giao sau cha mẹ chung"
+
+#: builtin/show-branch.c:659
+msgid "synonym to more=-1"
+msgstr "đồng nghĩa với more=-1"
+
+#: builtin/show-branch.c:660
+msgid "suppress naming strings"
+msgstr "chặn các chuỗi đặt tên"
+
+#: builtin/show-branch.c:662
+msgid "include the current branch"
+msgstr "bao gồm nhánh hiện hành"
+
+#: builtin/show-branch.c:664
+msgid "name commits with their object names"
+msgstr "đặt tên các lần chuyển giao bằng các tên của đối tượng của chúng"
+
+#: builtin/show-branch.c:666
+msgid "show possible merge bases"
+msgstr "hiển thị mọi cơ sở có thể dùng để hòa trộn"
+
+#: builtin/show-branch.c:668
+msgid "show refs unreachable from any other ref"
+msgstr "hiển thị các tham chiếu không thể được đọc bởi bất kỳ tham chiếu khác"
+
+#: builtin/show-branch.c:670
+msgid "show commits in topological order"
+msgstr "hiển thị các lần chuyển giao theo thứ tự tôpô"
+
+#: builtin/show-branch.c:672
+msgid "show only commits not on the first branch"
+msgstr "chỉ hiển thị các lần chuyển giao không nằm trên nhánh đầu tiên"
+
+#: builtin/show-branch.c:674
+msgid "show merges reachable from only one tip"
+msgstr "hiển thị các lần hòa trộn có thể đọc được chỉ từ một đầu mút"
+
+#: builtin/show-branch.c:676
+msgid "show commits where no parent comes before its children"
+msgstr "hiển thị các lần chuyển giao nơi mà cha mẹ đến trước con của nó"
+
+#: builtin/show-branch.c:678
+msgid "<n>[,<base>]"
+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)"
+
+#: 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] [--] [mẫu*] "
+
+#: builtin/show-ref.c:11
+msgid "git show-ref --exclude-existing[=pattern] < ref-list"
+msgstr "git show-ref --exclude-existing[=mẫu] < ref-list"
+
+#: builtin/show-ref.c:182
+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
+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
+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
+msgid "show the HEAD reference"
+msgstr "hiển thị tham chiếu của HEAD"
+
+#: builtin/show-ref.c:191
+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
+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
+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
+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 ở "
+"kho nội bộ"
+
+#: builtin/symbolic-ref.c:7
+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
+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)"
+
+#: builtin/symbolic-ref.c:39
+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
+msgid "reason"
+msgstr "lý do"
+
+#: builtin/symbolic-ref.c:40 builtin/update-ref.c:18
+msgid "reason of the update"
+msgstr "lý do cập nhật"
+
+#: 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 <key-id>] [-f] [-m <msg>|-F <tập-tin>] <tên-thẻ> [<head>]"
+
+#: builtin/tag.c:23
+msgid "git tag -d <tagname>..."
+msgstr "git tag -d <tên-thẻ>..."
+
+#: builtin/tag.c:24
+msgid ""
+"git tag -l [-n[<num>]] [--contains <commit>] [--points-at <object>] \n"
+"\t\t[<pattern>...]"
+msgstr ""
+"git tag -l [-n[<num>]] [--contains <commit>] [--points-at <đối-tượng>] \n"
+"\t\t[<mẫu>...]"
+
+#: builtin/tag.c:26
+msgid "git tag -v <tagname>..."
+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
@@ -4639,17 +8213,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 ""
@@ -4670,13 +8244,15 @@ msgid ""
 "\n"
 "#\n"
 "# Write a tag message\n"
-"# Lines starting with '#' will be kept; you may remove them yourself if you want to.\n"
+"# Lines starting with '#' will be kept; you may remove them yourself if you "
+"want to.\n"
 "#\n"
 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 nếu muốn.\n"
+"# 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"
 
 #: builtin/tag.c:298
@@ -4711,7 +8287,63 @@ 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"
+msgstr "chỉ liệt kê tên các thẻ"
+
+#: builtin/tag.c:449
+msgid "print <n> lines of each tag message"
+msgstr "hiển thị <n> dòng cho mỗi ghi chú"
+
+#: builtin/tag.c:451
+msgid "delete tags"
+msgstr "xóa thẻ"
+
+#: builtin/tag.c:452
+msgid "verify tags"
+msgstr "thẩm tra thẻ"
+
+#: builtin/tag.c:454
+msgid "Tag creation options"
+msgstr "Tùy chọn tạo tag"
+
+#: builtin/tag.c:456
+msgid "annotated tag, needs a message"
+msgstr "để chú giải cho thẻ, cần một lời ghi chú"
+
+#: builtin/tag.c:458
+msgid "tag message"
+msgstr "tin nhắn cho thẻ (tag)"
+
+#: builtin/tag.c:460
+msgid "annotated and GPG-signed tag"
+msgstr "thẻ chú giải và ký kiểu GPG"
+
+#: builtin/tag.c:464
+msgid "use another key to sign the tag"
+msgstr "dùng kháo khác để ký thẻ"
+
+#: builtin/tag.c:465
+msgid "replace the tag if exists"
+msgstr "thay thế nếu tag đó đã có trước"
+
+#: builtin/tag.c:466
+msgid "show tag list in columns"
+msgstr "hiển thị danh sách thẻ trong các cột"
+
+#: builtin/tag.c:468
+msgid "Tag listing options"
+msgstr "Các tùy chọn liệt kê thẻ"
+
+#: builtin/tag.c:471
+msgid "print only tags that contain the commit"
+msgstr "chỉ hiển thị những nhánh mà nó chứa lần chuyển giao"
+
+#: builtin/tag.c:477
+msgid "print only tags of the object"
+msgstr "chỉ hiển thị các thẻ của đối tượng"
 
 #: builtin/tag.c:506
 msgid "--column and -n are incompatible"
@@ -4740,12 +8372,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
@@ -4760,28 +8392,188 @@ 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 "Thẻ đã cập nhật `%s' (cũ là %s)\n"
 
-#: 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."
+#: builtin/update-index.c:401
+msgid "git update-index [options] [--] [<file>...]"
+msgstr "git update-index [các-tùy-chọn] [<tập-tin>...]"
 
-#: parse-options.h:133
-#: parse-options.h:235
-msgid "n"
-msgstr "n"
+#: builtin/update-index.c:717
+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"
 
-#: parse-options.h:141
-msgid "time"
-msgstr "thời-gian"
+#: builtin/update-index.c:720
+msgid "refresh: ignore submodules"
+msgstr "refresh: lờ đi mô-đun-con"
 
-#: parse-options.h:149
-msgid "file"
-msgstr "tập-tin"
+#: builtin/update-index.c:723
+msgid "do not ignore new files"
+msgstr "không bỏ qua các tập tin mới tạo"
 
-#: parse-options.h:151
-msgid "when"
-msgstr "khi"
+#: builtin/update-index.c:725
+msgid "let files replace directories and vice-versa"
+msgstr "để các tập tin thay thế các thư mục và `vice-versa'"
+
+#: builtin/update-index.c:727
+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
+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
+msgid "refresh stat information"
+msgstr "lấy lại thông tin thống kê"
+
+#: builtin/update-index.c:736
+msgid "like --refresh, but ignore assume-unchanged setting"
+msgstr "giống --refresh, nhưng bỏ qua các cài đặt `assume-unchanged'"
+
+#: builtin/update-index.c:740
+msgid "<mode> <object> <path>"
+msgstr "<mode> <đối tượng> <đường dẫn>"
+
+#: builtin/update-index.c:741
+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
+msgid "(+/-)x"
+msgstr "(+/-)x"
+
+#: builtin/update-index.c:746
+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
+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
+msgid "clear assumed-unchanged bit"
+msgstr "xóa bít  assumed-unchanged"
+
+#: builtin/update-index.c:756
+msgid "mark files as \"index-only\""
+msgstr "đánh dấu các tập tin là `chỉ-đọc'"
+
+#: builtin/update-index.c:759
+msgid "clear skip-worktree bit"
+msgstr "xóa bít skip-worktree"
+
+#: builtin/update-index.c:762
+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
+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
+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
+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
+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
+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
+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
+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
+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
+msgid "(for porcelains) forget saved unresolved conflicts"
+msgstr "(cho `porcelains') quên các xung đột chưa được giải quyết đã ghi"
+
+#: builtin/update-index.c:793
+msgid "write index in this format"
+msgstr "ghi mục lục ở định dạng này"
+
+#: builtin/update-ref.c:7
+msgid "git update-ref [options] -d <refname> [<oldval>]"
+msgstr "git update-ref [các-tùy-chọn] -d <refname> [<biến-cũ>]"
+
+#: builtin/update-ref.c:8
+msgid "git update-ref [options]    <refname> <newval> [<oldval>]"
+msgstr "git update-ref [các-tùy-chọn]    <refname> <biến-mới> [<biến-cũ>]"
+
+#: builtin/update-ref.c:19
+msgid "delete the reference"
+msgstr "xóa tham chiếu"
+
+#: builtin/update-ref.c:21
+msgid "update <refname> not the one it points to"
+msgstr "cập nhật <tên-tham-chiếu> không phải cái nó chỉ tới"
+
+#: 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 "cập nhật các tập tin thông tin từ điểm xuất phát"
+
+#: builtin/verify-pack.c:56
+msgid "git verify-pack [-v|--verbose] [-s|--stat-only] <pack>..."
+msgstr "git verify-pack [-v|--verbose] [-s|--stat-only] <gói>..."
+
+#: builtin/verify-pack.c:66
+msgid "verbose"
+msgstr "chi tiết"
+
+#: builtin/verify-pack.c:68
+msgid "show statistics only"
+msgstr "chỉ hiển thị thống kê"
+
+#: builtin/verify-tag.c:17
+msgid "git verify-tag [-v|--verbose] <tag>..."
+msgstr "git verify-tag [-v|--verbose] <thẻ>..."
+
+#: builtin/verify-tag.c:73
+msgid "print tag contents"
+msgstr "hiển thị nội dung của thẻ"
+
+#: builtin/write-tree.c:13
+msgid "git write-tree [--missing-ok] [--prefix=<prefix>/]"
+msgstr "git write-tree [--missing-ok] [--prefix=<tiền-tố>/]"
+
+#: builtin/write-tree.c:26
+msgid "<prefix>/"
+msgstr "<iền tố>/"
+
+#: builtin/write-tree.c:27
+msgid "write tree object for a subdirectory <prefix>"
+msgstr "ghi đối tượng cây (tree) cho <tiền tố> thư mục con"
+
+#: builtin/write-tree.c:30
+msgid "only useful for debugging"
+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."
 
 #: parse-options.h:156
 msgid "no-op (backward compatibility)"
@@ -4813,7 +8605,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á»\99t nhánh hay các Ä\91Æ°á»\9dng dẫn tá»\9di cây làm việc"
+msgstr "Checkout má»\99t nhánh hay các Ä\91Æ°á»\9dng dẫn tá»\9bi cây làm việc"
 
 #: common-cmds.h:12
 msgid "Clone a repository into a new directory"
@@ -4825,7 +8617,9 @@ msgstr "Ghi các thay đổi vào kho chứa"
 
 #: common-cmds.h:14
 msgid "Show changes between commits, commit and working tree, etc"
-msgstr "Hiển thị các thay đổi giữa những lần chuyển giao (commit), commit và cây làm việc, v.v.."
+msgstr ""
+"Hiển thị các thay đổi giữa những lần chuyển giao (commit), commit và cây làm "
+"việc, v.v.."
 
 #: common-cmds.h:15
 msgid "Download objects and refs from another repository"
@@ -4837,7 +8631,8 @@ msgstr "In ra những dòng khớp với một mẫu"
 
 #: common-cmds.h:17
 msgid "Create an empty git repository or reinitialize an existing one"
-msgstr "Tạo một kho git trống rỗng hay khởi tạo lại một kho đã tồn tại từ trước"
+msgstr ""
+"Tạo một kho git trống rỗng hay khởi tạo lại một kho đã tồn tại từ trước"
 
 #: common-cmds.h:18
 msgid "Show commit logs"
@@ -4845,7 +8640,9 @@ msgstr "hiển thị nhật ký các lần commit (chuyển giao)"
 
 #: common-cmds.h:19
 msgid "Join two or more development histories together"
-msgstr "Hợp nhất hai hay nhiều hơn lịch sử của các nhà phát triển phần mềm lại với nhau"
+msgstr ""
+"Hợp nhất hai hay nhiều hơn lịch sử của các nhà phát triển phần mềm lại với "
+"nhau"
 
 #: common-cmds.h:20
 msgid "Move or rename a file, a directory, or a symlink"
@@ -4857,11 +8654,13 @@ msgstr "Fetch (lấy về) và hòa trộng với kho khác hay nhánh nội b
 
 #: common-cmds.h:22
 msgid "Update remote refs along with associated objects"
-msgstr "Cập nhật tham chiếu (refs) máy chủ cùng với các đối tượng liên quan đến nó"
+msgstr ""
+"Cập nhật tham chiếu (refs) máy chủ cùng với các đối tượng liên quan đến nó"
 
 #: common-cmds.h:23
 msgid "Forward-port local commits to the updated upstream head"
-msgstr "Forward-port những lần chuyển giao nội bộ tới head dòng ngược đã cập nhật"
+msgstr ""
+"Forward-port những lần chuyển giao nội bộ tới head thượng nguồn đã cập nhật"
 
 #: common-cmds.h:24
 msgid "Reset current HEAD to the specified state"
@@ -4881,7 +8680,9 @@ msgstr "Hiển thị trạng thái cây làm việc"
 
 #: common-cmds.h:28
 msgid "Create, list, delete or verify a tag object signed with GPG"
-msgstr "Tạo, liệt kê, xóa hay xác thực một đối tượng thẻ (tag) mà nó được ký sử dụng GPG"
+msgstr ""
+"Tạo, liệt kê, xóa hay xác thực một đối tượng thẻ (tag) mà nó được ký sử dụng "
+"GPG"
 
 #: git-am.sh:50
 msgid "You need to set your committer info first"
@@ -4898,13 +8699,15 @@ msgstr ""
 #: git-am.sh:105
 #, sh-format
 msgid ""
-"When you have resolved this problem run \"$cmdline --resolved\".\n"
-"If you would prefer to skip this patch, instead run \"$cmdline --skip\".\n"
-"To restore the original branch and stop patching run \"$cmdline --abort\"."
+"When you have resolved this problem, run \"$cmdline --resolved\".\n"
+"If you prefer to skip this patch, run \"$cmdline --skip\" instead.\n"
+"To restore the original branch and stop patching, run \"$cmdline --abort\"."
 msgstr ""
 "Khi bạn cần giải quyết vấn đề này hãy chạy lệnh \"$cmdline --resolved\".\n"
-"Nếu bạn có ý định bỏ qua miếng vá, thay vào đó bạn chạy \"$cmdline --skip\".\n"
-"Để phục hồi lại thành nhánh nguyên bản và dừng việc vá lại thì chạy \"$cmdline --abort\"."
+"Nếu bạn có ý định bỏ qua miếng vá, thay vào đó bạn chạy \"$cmdline --skip"
+"\".\n"
+"Để phục hồi lại thành nhánh nguyên thủy và dừng việc vá lại thì chạy "
+"\"$cmdline --abort\"."
 
 #: git-am.sh:121
 msgid "Cannot fall back to three-way merge."
@@ -4914,6 +8717,11 @@ msgstr "Đang trở lại để hòa trộn kiểu 'three-way'."
 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'."
 
+#: git-am.sh:139
+msgid "Using index info to reconstruct a base tree..."
+msgstr ""
+"Sử dụng thông tin trong bảng mục lục để cấu trúc lại một cây (tree) cơ sở..."
+
 #: git-am.sh:154
 msgid ""
 "Did you hand edit your patch?\n"
@@ -4926,42 +8734,51 @@ msgstr ""
 msgid "Falling back to patching base and 3-way merge..."
 msgstr "Đang trở lại để vá cơ sở và '3-way merge'..."
 
-#: git-am.sh:275
+#: git-am.sh:179
+msgid "Failed to merge in the changes."
+msgstr "Gặp lỗi khi trộn vào các thay đổi."
+
+#: git-am.sh:274
 msgid "Only one StGIT patch series can be applied at once"
 msgstr "Chỉ có một sê-ri miếng vá StGIT được áp dụng một lúc"
 
-#: git-am.sh:362
+#: git-am.sh:361
 #, sh-format
 msgid "Patch format $patch_format is not supported."
 msgstr "Định dạng miếng vá $patch_format không được hỗ trợ."
 
-#: git-am.sh:364
+#: git-am.sh:363
 msgid "Patch format detection failed."
 msgstr "Dò tìm định dạng miếng vá gặp lỗi."
 
-#: git-am.sh:418
-msgid "-d option is no longer supported.  Do not use."
-msgstr "Tùy chọn -d không còn được hỗ trợ nữa. Xin đừng sử dụng."
+#: git-am.sh:389
+msgid ""
+"The -b/--binary option has been a no-op for long time, and\n"
+"it will be removed. Please do not use it anymore."
+msgstr ""
+"Tùy chọn -b/--binary đã không dùng từ lâu rồi, và\n"
+"nó sẽ được bỏ đi. Xin đừng sử dụng nó thêm nữa."
 
-#: git-am.sh:481
+#: git-am.sh:477
 #, sh-format
 msgid "previous rebase directory $dotest still exists but mbox given."
 msgstr "thư mục rebase trước $dotest vẫn chưa sẵn sàng nhưng mbox được đưa ra."
 
-#: git-am.sh:486
+#: git-am.sh:482
 msgid "Please make up your mind. --skip or --abort?"
 msgstr "Xin hãy rõ ràng. --skip hay --abort?"
 
-#: git-am.sh:513
+#: git-am.sh:509
 msgid "Resolve operation not in progress, we are not resuming."
-msgstr "Thao tác phân giải không đang được tiến hành, chúng ta không phục hồi lại."
+msgstr ""
+"Thao tác phân giải không đang được tiến hành, chúng ta không phục hồi lại."
 
-#: git-am.sh:579
+#: git-am.sh:575
 #, sh-format
 msgid "Dirty index: cannot apply patches (dirty: $files)"
 msgstr "Bảng mục lục sai: không thể áp dụng các miếng vá (sai: $files)"
 
-#: git-am.sh:671
+#: git-am.sh:679
 #, sh-format
 msgid ""
 "Patch is empty.  Was it split wrong?\n"
@@ -4969,61 +8786,76 @@ msgid ""
 "To restore the original branch and stop patching run \"$cmdline --abort\"."
 msgstr ""
 "Miếng vá trống rỗng.  Nó đã bị chia cắt sai phải không?\n"
-"Nếu bạn thích bỏ qua miếng vá này, hãy chạy lệnh sau để thay thế \"$cmdline --skip\".\n"
-"Để phục hồi lại nhánh nguyên bản và dừng vá lại hãy chạy lệnh \"$cmdline --abort\"."
+"Nếu bạn thích bỏ qua miếng vá này, hãy chạy lệnh sau để thay thế \"$cmdline "
+"--skip\".\n"
+"Để phục hồi lại nhánh nguyên thủy và dừng vá lại hãy chạy lệnh \"$cmdline --"
+"abort\"."
 
-#: git-am.sh:708
+#: git-am.sh:706
 msgid "Patch does not have a valid e-mail address."
 msgstr "Miếng vá không có địa chỉ e-mail hợp lệ."
 
-#: git-am.sh:755
+#: git-am.sh:753
 msgid "cannot be interactive without stdin connected to a terminal."
-msgstr "không thể được tương tác mà không có stdin kết nối với một thiết bị cuối"
+msgstr ""
+"không thể được tương tác mà không có stdin kết nối với một thiết bị cuối"
 
-#: git-am.sh:759
+#: git-am.sh:757
 msgid "Commit Body is:"
 msgstr "Thân của lần chuyển giao (commit) là:"
 
 #. TRANSLATORS: Make sure to include [y], [n], [e], [v] and [a]
 #. in your translation. The program will only accept English
 #. input at this point.
-#: git-am.sh:766
+#: git-am.sh:764
 msgid "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all "
-msgstr "Áp dụng? đồng ý [y]/không [n]/chỉnh sửa [e]/hiển thị miếng [v]á/đồng ý tất cả [a]"
+msgstr ""
+"Áp dụng? đồng ý [y]/không [n]/chỉnh sửa [e]/hiển thị miếng [v]á/đồng ý tất "
+"cả [a] "
 
-#: git-am.sh:802
+#: git-am.sh:800
 #, sh-format
 msgid "Applying: $FIRSTLINE"
 msgstr "Đang áp dụng (miếng vá): $FIRSTLINE"
 
-#: git-am.sh:823
+#: git-am.sh:821
 msgid ""
 "No changes - did you forget to use 'git add'?\n"
 "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."
+"đã 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."
 
-#: git-am.sh:831
+#: git-am.sh:829
 msgid ""
 "You still have unmerged paths in your index\n"
 "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:847
+#: git-am.sh:845
 msgid "No changes -- Patch already applied."
 msgstr "Không thay đổi gì cả -- Miếng vá đã được áp dụng rồi."
 
-#: git-am.sh:857
+#: git-am.sh:855
 #, sh-format
 msgid "Patch failed at $msgnum $FIRSTLINE"
 msgstr "Vá gặp lỗi tại $msgnum $FIRSTLINE"
 
-#: git-am.sh:873
+#: git-am.sh:858
+#, sh-format
+msgid ""
+"The copy of the patch that failed is found in:\n"
+"   $dotest/patch"
+msgstr ""
+"Bản sao chép của miếng vá mà nó gặp lỗi thì được tìm thấy trong:\n"
+"   $dotest/patch"
+
+#: git-am.sh:876
 msgid "applying to an empty history"
 msgstr "áp dụng vào một lịch sử trống rỗng"
 
@@ -5054,8 +8886,11 @@ msgstr "HEAD sai - Tôi cần một HEAD"
 
 #: git-bisect.sh:130
 #, sh-format
-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ệ>'."
+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ệ>'."
 
 #: git-bisect.sh:140
 msgid "won't bisect on seeked tree"
@@ -5086,20 +8921,21 @@ 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.
 #: git-bisect.sh:273
 msgid "Warning: bisecting only with a bad commit."
-msgstr "Cảnh báo: chỉ thực hiện việc bisect với một lần chuyển giao (commit) sai."
+msgstr ""
+"Cảnh báo: chỉ thực hiện việc bisect với một lần chuyển giao (commit) sai."
 
 #. TRANSLATORS: Make sure to include [Y] and [n] in your
 #. translation. The program will only accept English input
 #. at this point.
 #: git-bisect.sh:279
 msgid "Are you sure [Y/n]? "
-msgstr "Bạn có chắc chắn chưa [Y/n]?"
+msgstr "Bạn có chắc chắn chưa [Y/n]? "
 
 #: git-bisect.sh:289
 msgid ""
@@ -5116,11 +8952,11 @@ msgid ""
 "(You can use \"git bisect bad\" and \"git bisect good\" for that.)"
 msgstr ""
 "Bạn cần bắt đầu bằng lệnh \"git bisect start\".\n"
-"Bạn sau đó cần phải chỉ cho tôi ít nhất một điểm xét duyệt đúng và một điểm sai.\n"
+"Bạn sau đó cần phải chỉ cho tôi ít nhất một điểm xét duyệt đúng và một điểm "
+"sai.\n"
 "(Bạn có thể sử dụng \"git bisect bad\" và \"git bisect good\" cho chúng.)"
 
-#: git-bisect.sh:347
-#: git-bisect.sh:474
+#: git-bisect.sh:347 git-bisect.sh:474
 msgid "We are not bisecting."
 msgstr "Chúng tôi không bisect."
 
@@ -5135,8 +8971,8 @@ msgid ""
 "Could not check out original HEAD '$branch'.\n"
 "Try 'git bisect reset <commit>'."
 msgstr ""
-"Không thể check out original HEAD '$branch'.\n"
-"Hãy thử 'git bisect reset <commit>'."
+"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"
@@ -5189,16 +9025,20 @@ 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."
-msgstr "Full là không thể thực hiện bởi vì bạn có những tập tin chưa được hòa trộn."
+msgstr ""
+"Full là không thể thực hiện bởi vì bạn có những tập tin chưa được hòa trộn."
 
 #: git-pull.sh:197
 msgid "updating an unborn branch with changes added to the index"
-msgstr "đang cập nhật một nhánh chưa được sinh ra với các thay đổi được thêm vào bảng mục lục"
+msgstr ""
+"đang cập nhật một nhánh chưa được sinh ra với các thay đổi được thêm vào "
+"bảng mục lục"
 
 #. The fetch involved updating the current branch.
 #. The working tree and the index file is still based on the
@@ -5223,9 +9063,142 @@ msgstr "Không thể hòa trộn nhiều nhánh và trong một head trống r
 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"
 
+#: 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"
+"To check out the original branch and stop rebasing, run \"git rebase --abort"
+"\"."
+msgstr ""
+"Khi bạn cần giải quyết vấn đề này hãy chạy lệnh \"git rebase --continue\".\n"
+"Nếu bạn có ý định bỏ qua miếng vá, thay vào đó bạn chạy \"git rebase --skip"
+"\".\n"
+"Để phục hồi lại thành nhánh nguyên thủy và dừng việc vá lại thì chạy \"git "
+"rebase --abort\"."
+
+#: 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."
+
+#: git-rebase.sh:165
+msgid "It looks like git-am is in progress. Cannot rebase."
+msgstr ""
+"Hình như đang trong quá trình thực hiện lệnh git-am. Không thể chạy lệnh "
+"rebase."
+
+#: git-rebase.sh:296
+msgid "The --exec option must be used with the --interactive option"
+msgstr "Tùy chọn --exec phải được sử dụng cùng với tùy chọn --interactive"
+
+#: git-rebase.sh:301
+msgid "No rebase in progress?"
+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 "
+"sử) tương tác."
+
+#: git-rebase.sh:319
+msgid "Cannot read HEAD"
+msgstr "Không thể đọc HEAD"
+
+#: git-rebase.sh:322
+msgid ""
+"You must edit all merge conflicts and then\n"
+"mark them as resolved using git add"
+msgstr ""
+"Bạn phải sửa tất cả các lần hòa trộn xung đột và sau\n"
+"đó đánh dấu chúng là cần xử lý sử dụng lệnh git add"
+
+#: git-rebase.sh:340
+#, sh-format
+msgid "Could not move back to $head_name"
+msgstr "Không thể quay trở lại $head_name"
+
+#: git-rebase.sh:359
+#, sh-format
+msgid ""
+"It seems that there is already a $state_dir_base directory, and\n"
+"I wonder if you are in the middle of another rebase.  If that is the\n"
+"case, please try\n"
+"\t$cmd_live_rebase\n"
+"If that is not the case, please\n"
+"\t$cmd_clear_stale_rebase\n"
+"and run me again.  I am stopping in case you still have something\n"
+"valuable there."
+msgstr ""
+"Hình như là ở đây sẵn có một thư mục $state_dir_base directory, và\n"
+"Tôi tự hỏi có phải bạn đang ở giữa một lệnh rebase khác.  Nếu đúng là\n"
+"như vậy, xin hãy thử\n"
+"\t$cmd_live_rebase\n"
+"Nếu không phải thế, hãy thử\n"
+"\t$cmd_clear_stale_rebase\n"
+"và chạy TÔI lần nữa.  TÔI  dừng lại trong trường hợp bạn vẫn\n"
+"có một số thứ quý giá ở đây.\n"
+"\n"
+"TÔI: là lệnh bạn vừa gọi!"
+
+#: git-rebase.sh:404
+#, sh-format
+msgid "invalid upstream $upstream_name"
+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"
+
+#: 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"
+
+#: git-rebase.sh:440
+#, sh-format
+msgid "Does not point to a valid commit: $onto_name"
+msgstr "Không chỉ đến một lần chuyển giao (commit) không hợp lệ: $onto_name"
+
+#: git-rebase.sh:463
+#, sh-format
+msgid "fatal: no such branch: $branch_name"
+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."
+
+#: git-rebase.sh:501
+#, sh-format
+msgid "Current branch $branch_name is up to date."
+msgstr "Nhánh hiện tại $branch_name đã được cập nhật rồi."
+
+#: git-rebase.sh:504
+#, sh-format
+msgid "Current branch $branch_name is up to date, rebase forced."
+msgstr "Nhánh hiện tại $branch_name đã được cập nhật rồi, lệnh rebase ép buộc."
+
+#: git-rebase.sh:515
+#, sh-format
+msgid "Changes from $mb to $onto:"
+msgstr "Thay đổi từ $mb thành $onto:"
+
+#. Detach HEAD and reset the tree
+#: git-rebase.sh:524
+msgid "First, rewinding head to replay your work on top of it..."
+msgstr ""
+"Trước tiên, di chuyển head để xem lại các công việc trên đỉnh của nó..."
+
+#: git-rebase.sh:532
+#, sh-format
+msgid "Fast-forwarded $branch_name to $onto_name."
+msgstr "Fast-forward $branch_name thành $onto_name."
+
 #: git-stash.sh:51
 msgid "git stash clear with parameters is unimplemented"
-msgstr "git stash clear với các tham số là chưa được thực hiện (không nhận đối số)"
+msgstr ""
+"git stash clear với các tham số là chưa được thực hiện (không nhận đối số)"
 
 #: git-stash.sh:74
 msgid "You do not have the initial commit yet"
@@ -5235,8 +9208,7 @@ msgstr "Bạn chưa còn có lần chuyển giao (commit) khởi tạo"
 msgid "Cannot save the current index state"
 msgstr "Không thể ghi lại trạng thái bảng mục lục hiện hành"
 
-#: git-stash.sh:123
-#: git-stash.sh:136
+#: git-stash.sh:123 git-stash.sh:136
 msgid "Cannot save the current worktree state"
 msgstr "Không thể ghi lại trạng thái cây-làm-việc hiện hành"
 
@@ -5289,7 +9261,7 @@ msgstr "Không thể gỡ bỏ các thay đổi cây-làm-việc"
 
 #: git-stash.sh:352
 msgid "No stash found."
-msgstr "Không tìm thấy stast nào."
+msgstr "Không tìm thấy stash nào."
 
 #: git-stash.sh:359
 #, sh-format
@@ -5331,125 +9303,132 @@ msgstr "Không thể ghi lại cây chỉ mục"
 msgid "Cannot unstage modified files"
 msgstr "Không thể bỏ trạng thía của các tập tin đã được sửa chữa"
 
-#: git-stash.sh:474
+#: git-stash.sh:475
 msgid "Index was not unstashed."
 msgstr "Bảng mục lục đã không được bỏ stash."
 
-#: git-stash.sh:491
+#: git-stash.sh:492
 #, sh-format
 msgid "Dropped ${REV} ($s)"
 msgstr "Đã hạ xuống ${REV} ($s)"
 
-#: git-stash.sh:492
+#: git-stash.sh:493
 #, sh-format
 msgid "${REV}: Could not drop stash entry"
 msgstr "${REV}: Không thể xóa bỏ mục stash"
 
-#: git-stash.sh:499
+#: git-stash.sh:500
 msgid "No branch name specified"
 msgstr "Chưa chỉ ra tên của nhánh"
 
-#: git-stash.sh:570
+#: git-stash.sh:571
 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:56
+#: git-submodule.sh:88
 #, 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'"
 
-#: git-submodule.sh:109
+#: git-submodule.sh:167
 #, 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'"
+msgstr ""
+"Không tìm thấy ánh xạ (mapping) mô-đun-con trong .gitmodules cho đường dẫn "
+"'$sm_path'"
 
-#: git-submodule.sh:150
+#: 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"
 
-#: git-submodule.sh:160
+#: 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\""
+msgstr ""
+"Gitdir '$a' là bộ phận của đường dẫn mô-đun-con '$b' hoặc \"vice versa\""
 
-#: git-submodule.sh:249
+#: git-submodule.sh:312
 #, 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 ./|../"
+msgstr ""
+"repo URL: '$repo' phải là đường dẫn tuyệt đối hoặc là bắt đầu bằng ./|../"
 
-#: git-submodule.sh:266
+#: git-submodule.sh:329
 #, 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"
 
-#: git-submodule.sh:270
+#: git-submodule.sh:333
 #, sh-format
 msgid ""
 "The following path is ignored by one of your .gitignore files:\n"
 "$sm_path\n"
 "Use -f if you really want to add it."
 msgstr ""
-"Các đường dẫn theo sau đây sẽ bị lờ đi bởi một trong các tập tin .gitignore của bạn:\n"
+"Các đường dẫn theo sau đây sẽ bị lờ đi bởi một trong các tập tin .gitignore "
+"của bạn:\n"
 "$sm_path\n"
 "Sử dụng -f nếu bạn thực sự muốn thêm nó vào."
 
-#: git-submodule.sh:281
+#: git-submodule.sh:344
 #, 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"
 
-#: git-submodule.sh:283
+#: git-submodule.sh:346
 #, 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ệ"
 
-#: git-submodule.sh:297
+#: git-submodule.sh:360
 #, sh-format
 msgid "Unable to checkout submodule '$sm_path'"
 msgstr "Không thể checkout mô-đun con '$sm_path'"
 
-#: git-submodule.sh:302
+#: git-submodule.sh:365
 #, sh-format
 msgid "Failed to add submodule '$sm_path'"
 msgstr "Gặp lỗi khi thêm mô-đun con '$sm_path'"
 
-#: git-submodule.sh:307
+#: git-submodule.sh:370
 #, 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'"
 
-#: git-submodule.sh:349
+#: git-submodule.sh:413
 #, sh-format
 msgid "Entering '$prefix$sm_path'"
 msgstr "Đang nhập '$prefix$sm_path'"
 
-#: git-submodule.sh:363
+#: git-submodule.sh:427
 #, 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."
 
-#: git-submodule.sh:406
+#: git-submodule.sh:471
 #, 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"
+msgstr ""
+"Không tìm thấy url cho đường dẫn mô-đun-con '$sm_path' trong .gitmodules"
 
-#: git-submodule.sh:415
+#: git-submodule.sh:480
 #, 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'"
 
-#: git-submodule.sh:417
+#: git-submodule.sh:482
 #, 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'"
 
-#: git-submodule.sh:425
+#: git-submodule.sh:490
 #, 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'"
+msgstr ""
+"Gặp lỗi khi đăng ký chế độ cập nhật cho đường dẫn mô-đun-con '$sm_path'"
 
-#: git-submodule.sh:524
+#: git-submodule.sh:590
 #, sh-format
 msgid ""
 "Submodule path '$sm_path' not initialized\n"
@@ -5458,98 +9437,166 @@ 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'?"
 
-#: git-submodule.sh:537
+#: git-submodule.sh:603
 #, 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'"
+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'"
 
-#: git-submodule.sh:556
+#: git-submodule.sh:622
 #, 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'"
 
-#: git-submodule.sh:570
+#: git-submodule.sh:636
 #, 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'"
 
-#: git-submodule.sh:571
+#: git-submodule.sh:637
 #, 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'"
 
-#: git-submodule.sh:576
+#: git-submodule.sh:642
 #, 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'"
+msgstr ""
+"Không thể hòa trộn (merge) '$sha1' trong đường dẫn mô-đun-con '$sm_path'"
 
-#: git-submodule.sh:577
+#: git-submodule.sh:643
 #, 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'"
 
-#: git-submodule.sh:582
+#: git-submodule.sh:648
 #, 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'"
 
-#: git-submodule.sh:583
+#: git-submodule.sh:649
 #, sh-format
 msgid "Submodule path '$sm_path': checked out '$sha1'"
 msgstr "Đường dẫn mô-đun-con '$sm_path': được checkout '$sha1'"
 
-#: git-submodule.sh:605
-#: git-submodule.sh:928
+#: git-submodule.sh:671 git-submodule.sh:995
 #, 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'"
 
-#: git-submodule.sh:713
-msgid "--cached cannot be used with --files"
-msgstr "--cached không thể được sử dụng cùng với --files"
+#: git-submodule.sh:779
+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:753
+#: git-submodule.sh:819
 #, sh-format
 msgid "unexpected mode $mod_dst"
 msgstr "chế độ không như mong chờ $mod_dst"
 
-#: git-submodule.sh:771
+#: git-submodule.sh:837
 #, 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:774
+#: git-submodule.sh:840
 #, 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:777
+#: git-submodule.sh:843
 #, 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"
+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:802
+#: git-submodule.sh:868
 msgid "blob"
 msgstr "blob"
 
-#: git-submodule.sh:803
-msgid "submodule"
-msgstr "mô-đun con"
-
-#: git-submodule.sh:840
+#: git-submodule.sh:906
 msgid "# Submodules changed but not updated:"
 msgstr "# Những mô-đun-con đã bị thay đổi nhưng chưa được cập nhật:"
 
-#: git-submodule.sh:842
+#: git-submodule.sh:908
 msgid "# Submodule changes to be committed:"
 msgstr "# Những thay đổi mô-đun-con được chuyển giao (commit):"
 
-#: git-submodule.sh:974
+#: git-submodule.sh:1054
 #, sh-format
 msgid "Synchronizing submodule url for '$name'"
 msgstr "Đang đồng bộ hóa url mô-đun-con cho '$name'"
 
+#~ msgid " 0 files changed"
+#~ msgstr " 0 có tập tin nào thay đổi cả"
+
+#~ msgid " %d file changed"
+#~ msgid_plural " %d files changed"
+#~ msgstr[0] " %d tập tin thay đổi"
+#~ msgstr[1] " %d tập tin thay đổi"
+
+#~ msgid ", %d insertion(+)"
+#~ msgid_plural ", %d insertions(+)"
+#~ msgstr[0] ", %d thêm(+)"
+#~ msgstr[1] ", %d thêm(+)"
+
+#~ msgid ", %d deletion(-)"
+#~ msgid_plural ", %d deletions(-)"
+#~ msgstr[0] ", %d xóa(-)"
+#~ msgstr[1] ", %d xóa(-)"
+
+#~ msgid "Auto packing the repository for optimum performance.\n"
+#~ msgstr "Tự động đóng gói kho chứa để tối ưu hóa hiệu suất làm việc.\n"
+
+#~ msgid " (use \"git add\" to track)"
+#~ msgstr " (dùng \"git add\" để theo dõi dấu vết)"
+
+#~ msgid "-B cannot be used with -b"
+#~ msgstr "tùy chọn -B không thể dùng -b"
+
+#~ msgid "--patch is incompatible with all other options"
+#~ msgstr "--patch xung khắc với tất cả các tùy chọn khác"
+
+#~ msgid "--detach cannot be used with -b/-B/--orphan"
+#~ msgstr "--detach không thể được sử dụng với tùy chọn -b/-B/--orphan"
+
+#~ msgid "--detach cannot be used with -t"
+#~ msgstr "--detach không thể được sử dụng với tùy chọn -t"
+
+#~ msgid "--orphan and -b|-B are mutually exclusive"
+#~ msgstr "Tùy chọn --orphan và -b|-B loại từ lẫn nhau"
+
+#~ msgid "--orphan cannot be used with -t"
+#~ msgstr "--orphan không thể được sử dụng với tùy chọn -t"
+
+#~ msgid "git checkout: -f and -m are incompatible"
+#~ msgstr "git checkout: hai tùy chọn -f và -m xung khắc nhau"
+
+#~ msgid ""
+#~ "git checkout: updating paths is incompatible with switching branches."
+#~ msgstr ""
+#~ "git checkout: việc cập nhật các đường dẫn là xung khắc với việc chuyển "
+#~ "đổi các nhánh."
+
+#~ msgid "diff setup failed"
+#~ msgstr "cài đặt diff gặp lỗi"
+
+#~ msgid "merge-recursive: disk full?"
+#~ msgstr "merge-recursive: đĩa bị đầy?"
+
+#~ msgid "diff_setup_done failed"
+#~ msgstr "diff_setup_done gặp lỗi"
+
+#~ msgid "-d option is no longer supported.  Do not use."
+#~ msgstr "Tùy chọn -d không còn được hỗ trợ nữa. Xin đừng sử dụng."
+
+#~ msgid "%s: has been deleted/renamed"
+#~ 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."
+
 #~ msgid "--"
 #~ msgstr "--"
 
@@ -5564,7 +9611,3 @@ msgstr "Đang đồng bộ hóa url mô-đun-con cho '$name'"
 #, fuzzy
 #~ msgid "cherry-pick"
 #~ msgstr "< Chọn D-Mod"
-
-#, fuzzy
-#~ msgid "Too many options specified"
-#~ msgstr "đã ghi rõ quá nhiều kích cỡ"
index b46b53e6d6aaafff640c528bcaf86e74676fdee7..46d158ffd1ef5d819c5411d0d9906724fa57c215 100644 (file)
@@ -12,8 +12,8 @@ msgid ""
 msgstr ""
 "Project-Id-Version: Git\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2012-06-08 10:20+0800\n"
-"PO-Revision-Date: 2012-06-08 12:24+0800\n"
+"POT-Creation-Date: 2012-09-15 10:21+0800\n"
+"PO-Revision-Date: 2012-09-07 17:56+0800\n"
 "Last-Translator: Jiang Xin <worldhello.net@gmail.com>\n"
 "Language-Team: GitHub <https://github.com/gotgit/git/>\n"
 "Language: zh_CN\n"
@@ -42,6 +42,95 @@ msgstr ""
 "'git add/rm <file>' 标记解决方案,\n"
 "或使用 'git commit -a'。"
 
+#: archive.c:10
+#, fuzzy
+msgid "git archive [options] <tree-ish> [<path>...]"
+msgstr "git apply [选项] [<补丁>...]"
+
+#: archive.c:11
+#, fuzzy
+msgid "git archive --list"
+msgstr "git archive:NACK %s"
+
+#: archive.c:12
+msgid ""
+"git archive --remote <repo> [--exec <cmd>] [options] <tree-ish> [<path>...]"
+msgstr ""
+
+#: archive.c:13
+msgid "git archive --remote <repo> [--exec <cmd>] --list"
+msgstr ""
+
+#: archive.c:322
+msgid "fmt"
+msgstr ""
+
+#: archive.c:322
+msgid "archive format"
+msgstr ""
+
+#: archive.c:323 builtin/log.c:1079
+msgid "prefix"
+msgstr ""
+
+#: archive.c:324
+msgid "prepend prefix to each pathname in the archive"
+msgstr ""
+
+#: archive.c:325 builtin/archive.c:91 builtin/blame.c:2332
+#: builtin/blame.c:2333 builtin/config.c:56 builtin/fast-export.c:642
+#: builtin/fast-export.c:644 builtin/grep.c:800 builtin/hash-object.c:77
+#: builtin/ls-files.c:494 builtin/ls-files.c:497 builtin/notes.c:537
+#: builtin/notes.c:694 builtin/read-tree.c:107 parse-options.h:149
+msgid "file"
+msgstr "文件"
+
+#: archive.c:326 builtin/archive.c:92
+msgid "write the archive to this file"
+msgstr ""
+
+#: archive.c:328
+#, fuzzy
+msgid "read .gitattributes in working directory"
+msgstr "%s:已经存在于工作区中"
+
+#: archive.c:329
+msgid "report archived files on stderr"
+msgstr ""
+
+#: archive.c:330
+msgid "store only"
+msgstr ""
+
+#: archive.c:331
+msgid "compress faster"
+msgstr ""
+
+#: archive.c:339
+msgid "compress better"
+msgstr ""
+
+#: archive.c:342
+msgid "list supported archive formats"
+msgstr ""
+
+#: archive.c:344 builtin/archive.c:93 builtin/clone.c:85
+msgid "repo"
+msgstr ""
+
+#: archive.c:345 builtin/archive.c:94
+msgid "retrieve the archive from remote repository <repo>"
+msgstr ""
+
+#: archive.c:346 builtin/archive.c:95 builtin/notes.c:616
+#, fuzzy
+msgid "command"
+msgstr "运行 $command"
+
+#: archive.c:347 builtin/archive.c:96
+msgid "path to the remote git-upload-archive command"
+msgstr ""
+
 #: bundle.c:36
 #, c-format
 msgid "'%s' does not look like a v2 bundle file"
@@ -52,7 +141,7 @@ msgstr "'%s' 不像是一个 v2 版本的包文件"
 msgid "unrecognized header: %s%s (%d)"
 msgstr "未能识别的包头:%s%s (%d)"
 
-#: bundle.c:89 builtin/commit.c:696
+#: bundle.c:89 builtin/commit.c:714
 #, c-format
 msgid "could not open '%s'"
 msgstr "不能打开 '%s'"
@@ -61,8 +150,8 @@ msgstr "不能打开 '%s'"
 msgid "Repository lacks these prerequisite commits:"
 msgstr "版本库缺少这些必备的提交:"
 
-#: bundle.c:164 sequencer.c:550 sequencer.c:982 builtin/log.c:289
-#: builtin/log.c:720 builtin/log.c:1309 builtin/log.c:1528 builtin/merge.c:347
+#: bundle.c:164 sequencer.c:557 sequencer.c:989 builtin/log.c:290
+#: builtin/log.c:727 builtin/log.c:1313 builtin/log.c:1529 builtin/merge.c:347
 #: builtin/shortlog.c:181
 msgid "revision walk setup failed"
 msgstr "版本遍历设置失败"
@@ -75,44 +164,48 @@ msgstr[0] "这个包中含有 %d 个引用"
 msgstr[1] "这个包中含有 %d 个引用"
 
 #: bundle.c:192
+msgid "The bundle records a complete history."
+msgstr "这个包记录一个完整历史。"
+
+#: bundle.c:195
 #, c-format
 msgid "The bundle requires this ref"
 msgid_plural "The bundle requires these %d refs"
 msgstr[0] "这个包需要这个引用"
 msgstr[1] "这个包需要 %d 个这些引用"
 
-#: bundle.c:290
+#: bundle.c:294
 msgid "rev-list died"
 msgstr "rev-list 终止"
 
-#: bundle.c:296 builtin/log.c:1205 builtin/shortlog.c:284
+#: bundle.c:300 builtin/log.c:1209 builtin/shortlog.c:284
 #, c-format
 msgid "unrecognized argument: %s"
 msgstr "未能识别的参数:%s"
 
-#: bundle.c:331
+#: bundle.c:335
 #, c-format
 msgid "ref '%s' is excluded by the rev-list options"
 msgstr "引用 '%s' 被 rev-list 选项排除"
 
-#: bundle.c:376
+#: bundle.c:380
 msgid "Refusing to create empty bundle."
 msgstr "不能创建空包。"
 
-#: bundle.c:394
+#: bundle.c:398
 msgid "Could not spawn pack-objects"
 msgstr "不能生成 pack-objects 进程"
 
-#: bundle.c:412
+#: bundle.c:416
 msgid "pack-objects died"
 msgstr "pack-objects 终止"
 
-#: bundle.c:415
+#: bundle.c:419
 #, c-format
 msgid "cannot create '%s'"
 msgstr "不能创建 '%s'"
 
-#: bundle.c:437
+#: bundle.c:441
 msgid "index-pack died"
 msgstr "index-pack 终止"
 
@@ -232,32 +325,32 @@ msgstr ""
 "发现配置变量 'diff.dirstat' 中的错误:\n"
 "%s"
 
-#: diff.c:1400
-msgid " 0 files changed\n"
-msgstr " 0 个文件被修改\n"
+#: diff.c:1401
+msgid " 0 files changed"
+msgstr " 0 个文件被修改"
 
-#: diff.c:1404
+#: diff.c:1405
 #, c-format
 msgid " %d file changed"
 msgid_plural " %d files changed"
 msgstr[0] " %d 个文件被修改"
 msgstr[1] " %d 个文件被修改"
 
-#: diff.c:1421
+#: diff.c:1422
 #, c-format
 msgid ", %d insertion(+)"
 msgid_plural ", %d insertions(+)"
 msgstr[0] ",插入 %d 行(+)"
 msgstr[1] ",插入 %d 行(+)"
 
-#: diff.c:1432
+#: diff.c:1433
 #, c-format
 msgid ", %d deletion(-)"
 msgid_plural ", %d deletions(-)"
 msgstr[0] ",删除 %d 行(-)"
 msgstr[1] ",删除 %d 行(-)"
 
-#: diff.c:3478
+#: diff.c:3460
 #, c-format
 msgid ""
 "Failed to parse --dirstat/-X option parameter:\n"
@@ -293,16 +386,16 @@ msgstr "'%s':%s"
 msgid "'%s': short read %s"
 msgstr "'%s':读取不完整 %s"
 
-#: help.c:207
+#: help.c:212
 #, c-format
 msgid "available git commands in '%s'"
 msgstr "在 '%s' 下可用的 git 命令"
 
-#: help.c:214
+#: help.c:219
 msgid "git commands available from elsewhere on your $PATH"
 msgstr "在 $PATH 路径中的其他地方可用的 git 命令"
 
-#: help.c:270
+#: help.c:275
 #, c-format
 msgid ""
 "'%s' appears to be a git command, but we were not\n"
@@ -311,11 +404,11 @@ msgstr ""
 "'%s' 像是一个 git 命令,但却无法运行。\n"
 "可能是 git-%s 受损?"
 
-#: help.c:327
+#: help.c:332
 msgid "Uh oh. Your system reports no Git commands at all."
 msgstr "唉呀,您的系统中未发现 Git 命令。"
 
-#: help.c:349
+#: help.c:354
 #, c-format
 msgid ""
 "WARNING: You called a Git command named '%s', which does not exist.\n"
@@ -324,17 +417,17 @@ msgstr ""
 "警告:您运行一个不存在的 Git 命令 '%s'。继续执行假定您要要运行的\n"
 "是 '%s'"
 
-#: help.c:354
+#: help.c:359
 #, c-format
 msgid "in %0.1f seconds automatically..."
 msgstr "在 %0.1f 秒钟后自动运行..."
 
-#: help.c:361
+#: help.c:366
 #, c-format
 msgid "git: '%s' is not a git command. See 'git --help'."
 msgstr "git:'%s' 不是一个 git 命令。参见 'git --help'。"
 
-#: help.c:365
+#: help.c:370
 msgid ""
 "\n"
 "Did you mean this?"
@@ -346,38 +439,292 @@ msgstr[0] ""
 "您指的是这个么?"
 msgstr[1] ""
 "\n"
-"您指的是这些其中一个么?"
+"您指的是这其中的某一个么?"
+
+#: merge-recursive.c:190
+#, c-format
+msgid "(bad commit)\n"
+msgstr "(坏提交)\n"
+
+#: merge-recursive.c:206
+#, c-format
+msgid "addinfo_cache failed for path '%s'"
+msgstr "为路径 '%s' addinfo_cache 失败"
+
+#: merge-recursive.c:268
+msgid "error building trees"
+msgstr "无法创建树"
+
+#: merge-recursive.c:672
+#, c-format
+msgid "failed to create path '%s'%s"
+msgstr "无法创建路径 '%s'%s"
+
+#: merge-recursive.c:683
+#, c-format
+msgid "Removing %s to make room for subdirectory\n"
+msgstr "删除 %s 以便为子目录留出空间\n"
+
+#. something else exists
+#. .. but not some other error (who really cares what?)
+#: merge-recursive.c:697 merge-recursive.c:718
+msgid ": perhaps a D/F conflict?"
+msgstr ":可能是一个目录/文件冲突?"
+
+#: merge-recursive.c:708
+#, c-format
+msgid "refusing to lose untracked file at '%s'"
+msgstr "拒绝丢弃 '%s' 中的未跟踪文件"
+
+#: merge-recursive.c:748
+#, c-format
+msgid "cannot read object %s '%s'"
+msgstr "不能读取对象 %s '%s'"
+
+#: merge-recursive.c:750
+#, c-format
+msgid "blob expected for %s '%s'"
+msgstr "%s '%s' 应为二进制对象(blob)"
+
+#: merge-recursive.c:773 builtin/clone.c:302
+#, c-format
+msgid "failed to open '%s'"
+msgstr "无法打开 '%s'"
+
+#: merge-recursive.c:781
+#, c-format
+msgid "failed to symlink '%s'"
+msgstr "无法创建符号链接 '%s'"
+
+#: merge-recursive.c:784
+#, c-format
+msgid "do not know what to do with %06o %s '%s'"
+msgstr "不知道如何处理 %06o %s '%s'"
+
+#: merge-recursive.c:922
+msgid "Failed to execute internal merge"
+msgstr "无法执行内部合并"
+
+#: merge-recursive.c:926
+#, c-format
+msgid "Unable to add %s to database"
+msgstr "不能添加 %s 至对象库"
+
+#: merge-recursive.c:942
+msgid "unsupported object type in the tree"
+msgstr "在树中有不支持的对象类型"
+
+#: 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 "
+"in tree."
+msgstr ""
+"冲突(%1$s/删除):%2$s 在 %3$s 中被删除,在 %5$s 中被 %4$s。%7$s 在 %6$s 中"
+"的版本被保留。"
+
+#: 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 "
+"in tree at %s."
+msgstr ""
+"冲突(%1$s/删除):%2$s 在 %3$s 中被删除,在 %5$s 中被 %4$s。%7$s 在 %6$s 中"
+"的版本保留于 %8$s 中。"
+
+#: merge-recursive.c:1081
+msgid "rename"
+msgstr "重命名"
+
+#: merge-recursive.c:1081
+msgid "renamed"
+msgstr "重命名"
+
+#: merge-recursive.c:1137
+#, c-format
+msgid "%s is a directory in %s adding as %s instead"
+msgstr "%s 是 %s 中的一个目录而以 %s 为名被添加"
+
+#: merge-recursive.c:1159
+#, c-format
+msgid ""
+"CONFLICT (rename/rename): Rename \"%s\"->\"%s\" in branch \"%s\" rename \"%s"
+"\"->\"%s\" in \"%s\"%s"
+msgstr ""
+"冲突(重命名/重命名):在分支 \"%3$s\" 中重命名 \"%1$s\"->\"%2$s\",在分支 "
+"\"%6$s\" 中重命名 \"%4$s\"->\"%5$s\"%7$s"
+
+#: merge-recursive.c:1164
+msgid " (left unresolved)"
+msgstr "(留下未解决)"
+
+#: merge-recursive.c:1218
+#, c-format
+msgid "CONFLICT (rename/rename): Rename %s->%s in %s. Rename %s->%s in %s"
+msgstr ""
+"冲突(重命名/重命名):在 %3$s 中重命名 %1$s->%2$s,在 %6$s 中重命名 %4$s->"
+"%5$s"
+
+#: merge-recursive.c:1248
+#, c-format
+msgid "Renaming %s to %s and %s to %s instead"
+msgstr "而是重命名 %s 至 %s 以及 %s 至 %s"
+
+#: merge-recursive.c:1447
+#, c-format
+msgid "CONFLICT (rename/add): Rename %s->%s in %s. %s added in %s"
+msgstr "冲突(重命名/添加):在 %3$s 中重命名 %1$s->%2$s。在 %5$s 中添加 %4$s"
+
+#: merge-recursive.c:1457
+#, c-format
+msgid "Adding merged %s"
+msgstr "添加合并后的 %s"
+
+#: merge-recursive.c:1462 merge-recursive.c:1660
+#, c-format
+msgid "Adding as %s instead"
+msgstr "而是以 %s 为名添加"
+
+#: merge-recursive.c:1513
+#, c-format
+msgid "cannot read object %s"
+msgstr "不能读取对象 %s"
+
+#: merge-recursive.c:1516
+#, c-format
+msgid "object %s is not a blob"
+msgstr "对象 %s 不是一个二进制对象(blob)"
+
+#: merge-recursive.c:1564
+msgid "modify"
+msgstr "修改"
+
+#: merge-recursive.c:1564
+msgid "modified"
+msgstr "修改"
+
+#: merge-recursive.c:1574
+msgid "content"
+msgstr "内容"
+
+#: merge-recursive.c:1581
+msgid "add/add"
+msgstr "添加/添加"
+
+#: merge-recursive.c:1615
+#, c-format
+msgid "Skipped %s (merged same as existing)"
+msgstr "略过 %s(已经做过相同合并)"
+
+#: merge-recursive.c:1629
+#, c-format
+msgid "Auto-merging %s"
+msgstr "自动合并 %s"
+
+#: merge-recursive.c:1633 git-submodule.sh:869
+msgid "submodule"
+msgstr "子模组"
+
+#: merge-recursive.c:1634
+#, c-format
+msgid "CONFLICT (%s): Merge conflict in %s"
+msgstr "冲突(%s):合并冲突于 %s"
+
+#: merge-recursive.c:1724
+#, c-format
+msgid "Removing %s"
+msgstr "删除 %s"
+
+#: merge-recursive.c:1749
+msgid "file/directory"
+msgstr "文件/目录"
+
+#: merge-recursive.c:1755
+msgid "directory/file"
+msgstr "目录/文件"
+
+#: merge-recursive.c:1760
+#, c-format
+msgid "CONFLICT (%s): There is a directory with name %s in %s. Adding %s as %s"
+msgstr "冲突(%1$s):在 %3$s 中有一个名为 %2$s 的目录。以 %5$s 为名添加 %4$s"
+
+#: merge-recursive.c:1770
+#, c-format
+msgid "Adding %s"
+msgstr "添加 %s"
+
+#: merge-recursive.c:1787
+msgid "Fatal merge failure, shouldn't happen."
+msgstr "严重的合并错误,不应发生。"
 
-#: parse-options.c:493
+#: merge-recursive.c:1806
+msgid "Already up-to-date!"
+msgstr "已经是最新的!"
+
+#: merge-recursive.c:1815
+#, c-format
+msgid "merging of trees %s and %s failed"
+msgstr "无法合并树 %s 和 %s"
+
+#: merge-recursive.c:1845
+#, c-format
+msgid "Unprocessed path??? %s"
+msgstr "未处理的路径??? %s"
+
+#: merge-recursive.c:1890
+msgid "Merging:"
+msgstr "合并:"
+
+#: merge-recursive.c:1903
+#, c-format
+msgid "found %u common ancestor:"
+msgid_plural "found %u common ancestors:"
+msgstr[0] "发现 %u 个共同祖先:"
+msgstr[1] "发现 %u 个共同祖先:"
+
+#: merge-recursive.c:1940
+msgid "merge returned no commit"
+msgstr "合并未返回提交"
+
+#: merge-recursive.c:1997
+#, c-format
+msgid "Could not parse object '%s'"
+msgstr "不能解析对象 '%s'"
+
+#: merge-recursive.c:2009 builtin/merge.c:696
+msgid "Unable to write index."
+msgstr "不能写入索引。"
+
+#: parse-options.c:494
 msgid "..."
 msgstr "..."
 
-#: parse-options.c:511
+#: parse-options.c:512
 #, c-format
 msgid "usage: %s"
 msgstr "用法:%s"
 
 #. TRANSLATORS: the colon here should align with the
 #. one in "usage: %s" translation
-#: parse-options.c:515
+#: parse-options.c:516
 #, c-format
 msgid "   or: %s"
 msgstr "  或:%s"
 
 #  译者:为保证在输出中对齐,注意调整句中空格!
-#: parse-options.c:518
+#: parse-options.c:519
 #, c-format
 msgid "    %s"
 msgstr "    %s"
 
-#: remote.c:1629
+#: remote.c:1632
 #, 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] "您的分支领先 '%s' 共 %d 个提交。\n"
 msgstr[1] "您的分支领先 '%s' 共 %d 个提交。\n"
 
-#: remote.c:1635
+#: remote.c:1638
 #, c-format
 msgid "Your branch is behind '%s' by %d commit, and can be fast-forwarded.\n"
 msgid_plural ""
@@ -385,7 +732,7 @@ msgid_plural ""
 msgstr[0] "您的分支落后 '%s' 共 %d 个提交,并且可以快进。\n"
 msgstr[1] "您的分支落后 '%s' 共 %d 个提交,并且可以快进。\n"
 
-#: remote.c:1643
+#: remote.c:1646
 #, c-format
 msgid ""
 "Your branch and '%s' have diverged,\n"
@@ -395,19 +742,19 @@ msgid_plural ""
 "and have %d and %d different commits each, respectively.\n"
 msgstr[0] ""
 "您的分支和 '%s' 出现了偏离,\n"
-"并ä¸\94å\90\84è\87ªå\88\86å\88«æ\9c\89 %d å\92\8c %d å¤\84ä¸\8då\90\8cç\9a\84æ\8f\90交ã\80\82\n"
+"并且分别有 %d 和 %d 处不同的提交。\n"
 msgstr[1] ""
 "您的分支和 '%s' 出现了偏离,\n"
-"并ä¸\94å\90\84è\87ªå\88\86å\88«æ\9c\89 %d å\92\8c %d å¤\84ä¸\8då\90\8cç\9a\84æ\8f\90交ã\80\82\n"
+"并且分别有 %d 和 %d 处不同的提交。\n"
 
-#: sequencer.c:121 builtin/merge.c:865 builtin/merge.c:978
-#: builtin/merge.c:1088 builtin/merge.c:1098
+#: sequencer.c:121 builtin/merge.c:864 builtin/merge.c:977
+#: builtin/merge.c:1087 builtin/merge.c:1097
 #, c-format
 msgid "Could not open '%s' for writing"
 msgstr "不能为写入打开 '%s'"
 
-#: sequencer.c:123 builtin/merge.c:333 builtin/merge.c:868
-#: builtin/merge.c:1090 builtin/merge.c:1103
+#: sequencer.c:123 builtin/merge.c:333 builtin/merge.c:867
+#: builtin/merge.c:1089 builtin/merge.c:1102
 #, c-format
 msgid "Could not write to '%s'"
 msgstr "不能写入 '%s'"
@@ -429,7 +776,7 @@ msgstr ""
 "冲突解决完毕后,用 'git add <paths>' 或 'git rm <paths>'\n"
 "对修正后的文件做标记,然后用 'git commit' 提交"
 
-#: sequencer.c:160 sequencer.c:758 sequencer.c:841
+#: sequencer.c:160 sequencer.c:765 sequencer.c:848
 #, c-format
 msgid "Could not write to %s"
 msgstr "不能写入 %s"
@@ -465,473 +812,608 @@ msgstr "不能解析 HEAD 提交\n"
 msgid "Unable to update cache tree\n"
 msgstr "不能更新缓存\n"
 
-#: sequencer.c:324
+#: sequencer.c:327
 #, c-format
 msgid "Could not parse commit %s\n"
 msgstr "不能解析提交 %s\n"
 
-#: sequencer.c:329
+#: sequencer.c:332
 #, c-format
 msgid "Could not parse parent commit %s\n"
 msgstr "不能解析父提交 %s\n"
 
-#: sequencer.c:395
+#: sequencer.c:398
 msgid "Your index file is unmerged."
 msgstr "您的索引文件未完成合并。"
 
-#: sequencer.c:398
+#: sequencer.c:401
 msgid "You do not have a valid HEAD"
 msgstr "您没有一个有效的 HEAD"
 
-#: sequencer.c:413
+#: sequencer.c:416
 #, c-format
 msgid "Commit %s is a merge but no -m option was given."
 msgstr "提交 %s 是一个合并提交但未提供 -m 选项。"
 
-#: sequencer.c:421
+#: sequencer.c:424
 #, c-format
 msgid "Commit %s does not have parent %d"
 msgstr "提交 %s 没有父提交 %d"
 
-#: sequencer.c:425
+#: sequencer.c:428
 #, c-format
 msgid "Mainline was specified but commit %s is not a merge."
 msgstr "指定了主线但提交 %s 不是一个合并。"
 
 #. TRANSLATORS: The first %s will be "revert" or
 #. "cherry-pick", the second %s a SHA1
-#: sequencer.c:436
+#: sequencer.c:439
 #, c-format
 msgid "%s: cannot parse parent commit %s"
 msgstr "%s:不能解析父提交 %s"
 
-#: sequencer.c:440
+#: sequencer.c:443
 #, c-format
 msgid "Cannot get commit message for %s"
 msgstr "不能得到 %s 的提交说明"
 
-#: sequencer.c:524
+#: sequencer.c:527
 #, c-format
 msgid "could not revert %s... %s"
 msgstr "不能还原 %s... %s"
 
-#: sequencer.c:525
+#: sequencer.c:528
 #, c-format
 msgid "could not apply %s... %s"
 msgstr "不能应用 %s... %s"
 
-#: sequencer.c:553
+#: sequencer.c:560
 msgid "empty commit set passed"
 msgstr "提供了空的提交集"
 
-#: sequencer.c:561
+#: sequencer.c:568
 #, c-format
 msgid "git %s: failed to read the index"
 msgstr "git %s:无法读取索引"
 
-#: sequencer.c:566
+#: sequencer.c:573
 #, c-format
 msgid "git %s: failed to refresh the index"
 msgstr "git %s:无法刷新索引"
 
-#: sequencer.c:624
+#: sequencer.c:631
 #, c-format
 msgid "Cannot %s during a %s"
 msgstr "无法 %s 在一个 %s 过程中"
 
-#: sequencer.c:646
+#: sequencer.c:653
 #, c-format
 msgid "Could not parse line %d."
 msgstr "不能解析第 %d 行。"
 
-#: sequencer.c:651
+#: sequencer.c:658
 msgid "No commits parsed."
 msgstr "没有提交被解析。"
 
-#: sequencer.c:664
+#: sequencer.c:671
 #, c-format
 msgid "Could not open %s"
 msgstr "不能打开 %s"
 
-#: sequencer.c:668
+#: sequencer.c:675
 #, c-format
 msgid "Could not read %s."
 msgstr "不能读取 %s。"
 
-#: sequencer.c:675
+#: sequencer.c:682
 #, c-format
 msgid "Unusable instruction sheet: %s"
 msgstr "无用的指令表单:%s"
 
-#: sequencer.c:703
+#: sequencer.c:710
 #, c-format
 msgid "Invalid key: %s"
 msgstr "无效键名:%s"
 
-#: sequencer.c:706
+#: sequencer.c:713
 #, c-format
 msgid "Invalid value for %s: %s"
 msgstr "%s 的值无效:%s"
 
-#: sequencer.c:718
+#: sequencer.c:725
 #, c-format
 msgid "Malformed options sheet: %s"
 msgstr "非法的选项表单:%s"
 
-#: sequencer.c:739
+#: sequencer.c:746
 msgid "a cherry-pick or revert is already in progress"
 msgstr "一个拣选或还原操作已在进行"
 
-#: sequencer.c:740
+#: sequencer.c:747
 msgid "try \"git cherry-pick (--continue | --quit | --abort)\""
 msgstr "尝试 \"git cherry-pick (--continue | --quit | --abort)\""
 
-#: sequencer.c:744
+#: sequencer.c:751
 #, c-format
 msgid "Could not create sequencer directory %s"
 msgstr "不能创建序列目录 %s"
 
-#: sequencer.c:760 sequencer.c:845
+#: sequencer.c:767 sequencer.c:852
 #, c-format
 msgid "Error wrapping up %s."
 msgstr "错误收尾 %s。"
 
-#: sequencer.c:779 sequencer.c:913
+#: sequencer.c:786 sequencer.c:920
 msgid "no cherry-pick or revert in progress"
-msgstr "没æ\9c\89æ\8b£é\80\89æ\88\96è¿\98å\8e\9fæ\93\8dä½\9cå\9c¨进行"
+msgstr "æ\8b£é\80\89æ\88\96è¿\98å\8e\9fæ\93\8dä½\9c并æ\9cª进行"
 
-#: sequencer.c:781
+#: sequencer.c:788
 msgid "cannot resolve HEAD"
 msgstr "不能解析 HEAD"
 
-#: sequencer.c:783
+#: sequencer.c:790
 msgid "cannot abort from a branch yet to be born"
 msgstr "不能从尚未建立的分支终止"
 
-#: sequencer.c:805 builtin/apply.c:3697
+#: sequencer.c:812 builtin/apply.c:4005
 #, c-format
 msgid "cannot open %s: %s"
 msgstr "不能打开 %s:%s"
 
-#: sequencer.c:808
+#: sequencer.c:815
 #, c-format
 msgid "cannot read %s: %s"
 msgstr "不能读取 %s:%s"
 
-#: sequencer.c:809
+#: sequencer.c:816
 msgid "unexpected end of file"
-msgstr "æ\9cªé¢\84æ\9c\9f的文件结束"
+msgstr "æ\84\8få¤\96的文件结束"
 
-#: sequencer.c:815
+#: sequencer.c:822
 #, c-format
 msgid "stored pre-cherry-pick HEAD file '%s' is corrupt"
 msgstr "保存拣选提交前的 HEAD 文件 '%s' 损坏"
 
-#: sequencer.c:838
+#: sequencer.c:845
 #, c-format
 msgid "Could not format %s."
 msgstr "不能格式化 %s。"
 
-#: sequencer.c:1000
+#: sequencer.c:1007
 msgid "Can't revert as initial commit"
 msgstr "不能作为初始提交还原"
 
-#: sequencer.c:1001
+#: sequencer.c:1008
 msgid "Can't cherry-pick into empty head"
 msgstr "不能拣选到空分支"
 
-#: sha1_name.c:864
+#: sha1_name.c:1044
 msgid "HEAD does not point to a branch"
 msgstr "HEAD 没有指向一个分支"
 
-#: sha1_name.c:867
+#: sha1_name.c:1047
 #, c-format
 msgid "No such branch: '%s'"
 msgstr "没有此分支:'%s'"
 
-#: sha1_name.c:869
+#: sha1_name.c:1049
 #, c-format
 msgid "No upstream configured for branch '%s'"
 msgstr "尚未给分支 '%s' 设置上游"
 
-#: sha1_name.c:872
+#: sha1_name.c:1052
 #, c-format
 msgid "Upstream branch '%s' not stored as a remote-tracking branch"
 msgstr "上游分支 '%s' 没有存储为一个远程跟踪分支"
 
-#: wrapper.c:413
+#: wrapper.c:408
+#, fuzzy, c-format
+msgid "unable to access '%s': %s"
+msgstr "不能创建 '%s'"
+
+#: wrapper.c:426
 #, c-format
 msgid "unable to look up current user in the passwd file: %s"
-msgstr "无法在 passwd 文件中查询到当前用户:%s"
+msgstr "无法在 passwd 文件中查询到用户:%s"
 
-#: wrapper.c:414
+#: wrapper.c:427
 msgid "no such user"
 msgstr "无此用户"
 
-#: wt-status.c:135
+#: wt-status.c:140
 msgid "Unmerged paths:"
 msgstr "未合并的路径:"
 
 #  译者:注意保持前导空格
-#: wt-status.c:141 wt-status.c:158
+#: wt-status.c:167 wt-status.c:194
 #, c-format
 msgid "  (use \"git reset %s <file>...\" to unstage)"
 msgstr "  (使用 \"git reset %s <file>...\" 撤出暂存区)"
 
 #  译者:注意保持前导空格
-#: wt-status.c:143 wt-status.c:160
+#: wt-status.c:169 wt-status.c:196
 msgid "  (use \"git rm --cached <file>...\" to unstage)"
 msgstr "  (使用 \"git rm --cached <file>...\" 撤出暂存区)"
 
 #  译者:注意保持前导空格
-#: wt-status.c:144
+#: wt-status.c:173
+msgid "  (use \"git add <file>...\" to mark resolution)"
+msgstr "  (使用 \"git add <file>...\" 标记解决方案)"
+
+#  译者:注意保持前导空格
+#: wt-status.c:175 wt-status.c:179
 msgid "  (use \"git add/rm <file>...\" as appropriate to mark resolution)"
 msgstr "  (酌情使用 \"git add/rm <file>...\" 标记解决方案)"
 
-#: wt-status.c:152
+#  译者:注意保持前导空格
+#: wt-status.c:177
+msgid "  (use \"git rm <file>...\" to mark resolution)"
+msgstr "  (使用 \"git rm <file>...\" 标记解决方案)"
+
+#: wt-status.c:188
 msgid "Changes to be committed:"
 msgstr "要提交的变更:"
 
-#: wt-status.c:170
+#: wt-status.c:206
 msgid "Changes not staged for commit:"
 msgstr "尚未暂存以备提交的变更:"
 
 #  译者:注意保持前导空格
-#: wt-status.c:174
+#: wt-status.c:210
 msgid "  (use \"git add <file>...\" to update what will be committed)"
 msgstr "  (使用 \"git add <file>...\" 更新要提交的内容)"
 
 #  译者:注意保持前导空格
-#: wt-status.c:176
+#: wt-status.c:212
 msgid "  (use \"git add/rm <file>...\" to update what will be committed)"
 msgstr "  (使用 \"git add/rm <file>...\" 更新要提交的内容)"
 
 #  译者:注意保持前导空格
-#: wt-status.c:177
+#: wt-status.c:213
 msgid ""
 "  (use \"git checkout -- <file>...\" to discard changes in working directory)"
 msgstr "  (使用 \"git checkout -- <file>...\" 丢弃工作区的改动)"
 
 #  译者:注意保持前导空格
-#: wt-status.c:179
+#: wt-status.c:215
 msgid "  (commit or discard the untracked or modified content in submodules)"
 msgstr "  (提交或丢弃子模组中未跟踪或修改的内容)"
 
-#: wt-status.c:188
-#, c-format
-msgid "%s files:"
-msgstr "%s文件:"
-
 #  译者:注意保持前导空格
-#: wt-status.c:191
+#: wt-status.c:227
 #, c-format
 msgid "  (use \"git %s <file>...\" to include in what will be committed)"
 msgstr "  (使用 \"git %s <file>...\" 以包含要提交的内容)"
 
-#: wt-status.c:208
+#: wt-status.c:244
 msgid "bug"
 msgstr "bug"
 
-#: wt-status.c:213
+#: wt-status.c:249
 msgid "both deleted:"
 msgstr "双方删除:"
 
-#: wt-status.c:214
+#: wt-status.c:250
 msgid "added by us:"
 msgstr "由我们添加:"
 
-#: wt-status.c:215
+#: wt-status.c:251
 msgid "deleted by them:"
 msgstr "由他们删除:"
 
-#: wt-status.c:216
+#: wt-status.c:252
 msgid "added by them:"
 msgstr "由他们添加:"
 
-#: wt-status.c:217
+#: wt-status.c:253
 msgid "deleted by us:"
 msgstr "由我们删除:"
 
-#: wt-status.c:218
+#: wt-status.c:254
 msgid "both added:"
 msgstr "双方添加:"
 
-#: wt-status.c:219
+#: wt-status.c:255
 msgid "both modified:"
 msgstr "双方修改:"
 
 #  译者:末尾两个字节可能被删减,如果翻译为中文标点会出现半个汉字
-#: wt-status.c:249
+#: wt-status.c:285
 msgid "new commits, "
 msgstr "新提交, "
 
 #  译者:末尾两个字节可能被删减,如果翻译为中文标点会出现半个汉字
-#: wt-status.c:251
+#: wt-status.c:287
 msgid "modified content, "
 msgstr "修改的内容, "
 
 #  译者:末尾两个字节可能被删减,如果翻译为中文标点会出现半个汉字
-#: wt-status.c:253
+#: wt-status.c:289
 msgid "untracked content, "
 msgstr "未跟踪的内容, "
 
 #  译者:为保证在输出中对齐,注意调整句中空格!
-#: wt-status.c:267
+#: wt-status.c:303
 #, c-format
 msgid "new file:   %s"
 msgstr "新文件:    %s"
 
 #  译者:为保证在输出中对齐,注意调整句中空格!
-#: wt-status.c:270
+#: wt-status.c:306
 #, c-format
 msgid "copied:     %s -> %s"
 msgstr "拷贝:      %s -> %s"
 
 #  译者:为保证在输出中对齐,注意调整句中空格!
-#: wt-status.c:273
+#: wt-status.c:309
 #, c-format
 msgid "deleted:    %s"
 msgstr "删除:      %s"
 
 #  译者:为保证在输出中对齐,注意调整句中空格!
-#: wt-status.c:276
+#: wt-status.c:312
 #, c-format
 msgid "modified:   %s"
 msgstr "修改:      %s"
 
 #  译者:为保证在输出中对齐,注意调整句中空格!
-#: wt-status.c:279
+#: wt-status.c:315
 #, c-format
 msgid "renamed:    %s -> %s"
 msgstr "重命名:    %s -> %s"
 
 #  译者:为保证在输出中对齐,注意调整句中空格!
-#: wt-status.c:282
+#: wt-status.c:318
 #, c-format
 msgid "typechange: %s"
 msgstr "类型变更:  %s"
 
 #  译者:为保证在输出中对齐,注意调整句中空格!
-#: wt-status.c:285
+#: wt-status.c:321
 #, c-format
 msgid "unknown:    %s"
 msgstr "未知:      %s"
 
 #  译者:为保证在输出中对齐,注意调整句中空格!
-#: wt-status.c:288
+#: wt-status.c:324
 #, c-format
 msgid "unmerged:   %s"
 msgstr "未合并:    %s"
 
-#: wt-status.c:291
+#: wt-status.c:327
 #, c-format
 msgid "bug: unhandled diff status %c"
 msgstr "bug:未处理的差异状态 %c"
 
-#: wt-status.c:737
+#: wt-status.c:785
+msgid "You have unmerged paths."
+msgstr "您有尚未合并的路径。"
+
+#  译者:注意保持前导空格
+#: wt-status.c:788 wt-status.c:912
+msgid "  (fix conflicts and run \"git commit\")"
+msgstr "  (解决冲突并运行 \"git commit\")"
+
+#: wt-status.c:791
+msgid "All conflicts fixed but you are still merging."
+msgstr "所有冲突已解决但您仍处于合并中。"
+
+#  译者:注意保持前导空格
+#: wt-status.c:794
+msgid "  (use \"git commit\" to conclude merge)"
+msgstr "  (使用 \"git commit\" 结束合并)"
+
+#: wt-status.c:804
+msgid "You are in the middle of an am session."
+msgstr "您正处于一个 am 过程中。"
+
+#: wt-status.c:807
+msgid "The current patch is empty."
+msgstr "当前的补丁为空。"
+
+#  译者:注意保持前导空格
+#: wt-status.c:811
+msgid "  (fix conflicts and then run \"git am --resolved\")"
+msgstr "  (解决冲突,然后运行 \"git am --resolved\")"
+
+#  译者:注意保持前导空格
+#: wt-status.c:813
+msgid "  (use \"git am --skip\" to skip this patch)"
+msgstr "  (使用 \"git am --skip\" 跳过此补丁)"
+
+#  译者:注意保持前导空格
+#: wt-status.c:815
+msgid "  (use \"git am --abort\" to restore the original branch)"
+msgstr "  (使用 \"git am --abort\" 恢复原有分支)"
+
+#: wt-status.c:873 wt-status.c:883
+msgid "You are currently rebasing."
+msgstr "您正在变基。"
+
+#  译者:注意保持前导空格
+#: wt-status.c:876
+msgid "  (fix conflicts and then run \"git rebase --continue\")"
+msgstr "  (解决冲突,然后运行 \"git rebase --continue\")"
+
+#  译者:注意保持前导空格
+#: wt-status.c:878
+msgid "  (use \"git rebase --skip\" to skip this patch)"
+msgstr "  (使用 \"git rebase --skip\" 跳过此补丁)"
+
+#  译者:注意保持前导空格
+#: wt-status.c:880
+msgid "  (use \"git rebase --abort\" to check out the original branch)"
+msgstr "  (使用 \"git rebase --abort\" 以检出原有分支)"
+
+#  译者:注意保持前导空格
+#: wt-status.c:886
+msgid "  (all conflicts fixed: run \"git rebase --continue\")"
+msgstr "  (所有冲突已解决:运行 \"git rebase --continue\")"
+
+#: wt-status.c:888
+msgid "You are currently splitting a commit during a rebase."
+msgstr "您正在变基过程中拆分一个提交。"
+
+#  译者:注意保持前导空格
+#: wt-status.c:891
+msgid "  (Once your working directory is clean, run \"git rebase --continue\")"
+msgstr "  (一旦您工作目录提交干净后,运行 \"git rebase --continue\")"
+
+#: wt-status.c:893
+msgid "You are currently editing a commit during a rebase."
+msgstr "您正在变基过程中编辑一个提交。"
+
+#  译者:注意保持前导空格
+#: wt-status.c:896
+msgid "  (use \"git commit --amend\" to amend the current commit)"
+msgstr "  (使用 \"git commit --amend\" 修补当前提交)"
+
+#  译者:注意保持前导空格
+#: wt-status.c:898
+msgid ""
+"  (use \"git rebase --continue\" once you are satisfied with your changes)"
+msgstr "  (当您对您的修改满意后执行 \"git rebase --continue\")"
+
+#: wt-status.c:908
+msgid "You are currently cherry-picking."
+msgstr "您正在做拣选操作。"
+
+#  译者:注意保持前导空格
+#: wt-status.c:915
+msgid "  (all conflicts fixed: run \"git commit\")"
+msgstr "  (解决所有冲突后,执行 \"git commit\")"
+
+#: wt-status.c:924
+msgid "You are currently bisecting."
+msgstr "您正在做二分查找。"
+
+#  译者:注意保持前导空格
+#: wt-status.c:927
+msgid "  (use \"git bisect reset\" to get back to the original branch)"
+msgstr "  (使用 \"git bisect reset\" 以回到原有分支)"
+
+#: wt-status.c:978
 msgid "On branch "
 msgstr "位于分支 "
 
-#: wt-status.c:744
+#: wt-status.c:985
 msgid "Not currently on any branch."
 msgstr "当前不在任何分支上。"
 
-#: wt-status.c:755
+#: wt-status.c:997
 msgid "Initial commit"
 msgstr "初始提交"
 
-#: wt-status.c:769
-msgid "Untracked"
+#: wt-status.c:1011
+#, fuzzy
+msgid "Untracked files"
 msgstr "未跟踪的"
 
-#: wt-status.c:771
-msgid "Ignored"
+#: wt-status.c:1013
+#, fuzzy
+msgid "Ignored files"
 msgstr "忽略的"
 
-#: wt-status.c:773
+#: wt-status.c:1015
 #, c-format
 msgid "Untracked files not listed%s"
 msgstr "未跟踪的文件没有列出%s"
 
 #  译者:中文字符串拼接,可删除前导空格
-#: wt-status.c:775
+#: wt-status.c:1017
 msgid " (use -u option to show untracked files)"
 msgstr "(使用 -u 参数显示未跟踪的文件)"
 
-#: wt-status.c:781
+#: wt-status.c:1023
 msgid "No changes"
 msgstr "没有修改"
 
-#: wt-status.c:785
-#, c-format
-msgid "no changes added to commit%s\n"
-msgstr "修改尚未加入提交%s\n"
-
 #  译者:中文字符串拼接,可删除前导空格
-#: wt-status.c:787
-msgid " (use \"git add\" and/or \"git commit -a\")"
+#: wt-status.c:1028
+#, fuzzy, c-format
+msgid "no changes added to commit (use \"git add\" and/or \"git commit -a\")\n"
 msgstr "(使用 \"git add\" 和/或 \"git commit -a\")"
 
-#: wt-status.c:789
-#, c-format
-msgid "nothing added to commit but untracked files present%s\n"
-msgstr "空提交但存在未跟踪文件%s\n"
+#: wt-status.c:1031
+#, fuzzy, c-format
+msgid "no changes added to commit\n"
+msgstr "修改尚未加入提交%s\n"
 
-#  译者:中文字符串拼接,可删除前导空格
-#: wt-status.c:791
-msgid " (use \"git add\" to track)"
-msgstr "(使用 \"git add\" 建立跟踪)"
+#: wt-status.c:1034
+#, fuzzy, c-format
+msgid ""
+"nothing added to commit but untracked files present (use \"git add\" to "
+"track)\n"
+msgstr "空提交但存在未跟踪文件%s\n"
 
-#: wt-status.c:793 wt-status.c:796 wt-status.c:799
-#, c-format
-msgid "nothing to commit%s\n"
-msgstr "无须提交%s\n"
+#: wt-status.c:1037
+#, fuzzy, c-format
+msgid "nothing added to commit but untracked files present\n"
+msgstr "空提交但存在未跟踪文件%s\n"
 
 #  译者:中文字符串拼接,可删除前导空格
-#: wt-status.c:794
-msgid " (create/copy files and use \"git add\" to track)"
+#: wt-status.c:1040
+#, fuzzy, c-format
+msgid "nothing to commit (create/copy files and use \"git add\" to track)\n"
 msgstr "(新建/拷贝的文件使用 \"git add\" 建立跟踪)"
 
+#: wt-status.c:1043 wt-status.c:1048
+#, fuzzy, c-format
+msgid "nothing to commit\n"
+msgstr "无须提交%s\n"
+
 #  译者:中文字符串拼接,可删除前导空格
-#: wt-status.c:797
-msgid " (use -u to show untracked files)"
+#: wt-status.c:1046
+#, fuzzy, c-format
+msgid "nothing to commit (use -u to show untracked files)\n"
 msgstr "(使用 -u 显示未跟踪文件)"
 
 #  译者:中文字符串拼接,可删除前导空格
-#: wt-status.c:800
-msgid " (working directory clean)"
+#: wt-status.c:1050
+#, fuzzy, c-format
+msgid "nothing to commit, working directory clean\n"
 msgstr "(干净的工作区)"
 
-#: wt-status.c:908
+#: wt-status.c:1158
 msgid "HEAD (no branch)"
 msgstr "HEAD(非分支)"
 
 #  译者:注意保持句尾空格
-#: wt-status.c:914
+#: wt-status.c:1164
 msgid "Initial commit on "
 msgstr "初始提交于 "
 
 #  译者:注意保持句尾空格
-#: wt-status.c:929
+#: wt-status.c:1179
 msgid "behind "
 msgstr "落后 "
 
 #  译者:注意保持句尾空格
-#: wt-status.c:932 wt-status.c:935
+#: wt-status.c:1182 wt-status.c:1185
 msgid "ahead "
 msgstr "领先 "
 
 #  译者:注意保持句尾空格
-#: wt-status.c:937
+#: wt-status.c:1187
 msgid ", behind "
 msgstr ",落后 "
 
+#: compat/precompose_utf8.c:58 builtin/clone.c:341
+#, c-format
+msgid "failed to unlink '%s'"
+msgstr "无法删除 '%s'"
+
+#: builtin/add.c:19
+#, fuzzy
+msgid "git add [options] [--] <filepattern>..."
+msgstr "git apply [选项] [<补丁>...]"
+
 #: builtin/add.c:62
 #, c-format
 msgid "unexpected diff status %c"
 msgstr "意外的差异状态 %c"
 
-#: builtin/add.c:67 builtin/commit.c:226
+#: builtin/add.c:67 builtin/commit.c:229
 msgid "updating files failed"
 msgstr "更新文件失败"
 
@@ -949,7 +1431,7 @@ msgstr "路径 '%s' 属于模组 '%.*s'"
 msgid "Unstaged changes after refreshing the index:"
 msgstr "刷新索引之后尚未被暂存的变更:"
 
-#: builtin/add.c:195 builtin/add.c:456 builtin/rm.c:186
+#: builtin/add.c:195 builtin/add.c:460 builtin/rm.c:186
 #, c-format
 msgid "pathspec '%s' did not match any files"
 msgstr "路径 '%s' 未匹配任何文件"
@@ -966,11 +1448,11 @@ msgstr "不能读取索引"
 #: builtin/add.c:286
 #, c-format
 msgid "Could not open '%s' for writing."
-msgstr "不能为写入打开 '%s'。"
+msgstr "不能打开 '%s' 以写入。"
 
 #: builtin/add.c:290
 msgid "Could not write patch"
-msgstr "不能补丁"
+msgstr "不能生成补丁"
 
 #: builtin/add.c:295
 #, c-format
@@ -986,110 +1468,165 @@ msgstr "空补丁。异常终止。"
 msgid "Could not apply '%s'"
 msgstr "不能应用 '%s'"
 
-#: builtin/add.c:312
+#: builtin/add.c:313
 msgid "The following paths are ignored by one of your .gitignore files:\n"
-msgstr "下列路径被您的一个 .gitignore 文件所忽略:\n"
+msgstr "下列路径根据您的一个 .gitignore 文件而被忽略:\n"
 
-#: builtin/add.c:352
-#, c-format
-msgid "Use -f if you really want to add them.\n"
-msgstr "使用 -f 参数如果您确实要添加它们。\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
+msgid "dry run"
+msgstr ""
 
-#: builtin/add.c:353
-msgid "no files added"
-msgstr "没有文件被添加"
+#: builtin/add.c:320 builtin/apply.c:4354 builtin/commit.c:1187
+#: builtin/count-objects.c:82 builtin/fsck.c:613 builtin/log.c:1477
+#: builtin/mv.c:62 builtin/read-tree.c:112
+msgid "be verbose"
+msgstr "冗长输出"
 
-#: builtin/add.c:359
-msgid "adding files failed"
-msgstr "添加文件失败"
+#: builtin/add.c:322
+#, fuzzy
+msgid "interactive picking"
+msgstr "交互式添加失败"
 
-#: builtin/add.c:391
-msgid "-A and -u are mutually incompatible"
-msgstr "-A 和 -u 选项互斥"
+#: builtin/add.c:323 builtin/checkout.c:1028 builtin/reset.c:248
+msgid "select hunks interactively"
+msgstr ""
 
-#: builtin/add.c:393
-msgid "Option --ignore-missing can only be used together with --dry-run"
-msgstr "选项 --ignore-missing 只能和 --dry-run 共用"
+#: builtin/add.c:324
+msgid "edit current diff and apply"
+msgstr ""
 
-#: builtin/add.c:413
+#: builtin/add.c:325
+msgid "allow adding otherwise ignored files"
+msgstr ""
+
+#: builtin/add.c:326
+#, fuzzy
+msgid "update tracked files"
+msgstr "无法存储包文件"
+
+#: builtin/add.c:327
+msgid "record only the fact that the path will be added later"
+msgstr ""
+
+#: builtin/add.c:328
+msgid "add changes from all tracked and untracked files"
+msgstr ""
+
+#: builtin/add.c:329
+#, fuzzy
+msgid "don't add, only refresh the index"
+msgstr "git %s:无法刷新索引"
+
+#: builtin/add.c:330
+msgid "just skip files which cannot be added because of errors"
+msgstr ""
+
+#: builtin/add.c:331
+msgid "check if - even missing - files are ignored in dry run"
+msgstr ""
+
+#: builtin/add.c:353
+#, c-format
+msgid "Use -f if you really want to add them.\n"
+msgstr "使用 -f 参数如果您确实要添加它们。\n"
+
+#: builtin/add.c:354
+msgid "no files added"
+msgstr "没有文件被添加"
+
+#: builtin/add.c:360
+msgid "adding files failed"
+msgstr "添加文件失败"
+
+#: builtin/add.c:392
+msgid "-A and -u are mutually incompatible"
+msgstr "-A 和 -u 选项互斥"
+
+#: builtin/add.c:394
+msgid "Option --ignore-missing can only be used together with --dry-run"
+msgstr "选项 --ignore-missing 只能和 --dry-run 同时使用"
+
+#: builtin/add.c:414
 #, c-format
 msgid "Nothing specified, nothing added.\n"
 msgstr "没有指定文件,也没有文件被添加。\n"
 
-#: builtin/add.c:414
+#: builtin/add.c:415
 #, c-format
 msgid "Maybe you wanted to say 'git add .'?\n"
 msgstr "也许您想要执行 'git add .'?\n"
 
-#: builtin/add.c:420 builtin/clean.c:95 builtin/commit.c:286 builtin/mv.c:82
+#: builtin/add.c:421 builtin/clean.c:95 builtin/commit.c:289 builtin/mv.c:82
 #: builtin/rm.c:162
 msgid "index file corrupt"
 msgstr "索引文件损坏"
 
-#: builtin/add.c:476 builtin/apply.c:4108 builtin/mv.c:229 builtin/rm.c:260
+#: builtin/add.c:481 builtin/apply.c:4450 builtin/mv.c:229 builtin/rm.c:260
 msgid "Unable to write new index file"
 msgstr "无法写入新索引文件"
 
-#: builtin/apply.c:53
+#: builtin/apply.c:57
 msgid "git apply [options] [<patch>...]"
 msgstr "git apply [选项] [<补丁>...]"
 
-#: builtin/apply.c:106
+#: builtin/apply.c:110
 #, c-format
 msgid "unrecognized whitespace option '%s'"
 msgstr "未能识别的空白字符选项 '%s'"
 
-#: builtin/apply.c:121
+#: builtin/apply.c:125
 #, c-format
 msgid "unrecognized whitespace ignore option '%s'"
 msgstr "未能识别的空白字符忽略选项 '%s'"
 
-#: builtin/apply.c:815
+#: builtin/apply.c:823
 #, c-format
 msgid "Cannot prepare timestamp regexp %s"
 msgstr "无法准备时间戳正则表达式 %s"
 
-#: builtin/apply.c:824
+#: builtin/apply.c:832
 #, c-format
 msgid "regexec returned %d for input: %s"
 msgstr "regexec 返回 %d,输入为:%s"
 
-#: builtin/apply.c:905
+#: builtin/apply.c:913
 #, c-format
 msgid "unable to find filename in patch at line %d"
 msgstr "不能在补丁的第 %d 行找到文件名"
 
-#: builtin/apply.c:937
+#: builtin/apply.c:945
 #, c-format
 msgid "git apply: bad git-diff - expected /dev/null, got %s on line %d"
-msgstr "git apply:错误的 git-diff - 期望 /dev/null,但在第 %2$d 行得到 %1$s"
+msgstr "git apply:错误的 git-diff - 应为 /dev/null,但在第 %2$d 行得到 %1$s"
 
-#: builtin/apply.c:941
+#: builtin/apply.c:949
 #, c-format
 msgid "git apply: bad git-diff - inconsistent new filename on line %d"
 msgstr "git apply:错误的 git-diff - 第 %d 行上新文件名不一致"
 
-#: builtin/apply.c:942
+#: builtin/apply.c:950
 #, c-format
 msgid "git apply: bad git-diff - inconsistent old filename on line %d"
 msgstr "git apply:错误的 git-diff - 第 %d 行上旧文件名不一致"
 
-#: builtin/apply.c:949
+#: builtin/apply.c:957
 #, c-format
 msgid "git apply: bad git-diff - expected /dev/null on line %d"
-msgstr "git apply:错误的 git-diff - 期望 /dev/null 于第 %d 行"
+msgstr "git apply:错误的 git-diff - 第 %d 行处应为 /dev/null"
 
-#: builtin/apply.c:1394
+#: builtin/apply.c:1420
 #, c-format
 msgid "recount: unexpected line: %.*s"
 msgstr "recount:意外的行:%.*s"
 
-#: builtin/apply.c:1451
+#: builtin/apply.c:1477
 #, c-format
 msgid "patch fragment without header at line %d: %.*s"
 msgstr "第 %d 行的补丁片段没有头信息:%.*s"
 
-#: builtin/apply.c:1468
+#: builtin/apply.c:1494
 #, c-format
 msgid ""
 "git diff header lacks filename information when removing %d leading pathname "
@@ -1100,82 +1637,82 @@ msgid_plural ""
 msgstr[0] "当移除 %d 个前导路径后 git diff 头缺乏文件名信息(第 %d 行)"
 msgstr[1] "当移除 %d 个前导路径后 git diff 头缺乏文件名信息(第 %d 行)"
 
-#: builtin/apply.c:1628
+#: builtin/apply.c:1654
 msgid "new file depends on old contents"
 msgstr "新文件依赖旧内容"
 
-#: builtin/apply.c:1630
+#: builtin/apply.c:1656
 msgid "deleted file still has contents"
 msgstr "删除的文件仍有内容"
 
-#: builtin/apply.c:1656
+#: builtin/apply.c:1682
 #, c-format
 msgid "corrupt patch at line %d"
-msgstr "补丁损坏位于第 %d 行"
+msgstr "补丁在第 %d 行损坏"
 
-#: builtin/apply.c:1692
+#: builtin/apply.c:1718
 #, c-format
 msgid "new file %s depends on old contents"
 msgstr "新文件 %s 依赖旧内容"
 
-#: builtin/apply.c:1694
+#: builtin/apply.c:1720
 #, c-format
 msgid "deleted file %s still has contents"
 msgstr "删除的文件 %s 仍有内容"
 
-#: builtin/apply.c:1697
+#: builtin/apply.c:1723
 #, c-format
 msgid "** warning: file %s becomes empty but is not deleted"
 msgstr "** 警告:文件 %s 成为空文件但并未删除"
 
-#: builtin/apply.c:1843
+#: builtin/apply.c:1869
 #, c-format
 msgid "corrupt binary patch at line %d: %.*s"
 msgstr "二进制补丁在第 %d 行损坏:%.*s"
 
 #. there has to be one hunk (forward hunk)
-#: builtin/apply.c:1872
+#: builtin/apply.c:1898
 #, c-format
 msgid "unrecognized binary patch at line %d"
 msgstr "未能识别的二进制补丁位于第 %d 行"
 
-#: builtin/apply.c:1958
+#: builtin/apply.c:1984
 #, c-format
 msgid "patch with only garbage at line %d"
 msgstr "补丁文件的第 %d 行只有垃圾数据"
 
-#: builtin/apply.c:2048
+#: builtin/apply.c:2074
 #, c-format
 msgid "unable to read symlink %s"
 msgstr "无法读取符号链接 %s"
 
-#: builtin/apply.c:2052
+#: builtin/apply.c:2078
 #, c-format
 msgid "unable to open or read %s"
 msgstr "不能打开或读取 %s"
 
-#: builtin/apply.c:2123
+#: builtin/apply.c:2149
 msgid "oops"
 msgstr "哎哟"
 
-#: builtin/apply.c:2645
+#: builtin/apply.c:2671
 #, c-format
 msgid "invalid start of line: '%c'"
 msgstr "无效的行首字符:'%c'"
 
-#: builtin/apply.c:2763
+#: 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)."
 msgstr[0] "块 #%d 成功应用于 %d (偏移 %d 行)"
 msgstr[1] "块 #%d 成功应用于 %d (偏移 %d 行)"
 
-#: builtin/apply.c:2775
+#: builtin/apply.c:2801
 #, c-format
 msgid "Context reduced to (%ld/%ld) to apply fragment at %d"
 msgstr "上下文减少到(%ld/%ld)以在第 %d 行应用补丁片段"
 
-#: builtin/apply.c:2781
+#: builtin/apply.c:2807
 #, c-format
 msgid ""
 "while searching for:\n"
@@ -1184,313 +1721,319 @@ msgstr ""
 "当查询:\n"
 "%.*s"
 
-#: builtin/apply.c:2800
+#: builtin/apply.c:2826
 #, c-format
 msgid "missing binary patch data for '%s'"
 msgstr "缺失 '%s' 的二进制补丁数据"
 
-#: builtin/apply.c:2903
+#: builtin/apply.c:2929
 #, c-format
 msgid "binary patch does not apply to '%s'"
 msgstr "二进制补丁未应用到 '%s'"
 
-#: builtin/apply.c:2909
+#: builtin/apply.c:2935
 #, c-format
 msgid "binary patch to '%s' creates incorrect result (expecting %s, got %s)"
-msgstr "到 '%s' 的二进制补丁产生了不正确的结果(预期 %s,得到 %s)"
+msgstr "到 '%s' 的二进制补丁产生了不正确的结果(应为 %s,却为 %s)"
 
-#: builtin/apply.c:2930
+#: builtin/apply.c:2956
 #, c-format
 msgid "patch failed: %s:%ld"
 msgstr "打补丁失败:%s:%ld"
 
-#: builtin/apply.c:3045
+#: builtin/apply.c:3078
 #, c-format
-msgid "patch %s has been renamed/deleted"
-msgstr "补丁 %s 已经被重命名/删除"
+msgid "cannot checkout %s"
+msgstr "不能检出 %s"
 
-#: builtin/apply.c:3052 builtin/apply.c:3069
+#: builtin/apply.c:3123 builtin/apply.c:3132 builtin/apply.c:3176
 #, c-format
 msgid "read of %s failed"
 msgstr "读取 %s 失败"
 
-#: builtin/apply.c:3084
-msgid "removal patch leaves file contents"
-msgstr "移除补丁仍留下了文件内容"
-
-#: builtin/apply.c:3105
+#: builtin/apply.c:3156 builtin/apply.c:3378
 #, c-format
-msgid "%s: already exists in working directory"
-msgstr "%s:已经存在于工作区中"
+msgid "path %s has been renamed/deleted"
+msgstr "路径 %s 已经被重命名/删除"
 
-#: builtin/apply.c:3143
+#: builtin/apply.c:3237 builtin/apply.c:3392
 #, c-format
-msgid "%s: has been deleted/renamed"
-msgstr "%s:已经被删除/重命名"
+msgid "%s: does not exist in index"
+msgstr "%s:不存在于索引中"
 
-#: builtin/apply.c:3148 builtin/apply.c:3179
+#: builtin/apply.c:3241 builtin/apply.c:3384 builtin/apply.c:3406
 #, c-format
 msgid "%s: %s"
 msgstr "%s:%s"
 
-#: builtin/apply.c:3159
-#, c-format
-msgid "%s: does not exist in index"
-msgstr "%s:不存在于索引中"
-
-#: builtin/apply.c:3173
+#: builtin/apply.c:3246 builtin/apply.c:3400
 #, c-format
 msgid "%s: does not match index"
 msgstr "%s:和索引不匹配"
 
-#: builtin/apply.c:3190
+#: builtin/apply.c:3348
+msgid "removal patch leaves file contents"
+msgstr "移除补丁仍留下了文件内容"
+
+#: builtin/apply.c:3417
 #, c-format
 msgid "%s: wrong type"
 msgstr "%s:错误类型"
 
-#: builtin/apply.c:3192
+#: builtin/apply.c:3419
 #, c-format
 msgid "%s has type %o, expected %o"
-msgstr "%s 的类型是 %o,预期是 %o"
+msgstr "%s 的类型是 %o,应为 %o"
 
-#: builtin/apply.c:3247
+#: builtin/apply.c:3520
 #, c-format
 msgid "%s: already exists in index"
 msgstr "%s:已经存在于索引中"
 
-#: builtin/apply.c:3267
+#: builtin/apply.c:3523
+#, c-format
+msgid "%s: already exists in working directory"
+msgstr "%s:已经存在于工作区中"
+
+#: builtin/apply.c:3543
 #, c-format
 msgid "new mode (%o) of %s does not match old mode (%o)"
 msgstr "%2$s 的新模式(%1$o)和旧模式(%3$o)不匹配"
 
-#: builtin/apply.c:3272
+#: builtin/apply.c:3548
 #, c-format
 msgid "new mode (%o) of %s does not match old mode (%o) of %s"
 msgstr "%2$s 的新模式(%1$o)和 %4$s 的旧模式(%3$o)不匹配"
 
-#: builtin/apply.c:3280
+#: builtin/apply.c:3556
 #, c-format
 msgid "%s: patch does not apply"
 msgstr "%s:补丁未应用"
 
-#: builtin/apply.c:3293
+#: builtin/apply.c:3569
 #, c-format
 msgid "Checking patch %s..."
 msgstr "检查补丁 %s..."
 
-#: builtin/apply.c:3348 builtin/checkout.c:212 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 "对路径 '%s' 的 make_cache_entry 操作失败"
 
-#: builtin/apply.c:3491
+#: builtin/apply.c:3767
 #, c-format
 msgid "unable to remove %s from index"
 msgstr "不能从索引中移除 %s"
 
-#: builtin/apply.c:3518
+#: builtin/apply.c:3795
 #, c-format
 msgid "corrupt patch for subproject %s"
 msgstr "子项目 %s 损坏的补丁"
 
-#: builtin/apply.c:3522
+#: builtin/apply.c:3799
 #, c-format
 msgid "unable to stat newly created file '%s'"
 msgstr "不能枚举新建文件 '%s' 的状态"
 
-#: builtin/apply.c:3527
+#: builtin/apply.c:3804
 #, c-format
 msgid "unable to create backing store for newly created file %s"
 msgstr "不能为新建文件 %s 创建后端存储"
 
-#: builtin/apply.c:3530
+#: builtin/apply.c:3807 builtin/apply.c:3915
 #, c-format
 msgid "unable to add cache entry for %s"
 msgstr "无法为 %s 添加缓存条目"
 
-#: builtin/apply.c:3563
+#: builtin/apply.c:3840
 #, c-format
 msgid "closing file '%s'"
 msgstr "关闭文件 '%s'"
 
-#: builtin/apply.c:3612
+#: builtin/apply.c:3889
 #, c-format
 msgid "unable to write file '%s' mode %o"
 msgstr "不能写文件 '%s' 权限 %o"
 
-#: builtin/apply.c:3668
+#: builtin/apply.c:3976
 #, c-format
 msgid "Applied patch %s cleanly."
 msgstr "成功应用补丁 %s。"
 
-#: builtin/apply.c:3676
+#: builtin/apply.c:3984
 msgid "internal error"
 msgstr "内部错误"
 
 #. Say this even without --verbose
-#: builtin/apply.c:3679
+#: builtin/apply.c:3987
 #, c-format
 msgid "Applying patch %%s with %d reject..."
 msgid_plural "Applying patch %%s with %d rejects..."
-msgstr[0] "应用补丁 %%s 时 %d 个被拒绝..."
-msgstr[1] "应用补丁 %%s 时 %d 个被拒绝..."
+msgstr[0] "应用 %%s 个补丁,其中 %d 个被拒绝..."
+msgstr[1] "应用 %%s 个补丁,其中 %d 个被拒绝..."
 
-#: builtin/apply.c:3689
+#: builtin/apply.c:3997
 #, c-format
 msgid "truncating .rej filename to %.*s.rej"
 msgstr "截短 .rej 文件名为 %.*s.rej"
 
-#: builtin/apply.c:3710
+#: builtin/apply.c:4018
 #, c-format
 msgid "Hunk #%d applied cleanly."
 msgstr "第 #%d 个片段成功应用。"
 
-#: builtin/apply.c:3713
+#: builtin/apply.c:4021
 #, c-format
 msgid "Rejected hunk #%d."
 msgstr "拒绝第 #%d 个片段。"
 
-#: builtin/apply.c:3844
+#: builtin/apply.c:4171
 msgid "unrecognized input"
 msgstr "未能识别的输入"
 
-#: builtin/apply.c:3855
+#: builtin/apply.c:4182
 msgid "unable to read index file"
 msgstr "无法读取索引文件"
 
-#: builtin/apply.c:3970 builtin/apply.c:3973
+#: builtin/apply.c:4301 builtin/apply.c:4304 builtin/clone.c:91
+#: builtin/fetch.c:63
 msgid "path"
 msgstr "路径"
 
-#: builtin/apply.c:3971
+#: builtin/apply.c:4302
 msgid "don't apply changes matching the given path"
 msgstr "不要应用与给出路径向匹配的变更"
 
-#: builtin/apply.c:3974
+#: builtin/apply.c:4305
 msgid "apply changes matching the given path"
 msgstr "应用与给出路径向匹配的变更"
 
-#: builtin/apply.c:3976
+#: builtin/apply.c:4307
 msgid "num"
 msgstr "数字"
 
-#: builtin/apply.c:3977
+#: builtin/apply.c:4308
 msgid "remove <num> leading slashes from traditional diff paths"
 msgstr "从传统的 diff 路径中移除 <数字> 个前导路径"
 
-#: builtin/apply.c:3980
+#: builtin/apply.c:4311
 msgid "ignore additions made by the patch"
 msgstr "忽略补丁中的添加的文件"
 
-#: builtin/apply.c:3982
+#: builtin/apply.c:4313
 msgid "instead of applying the patch, output diffstat for the input"
 msgstr "不应用补丁,而是显示输入的差异统计(diffstat)"
 
-#: builtin/apply.c:3986
-msgid "shows number of added and deleted lines in decimal notation"
+#: builtin/apply.c:4317
+#, fuzzy
+msgid "show number of added and deleted lines in decimal notation"
 msgstr "以数字方式显示添加或删除行的数量"
 
-#: builtin/apply.c:3988
+#: builtin/apply.c:4319
 msgid "instead of applying the patch, output a summary for the input"
 msgstr "不应用补丁,而是显示输入的概要"
 
-#: builtin/apply.c:3990
+#: builtin/apply.c:4321
 msgid "instead of applying the patch, see if the patch is applicable"
 msgstr "不应用补丁,而是查看补丁是否可应用"
 
-#: builtin/apply.c:3992
+#: builtin/apply.c:4323
 msgid "make sure the patch is applicable to the current index"
 msgstr "确认补丁可以应用到当前索引"
 
-#: builtin/apply.c:3994
+#: builtin/apply.c:4325
 msgid "apply a patch without touching the working tree"
 msgstr "应用补丁而不修改工作区"
 
-#: builtin/apply.c:3996
+#: builtin/apply.c:4327
 msgid "also apply the patch (use with --stat/--summary/--check)"
-msgstr "同时应用此补丁(和 --stat/--summary/--check 共用)"
+msgstr "还应用此补丁(与 --stat/--summary/--check 选项同时使用)"
 
-#: builtin/apply.c:3998
+#: builtin/apply.c:4329
+msgid "attempt three-way merge if a patch does not apply"
+msgstr "如果一个补丁不能应用则尝试三路合并"
+
+#: builtin/apply.c:4331
 msgid "build a temporary index based on embedded index information"
 msgstr "创建一个临时索引基于嵌入的索引信息"
 
-#: builtin/apply.c:4000
+#: builtin/apply.c:4333 builtin/checkout-index.c:197 builtin/ls-files.c:460
 msgid "paths are separated with NUL character"
 msgstr "路径以 NUL 字符分隔"
 
-#: builtin/apply.c:4003
+#: builtin/apply.c:4336
 msgid "ensure at least <n> lines of context match"
 msgstr "确保至少匹配 <n> 行上下文"
 
-#: builtin/apply.c:4004
+#: builtin/apply.c:4337
 msgid "action"
 msgstr "动作"
 
-#: builtin/apply.c:4005
+#: builtin/apply.c:4338
 msgid "detect new or modified lines that have whitespace errors"
 msgstr "检查新增和修改的行中间的空白字符滥用"
 
-#: builtin/apply.c:4008 builtin/apply.c:4011
+#: builtin/apply.c:4341 builtin/apply.c:4344
 msgid "ignore changes in whitespace when finding context"
 msgstr "查找上下文时忽略空白字符的变更"
 
-#: builtin/apply.c:4014
+#: builtin/apply.c:4347
 msgid "apply the patch in reverse"
 msgstr "反向应用补丁"
 
-#: builtin/apply.c:4016
+#: builtin/apply.c:4349
 msgid "don't expect at least one line of context"
 msgstr "无需至少一行上下文"
 
-#: builtin/apply.c:4018
+#: builtin/apply.c:4351
 msgid "leave the rejected hunks in corresponding *.rej files"
 msgstr "将拒绝的补丁片段保存在对应的 *.rej 文件中"
 
-#: builtin/apply.c:4020
+#: builtin/apply.c:4353
 msgid "allow overlapping hunks"
 msgstr "允许重叠的补丁片段"
 
-#: builtin/apply.c:4021
-msgid "be verbose"
-msgstr "冗长输出"
-
-#: builtin/apply.c:4023
+#: builtin/apply.c:4356
 msgid "tolerate incorrectly detected missing new-line at the end of file"
-msgstr "宽容不正确的文件末尾换行符"
+msgstr "å\85\81许不正确的文件末尾换行符"
 
-#: builtin/apply.c:4026
+#: builtin/apply.c:4359
 msgid "do not trust the line counts in the hunk headers"
 msgstr "不信任补丁片段的头信息中的行号"
 
-#: builtin/apply.c:4028
+#: builtin/apply.c:4361
 msgid "root"
 msgstr "根目录"
 
-#: builtin/apply.c:4029
+#: builtin/apply.c:4362
 msgid "prepend <root> to all filenames"
 msgstr "为所有文件名前添加 <根目录>"
 
-#: builtin/apply.c:4050
+#: builtin/apply.c:4384
+msgid "--3way outside a repository"
+msgstr "--3way 在一个版本库之外"
+
+#: builtin/apply.c:4392
 msgid "--index outside a repository"
 msgstr "--index 在一个版本库之外"
 
-#: builtin/apply.c:4053
+#: builtin/apply.c:4395
 msgid "--cached outside a repository"
 msgstr "--cached 在一个版本库之外"
 
-#: builtin/apply.c:4069
+#: builtin/apply.c:4411
 #, c-format
 msgid "can't open patch '%s'"
 msgstr "不能打开补丁 '%s'"
 
-#: builtin/apply.c:4083
+#: builtin/apply.c:4425
 #, c-format
 msgid "squelched %d whitespace error"
 msgid_plural "squelched %d whitespace errors"
 msgstr[0] "抑制下仍有 %d 个空白字符误用"
 msgstr[1] "抑制下仍有 %d 个空白字符误用"
 
-#: builtin/apply.c:4089 builtin/apply.c:4099
+#: builtin/apply.c:4431 builtin/apply.c:4441
 #, c-format
 msgid "%d line adds whitespace errors."
 msgid_plural "%d lines add whitespace errors."
@@ -1504,7 +2047,7 @@ msgstr "不能创建归档文件 '%s'"
 
 #: builtin/archive.c:20
 msgid "could not redirect output"
-msgstr "不能输出重定向"
+msgstr "不能重定向输出"
 
 #: builtin/archive.c:37
 msgid "git archive: Remote with no URL"
@@ -1512,7 +2055,7 @@ msgstr "git archive:未提供远程URL"
 
 #: builtin/archive.c:58
 msgid "git archive: expected ACK/NAK, got EOF"
-msgstr "git archive:期待ACK/NACK,却得到EOF"
+msgstr "git archive:应为ACK/NACK,却得到EOF"
 
 #: builtin/archive.c:63
 #, c-format
@@ -1530,10 +2073,142 @@ msgstr "git archive:协议错误"
 
 #: builtin/archive.c:71
 msgid "git archive: expected a flush"
-msgstr "git archive:预期一个刷新"
+msgstr "git archive:应为刷新"
+
+#: builtin/bisect--helper.c:7
+msgid "git bisect--helper --next-all [--no-checkout]"
+msgstr ""
+
+#: builtin/bisect--helper.c:17
+msgid "perform 'git bisect next'"
+msgstr ""
+
+#: builtin/bisect--helper.c:19
+msgid "update BISECT_HEAD instead of checking out the current commit"
+msgstr ""
+
+#: builtin/blame.c:25
+msgid "git blame [options] [rev-opts] [rev] [--] file"
+msgstr ""
+
+#: builtin/blame.c:30 builtin/shortlog.c:15
+msgid "[rev-opts] are documented in git-rev-list(1)"
+msgstr ""
+
+#: builtin/blame.c:2316
+msgid "Show blame entries as we find them, incrementally"
+msgstr ""
+
+#: builtin/blame.c:2317
+msgid "Show blank SHA-1 for boundary commits (Default: off)"
+msgstr ""
+
+#: builtin/blame.c:2318
+msgid "Do not treat root commits as boundaries (Default: off)"
+msgstr ""
+
+#: builtin/blame.c:2319
+#, fuzzy
+msgid "Show work cost statistics"
+msgstr "显示工作区状态"
+
+#: builtin/blame.c:2320
+msgid "Show output score for blame entries"
+msgstr ""
+
+#: builtin/blame.c:2321
+msgid "Show original filename (Default: auto)"
+msgstr ""
+
+#: builtin/blame.c:2322
+msgid "Show original linenumber (Default: off)"
+msgstr ""
+
+#: builtin/blame.c:2323
+msgid "Show in a format designed for machine consumption"
+msgstr ""
+
+#: builtin/blame.c:2324
+msgid "Show porcelain format with per-line commit information"
+msgstr ""
+
+#: builtin/blame.c:2325
+msgid "Use the same output mode as git-annotate (Default: off)"
+msgstr ""
+
+#: builtin/blame.c:2326
+msgid "Show raw timestamp (Default: off)"
+msgstr ""
+
+#: builtin/blame.c:2327
+msgid "Show long commit SHA1 (Default: off)"
+msgstr ""
+
+#: builtin/blame.c:2328
+msgid "Suppress author name and timestamp (Default: off)"
+msgstr ""
+
+#: builtin/blame.c:2329
+msgid "Show author email instead of name (Default: off)"
+msgstr ""
+
+#: builtin/blame.c:2330
+msgid "Ignore whitespace differences"
+msgstr ""
+
+#: builtin/blame.c:2331
+msgid "Spend extra cycles to find better match"
+msgstr ""
+
+#: builtin/blame.c:2332
+msgid "Use revisions from <file> instead of calling git-rev-list"
+msgstr ""
+
+#: builtin/blame.c:2333
+#, fuzzy
+msgid "Use <file>'s contents as the final image"
+msgstr "添加文件内容至索引"
+
+#: builtin/blame.c:2334 builtin/blame.c:2335
+msgid "score"
+msgstr ""
+
+#: builtin/blame.c:2334
+msgid "Find line copies within and across files"
+msgstr ""
+
+#: builtin/blame.c:2335
+msgid "Find line movements within and across files"
+msgstr ""
+
+#: builtin/blame.c:2336
+#, fuzzy
+msgid "n,m"
+msgstr "数字"
+
+#: builtin/blame.c:2336
+msgid "Process only line range n,m, counting from 1"
+msgstr ""
+
+#: builtin/branch.c:23
+msgid "git branch [options] [-r | -a] [--merged | --no-merged]"
+msgstr ""
+
+#: builtin/branch.c:24
+msgid "git branch [options] [-l] [-f] <branchname> [<start-point>]"
+msgstr ""
+
+#: builtin/branch.c:25
+#, fuzzy
+msgid "git branch [options] [-r] (-d | -D) <branchname>..."
+msgstr "git apply [选项] [<补丁>...]"
+
+#: builtin/branch.c:26
+msgid "git branch [options] (-m | -M) [<oldbranch>] <newbranch>"
+msgstr ""
 
 #  译者:保持原换行格式,在输出时 %s 的替代内容会让字符串变长
-#: builtin/branch.c:144
+#: builtin/branch.c:145
 #, c-format
 msgid ""
 "deleting branch '%s' that has been merged to\n"
@@ -1543,7 +2218,7 @@ msgstr ""
 "         '%s',但未合并到 HEAD。"
 
 #  译者:保持原换行格式,在输出时 %s 的替代内容会让字符串变长
-#: builtin/branch.c:148
+#: builtin/branch.c:149
 #, c-format
 msgid ""
 "not deleting branch '%s' that is not yet merged to\n"
@@ -1552,35 +2227,35 @@ msgstr ""
 "并未删除分支 '%s', 虽然它已经合并到 HEAD,\n"
 "         然而却尚未被合并到分支 '%s' 。"
 
-#: builtin/branch.c:180
+#: builtin/branch.c:181
 msgid "cannot use -a with -d"
-msgstr "ä¸\8dè\83½å°\86 -a å\92\8c -d å\85±用"
+msgstr "ä¸\8dè\83½å°\86 -a å\92\8c -d å\90\8cæ\97¶ä½¿用"
 
-#: builtin/branch.c:186
+#: builtin/branch.c:187
 msgid "Couldn't look up commit object for HEAD"
 msgstr "无法查询 HEAD 指向的提交对象"
 
-#: builtin/branch.c:191
+#: builtin/branch.c:192
 #, c-format
 msgid "Cannot delete the branch '%s' which you are currently on."
 msgstr "无法删除您当前所在的分支 '%s'。"
 
-#: builtin/branch.c:202
+#: builtin/branch.c:203
 #, c-format
 msgid "remote branch '%s' not found."
 msgstr "远程分支 '%s' 未发现。"
 
-#: builtin/branch.c:203
+#: builtin/branch.c:204
 #, c-format
 msgid "branch '%s' not found."
 msgstr "分支 '%s' 未发现。"
 
-#: builtin/branch.c:210
+#: builtin/branch.c:211
 #, c-format
 msgid "Couldn't look up commit object for '%s'"
 msgstr "无法查询 '%s' 指向的提交对象"
 
-#: builtin/branch.c:216
+#: builtin/branch.c:217
 #, c-format
 msgid ""
 "The branch '%s' is not fully merged.\n"
@@ -1589,126 +2264,258 @@ msgstr ""
 "分支 '%s' 没有完全合并。\n"
 "如果您确认要删除它,执行 'git branch -D %s'。"
 
-#: builtin/branch.c:225
+#: builtin/branch.c:226
 #, c-format
 msgid "Error deleting remote branch '%s'"
 msgstr "删除远程分支 '%s' 时出错"
 
-#: builtin/branch.c:226
+#: builtin/branch.c:227
 #, c-format
 msgid "Error deleting branch '%s'"
 msgstr "删除分支 '%s' 时出错"
 
-#: builtin/branch.c:233
+#: builtin/branch.c:234
 #, c-format
 msgid "Deleted remote branch %s (was %s).\n"
 msgstr "已删除远程分支 %s(曾为 %s)。\n"
 
-#: builtin/branch.c:234
+#: builtin/branch.c:235
 #, c-format
 msgid "Deleted branch %s (was %s).\n"
 msgstr "已删除分支 %s(曾为 %s)。\n"
 
-#: builtin/branch.c:239
+#: builtin/branch.c:240
 msgid "Update of config-file failed"
 msgstr "无法更新 config 文件"
 
-#: builtin/branch.c:337
+#: builtin/branch.c:338
 #, c-format
 msgid "branch '%s' does not point at a commit"
 msgstr "分支 '%s' 未指向一个提交"
 
-#: builtin/branch.c:409
+#: builtin/branch.c:410
 #, c-format
 msgid "[%s: behind %d]"
 msgstr "[%s:落后 %d]"
 
-#: builtin/branch.c:411
+#: builtin/branch.c:412
 #, c-format
 msgid "[behind %d]"
 msgstr "[落后 %d]"
 
-#: builtin/branch.c:415
+#: builtin/branch.c:416
 #, c-format
 msgid "[%s: ahead %d]"
 msgstr "[%s:领先 %d]"
 
-#: builtin/branch.c:417
+#: builtin/branch.c:418
 #, c-format
 msgid "[ahead %d]"
 msgstr "[领先 %d]"
 
-#: builtin/branch.c:420
+#: builtin/branch.c:421
 #, c-format
 msgid "[%s: ahead %d, behind %d]"
 msgstr "[%s:领先 %d,落后 %d]"
 
-#: builtin/branch.c:423
+#: builtin/branch.c:424
 #, c-format
 msgid "[ahead %d, behind %d]"
 msgstr "[领先 %d,落后 %d]"
 
-#: builtin/branch.c:535
+#: builtin/branch.c:537
 msgid "(no branch)"
 msgstr "(非分支)"
 
-#: builtin/branch.c:600
+#: builtin/branch.c:602
 msgid "some refs could not be read"
 msgstr "一些引用不能读取"
 
-#: builtin/branch.c:613
+#: builtin/branch.c:615
 msgid "cannot rename the current branch while not on any."
 msgstr "无法重命名当前分支因为不处于任何分支上。"
 
-#: builtin/branch.c:623
+#: builtin/branch.c:625
 #, c-format
 msgid "Invalid branch name: '%s'"
 msgstr "无效的分支名:'%s'"
 
-#: builtin/branch.c:638
+#: builtin/branch.c:640
 msgid "Branch rename failed"
 msgstr "分支重命名失败"
 
-#: builtin/branch.c:642
+#: builtin/branch.c:644
 #, c-format
 msgid "Renamed a misnamed branch '%s' away"
 msgstr "重命名掉一个错误命名的旧分支 '%s'"
 
-#: builtin/branch.c:646
+#: builtin/branch.c:648
 #, c-format
 msgid "Branch renamed to %s, but HEAD is not updated!"
 msgstr "分支重命名为 %s,但 HEAD 没有更新!"
 
-#: builtin/branch.c:653
+#: builtin/branch.c:655
 msgid "Branch is renamed, but update of config-file failed"
 msgstr "分支被重命名,但更新 config 文件失败"
 
-#: builtin/branch.c:668
+#: builtin/branch.c:670
 #, c-format
 msgid "malformed object name %s"
 msgstr "非法的对象名 %s"
 
-#: builtin/branch.c:692
+#: builtin/branch.c:694
 #, c-format
 msgid "could not write branch description template: %s"
 msgstr "不能写分支描述模版:%s"
 
-#: builtin/branch.c:783
+#: builtin/branch.c:724
+#, fuzzy
+msgid "Generic options"
+msgstr "无效选项:%s"
+
+#: builtin/branch.c:726
+msgid "show hash and subject, give twice for upstream branch"
+msgstr ""
+
+#: builtin/branch.c:727
+msgid "suppress informational messages"
+msgstr ""
+
+#: builtin/branch.c:728
+msgid "set up tracking mode (see git-pull(1))"
+msgstr ""
+
+#: builtin/branch.c:730
+msgid "change upstream info"
+msgstr ""
+
+#: builtin/branch.c:734
+#, fuzzy
+msgid "use colored output"
+msgstr "不能输出重定向"
+
+#: builtin/branch.c:735
+#, fuzzy
+msgid "act on remote-tracking branches"
+msgstr "%s 没有来自 %s 的远程跟踪分支"
+
+#: builtin/branch.c:738 builtin/branch.c:744 builtin/branch.c:765
+#: builtin/branch.c:771 builtin/commit.c:1395 builtin/commit.c:1396
+#: builtin/commit.c:1397 builtin/commit.c:1398 builtin/tag.c:470
+#, fuzzy
+msgid "commit"
+msgstr "(坏提交)\n"
+
+#: builtin/branch.c:739 builtin/branch.c:745
+msgid "print only branches that contain the commit"
+msgstr ""
+
+#: builtin/branch.c:751
+msgid "Specific git-branch actions:"
+msgstr ""
+
+#: builtin/branch.c:752
+msgid "list both remote-tracking and local branches"
+msgstr ""
+
+#: builtin/branch.c:754
+msgid "delete fully merged branch"
+msgstr ""
+
+#: builtin/branch.c:755
+msgid "delete branch (even if not merged)"
+msgstr ""
+
+#: builtin/branch.c:756
+msgid "move/rename a branch and its reflog"
+msgstr ""
+
+#: builtin/branch.c:757
+msgid "move/rename a branch, even if target exists"
+msgstr ""
+
+#: builtin/branch.c:758
+#, fuzzy
+msgid "list branch names"
+msgstr "无效的分支名:'%s'"
+
+#: builtin/branch.c:759
+msgid "create the branch's reflog"
+msgstr ""
+
+#: builtin/branch.c:761
+msgid "edit the description for the branch"
+msgstr ""
+
+#: builtin/branch.c:762
+#, fuzzy
+msgid "force creation (when already exists)"
+msgstr "远程 %s 已经存在。"
+
+#: builtin/branch.c:765
+#, fuzzy
+msgid "print only not merged branches"
+msgstr "无法移除分支 %s"
+
+#: builtin/branch.c:771
+msgid "print only merged branches"
+msgstr ""
+
+#: builtin/branch.c:775
+msgid "list branches in columns"
+msgstr ""
+
+#: builtin/branch.c:788
 msgid "Failed to resolve HEAD as a valid ref."
 msgstr "无法将 HEAD 解析为有效引用。"
 
-#: builtin/branch.c:788 builtin/clone.c:558
+#: builtin/branch.c:793 builtin/clone.c:561
 msgid "HEAD not found below refs/heads!"
 msgstr "HEAD 没有位于 /refs/heads 之下!"
 
-#: builtin/branch.c:808
+#: builtin/branch.c:813
 msgid "--column and --verbose are incompatible"
 msgstr "--column 和 --verbose 不兼容"
 
-#: builtin/branch.c:857
+#: builtin/branch.c:864
+#, fuzzy, c-format
+msgid "branch '%s' does not exist"
+msgstr "版本库 '%s' 不存在"
+
+#: builtin/branch.c:876
+#, c-format
+msgid "Branch '%s' has no upstream information"
+msgstr ""
+
+#: builtin/branch.c:891
 msgid "-a and -r options to 'git branch' do not make sense with a branch name"
 msgstr "'git branch' 的 -a 和 -r 选项带一个分支名参数没有意义"
 
+#: builtin/branch.c:894
+#, 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
+#, c-format
+msgid ""
+"\n"
+"If you wanted to make '%s' track '%s', do this:\n"
+"\n"
+msgstr ""
+
+#: builtin/branch.c:912
+#, fuzzy, c-format
+msgid "    git branch -d %s\n"
+msgstr "  HEAD分支:%s"
+
+#: builtin/branch.c:913
+#, c-format
+msgid "    git branch --set-upstream-to %s\n"
+msgstr ""
+
 #: builtin/bundle.c:47
 #, c-format
 msgid "%s is okay\n"
@@ -1722,100 +2529,238 @@ msgstr "需要一个版本库来创建包。"
 msgid "Need a repository to unbundle."
 msgstr "需要一个版本库来解包。"
 
-#: builtin/checkout.c:113 builtin/checkout.c:146
+#: builtin/cat-file.c:247
+msgid "git cat-file (-t|-s|-e|-p|<type>|--textconv) <object>"
+msgstr ""
+
+#: builtin/cat-file.c:248
+msgid "git cat-file (--batch|--batch-check) < <list_of_objects>"
+msgstr ""
+
+#: builtin/cat-file.c:266
+msgid "<type> can be one of: blob, tree, commit, tag"
+msgstr ""
+
+#: builtin/cat-file.c:267
+#, fuzzy
+msgid "show object type"
+msgstr "坏的对象类型。"
+
+#: builtin/cat-file.c:268
+#, fuzzy
+msgid "show object size"
+msgstr "坏对象 %s"
+
+#: builtin/cat-file.c:270
+msgid "exit with zero when there's no error"
+msgstr ""
+
+#: builtin/cat-file.c:271
+msgid "pretty-print object's content"
+msgstr ""
+
+#: builtin/cat-file.c:273
+msgid "for blob objects, run textconv on object's content"
+msgstr ""
+
+#: builtin/cat-file.c:275
+msgid "show info and content of objects fed from the standard input"
+msgstr ""
+
+#: builtin/cat-file.c:278
+#, fuzzy
+msgid "show info about objects fed from the standard input"
+msgstr "不能从标准输入中读取日志信息"
+
+#: builtin/check-attr.c:11
+msgid "git check-attr [-a | --all | attr...] [--] pathname..."
+msgstr ""
+
+#: builtin/check-attr.c:12
+msgid "git check-attr --stdin [-a | --all | attr...] < <list-of-paths>"
+msgstr ""
+
+#: builtin/check-attr.c:19
+msgid "report all attributes set on file"
+msgstr ""
+
+#: builtin/check-attr.c:20
+msgid "use .gitattributes only from the index"
+msgstr ""
+
+#: builtin/check-attr.c:21 builtin/hash-object.c:75
+#, fuzzy
+msgid "read file names from stdin"
+msgstr "(正从标准输入中读取日志信息)\n"
+
+#: builtin/check-attr.c:23
+#, fuzzy
+msgid "input paths are terminated by a null character"
+msgstr "路径以 NUL 字符分隔"
+
+#: builtin/checkout-index.c:126
+msgid "git checkout-index [options] [--] [<file>...]"
+msgstr ""
+
+#: builtin/checkout-index.c:187
+msgid "check out all files in the index"
+msgstr ""
+
+#: builtin/checkout-index.c:188
+msgid "force overwrite of existing files"
+msgstr ""
+
+#: builtin/checkout-index.c:190
+msgid "no warning for existing files and files not in index"
+msgstr ""
+
+#: builtin/checkout-index.c:192
+#, fuzzy
+msgid "don't checkout new files"
+msgstr "不能检出 %s"
+
+#: builtin/checkout-index.c:194
+#, fuzzy
+msgid "update stat information in the index file"
+msgstr "无法写新的索引文件"
+
+#: builtin/checkout-index.c:200
+#, fuzzy
+msgid "read list of paths from the standard input"
+msgstr "(正从标准输入中读取日志信息)\n"
+
+#: builtin/checkout-index.c:202
+msgid "write the content to temporary files"
+msgstr ""
+
+#: builtin/checkout-index.c:203 builtin/column.c:30
+msgid "string"
+msgstr ""
+
+#: builtin/checkout-index.c:204
+msgid "when creating files, prepend <string>"
+msgstr ""
+
+#: builtin/checkout-index.c:207
+msgid "copy out the files from named stage"
+msgstr ""
+
+#: builtin/checkout.c:25
+#, fuzzy
+msgid "git checkout [options] <branch>"
+msgstr "git apply [选项] [<补丁>...]"
+
+#: builtin/checkout.c:26
+#, fuzzy
+msgid "git checkout [options] [<branch>] -- <file>..."
+msgstr "git apply [选项] [<补丁>...]"
+
+#: builtin/checkout.c:116 builtin/checkout.c:149
 #, c-format
 msgid "path '%s' does not have our version"
 msgstr "路径 '%s' 没有我们的版本"
 
-#: builtin/checkout.c:115 builtin/checkout.c:148
+#: builtin/checkout.c:118 builtin/checkout.c:151
 #, c-format
 msgid "path '%s' does not have their version"
 msgstr "路径 '%s' 没有他们的版本"
 
-#: builtin/checkout.c:131
+#: builtin/checkout.c:134
 #, c-format
 msgid "path '%s' does not have all necessary versions"
 msgstr "路径 '%s' 没有全部必须的版本"
 
-#: builtin/checkout.c:175
+#: builtin/checkout.c:178
 #, c-format
 msgid "path '%s' does not have necessary versions"
 msgstr "路径 '%s' 没有必须的版本"
 
-#: builtin/checkout.c:192
+#: builtin/checkout.c:195
 #, c-format
 msgid "path '%s': cannot merge"
 msgstr "path '%s':无法合并"
 
-#: builtin/checkout.c:209
+#: builtin/checkout.c:212
 #, c-format
 msgid "Unable to add merge result for '%s'"
 msgstr "无法为 '%s' 添加合并结果"
 
-#: builtin/checkout.c:234 builtin/checkout.c:392
+#: builtin/checkout.c:236 builtin/checkout.c:239 builtin/checkout.c:242
+#: builtin/checkout.c:245
+#, fuzzy, c-format
+msgid "'%s' cannot be used with updating paths"
+msgstr "%s:%s 不能和 %s 同时使用"
+
+#: builtin/checkout.c:248 builtin/checkout.c:251
+#, fuzzy, c-format
+msgid "'%s' cannot be used with %s"
+msgstr "%s:%s 不能和 %s 同时使用"
+
+#: builtin/checkout.c:254
+#, c-format
+msgid "Cannot update paths and switch to branch '%s' at the same time."
+msgstr ""
+
+#: builtin/checkout.c:265 builtin/checkout.c:426
 msgid "corrupt index file"
 msgstr "损坏的索引文件"
 
-#: builtin/checkout.c:264 builtin/checkout.c:271
+#: builtin/checkout.c:295 builtin/checkout.c:302
 #, c-format
 msgid "path '%s' is unmerged"
 msgstr "路径 '%s' 未合并"
 
-#: builtin/checkout.c:302 builtin/checkout.c:498 builtin/clone.c:583
-#: builtin/merge.c:812
+#: 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:319 builtin/diff.c:302 builtin/merge.c:408
-msgid "diff_setup_done failed"
-msgstr "diff_setup_done 失败"
-
-#: builtin/checkout.c:414
+#: builtin/checkout.c:448
 msgid "you need to resolve your current index first"
 msgstr "您需要先解决当前索引的冲突"
 
-#: builtin/checkout.c:533
+#: builtin/checkout.c:569
 #, c-format
 msgid "Can not do reflog for '%s'\n"
 msgstr "不能对 '%s' 执行 reflog 操作\n"
 
-#: builtin/checkout.c:566
+#: builtin/checkout.c:602
 msgid "HEAD is now at"
 msgstr "HEAD 目前位于"
 
-#: builtin/checkout.c:573
+#: builtin/checkout.c:609
 #, c-format
 msgid "Reset branch '%s'\n"
 msgstr "重置分支 '%s'\n"
 
-#: builtin/checkout.c:576
+#: builtin/checkout.c:612
 #, c-format
 msgid "Already on '%s'\n"
 msgstr "已经位于 '%s'\n"
 
-#: builtin/checkout.c:580
+#: builtin/checkout.c:616
 #, c-format
 msgid "Switched to and reset branch '%s'\n"
 msgstr "切换并重置分支 '%s'\n"
 
-#: builtin/checkout.c:582
+#: builtin/checkout.c:618
 #, c-format
 msgid "Switched to a new branch '%s'\n"
 msgstr "切换到一个新分支 '%s'\n"
 
-#: builtin/checkout.c:584
+#: builtin/checkout.c:620
 #, c-format
 msgid "Switched to branch '%s'\n"
 msgstr "切换到分支 '%s'\n"
 
 #  译者:注意保持前导空格
-#: builtin/checkout.c:640
+#: builtin/checkout.c:676
 #, c-format
 msgid " ... and %d more.\n"
 msgstr " ... 及其它 %d 个。\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"
@@ -1836,7 +2781,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"
@@ -1851,105 +2796,201 @@ msgstr ""
 " git branch new_branch_name %s\n"
 "\n"
 
-#: builtin/checkout.c:694
+#: builtin/checkout.c:730
 msgid "internal error in revision walk"
 msgstr "在版本遍历时遇到内部错误"
 
-#: builtin/checkout.c:698
+#: builtin/checkout.c:734
 msgid "Previous HEAD position was"
 msgstr "之前的 HEAD 位置是"
 
-#: builtin/checkout.c:724
+#: builtin/checkout.c:761 builtin/checkout.c:950
 msgid "You are on a branch yet to be born"
 msgstr "您位于一个尚未初始化的分支"
 
 #. case (1)
-#: builtin/checkout.c:855
+#: builtin/checkout.c:886
 #, c-format
 msgid "invalid reference: %s"
 msgstr "无效引用:%s"
 
 #. case (1): want a tree
-#: builtin/checkout.c:894
+#: builtin/checkout.c:925
 #, c-format
 msgid "reference is not a tree: %s"
 msgstr "引用不是一个树:%s"
 
-#: builtin/checkout.c:974
-msgid "-B cannot be used with -b"
-msgstr "-B 不能和 -b 共用"
+#: builtin/checkout.c:961
+#, fuzzy
+msgid "paths cannot be used with switching branches"
+msgstr "--ours/--theirs 和切换分支不兼容。"
 
-#: builtin/checkout.c:983
-msgid "--patch is incompatible with all other options"
-msgstr "--patch 选项和其他选项不兼容"
+#: builtin/checkout.c:964 builtin/checkout.c:968
+#, fuzzy, c-format
+msgid "'%s' cannot be used with switching branches"
+msgstr "%s:%s 不能和 %s 同时使用"
 
-#: builtin/checkout.c:986
-msgid "--detach cannot be used with -b/-B/--orphan"
-msgstr "--detach 不能和 -b/-B/--orphan 共用"
+#: builtin/checkout.c:972 builtin/checkout.c:975 builtin/checkout.c:980
+#: builtin/checkout.c:983
+#, fuzzy, c-format
+msgid "'%s' cannot be used with '%s'"
+msgstr "%s:%s 不能和 %s 同时使用"
 
 #: builtin/checkout.c:988
-msgid "--detach cannot be used with -t"
-msgstr "--detach 不能和 -t 共用"
+#, fuzzy, c-format
+msgid "Cannot switch branch to a non-commit '%s'"
+msgstr "无法切换分支到一个非提交。"
 
-#: builtin/checkout.c:994
-msgid "--track needs a branch name"
-msgstr "--track 需要一个分支名"
+#: builtin/checkout.c:1009 builtin/gc.c:177
+msgid "suppress progress reporting"
+msgstr ""
 
-#: builtin/checkout.c:1001
-msgid "Missing branch name; try -b"
-msgstr "缺少分支名;尝试 -b"
+#: builtin/checkout.c:1010 builtin/checkout.c:1012 builtin/clone.c:89
+#: builtin/remote.c:169 builtin/remote.c:171
+#, fuzzy
+msgid "branch"
+msgstr "位于分支 "
 
-#: builtin/checkout.c:1007
-msgid "--orphan and -b|-B are mutually exclusive"
-msgstr "--orphan 和 -b|-B 互斥"
+#: builtin/checkout.c:1011
+msgid "create and checkout a new branch"
+msgstr ""
+
+#: builtin/checkout.c:1013
+msgid "create/reset and checkout a branch"
+msgstr ""
+
+#: builtin/checkout.c:1014
+#, fuzzy
+msgid "create reflog for new branch"
+msgstr "列出、创建或删除分支"
+
+#: builtin/checkout.c:1015
+msgid "detach the HEAD at named commit"
+msgstr ""
+
+#: builtin/checkout.c:1016
+#, fuzzy
+msgid "set upstream info for new branch"
+msgstr "尚未给分支 '%s' 设置上游"
+
+#: builtin/checkout.c:1018
+#, fuzzy
+msgid "new branch"
+msgstr "[新分支]"
 
-#: builtin/checkout.c:1009
-msgid "--orphan cannot be used with -t"
-msgstr "--orphan 不能和 -t 共用"
+#: builtin/checkout.c:1018
+#, fuzzy
+msgid "new unparented branch"
+msgstr "没有当前分支。"
 
 #: builtin/checkout.c:1019
-msgid "git checkout: -f and -m are incompatible"
-msgstr "git checkout:-f 和 -m 不兼容"
+msgid "checkout our version for unmerged files"
+msgstr ""
+
+#: builtin/checkout.c:1021
+msgid "checkout their version for unmerged files"
+msgstr ""
+
+#: builtin/checkout.c:1023
+msgid "force checkout (throw away local modifications)"
+msgstr ""
+
+#: builtin/checkout.c:1024
+msgid "perform a 3-way merge with the new branch"
+msgstr ""
+
+#: builtin/checkout.c:1025 builtin/merge.c:215
+#, fuzzy
+msgid "update ignored files (default)"
+msgstr "更新文件失败"
+
+#: builtin/checkout.c:1026 builtin/log.c:1111 parse-options.h:241
+msgid "style"
+msgstr ""
+
+#: builtin/checkout.c:1027
+msgid "conflict style (merge or diff3)"
+msgstr ""
+
+#: builtin/checkout.c:1030
+msgid "second guess 'git checkout no-such-branch'"
+msgstr ""
+
+#: builtin/checkout.c:1054
+#, fuzzy
+msgid "-b, -B and --orphan are mutually exclusive"
+msgstr "-n 和 -k 互斥。"
+
+#: builtin/checkout.c:1071
+msgid "--track needs a branch name"
+msgstr "--track 需要一个分支名"
+
+#: builtin/checkout.c:1078
+msgid "Missing branch name; try -b"
+msgstr "缺少分支名;尝试 -b"
 
-#: builtin/checkout.c:1053
+#: builtin/checkout.c:1113
 msgid "invalid path specification"
 msgstr "无效的路径规格"
 
-#: builtin/checkout.c:1061
-#, c-format
+#: builtin/checkout.c:1120
+#, fuzzy, 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:更新路径和切换分支不兼容。\n"
 "您是想要检出 '%s' 但未能将其解析为提交么?"
 
-#: builtin/checkout.c:1063
-msgid "git checkout: updating paths is incompatible with switching branches."
-msgstr "git checkout:更新路径和切换分支不兼容。"
-
-#: builtin/checkout.c:1068
-msgid "git checkout: --detach does not take a path argument"
+#: builtin/checkout.c:1125
+#, fuzzy, c-format
+msgid "git checkout: --detach does not take a path argument '%s'"
 msgstr "git checkout:--detach 不跟路径参数"
 
-#: builtin/checkout.c:1071
+#: builtin/checkout.c:1129
 msgid ""
 "git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
 "checking out of the index."
 msgstr ""
 "git checkout:在从索引检出时,--ours/--theirs、--force 和 --merge 不兼容。"
 
-#: builtin/checkout.c:1090
-msgid "Cannot switch branch to a non-commit."
-msgstr "无法切换分支到一个非提交。"
+#: builtin/clean.c:19
+msgid "git clean [-d] [-f] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>..."
+msgstr ""
 
-#: builtin/checkout.c:1093
-msgid "--ours/--theirs is incompatible with switching branches."
-msgstr "--ours/--theirs 和切换分支不兼容。"
+#: builtin/clean.c:51
+msgid "do not print names of files removed"
+msgstr ""
+
+#: builtin/clean.c:53
+msgid "force"
+msgstr ""
+
+#: builtin/clean.c:55
+#, fuzzy
+msgid "remove whole directories"
+msgstr "两个输出目录?"
+
+#: builtin/clean.c:56 builtin/describe.c:413 builtin/grep.c:802
+#: builtin/ls-files.c:491 builtin/name-rev.c:231 builtin/show-ref.c:199
+msgid "pattern"
+msgstr ""
+
+#: builtin/clean.c:57
+msgid "add <pattern> to ignore rules"
+msgstr ""
+
+#: builtin/clean.c:58
+msgid "remove ignored files, too"
+msgstr ""
+
+#: builtin/clean.c:60
+msgid "remove only ignored files"
+msgstr ""
 
 #: builtin/clean.c:78
 msgid "-x and -X cannot be used together"
-msgstr "-x å\92\8c -X ä¸\8dè\83½å\85±用"
+msgstr "-x å\92\8c -X ä¸\8dè\83½å\90\8cæ\97¶ä½¿用"
 
 #: builtin/clean.c:82
 msgid ""
@@ -1989,22 +3030,115 @@ msgstr "不会删除 %s\n"
 msgid "Not removing %s\n"
 msgstr "未删除 %s\n"
 
+#: builtin/clone.c:36
+msgid "git clone [options] [--] <repo> [<dir>]"
+msgstr ""
+
+#: builtin/clone.c:64 builtin/fetch.c:82 builtin/merge.c:212
+#: builtin/push.c:399
+msgid "force progress reporting"
+msgstr ""
+
+#: builtin/clone.c:66
+msgid "don't create a checkout"
+msgstr ""
+
+#: builtin/clone.c:67 builtin/clone.c:69 builtin/init-db.c:488
+#, fuzzy
+msgid "create a bare repository"
+msgstr "不是一个 git 版本库"
+
+#: builtin/clone.c:72
+msgid "create a mirror repository (implies bare)"
+msgstr ""
+
+#: builtin/clone.c:74
+msgid "to clone from a local repository"
+msgstr ""
+
+#: builtin/clone.c:76
+msgid "don't use local hardlinks, always copy"
+msgstr ""
+
+#: builtin/clone.c:78
+#, fuzzy
+msgid "setup as shared repository"
+msgstr "不是一个 git 版本库"
+
+#: builtin/clone.c:80 builtin/clone.c:82
+msgid "initialize submodules in the clone"
+msgstr ""
+
+#: builtin/clone.c:83 builtin/init-db.c:485
+#, fuzzy
+msgid "template-directory"
+msgstr "文件/目录"
+
+#: builtin/clone.c:84 builtin/init-db.c:486
+msgid "directory from which templates will be used"
+msgstr ""
+
+#: builtin/clone.c:86
+msgid "reference repository"
+msgstr ""
+
+#: builtin/clone.c:87 builtin/column.c:26 builtin/merge-file.c:44
+#, fuzzy
+msgid "name"
+msgstr "重命名"
+
+#: builtin/clone.c:88
+msgid "use <name> instead of 'origin' to track upstream"
+msgstr ""
+
+#: builtin/clone.c:90
+msgid "checkout <branch> instead of the remote's HEAD"
+msgstr ""
+
+#: builtin/clone.c:92
+msgid "path to git-upload-pack on the remote"
+msgstr ""
+
+#: builtin/clone.c:93 builtin/fetch.c:83 builtin/grep.c:747
+msgid "depth"
+msgstr ""
+
+#: builtin/clone.c:94
+msgid "create a shallow clone of that depth"
+msgstr ""
+
+#: builtin/clone.c:96
+msgid "clone only one branch, HEAD or --branch"
+msgstr ""
+
+#: builtin/clone.c:97 builtin/init-db.c:494
+msgid "gitdir"
+msgstr ""
+
+#: builtin/clone.c:98 builtin/init-db.c:495
+msgid "separate git dir from working tree"
+msgstr ""
+
+#: builtin/clone.c:99
+msgid "key=value"
+msgstr ""
+
+#: builtin/clone.c:100
+#, fuzzy
+msgid "set config inside the new repository"
+msgstr "记录变更到版本库"
+
 #: builtin/clone.c:243
 #, c-format
 msgid "reference repository '%s' is not a local directory."
 msgstr "引用版本库 '%s' 不是一个本地目录。"
 
-#: builtin/clone.c:302
-#, c-format
-msgid "failed to open '%s'"
-msgstr "无法打开 '%s'"
-
 #: builtin/clone.c:306
 #, c-format
 msgid "failed to create directory '%s'"
 msgstr "无法创建目录 '%s'"
 
-#: builtin/clone.c:308 builtin/diff.c:75
+#: builtin/clone.c:308 builtin/diff.c:77
 #, c-format
 msgid "failed to stat '%s'"
 msgstr "无法枚举 '%s' 状态"
@@ -2019,11 +3153,6 @@ msgstr "%s 存在且不是一个目录"
 msgid "failed to stat %s\n"
 msgstr "无法枚举 %s 状态\n"
 
-#: builtin/clone.c:341
-#, c-format
-msgid "failed to unlink '%s'"
-msgstr "无法删除 '%s'"
-
 #: builtin/clone.c:346
 #, c-format
 msgid "failed to create link '%s'"
@@ -2039,85 +3168,124 @@ msgstr "无法拷贝文件至 '%s'"
 msgid "done.\n"
 msgstr "完成。\n"
 
-#: builtin/clone.c:440
+#: builtin/clone.c:443
 #, c-format
 msgid "Could not find remote branch %s to clone."
 msgstr "不能发现要克隆的远程分支 %s。"
 
-#: builtin/clone.c:549
+#: builtin/clone.c:552
 msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n"
 msgstr "远程 HEAD 指向一个不存在的引用,无法检出。\n"
 
-#: builtin/clone.c:639
+#: builtin/clone.c:642
 msgid "Too many arguments."
 msgstr "太多参数。"
 
-#: builtin/clone.c:643
+#: builtin/clone.c:646
 msgid "You must specify a repository to clone."
 msgstr "您必须指定一个版本库来克隆。"
 
-#: builtin/clone.c:654
+#: builtin/clone.c:657
 #, c-format
 msgid "--bare and --origin %s options are incompatible."
 msgstr "--bare 和 --origin %s 选项不兼容。"
 
-#: builtin/clone.c:668
+#: builtin/clone.c:671
 #, c-format
 msgid "repository '%s' does not exist"
 msgstr "版本库 '%s' 不存在"
 
-#: builtin/clone.c:673
+#: builtin/clone.c:676
 msgid "--depth is ignored in local clones; use file:// instead."
 msgstr "--depth 在本地克隆被忽略,改为 file:// 协议试试。"
 
-#: builtin/clone.c:683
+#: builtin/clone.c:686
 #, c-format
 msgid "destination path '%s' already exists and is not an empty directory."
 msgstr "目标路径 '%s' 已经存在,并且不是一个空目录。"
 
-#: builtin/clone.c:693
+#: builtin/clone.c:696
 #, c-format
 msgid "working tree '%s' already exists."
 msgstr "工作区 '%s' 已经存在。"
 
-#: builtin/clone.c:706 builtin/clone.c:720
+#: builtin/clone.c:709 builtin/clone.c:723
 #, c-format
 msgid "could not create leading directories of '%s'"
 msgstr "不能为 '%s' 创建先导目录"
 
-#: builtin/clone.c:709
+#: builtin/clone.c:712
 #, c-format
 msgid "could not create work tree dir '%s'."
 msgstr "不能为 '%s' 创建工作区目录。"
 
-#: builtin/clone.c:728
+#: builtin/clone.c:731
 #, c-format
 msgid "Cloning into bare repository '%s'...\n"
 msgstr "克隆到裸版本库 '%s'...\n"
 
-#: builtin/clone.c:730
+#: builtin/clone.c:733
 #, c-format
 msgid "Cloning into '%s'...\n"
 msgstr "正克隆到 '%s'...\n"
 
-#: builtin/clone.c:786
+#: builtin/clone.c:789
 #, c-format
 msgid "Don't know how to clone %s"
 msgstr "不知道如何克隆 %s"
 
-#: builtin/clone.c:835
+#: builtin/clone.c:838
 #, c-format
 msgid "Remote branch %s not found in upstream %s"
 msgstr "远程分支 %s 在上游 %s 未发现"
 
-#: builtin/clone.c:842
+#: builtin/clone.c:845
 msgid "You appear to have cloned an empty repository."
 msgstr "您似乎克隆了一个空版本库。"
 
+#: builtin/column.c:9
+msgid "git column [options]"
+msgstr ""
+
+#: builtin/column.c:26
+msgid "lookup config vars"
+msgstr ""
+
+#: builtin/column.c:27 builtin/column.c:28
+#, fuzzy
+msgid "layout to use"
+msgstr "本地已过时"
+
+#: builtin/column.c:29
+msgid "Maximum width"
+msgstr ""
+
+#: builtin/column.c:30
+msgid "Padding space on left border"
+msgstr ""
+
+#: builtin/column.c:31
+msgid "Padding space on right border"
+msgstr ""
+
+#: builtin/column.c:32
+msgid "Padding space between columns"
+msgstr ""
+
 #: builtin/column.c:51
 msgid "--command must be the first argument"
 msgstr "--command 必须是第一个参数"
 
+#: builtin/commit.c:33
+#, fuzzy
+msgid "git commit [options] [--] <filepattern>..."
+msgstr "git apply [选项] [<补丁>...]"
+
+#: builtin/commit.c:38
+#, fuzzy
+msgid "git status [options] [--] <filepattern>..."
+msgstr "git apply [选项] [<补丁>...]"
+
 #: builtin/commit.c:43
 msgid ""
 "Your name and email address were configured automatically based\n"
@@ -2166,93 +3334,93 @@ msgstr ""
 "\n"
 "否则,请使用命令 'git reset'\n"
 
-#: builtin/commit.c:253
+#: builtin/commit.c:256
 msgid "failed to unpack HEAD tree object"
 msgstr "无法解包 HEAD 树对象"
 
-#: builtin/commit.c:295
+#: builtin/commit.c:298
 msgid "unable to create temporary index"
 msgstr "不能创建临时索引"
 
-#: builtin/commit.c:301
+#: builtin/commit.c:304
 msgid "interactive add failed"
 msgstr "交互式添加失败"
 
-#: builtin/commit.c:334 builtin/commit.c:355 builtin/commit.c:405
+#: builtin/commit.c:337 builtin/commit.c:358 builtin/commit.c:408
 msgid "unable to write new_index file"
 msgstr "无法写 new_index 文件"
 
-#: builtin/commit.c:386
+#: builtin/commit.c:389
 msgid "cannot do a partial commit during a merge."
 msgstr "在合并过程中不能做部分提交。"
 
-#: builtin/commit.c:388
+#: builtin/commit.c:391
 msgid "cannot do a partial commit during a cherry-pick."
 msgstr "在拣选过程中不能做部分提交。"
 
-#: builtin/commit.c:398
+#: builtin/commit.c:401
 msgid "cannot read the index"
 msgstr "无法读取索引"
 
-#: builtin/commit.c:418
+#: builtin/commit.c:421
 msgid "unable to write temporary index file"
 msgstr "无法写临时索引文件"
 
-#: builtin/commit.c:493 builtin/commit.c:499
+#: builtin/commit.c:510 builtin/commit.c:516
 #, c-format
 msgid "invalid commit: %s"
 msgstr "无效的提交:%s"
 
-#: builtin/commit.c:522
+#: builtin/commit.c:539
 msgid "malformed --author parameter"
 msgstr "非法的 --author 参数"
 
-#: builtin/commit.c:582
+#: builtin/commit.c:600
 #, c-format
 msgid "Malformed ident string: '%s'"
 msgstr "非法的身份字符串:'%s'"
 
-#: builtin/commit.c:620 builtin/commit.c:653 builtin/commit.c:967
+#: builtin/commit.c:638 builtin/commit.c:671 builtin/commit.c:985
 #, c-format
 msgid "could not lookup commit %s"
 msgstr "不能查询提交 %s"
 
-#: builtin/commit.c:632 builtin/shortlog.c:296
+#: builtin/commit.c:650 builtin/shortlog.c:296
 #, c-format
 msgid "(reading log message from standard input)\n"
 msgstr "(正从标准输入中读取日志信息)\n"
 
-#: builtin/commit.c:634
+#: builtin/commit.c:652
 msgid "could not read log from standard input"
 msgstr "不能从标准输入中读取日志信息"
 
-#: builtin/commit.c:638
+#: builtin/commit.c:656
 #, c-format
 msgid "could not read log file '%s'"
 msgstr "不能读取日志文件 '%s'"
 
-#: builtin/commit.c:644
+#: builtin/commit.c:662
 msgid "commit has empty message"
 msgstr "提交说明为空"
 
-#: builtin/commit.c:660
+#: builtin/commit.c:678
 msgid "could not read MERGE_MSG"
 msgstr "不能读取 MERGE_MSG"
 
-#: builtin/commit.c:664
+#: builtin/commit.c:682
 msgid "could not read SQUASH_MSG"
 msgstr "不能读取 SQUASH_MSG"
 
-#: builtin/commit.c:668
+#: builtin/commit.c:686
 #, c-format
 msgid "could not read '%s'"
 msgstr "不能读取 '%s'"
 
-#: builtin/commit.c:720
+#: builtin/commit.c:738
 msgid "could not write commit template"
 msgstr "不能写提交模版"
 
-#: builtin/commit.c:731
+#: builtin/commit.c:749
 #, c-format
 msgid ""
 "\n"
@@ -2262,11 +3430,11 @@ msgid ""
 "and try again.\n"
 msgstr ""
 "\n"
-"看起来您正在做一个合并提交。如果不对,请删除文件\n"
+"似乎您正在做一个合并提交。如果不对,请删除文件\n"
 "\t%s\n"
 "然后重试。\n"
 
-#: builtin/commit.c:736
+#: builtin/commit.c:754
 #, c-format
 msgid ""
 "\n"
@@ -2276,11 +3444,11 @@ msgid ""
 "and try again.\n"
 msgstr ""
 "\n"
-"看起来您正在做一个拣选提交。如果不对,请删除文件\n"
+"似乎您正在做一个拣选提交。如果不对,请删除文件\n"
 "\t%s\n"
 "然后重试。\n"
 
-#: builtin/commit.c:748
+#: builtin/commit.c:766
 msgid ""
 "Please enter the commit message for your changes. Lines starting\n"
 "with '#' will be ignored, and an empty message aborts the commit.\n"
@@ -2288,7 +3456,7 @@ msgstr ""
 "请为您的变更输入提交说明。以 '#' 开始的行将被忽略,而一个空的提交\n"
 "说明将会终止提交。\n"
 
-#: builtin/commit.c:753
+#: builtin/commit.c:771
 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"
@@ -2298,160 +3466,357 @@ msgstr ""
 "如果您想这样做的话。而一个空的提交说明将会终止提交。\n"
 
 #  译者:为保证在输出中对齐,注意调整句中空格!
-#: builtin/commit.c:766
+#: builtin/commit.c:784
 #, c-format
 msgid "%sAuthor:    %s"
 msgstr "%s作者:     %s"
 
 #  译者:为保证在输出中对齐,注意调整句中空格!
-#: builtin/commit.c:773
+#: builtin/commit.c:791
 #, c-format
 msgid "%sCommitter: %s"
 msgstr "%s提交者:   %s"
 
-#: builtin/commit.c:793
+#: builtin/commit.c:811
 msgid "Cannot read index"
 msgstr "无法读取索引"
 
-#: builtin/commit.c:830
+#: builtin/commit.c:848
 msgid "Error building trees"
 msgstr "无法创建树对象"
 
-#: builtin/commit.c:845 builtin/tag.c:361
+#: builtin/commit.c:863 builtin/tag.c:361
 #, c-format
 msgid "Please supply the message using either -m or -F option.\n"
 msgstr "请使用 -m 或者 -F 选项提供提交说明。\n"
 
-#: builtin/commit.c:942
+#: builtin/commit.c:960
 #, c-format
 msgid "No existing author found with '%s'"
 msgstr "没有找到匹配 '%s' 的作者"
 
-#: builtin/commit.c:957 builtin/commit.c:1157
+#: builtin/commit.c:975 builtin/commit.c:1175
 #, c-format
 msgid "Invalid untracked files mode '%s'"
 msgstr "无效的未追踪文件参数 '%s'"
 
-#: builtin/commit.c:997
+#: builtin/commit.c:1015
 msgid "Using both --reset-author and --author does not make sense"
 msgstr "同时使用 --reset-author 和 --author 没有意义"
 
-#: builtin/commit.c:1008
+#: builtin/commit.c:1026
 msgid "You have nothing to amend."
 msgstr "您没有可修补的提交。"
 
-#: builtin/commit.c:1011
+#: builtin/commit.c:1029
 msgid "You are in the middle of a merge -- cannot amend."
 msgstr "您正处于一个合并过程中 -- 无法修补提交。"
 
-#: builtin/commit.c:1013
+#: builtin/commit.c:1031
 msgid "You are in the middle of a cherry-pick -- cannot amend."
 msgstr "您正处于一个拣选过程中 -- 无法修补提交。"
 
-#: builtin/commit.c:1016
+#: builtin/commit.c:1034
 msgid "Options --squash and --fixup cannot be used together"
-msgstr "é\80\89项 --squash å\92\8c --fixup ä¸\8dè\83½å\85±用"
+msgstr "é\80\89项 --squash å\92\8c --fixup ä¸\8dè\83½å\90\8cæ\97¶ä½¿用"
 
-#: builtin/commit.c:1026
+#: builtin/commit.c:1044
 msgid "Only one of -c/-C/-F/--fixup can be used."
 msgstr "只能用一个 -c/-C/-F/--fixup 选项。"
 
-#: builtin/commit.c:1028
+#: builtin/commit.c:1046
 msgid "Option -m cannot be combined with -c/-C/-F/--fixup."
-msgstr "é\80\89项 -m ä¸\8dè\83½å\92\8c -c/-C/-F/--fixup å\85±用。"
+msgstr "é\80\89项 -m ä¸\8dè\83½å\92\8c -c/-C/-F/--fixup å\90\8cæ\97¶ä½¿用。"
 
-#: builtin/commit.c:1036
+#: builtin/commit.c:1054
 msgid "--reset-author can be used only with -C, -c or --amend."
-msgstr "--reset-author å\8fªè\83½å\92\8c -Cã\80\81-c æ\88\96 --amend å\85±用。"
+msgstr "--reset-author å\8fªè\83½å\92\8c -Cã\80\81-c æ\88\96 --amend å\90\8cæ\97¶ä½¿用。"
 
-#: builtin/commit.c:1053
+#: builtin/commit.c:1071
 msgid "Only one of --include/--only/--all/--interactive/--patch can be used."
 msgstr "只能用一个 --include/--only/--all/--interactive/--patch 选项。"
 
-#: builtin/commit.c:1055
+#: builtin/commit.c:1073
 msgid "No paths with --include/--only does not make sense."
 msgstr "参数 --include/--only 不跟路径没有意义。"
 
-#: builtin/commit.c:1057
+#: builtin/commit.c:1075
 msgid "Clever... amending the last one with dirty index."
 msgstr "聪明... 在索引不干净下修补最后的提交。"
 
-#: builtin/commit.c:1059
+#: builtin/commit.c:1077
 msgid "Explicit paths specified without -i nor -o; assuming --only paths..."
 msgstr "指定了明确的路径而没有使用 -i 或 -o 选项;认为是 --only paths..."
 
-#: builtin/commit.c:1069 builtin/tag.c:577
+#: builtin/commit.c:1087 builtin/tag.c:577
 #, c-format
 msgid "Invalid cleanup mode %s"
 msgstr "无效的清理模式 %s"
 
-#: builtin/commit.c:1074
+#: builtin/commit.c:1092
 msgid "Paths with -a does not make sense."
-msgstr "路径和 -a 选项共用没有意义。"
+msgstr "路径和 -a 选项同时使用没有意义。"
+
+#: builtin/commit.c:1189 builtin/commit.c:1417
+msgid "show status concisely"
+msgstr ""
+
+#: builtin/commit.c:1191 builtin/commit.c:1419
+msgid "show branch information"
+msgstr ""
+
+#: builtin/commit.c:1193 builtin/commit.c:1421 builtin/push.c:389
+msgid "machine-readable output"
+msgstr ""
+
+#: builtin/commit.c:1196 builtin/commit.c:1423
+msgid "terminate entries with NUL"
+msgstr ""
+
+#: builtin/commit.c:1198 builtin/commit.c:1426 builtin/fast-export.c:636
+#: builtin/fast-export.c:639 builtin/tag.c:461
+msgid "mode"
+msgstr ""
+
+#: builtin/commit.c:1199 builtin/commit.c:1426
+msgid "show untracked files, optional modes: all, normal, no. (Default: all)"
+msgstr ""
+
+#: builtin/commit.c:1202
+msgid "show ignored files"
+msgstr ""
+
+#: builtin/commit.c:1203 parse-options.h:151
+msgid "when"
+msgstr "何时"
+
+#: builtin/commit.c:1204
+msgid ""
+"ignore changes to submodules, optional when: all, dirty, untracked. "
+"(Default: all)"
+msgstr ""
+
+#: builtin/commit.c:1206
+#, fuzzy
+msgid "list untracked files in columns"
+msgstr "无效的未追踪文件参数 '%s'"
 
-#: builtin/commit.c:1257
+#: builtin/commit.c:1275
 msgid "couldn't look up newly created commit"
 msgstr "无法找到新创建的提交"
 
-#: builtin/commit.c:1259
+#: builtin/commit.c:1277
 msgid "could not parse newly created commit"
 msgstr "不能解析新创建的提交"
 
-#: builtin/commit.c:1300
+#: builtin/commit.c:1318
 msgid "detached HEAD"
 msgstr "分离头指针"
 
 #  译者:中文字符串拼接,可删除前导空格
-#: builtin/commit.c:1302
+#: builtin/commit.c:1320
 msgid " (root-commit)"
 msgstr "(根提交)"
 
-#: builtin/commit.c:1446
+#: builtin/commit.c:1387
+msgid "suppress summary after successful commit"
+msgstr ""
+
+#: builtin/commit.c:1388
+msgid "show diff in commit message template"
+msgstr ""
+
+#: builtin/commit.c:1390
+#, fuzzy
+msgid "Commit message options"
+msgstr "不能得到 %s 的提交说明"
+
+#: builtin/commit.c:1391 builtin/tag.c:459
+msgid "read message from file"
+msgstr ""
+
+#: builtin/commit.c:1392
+msgid "author"
+msgstr ""
+
+#: builtin/commit.c:1392
+#, fuzzy
+msgid "override author for commit"
+msgstr "合并未返回提交"
+
+#: builtin/commit.c:1393 builtin/gc.c:178
+msgid "date"
+msgstr ""
+
+#: builtin/commit.c:1393
+#, fuzzy
+msgid "override date for commit"
+msgstr "合并未返回提交"
+
+#: builtin/commit.c:1394 builtin/merge.c:206 builtin/notes.c:534
+#: builtin/notes.c:691 builtin/tag.c:457
+#, fuzzy
+msgid "message"
+msgstr "无 tag 说明?"
+
+#: builtin/commit.c:1394
+#, fuzzy
+msgid "commit message"
+msgstr "空提交信息。"
+
+#: builtin/commit.c:1395
+msgid "reuse and edit message from specified commit"
+msgstr ""
+
+#: builtin/commit.c:1396
+msgid "reuse message from specified commit"
+msgstr ""
+
+#: builtin/commit.c:1397
+msgid "use autosquash formatted message to fixup specified commit"
+msgstr ""
+
+#: builtin/commit.c:1398
+msgid "use autosquash formatted message to squash specified commit"
+msgstr ""
+
+#: builtin/commit.c:1399
+msgid "the commit is authored by me now (used with -C/-c/--amend)"
+msgstr ""
+
+#: builtin/commit.c:1400 builtin/log.c:1068 builtin/revert.c:109
+msgid "add Signed-off-by:"
+msgstr ""
+
+#: builtin/commit.c:1401
+msgid "use specified template file"
+msgstr ""
+
+#: builtin/commit.c:1402
+#, fuzzy
+msgid "force edit of commit"
+msgstr "合并未返回提交"
+
+#: builtin/commit.c:1403
+msgid "default"
+msgstr ""
+
+#: builtin/commit.c:1403 builtin/tag.c:462
+msgid "how to strip spaces and #comments from message"
+msgstr ""
+
+#: builtin/commit.c:1404
+#, fuzzy
+msgid "include status in commit message template"
+msgstr "不能写提交模版"
+
+#: builtin/commit.c:1405 builtin/merge.c:213 builtin/tag.c:463
+msgid "key id"
+msgstr ""
+
+#: builtin/commit.c:1406 builtin/merge.c:214
+msgid "GPG sign commit"
+msgstr ""
+
+#. end commit message options
+#: builtin/commit.c:1409
+msgid "Commit contents options"
+msgstr ""
+
+#: builtin/commit.c:1410
+msgid "commit all changed files"
+msgstr ""
+
+#: builtin/commit.c:1411
+msgid "add specified files to index for commit"
+msgstr ""
+
+#: builtin/commit.c:1412
+#, fuzzy
+msgid "interactively add files"
+msgstr "交互式添加失败"
+
+#: builtin/commit.c:1413
+#, fuzzy
+msgid "interactively add changes"
+msgstr "交互式添加失败"
+
+#: builtin/commit.c:1414
+#, fuzzy
+msgid "commit only specified files"
+msgstr "无法还原修改的文件"
+
+#: builtin/commit.c:1415
+msgid "bypass pre-commit hook"
+msgstr ""
+
+#: builtin/commit.c:1416
+#, fuzzy
+msgid "show what would be committed"
+msgstr "要提交的变更:"
+
+#: builtin/commit.c:1424
+msgid "amend previous commit"
+msgstr ""
+
+#: builtin/commit.c:1425
+msgid "bypass post-rewrite hook"
+msgstr ""
+
+#: builtin/commit.c:1430
+msgid "ok to record an empty change"
+msgstr ""
+
+#: builtin/commit.c:1433
+msgid "ok to record a change with an empty message"
+msgstr ""
+
+#: builtin/commit.c:1464
 msgid "could not parse HEAD commit"
 msgstr "不能解析 HEAD 提交"
 
-#: builtin/commit.c:1484 builtin/merge.c:509
+#: builtin/commit.c:1502 builtin/merge.c:508
 #, c-format
 msgid "could not open '%s' for reading"
 msgstr "不能为读入打开 '%s'"
 
-#: builtin/commit.c:1491
+#: builtin/commit.c:1509
 #, c-format
 msgid "Corrupt MERGE_HEAD file (%s)"
 msgstr "损坏的 MERGE_HEAD 文件(%s)"
 
-#: builtin/commit.c:1498
+#: builtin/commit.c:1516
 msgid "could not read MERGE_MODE"
 msgstr "不能读取 MERGE_MODE"
 
-#: builtin/commit.c:1517
+#: builtin/commit.c:1535
 #, c-format
 msgid "could not read commit message: %s"
 msgstr "不能读取提交说明:%s"
 
-#: builtin/commit.c:1531
+#: builtin/commit.c:1549
 #, c-format
 msgid "Aborting commit; you did not edit the message.\n"
 msgstr "终止提交;您未更改来自模版的提交说明。\n"
 
-#: builtin/commit.c:1536
+#: builtin/commit.c:1554
 #, c-format
 msgid "Aborting commit due to empty commit message.\n"
 msgstr "终止提交因为提交说明为空。\n"
 
-#: builtin/commit.c:1551 builtin/merge.c:936 builtin/merge.c:961
+#: builtin/commit.c:1569 builtin/merge.c:935 builtin/merge.c:960
 msgid "failed to write commit object"
 msgstr "无法写提交对象"
 
-#: builtin/commit.c:1572
+#: builtin/commit.c:1590
 msgid "cannot lock HEAD ref"
 msgstr "无法锁定 HEAD 引用"
 
-#: builtin/commit.c:1576
+#: builtin/commit.c:1594
 msgid "cannot update HEAD ref"
 msgstr "无法更新 HEAD 引用"
 
-#: builtin/commit.c:1587
+#: builtin/commit.c:1605
 msgid ""
 "Repository has been updated, but unable to write\n"
 "new_index file. Check that disk is not full or quota is\n"
@@ -2460,28 +3825,160 @@ msgstr ""
 "版本库已更新,但无法写 new_index 文件。检查是否磁盘已满\n"
 "或磁盘配额已耗尽,然后执行 \"git reset HEAD\" 恢复。"
 
-#: builtin/describe.c:234
-#, c-format
-msgid "annotated tag %s not available"
-msgstr "注释 tag %s 无效"
+#: builtin/config.c:7
+msgid "git config [options]"
+msgstr ""
 
-#: builtin/describe.c:238
-#, c-format
-msgid "annotated tag %s has no embedded name"
-msgstr "注释 tag %s 没有嵌入名称"
+#: builtin/config.c:52
+msgid "Config file location"
+msgstr ""
 
-#: builtin/describe.c:240
-#, c-format
-msgid "tag '%s' is really '%s' here"
-msgstr "tag '%s' 的确是在 '%s'"
+#: builtin/config.c:53
+#, fuzzy
+msgid "use global config file"
+msgstr "无法更新 config 文件"
 
-#: builtin/describe.c:267
-#, c-format
-msgid "Not a valid object name %s"
-msgstr "不是一个有效的对象名 %s"
+#: builtin/config.c:54
+msgid "use system config file"
+msgstr ""
 
-#: builtin/describe.c:270
-#, c-format
+#: builtin/config.c:55
+#, fuzzy
+msgid "use repository config file"
+msgstr "需要一个版本库来解包。"
+
+#: builtin/config.c:56
+#, fuzzy
+msgid "use given config file"
+msgstr "未预期的文件结束"
+
+#: builtin/config.c:57
+#, fuzzy
+msgid "Action"
+msgstr "动作"
+
+#: builtin/config.c:58
+msgid "get value: name [value-regex]"
+msgstr ""
+
+#: builtin/config.c:59
+msgid "get all values: key [value-regex]"
+msgstr ""
+
+#: builtin/config.c:60
+msgid "get values for regexp: name-regex [value-regex]"
+msgstr ""
+
+#: builtin/config.c:61
+msgid "replace all matching variables: name value [value_regex]"
+msgstr ""
+
+#: builtin/config.c:62
+msgid "add a new variable: name value"
+msgstr ""
+
+#: builtin/config.c:63
+msgid "remove a variable: name [value-regex]"
+msgstr ""
+
+#: builtin/config.c:64
+msgid "remove all matches: name [value-regex]"
+msgstr ""
+
+#: builtin/config.c:65
+msgid "rename section: old-name new-name"
+msgstr ""
+
+#: builtin/config.c:66
+msgid "remove a section: name"
+msgstr ""
+
+#: builtin/config.c:67
+msgid "list all"
+msgstr ""
+
+#: builtin/config.c:68
+msgid "open an editor"
+msgstr ""
+
+#: builtin/config.c:69 builtin/config.c:70
+msgid "slot"
+msgstr ""
+
+#: builtin/config.c:69
+msgid "find the color configured: [default]"
+msgstr ""
+
+#: builtin/config.c:70
+msgid "find the color setting: [stdout-is-tty]"
+msgstr ""
+
+#: builtin/config.c:71
+msgid "Type"
+msgstr ""
+
+#: builtin/config.c:72
+msgid "value is \"true\" or \"false\""
+msgstr ""
+
+#: builtin/config.c:73
+msgid "value is decimal number"
+msgstr ""
+
+#: builtin/config.c:74
+msgid "value is --bool or --int"
+msgstr ""
+
+#: builtin/config.c:75
+msgid "value is a path (file or directory name)"
+msgstr ""
+
+#: builtin/config.c:76
+msgid "Other"
+msgstr ""
+
+#: builtin/config.c:77
+msgid "terminate values with NUL byte"
+msgstr ""
+
+#: builtin/config.c:78
+msgid "respect include directives on lookup"
+msgstr ""
+
+#: builtin/count-objects.c:69
+msgid "git count-objects [-v]"
+msgstr ""
+
+#: builtin/describe.c:15
+msgid "git describe [options] <committish>*"
+msgstr ""
+
+#: builtin/describe.c:16
+msgid "git describe [options] --dirty"
+msgstr ""
+
+#: builtin/describe.c:234
+#, c-format
+msgid "annotated tag %s not available"
+msgstr "注释 tag %s 无效"
+
+#: builtin/describe.c:238
+#, c-format
+msgid "annotated tag %s has no embedded name"
+msgstr "注释 tag %s 没有嵌入名称"
+
+#: builtin/describe.c:240
+#, c-format
+msgid "tag '%s' is really '%s' here"
+msgstr "tag '%s' 的确是在 '%s'"
+
+#: builtin/describe.c:267
+#, c-format
+msgid "Not a valid object name %s"
+msgstr "不是一个有效的对象名 %s"
+
+#: builtin/describe.c:270
+#, c-format
 msgid "%s is not a valid '%s' object"
 msgstr "%s 不是一个有效的 '%s' 对象"
 
@@ -2532,6 +4029,52 @@ msgstr ""
 "发现多于 %i 个 tag,列出最近的 %i 个\n"
 "在 %s 放弃搜索\n"
 
+#: builtin/describe.c:403
+msgid "find the tag that comes after the commit"
+msgstr ""
+
+#: builtin/describe.c:404
+msgid "debug search strategy on stderr"
+msgstr ""
+
+#: builtin/describe.c:405
+msgid "use any ref in .git/refs"
+msgstr ""
+
+#: builtin/describe.c:406
+msgid "use any tag in .git/refs/tags"
+msgstr ""
+
+#: builtin/describe.c:407
+msgid "always use long format"
+msgstr ""
+
+#: builtin/describe.c:410
+#, fuzzy
+msgid "only output exact matches"
+msgstr "没有 tag 准确匹配 '%s'"
+
+#: builtin/describe.c:412
+msgid "consider <n> most recent tags (default: 10)"
+msgstr ""
+
+#: builtin/describe.c:414
+#, fuzzy
+msgid "only consider tags matching <pattern>"
+msgstr "输出和模式匹配的行"
+
+#: builtin/describe.c:416 builtin/name-rev.c:238
+msgid "show abbreviated commit object as fallback"
+msgstr ""
+
+#: builtin/describe.c:417
+msgid "mark"
+msgstr ""
+
+#: builtin/describe.c:418
+msgid "append <mark> on dirty working tree (default: \"-dirty\")"
+msgstr ""
+
 #: builtin/describe.c:436
 msgid "--long is incompatible with --abbrev=0"
 msgstr "--long 与 --abbrev=0 不兼容"
@@ -2542,113 +4085,239 @@ msgstr "没有发现名称,无法描述任何东西。"
 
 #: builtin/describe.c:482
 msgid "--dirty is incompatible with committishes"
-msgstr "--dirty ä¸\8dè\83½ä¸\8eæ\8f\90交å\85±用"
+msgstr "--dirty ä¸\8dè\83½ä¸\8eæ\8f\90交å\90\8cæ\97¶ä½¿用"
 
-#: builtin/diff.c:77
+#: builtin/diff.c:79
 #, c-format
 msgid "'%s': not a regular file or symlink"
 msgstr "'%s':不是一个正规文件或符号链接"
 
-#: builtin/diff.c:220
+#: builtin/diff.c:224
 #, c-format
 msgid "invalid option: %s"
 msgstr "无效选项:%s"
 
-#: builtin/diff.c:297
+#: builtin/diff.c:301
 msgid "Not a git repository"
 msgstr "不是一个 git 版本库"
 
-#: builtin/diff.c:347
+#: builtin/diff.c:344
 #, c-format
 msgid "invalid object '%s' given."
 msgstr "提供了无效对象 '%s'。"
 
-#: builtin/diff.c:352
+#: builtin/diff.c:349
 #, c-format
 msgid "more than %d trees given: '%s'"
 msgstr "提供了超过 %d 个树对象:'%s'"
 
-#: builtin/diff.c:362
+#: builtin/diff.c:359
 #, c-format
 msgid "more than two blobs given: '%s'"
-msgstr "提供了超过两个 blob 对象:'%s'"
+msgstr "提供了超过两个二进制对象(blob):'%s'"
 
-#: builtin/diff.c:370
+#: builtin/diff.c:367
 #, c-format
 msgid "unhandled object '%s' given."
 msgstr "提供了无法处理的对象 '%s'。"
 
-#: builtin/fetch.c:200
+#: builtin/fast-export.c:22
+msgid "git fast-export [rev-list-opts]"
+msgstr ""
+
+#: builtin/fast-export.c:635
+#, fuzzy
+msgid "show progress after <n> objects"
+msgstr "显示各种类型的对象"
+
+#: builtin/fast-export.c:637
+msgid "select handling of signed tags"
+msgstr ""
+
+#: builtin/fast-export.c:640
+msgid "select handling of tags that tag filtered objects"
+msgstr ""
+
+#: builtin/fast-export.c:643
+msgid "Dump marks to this file"
+msgstr ""
+
+#: builtin/fast-export.c:645
+msgid "Import marks from this file"
+msgstr ""
+
+#: builtin/fast-export.c:647
+msgid "Fake a tagger when tags lack one"
+msgstr ""
+
+#: builtin/fast-export.c:649
+msgid "Output full tree for each commit"
+msgstr ""
+
+#: builtin/fast-export.c:651
+msgid "Use the done feature to terminate the stream"
+msgstr ""
+
+#: builtin/fast-export.c:652
+msgid "Skip output of blob data"
+msgstr ""
+
+#: builtin/fetch.c:20
+#, fuzzy
+msgid "git fetch [<options>] [<repository> [<refspec>...]]"
+msgstr "git apply [选项] [<补丁>...]"
+
+#: builtin/fetch.c:21
+msgid "git fetch [<options>] <group>"
+msgstr ""
+
+#: builtin/fetch.c:22
+msgid "git fetch --multiple [<options>] [(<repository> | <group>)...]"
+msgstr ""
+
+#: builtin/fetch.c:23
+msgid "git fetch --all [<options>]"
+msgstr ""
+
+#: builtin/fetch.c:60
+msgid "fetch from all remotes"
+msgstr ""
+
+#: builtin/fetch.c:62
+msgid "append to .git/FETCH_HEAD instead of overwriting"
+msgstr ""
+
+#: builtin/fetch.c:64
+msgid "path to upload pack on remote end"
+msgstr ""
+
+#: builtin/fetch.c:65
+msgid "force overwrite of local branch"
+msgstr ""
+
+#: builtin/fetch.c:67
+msgid "fetch from multiple remotes"
+msgstr ""
+
+#: builtin/fetch.c:69
+#, fuzzy
+msgid "fetch all tags and associated objects"
+msgstr "更新远程引用和相关的对象"
+
+#: builtin/fetch.c:71
+msgid "do not fetch all tags (--no-tags)"
+msgstr ""
+
+#: builtin/fetch.c:73
+#, fuzzy
+msgid "prune remote-tracking branches no longer on remote"
+msgstr "%s 没有来自 %s 的远程跟踪分支"
+
+#: builtin/fetch.c:74
+msgid "on-demand"
+msgstr ""
+
+#: builtin/fetch.c:75
+msgid "control recursive fetching of submodules"
+msgstr ""
+
+#: builtin/fetch.c:79
+msgid "keep downloaded pack"
+msgstr ""
+
+#: builtin/fetch.c:81
+#, fuzzy
+msgid "allow updating of HEAD ref"
+msgstr "无法更新 HEAD 引用"
+
+#: builtin/fetch.c:84
+msgid "deepen history of shallow clone"
+msgstr ""
+
+#: builtin/fetch.c:85 builtin/log.c:1083
+msgid "dir"
+msgstr ""
+
+#: builtin/fetch.c:86
+#, fuzzy
+msgid "prepend this to submodule path output"
+msgstr "无法递归进子模组路径 '$sm_path'"
+
+#: builtin/fetch.c:89
+msgid "default mode for recursion"
+msgstr ""
+
+#: builtin/fetch.c:201
 msgid "Couldn't find remote ref HEAD"
 msgstr "无法发现远程 HEAD 引用"
 
-#: builtin/fetch.c:253
+#: builtin/fetch.c:254
 #, c-format
 msgid "object %s not found"
 msgstr "对象 %s 未发现"
 
-#: builtin/fetch.c:259
+#: builtin/fetch.c:260
 msgid "[up to date]"
 msgstr "[最新]"
 
-#: builtin/fetch.c:273
+#: builtin/fetch.c:274
 #, c-format
 msgid "! %-*s %-*s -> %s  (can't fetch in current branch)"
 msgstr "! %-*s %-*s -> %s  (在当前分支下不能获取)"
 
-#: builtin/fetch.c:274 builtin/fetch.c:360
+#: builtin/fetch.c:275 builtin/fetch.c:361
 msgid "[rejected]"
 msgstr "[已拒绝]"
 
-#: builtin/fetch.c:285
+#: builtin/fetch.c:286
 msgid "[tag update]"
 msgstr "[tag更新]"
 
 #  译者:注意保持前导空格
-#: builtin/fetch.c:287 builtin/fetch.c:322 builtin/fetch.c:340
+#: builtin/fetch.c:288 builtin/fetch.c:323 builtin/fetch.c:341
 msgid "  (unable to update local ref)"
 msgstr "  (不能更新本地引用)"
 
-#: builtin/fetch.c:305
+#: builtin/fetch.c:306
 msgid "[new tag]"
 msgstr "[新tag]"
 
-#: builtin/fetch.c:308
+#: builtin/fetch.c:309
 msgid "[new branch]"
 msgstr "[新分支]"
 
-#: builtin/fetch.c:311
+#: builtin/fetch.c:312
 msgid "[new ref]"
 msgstr "[新引用]"
 
-#: builtin/fetch.c:356
+#: builtin/fetch.c:357
 msgid "unable to update local ref"
 msgstr "不能更新本地引用"
 
-#: builtin/fetch.c:356
+#: builtin/fetch.c:357
 msgid "forced update"
 msgstr "强制更新"
 
-#: builtin/fetch.c:362
+#: builtin/fetch.c:363
 msgid "(non-fast-forward)"
 msgstr "(非快进式)"
 
-#: builtin/fetch.c:393 builtin/fetch.c:685
+#: builtin/fetch.c:394 builtin/fetch.c:686
 #, c-format
 msgid "cannot open %s: %s\n"
 msgstr "无法打开 %s:%s\n"
 
-#: builtin/fetch.c:402
+#: builtin/fetch.c:403
 #, c-format
 msgid "%s did not send all necessary objects\n"
 msgstr "%s 未发送所有必须的对象\n"
 
-#: builtin/fetch.c:488
+#: builtin/fetch.c:489
 #, c-format
 msgid "From %.*s\n"
 msgstr "来自 %.*s\n"
 
-#: builtin/fetch.c:499
+#: builtin/fetch.c:500
 #, c-format
 msgid ""
 "some local refs could not be updated; try running\n"
@@ -2658,82 +4327,204 @@ msgstr ""
 " 'git remote prune %s' 来删除旧的、有冲突的分支"
 
 #  译者:注意保持前导空格
-#: builtin/fetch.c:549
+#: builtin/fetch.c:550
 #, c-format
 msgid "   (%s will become dangling)"
 msgstr "   (%s 将成为悬空状态)"
 
 #  译者:注意保持前导空格
-#: builtin/fetch.c:550
+#: builtin/fetch.c:551
 #, c-format
 msgid "   (%s has become dangling)"
 msgstr "   (%s 已成为悬空状态)"
 
-#: builtin/fetch.c:557
+#: builtin/fetch.c:558
 msgid "[deleted]"
 msgstr "[已删除]"
 
-#: builtin/fetch.c:558 builtin/remote.c:1055
+#: builtin/fetch.c:559 builtin/remote.c:1055
 msgid "(none)"
 msgstr "(无)"
 
-#: builtin/fetch.c:675
+#: builtin/fetch.c:676
 #, c-format
 msgid "Refusing to fetch into current branch %s of non-bare repository"
 msgstr "拒绝获取到非裸版本库的当前分支 %s"
 
-#: builtin/fetch.c:709
+#: builtin/fetch.c:710
 #, c-format
 msgid "Don't know how to fetch from %s"
 msgstr "不知道如何从 %s 获取"
 
-#: builtin/fetch.c:786
+#: builtin/fetch.c:787
 #, c-format
 msgid "Option \"%s\" value \"%s\" is not valid for %s"
 msgstr "选项 \"%s\" 的值 \"%s\" 对于 %s 是无效的"
 
-#: builtin/fetch.c:789
+#: builtin/fetch.c:790
 #, c-format
 msgid "Option \"%s\" is ignored for %s\n"
 msgstr "选项 \"%s\" 为 %s 所忽略\n"
 
-#: builtin/fetch.c:888
+#: builtin/fetch.c:892
 #, c-format
 msgid "Fetching %s\n"
 msgstr "正在获取 %s\n"
 
-#: builtin/fetch.c:890 builtin/remote.c:100
+#: builtin/fetch.c:894 builtin/remote.c:100
 #, c-format
 msgid "Could not fetch %s"
 msgstr "不能获取 %s"
 
-#: builtin/fetch.c:907
+#: builtin/fetch.c:913
 msgid ""
 "No remote repository specified.  Please, specify either a URL or a\n"
 "remote name from which new revisions should be fetched."
 msgstr "未指定远程版本库。请通过一个URL或远程版本库名指定,用以获取新提交。"
 
-#: builtin/fetch.c:927
+#: builtin/fetch.c:933
 msgid "You need to specify a tag name."
 msgstr "您需要指定一个 tag 名称。"
 
-#: builtin/fetch.c:979
+#: builtin/fetch.c:985
 msgid "fetch --all does not take a repository argument"
 msgstr "fetch --all 不能带一个版本库参数"
 
-#: builtin/fetch.c:981
+#: builtin/fetch.c:987
 msgid "fetch --all does not make sense with refspecs"
 msgstr "fetch --all 带引用表达式没有任何意义"
 
-#: builtin/fetch.c:992
+#: builtin/fetch.c:998
 #, c-format
 msgid "No such remote or remote group: %s"
 msgstr "没有这样的远程或远程组:%s"
 
-#: builtin/fetch.c:1000
+#: builtin/fetch.c:1006
 msgid "Fetching a group and specifying refspecs does not make sense"
 msgstr "获取组并指定引用表达式没有意义"
 
+#: builtin/fmt-merge-msg.c:13
+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:786
+#: builtin/merge.c:188 builtin/show-branch.c:656 builtin/show-ref.c:192
+#: builtin/tag.c:448 parse-options.h:133 parse-options.h:235
+msgid "n"
+msgstr "数字"
+
+#: builtin/fmt-merge-msg.c:654
+msgid "populate log with at most <n> entries from shortlog"
+msgstr ""
+
+#: builtin/fmt-merge-msg.c:657
+msgid "alias for --log (deprecated)"
+msgstr ""
+
+#: builtin/fmt-merge-msg.c:660
+msgid "text"
+msgstr ""
+
+#: builtin/fmt-merge-msg.c:661
+msgid "use <text> as start of message"
+msgstr ""
+
+#: builtin/fmt-merge-msg.c:662
+#, fuzzy
+msgid "file to read from"
+msgstr "不能读 %s"
+
+#: builtin/for-each-ref.c:979
+#, fuzzy
+msgid "git for-each-ref [options] [<pattern>]"
+msgstr "git apply [选项] [<补丁>...]"
+
+#: builtin/for-each-ref.c:994
+msgid "quote placeholders suitably for shells"
+msgstr ""
+
+#: builtin/for-each-ref.c:996
+msgid "quote placeholders suitably for perl"
+msgstr ""
+
+#: builtin/for-each-ref.c:998
+msgid "quote placeholders suitably for python"
+msgstr ""
+
+#: builtin/for-each-ref.c:1000
+msgid "quote placeholders suitably for tcl"
+msgstr ""
+
+#: builtin/for-each-ref.c:1003
+msgid "show only <n> matched refs"
+msgstr ""
+
+#: builtin/for-each-ref.c:1004
+msgid "format"
+msgstr ""
+
+#: builtin/for-each-ref.c:1004
+msgid "format to use for the output"
+msgstr ""
+
+#: builtin/for-each-ref.c:1005
+msgid "key"
+msgstr ""
+
+#: builtin/for-each-ref.c:1006
+msgid "field name to sort on"
+msgstr ""
+
+#: builtin/fsck.c:608
+#, fuzzy
+msgid "git fsck [options] [<object>...]"
+msgstr "git apply [选项] [<补丁>...]"
+
+#: builtin/fsck.c:614
+msgid "show unreachable objects"
+msgstr ""
+
+#: builtin/fsck.c:615
+#, fuzzy
+msgid "show dangling objects"
+msgstr "索引对象中"
+
+#: builtin/fsck.c:616
+msgid "report tags"
+msgstr ""
+
+#: builtin/fsck.c:617
+msgid "report root nodes"
+msgstr ""
+
+#: builtin/fsck.c:618
+msgid "make index objects head nodes"
+msgstr ""
+
+#: builtin/fsck.c:619
+msgid "make reflogs head nodes (default)"
+msgstr ""
+
+#: builtin/fsck.c:620
+msgid "also consider packs and alternate objects"
+msgstr ""
+
+#: builtin/fsck.c:621
+msgid "enable more strict checking"
+msgstr ""
+
+#: builtin/fsck.c:623
+msgid "write dangling objects in .git/lost-found"
+msgstr ""
+
+#: builtin/fsck.c:624 builtin/prune.c:134
+msgid "show progress"
+msgstr ""
+
+#: builtin/gc.c:22
+msgid "git gc [options]"
+msgstr ""
+
 #: builtin/gc.c:63
 #, c-format
 msgid "Invalid %s: '%s'"
@@ -2744,6 +4535,18 @@ msgstr "无效的 %s:'%s'"
 msgid "insanely long object directory %.*s"
 msgstr "不正常的长对象目录 %.*s"
 
+#: builtin/gc.c:179
+msgid "prune unreferenced objects"
+msgstr ""
+
+#: builtin/gc.c:181
+msgid "be more thorough (increased runtime)"
+msgstr ""
+
+#: builtin/gc.c:182
+msgid "enable auto-gc mode"
+msgstr ""
+
 #: builtin/gc.c:221
 #, c-format
 msgid "Auto packing the repository for optimum performance.\n"
@@ -2763,89 +4566,317 @@ msgid ""
 "There are too many unreachable loose objects; run 'git prune' to remove them."
 msgstr "有太多不可达的松散对象,运行 'git prune' 删除它们。"
 
+#: builtin/grep.c:22
+msgid "git grep [options] [-e] <pattern> [<rev>...] [[--] <path>...]"
+msgstr ""
+
 #: builtin/grep.c:216
 #, c-format
 msgid "grep: failed to create thread: %s"
 msgstr "grep:无法创建线程:%s"
 
-#: builtin/grep.c:402
+#: builtin/grep.c:454
 #, c-format
 msgid "Failed to chdir: %s"
 msgstr "无法切换目录:%s"
 
-#: builtin/grep.c:478 builtin/grep.c:512
+#: builtin/grep.c:530 builtin/grep.c:564
 #, c-format
 msgid "unable to read tree (%s)"
 msgstr "无法读取树(%s)"
 
-#: builtin/grep.c:526
+#: builtin/grep.c:578
 #, c-format
 msgid "unable to grep from object of type %s"
 msgstr "无法抓取来自于 %s 类型的对象"
 
-#: builtin/grep.c:584
+#: builtin/grep.c:636
 #, c-format
 msgid "switch `%c' expects a numerical value"
 msgstr "开关 `%c' 期望一个数字值"
 
-#: builtin/grep.c:601
+#: builtin/grep.c:653
 #, c-format
 msgid "cannot open '%s'"
 msgstr "不能打开 '%s'"
 
-#: builtin/grep.c:885
+#: builtin/grep.c:728
+msgid "search in index instead of in the work tree"
+msgstr ""
+
+#: builtin/grep.c:730
+msgid "find in contents not managed by git"
+msgstr ""
+
+#  译者:中文字符串拼接,可删除前导空格
+#: builtin/grep.c:732
+#, fuzzy
+msgid "search in both tracked and untracked files"
+msgstr "(使用 -u 参数显示未跟踪的文件)"
+
+#: builtin/grep.c:734
+msgid "search also in ignored files"
+msgstr ""
+
+#: builtin/grep.c:737
+msgid "show non-matching lines"
+msgstr ""
+
+#: builtin/grep.c:739
+msgid "case insensitive matching"
+msgstr ""
+
+#: builtin/grep.c:741
+msgid "match patterns only at word boundaries"
+msgstr ""
+
+#: builtin/grep.c:743
+msgid "process binary files as text"
+msgstr ""
+
+#: builtin/grep.c:745
+msgid "don't match patterns in binary files"
+msgstr ""
+
+#: builtin/grep.c:748
+msgid "descend at most <depth> levels"
+msgstr ""
+
+#: builtin/grep.c:752
+msgid "use extended POSIX regular expressions"
+msgstr ""
+
+#: builtin/grep.c:755
+msgid "use basic POSIX regular expressions (default)"
+msgstr ""
+
+#: builtin/grep.c:758
+msgid "interpret patterns as fixed strings"
+msgstr ""
+
+#: builtin/grep.c:761
+msgid "use Perl-compatible regular expressions"
+msgstr ""
+
+#: builtin/grep.c:764
+msgid "show line numbers"
+msgstr ""
+
+#: builtin/grep.c:765
+msgid "don't show filenames"
+msgstr ""
+
+#: builtin/grep.c:766
+#, fuzzy
+msgid "show filenames"
+msgstr "%s文件:"
+
+#: builtin/grep.c:768
+msgid "show filenames relative to top directory"
+msgstr ""
+
+#: builtin/grep.c:770
+msgid "show only filenames instead of matching lines"
+msgstr ""
+
+#: builtin/grep.c:772
+msgid "synonym for --files-with-matches"
+msgstr ""
+
+#: builtin/grep.c:775
+msgid "show only the names of files without match"
+msgstr ""
+
+#: builtin/grep.c:777
+#, fuzzy
+msgid "print NUL after filenames"
+msgstr "为所有文件名前添加 <根目录>"
+
+#: builtin/grep.c:779
+msgid "show the number of matches instead of matching lines"
+msgstr ""
+
+#: builtin/grep.c:780
+msgid "highlight matches"
+msgstr ""
+
+#: builtin/grep.c:782
+msgid "print empty line between matches from different files"
+msgstr ""
+
+#: builtin/grep.c:784
+msgid "show filename only once above matches from same file"
+msgstr ""
+
+#: builtin/grep.c:787
+msgid "show <n> context lines before and after matches"
+msgstr ""
+
+#: builtin/grep.c:790
+msgid "show <n> context lines before matches"
+msgstr ""
+
+#: builtin/grep.c:792
+msgid "show <n> context lines after matches"
+msgstr ""
+
+#: builtin/grep.c:793
+msgid "shortcut for -C NUM"
+msgstr ""
+
+#: builtin/grep.c:796
+msgid "show a line with the function name before matches"
+msgstr ""
+
+#: builtin/grep.c:798
+msgid "show the surrounding function"
+msgstr ""
+
+#: builtin/grep.c:801
+msgid "read patterns from file"
+msgstr ""
+
+#: builtin/grep.c:803
+msgid "match <pattern>"
+msgstr ""
+
+#: builtin/grep.c:805
+msgid "combine patterns specified with -e"
+msgstr ""
+
+#: builtin/grep.c:817
+msgid "indicate hit with exit status without output"
+msgstr ""
+
+#: builtin/grep.c:819
+msgid "show only matches from files that match all patterns"
+msgstr ""
+
+#: builtin/grep.c:822
+msgid "pager"
+msgstr ""
+
+#: builtin/grep.c:822
+msgid "show matching files in the pager"
+msgstr ""
+
+#: builtin/grep.c:825
+msgid "allow calling of grep(1) (ignored by this build)"
+msgstr ""
+
+#: builtin/grep.c:826 builtin/show-ref.c:201
+msgid "show usage"
+msgstr ""
+
+#: builtin/grep.c:917
 msgid "no pattern given."
 msgstr "未提供模式匹配。"
 
-#: builtin/grep.c:899
+#: builtin/grep.c:931
 #, c-format
 msgid "bad object %s"
 msgstr "坏对象 %s"
 
-#: builtin/grep.c:940
+#: builtin/grep.c:972
 msgid "--open-files-in-pager only works on the worktree"
 msgstr "--open-files-in-pager 仅用于工作区"
 
-#: builtin/grep.c:963
+#: builtin/grep.c:995
 msgid "--cached or --untracked cannot be used with --no-index."
-msgstr "--cached æ\88\96 --untracked ä¸\8dè\83½ä¸\8e --no-index å\85±用。"
+msgstr "--cached æ\88\96 --untracked ä¸\8dè\83½ä¸\8e --no-index å\90\8cæ\97¶ä½¿用。"
 
-#: builtin/grep.c:968
+#: builtin/grep.c:1000
 msgid "--no-index or --untracked cannot be used with revs."
-msgstr "--no-index æ\88\96 --untracked ä¸\8dè\83½å\92\8cç\89\88æ\9c¬å\85±用。"
+msgstr "--no-index æ\88\96 --untracked ä¸\8dè\83½å\92\8cç\89\88æ\9c¬å\90\8cæ\97¶ä½¿用。"
 
-#: builtin/grep.c:971
+#: builtin/grep.c:1003
 msgid "--[no-]exclude-standard cannot be used for tracked contents."
 msgstr "--[no-]exclude-standard 不能用于已跟踪内容。"
 
-#: builtin/grep.c:979
+#: builtin/grep.c:1011
 msgid "both --cached and trees are given."
 msgstr "同时给出了 --cached 和树对象。"
 
-#: builtin/help.c:59
+#: builtin/hash-object.c:60
+msgid ""
+"git hash-object [-t <type>] [-w] [--path=<file>|--no-filters] [--stdin] [--] "
+"<file>..."
+msgstr ""
+
+#: builtin/hash-object.c:61
+msgid "git hash-object  --stdin-paths < <list-of-paths>"
+msgstr ""
+
+#: builtin/hash-object.c:72
+msgid "type"
+msgstr ""
+
+#: builtin/hash-object.c:72
+#, fuzzy
+msgid "object type"
+msgstr "坏的对象类型。"
+
+#: builtin/hash-object.c:73
+msgid "write the object into the object database"
+msgstr ""
+
+#: builtin/hash-object.c:74
+msgid "read the object from stdin"
+msgstr ""
+
+#: builtin/hash-object.c:76
+msgid "store file as is without filters"
+msgstr ""
+
+#: builtin/hash-object.c:77
+msgid "process file as it were from this path"
+msgstr ""
+
+#: builtin/help.c:43
+#, fuzzy
+msgid "print all available commands"
+msgstr "在 '%s' 下可用的 git 命令"
+
+#: builtin/help.c:44
+msgid "show man page"
+msgstr ""
+
+#: builtin/help.c:45
+msgid "show manual in web browser"
+msgstr ""
+
+#: builtin/help.c:47
+msgid "show info page"
+msgstr ""
+
+#: builtin/help.c:53
+msgid "git help [--all] [--man|--web|--info] [command]"
+msgstr ""
+
+#: builtin/help.c:65
 #, c-format
 msgid "unrecognized help format '%s'"
 msgstr "未能识别的帮助格式 '%s'"
 
-#: builtin/help.c:87
+#: builtin/help.c:93
 msgid "Failed to start emacsclient."
 msgstr "无法启动 emacsclient。"
 
-#: builtin/help.c:100
+#: builtin/help.c:106
 msgid "Failed to parse emacsclient version."
 msgstr "无法解析 emacsclient 版本。"
 
-#: builtin/help.c:108
+#: builtin/help.c:114
 #, c-format
 msgid "emacsclient version '%d' too old (< 22)."
 msgstr "emacsclient 版本 '%d' 太老 (< 22)。"
 
-#: builtin/help.c:126 builtin/help.c:154 builtin/help.c:163 builtin/help.c:171
+#: 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 "无法执行 '%s':%s"
 
-#: builtin/help.c:211
+#: builtin/help.c:217
 #, c-format
 msgid ""
 "'%s': path for unsupported man viewer.\n"
@@ -2854,7 +4885,7 @@ msgstr ""
 "'%s':不支持的 man 手册查看器的路径。\n"
 "请使用 'man.<tool>.cmd'。"
 
-#: builtin/help.c:223
+#: builtin/help.c:229
 #, c-format
 msgid ""
 "'%s': cmd for supported man viewer.\n"
@@ -2863,266 +4894,307 @@ msgstr ""
 "'%s': 支持的 man 手册查看器命令。\n"
 "请使用 'man.<tool>.path'。"
 
-#: builtin/help.c:287
+#: builtin/help.c:299
 msgid "The most commonly used git commands are:"
 msgstr "最常用的 git 命令有:"
 
-#: builtin/help.c:355
+#: builtin/help.c:367
 #, c-format
 msgid "'%s': unknown man viewer."
 msgstr "'%s':未知的 man 查看器。"
 
-#: builtin/help.c:372
+#: builtin/help.c:384
 msgid "no man viewer handled the request"
 msgstr "没有 man 查看器处理此请求"
 
-#: builtin/help.c:380
+#: builtin/help.c:392
 msgid "no info viewer handled the request"
 msgstr "没有 info 查看器处理此请求"
 
-#: builtin/help.c:391
-#, c-format
-msgid "'%s': not a documentation directory."
-msgstr "'%s':不是一个文档目录。"
-
-#: builtin/help.c:432 builtin/help.c:439
+#: builtin/help.c:447 builtin/help.c:454
 #, c-format
 msgid "usage: %s%s"
 msgstr "用法:%s%s"
 
-#: builtin/help.c:453
+#: builtin/help.c:470
 #, c-format
 msgid "`git %s' is aliased to `%s'"
 msgstr "`git %s' 是 `%s' 的别名"
 
-#: builtin/index-pack.c:169
+#: builtin/index-pack.c:170
 #, c-format
 msgid "object type mismatch at %s"
 msgstr "%s 的对象类型不匹配"
 
-#: builtin/index-pack.c:189
+#: builtin/index-pack.c:190
 msgid "object of unexpected type"
 msgstr "意外的类型的对象"
 
-#: builtin/index-pack.c:226
+#: builtin/index-pack.c:227
 #, c-format
 msgid "cannot fill %d byte"
 msgid_plural "cannot fill %d bytes"
 msgstr[0] "无法填充 %d 字节"
 msgstr[1] "无法填充 %d 字节"
 
-#: builtin/index-pack.c:236
+#: builtin/index-pack.c:237
 msgid "early EOF"
 msgstr "过早的文件结束符(EOF)"
 
-#: builtin/index-pack.c:237
+#: builtin/index-pack.c:238
 msgid "read error on input"
 msgstr "输入上的读错误"
 
-#: builtin/index-pack.c:249
+#: builtin/index-pack.c:250
 msgid "used more bytes than were available"
 msgstr "用掉了超过可用的字节"
 
-#: builtin/index-pack.c:256
+#: builtin/index-pack.c:257
 msgid "pack too large for current definition of off_t"
 msgstr "包太大超过了当前 off_t 的定义"
 
-#: builtin/index-pack.c:272
+#: builtin/index-pack.c:273
 #, c-format
 msgid "unable to create '%s'"
 msgstr "不能创建 '%s'"
 
-#: builtin/index-pack.c:277
+#: builtin/index-pack.c:278
 #, c-format
 msgid "cannot open packfile '%s'"
 msgstr "无法打开包文件 '%s'"
 
-#: builtin/index-pack.c:291
+#: builtin/index-pack.c:292
 msgid "pack signature mismatch"
 msgstr "包签名不匹配"
 
-#: builtin/index-pack.c:311
+#: builtin/index-pack.c:294
+#, c-format
+msgid "pack version %<PRIu32> unsupported"
+msgstr ""
+
+#: builtin/index-pack.c:312
 #, c-format
 msgid "pack has bad object at offset %lu: %s"
 msgstr "包中有错误的对象位于 %lu:%s"
 
-#: builtin/index-pack.c:405
+#: builtin/index-pack.c:434
 #, c-format
 msgid "inflate returned %d"
 msgstr "解压缩返回 %d"
 
-#: builtin/index-pack.c:450
+#: builtin/index-pack.c:483
 msgid "offset value overflow for delta base object"
 msgstr "偏移值覆盖了 delta 基准对象"
 
-#: builtin/index-pack.c:458
+#: builtin/index-pack.c:491
 msgid "delta base offset is out of bound"
 msgstr "delta 基准偏移越界"
 
-#: builtin/index-pack.c:466
+#: builtin/index-pack.c:499
 #, c-format
 msgid "unknown object type %d"
 msgstr "未知对象类型 %d"
 
-#: builtin/index-pack.c:495
+#: builtin/index-pack.c:530
 msgid "cannot pread pack file"
 msgstr "无法读取包文件"
 
-#: builtin/index-pack.c:497
+#: builtin/index-pack.c:532
 #, c-format
 msgid "premature end of pack file, %lu byte missing"
 msgid_plural "premature end of pack file, %lu bytes missing"
 msgstr[0] "包文件过早结束,缺少 %lu 字节"
 msgstr[1] "包文件过早结束,缺少 %lu 字节"
 
-#: builtin/index-pack.c:510
+#: builtin/index-pack.c:558
 msgid "serious inflate inconsistency"
 msgstr "解压缩严重的不一致"
 
-#: builtin/index-pack.c:583
-#, c-format
-msgid "cannot read existing object %s"
-msgstr "不能读取现存对象 %s"
-
-#: builtin/index-pack.c:586
+#: builtin/index-pack.c:649 builtin/index-pack.c:655 builtin/index-pack.c:678
+#: builtin/index-pack.c:712 builtin/index-pack.c:721
 #, c-format
 msgid "SHA1 COLLISION FOUND WITH %s !"
 msgstr "发现 %s 出现 SHA1 冲突!"
 
-#: builtin/index-pack.c:598
+#: builtin/index-pack.c:652 builtin/pack-objects.c:170
+#: builtin/pack-objects.c:262
+#, c-format
+msgid "unable to read %s"
+msgstr "不能读 %s"
+
+#: builtin/index-pack.c:718
+#, c-format
+msgid "cannot read existing object %s"
+msgstr "不能读取现存对象 %s"
+
+#: builtin/index-pack.c:732
 #, c-format
 msgid "invalid blob object %s"
-msgstr "无效的 blob 对象 %s"
+msgstr "无效的二进制对象(blob)%s"
 
-#: builtin/index-pack.c:610
+#: builtin/index-pack.c:747
 #, c-format
 msgid "invalid %s"
 msgstr "无效的 %s"
 
-#: builtin/index-pack.c:612
+#: builtin/index-pack.c:749
 msgid "Error in object"
 msgstr "对象中出错"
 
-#: builtin/index-pack.c:614
+#: builtin/index-pack.c:751
 #, c-format
 msgid "Not all child objects of %s are reachable"
 msgstr "%s 的所有子对象并非都可达"
 
-#: builtin/index-pack.c:687 builtin/index-pack.c:713
+#: builtin/index-pack.c:821 builtin/index-pack.c:847
 msgid "failed to apply delta"
 msgstr "无法应用 delta"
 
-#: builtin/index-pack.c:850
+#: builtin/index-pack.c:986
 msgid "Receiving objects"
 msgstr "接收对象中"
 
-#: builtin/index-pack.c:850
+#: builtin/index-pack.c:986
 msgid "Indexing objects"
 msgstr "索引对象中"
 
-#: builtin/index-pack.c:872
+#: builtin/index-pack.c:1012
 msgid "pack is corrupted (SHA1 mismatch)"
 msgstr "包冲突(SHA1 不匹配)"
 
-#: builtin/index-pack.c:877
+#: builtin/index-pack.c:1017
 msgid "cannot fstat packfile"
 msgstr "不能枚举包文件状态"
 
-#: builtin/index-pack.c:880
+#: builtin/index-pack.c:1020
 msgid "pack has junk at the end"
 msgstr "包的结尾有垃圾数据"
 
-#: builtin/index-pack.c:903
+#: builtin/index-pack.c:1031
+msgid "confusion beyond insanity in parse_pack_objects()"
+msgstr "parse_pack_objects() 中遇到不可理喻的问题"
+
+#: builtin/index-pack.c:1054
 msgid "Resolving deltas"
 msgstr "处理 delta 中"
 
-#: builtin/index-pack.c:954
+#: builtin/index-pack.c:1064
+#, fuzzy, c-format
+msgid "unable to create thread: %s"
+msgstr "grep:无法创建线程:%s"
+
+#: builtin/index-pack.c:1106
 msgid "confusion beyond insanity"
 msgstr "不可理喻"
 
-#: builtin/index-pack.c:973
+#: builtin/index-pack.c:1112
+#, c-format
+msgid "completed with %d local objects"
+msgstr ""
+
+#: builtin/index-pack.c:1121
+#, c-format
+msgid "Unexpected tail checksum for %s (disk corruption?)"
+msgstr ""
+
+#: builtin/index-pack.c:1125
 #, c-format
 msgid "pack has %d unresolved delta"
 msgid_plural "pack has %d unresolved deltas"
 msgstr[0] "包有 %d 个未解决的 delta"
 msgstr[1] "包有 %d 个未解决的 delta"
 
-#: builtin/index-pack.c:998
+#: builtin/index-pack.c:1150
 #, c-format
 msgid "unable to deflate appended object (%d)"
 msgstr "不能缩小附加对象(%d)"
 
-#: builtin/index-pack.c:1077
+#: builtin/index-pack.c:1229
 #, c-format
 msgid "local object %s is corrupt"
 msgstr "本地对象 %s 已损坏"
 
-#: builtin/index-pack.c:1101
+#: builtin/index-pack.c:1253
 msgid "error while closing pack file"
 msgstr "关闭包文件时出错"
 
-#: builtin/index-pack.c:1114
+#: builtin/index-pack.c:1266
 #, c-format
 msgid "cannot write keep file '%s'"
 msgstr "无法写保留文件 '%s'"
 
-#: builtin/index-pack.c:1122
+#: builtin/index-pack.c:1274
 #, c-format
 msgid "cannot close written keep file '%s'"
 msgstr "无法关闭保留文件 '%s'"
 
-#: builtin/index-pack.c:1135
+#: builtin/index-pack.c:1287
 msgid "cannot store pack file"
 msgstr "无法存储包文件"
 
-#: builtin/index-pack.c:1146
+#: builtin/index-pack.c:1298
 msgid "cannot store index file"
 msgstr "无法存储索引文件"
 
-#: builtin/index-pack.c:1247
+#: builtin/index-pack.c:1331
+#, fuzzy, c-format
+msgid "bad pack.indexversion=%<PRIu32>"
+msgstr "坏的索引版本 '%s'"
+
+#: builtin/index-pack.c:1337
+#, c-format
+msgid "invalid number of threads specified (%d)"
+msgstr ""
+
+#: builtin/index-pack.c:1341 builtin/index-pack.c:1514
+#, c-format
+msgid "no threads support, ignoring %s"
+msgstr ""
+
+#: builtin/index-pack.c:1399
 #, c-format
 msgid "Cannot open existing pack file '%s'"
 msgstr "无法打开现存包文件 '%s'"
 
-#: builtin/index-pack.c:1249
+#: builtin/index-pack.c:1401
 #, c-format
 msgid "Cannot open existing pack idx file for '%s'"
 msgstr "无法为 %s 打开包索引文件"
 
-#: builtin/index-pack.c:1296
+#: builtin/index-pack.c:1448
 #, c-format
 msgid "non delta: %d object"
 msgid_plural "non delta: %d objects"
 msgstr[0] "非 delta:%d 个对象"
 msgstr[1] "非 delta:%d 个对象"
 
-#: builtin/index-pack.c:1303
+#: builtin/index-pack.c:1455
 #, c-format
 msgid "chain length = %d: %lu object"
 msgid_plural "chain length = %d: %lu objects"
 msgstr[0] "链长 = %d: %lu 对象"
 msgstr[1] "链长 = %d: %lu 对象"
 
-#: builtin/index-pack.c:1330
+#: builtin/index-pack.c:1482
 msgid "Cannot come back to cwd"
 msgstr "无法返回当前工作目录"
 
-#: builtin/index-pack.c:1374 builtin/index-pack.c:1377
-#: builtin/index-pack.c:1389 builtin/index-pack.c:1393
+#: 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"
 
-#: builtin/index-pack.c:1407
+#: builtin/index-pack.c:1559
 msgid "--fix-thin cannot be used without --stdin"
-msgstr "--fix-thin ä¸\8dè\83½å\92\8c --stdin å\85±用"
+msgstr "--fix-thin ä¸\8dè\83½å\92\8c --stdin å\90\8cæ\97¶ä½¿用"
 
-#: builtin/index-pack.c:1411 builtin/index-pack.c:1421
+#: builtin/index-pack.c:1563 builtin/index-pack.c:1573
 #, c-format
 msgid "packfile name '%s' does not end with '.pack'"
 msgstr "包名 '%s' 没有以 '.pack' 结尾"
 
-#: builtin/index-pack.c:1430
+#: builtin/index-pack.c:1582
 msgid "--verify with no packfile name given"
 msgstr "--verify 没有提供包名参数"
 
@@ -3196,22 +5268,22 @@ msgstr "没有从 '%2$s' 复制带有错误版本 %1$d 的模版"
 msgid "insane git directory %s"
 msgstr "不正常的 git 目录 %s"
 
-#: builtin/init-db.c:322 builtin/init-db.c:325
+#: builtin/init-db.c:323 builtin/init-db.c:326
 #, c-format
 msgid "%s already exists"
 msgstr "%s 已经存在"
 
-#: builtin/init-db.c:354
+#: builtin/init-db.c:355
 #, c-format
 msgid "unable to handle file type %d"
 msgstr "不能处理 %d 类型的文件"
 
-#: builtin/init-db.c:357
+#: builtin/init-db.c:358
 #, c-format
 msgid "unable to move %s to %s"
 msgstr "不能移动 %s 至 %s"
 
-#: builtin/init-db.c:362
+#: builtin/init-db.c:363
 #, c-format
 msgid "Could not create git link %s"
 msgstr "不能创建 git link %s"
@@ -3221,39 +5293,58 @@ msgstr "不能创建 git link %s"
 #. * existing" or "Initialized empty", the second " shared" or
 #. * "", and the last '%s%s' is the verbatim directory name.
 #.
-#: builtin/init-db.c:419
+#: builtin/init-db.c:420
 #, c-format
 msgid "%s%s Git repository in %s%s\n"
 msgstr "%s%s Git 版本库于 %s%s\n"
 
-#: builtin/init-db.c:420
+#: builtin/init-db.c:421
 msgid "Reinitialized existing"
 msgstr "重新初始化现存的"
 
-#: builtin/init-db.c:420
+#: builtin/init-db.c:421
 msgid "Initialized empty"
 msgstr "初始化空的"
 
 #  译者:中文字符串拼接,可删除前导空格
-#: builtin/init-db.c:421
+#: builtin/init-db.c:422
 msgid " shared"
 msgstr "共享"
 
-#: builtin/init-db.c:440
+#: builtin/init-db.c:441
 msgid "cannot tell cwd"
 msgstr "无法获知当前路径"
 
-#: builtin/init-db.c:521 builtin/init-db.c:528
+#: builtin/init-db.c:467
+msgid ""
+"git init [-q | --quiet] [--bare] [--template=<template-directory>] [--shared"
+"[=<permissions>]] [directory]"
+msgstr ""
+
+#: builtin/init-db.c:490
+msgid "permissions"
+msgstr ""
+
+#: builtin/init-db.c:491
+msgid "specify that the git repository is to be shared amongst several users"
+msgstr ""
+
+#: builtin/init-db.c:493 builtin/prune-packed.c:77
+#, fuzzy
+msgid "be quiet"
+msgstr "更加安静"
+
+#: builtin/init-db.c:522 builtin/init-db.c:529
 #, c-format
 msgid "cannot mkdir %s"
 msgstr "不能创建目录 %s"
 
-#: builtin/init-db.c:532
+#: builtin/init-db.c:533
 #, c-format
 msgid "cannot chdir to %s"
 msgstr "不能切换目录到 %s"
 
-#: builtin/init-db.c:554
+#: builtin/init-db.c:555
 #, c-format
 msgid ""
 "%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-"
@@ -3262,113 +5353,413 @@ msgstr ""
 "不允许 %s(或 --work-tree=<directory>)而没有指定 %s(或 --git-"
 "dir=<directory>)"
 
-#: builtin/init-db.c:578
+#: builtin/init-db.c:579
 msgid "Cannot access current working directory"
 msgstr "不能访问当前工作目录"
 
-#: builtin/init-db.c:585
+#: builtin/init-db.c:586
 #, c-format
 msgid "Cannot access work tree '%s'"
 msgstr "不能访问工作区 '%s'"
 
-#: builtin/log.c:188
+#: builtin/log.c:37
+#, fuzzy
+msgid "git log [<options>] [<since>..<until>] [[--] <path>...]\n"
+msgstr "git apply [选项] [<补丁>...]"
+
+#: builtin/log.c:38
+#, fuzzy
+msgid "   or: git show [options] <object>..."
+msgstr "git apply [选项] [<补丁>...]"
+
+#: builtin/log.c:100
+msgid "suppress diff output"
+msgstr ""
+
+#: builtin/log.c:101
+#, fuzzy
+msgid "show source"
+msgstr "坏的源"
+
+#: builtin/log.c:102
+msgid "decorate options"
+msgstr ""
+
+#: builtin/log.c:189
 #, c-format
 msgid "Final output: %d %s\n"
 msgstr "最终输出:%d %s\n"
 
-#: builtin/log.c:401 builtin/log.c:489
+#: builtin/log.c:403 builtin/log.c:494
 #, c-format
 msgid "Could not read object %s"
 msgstr "不能读取对象 %s"
 
-#: builtin/log.c:513
+#: builtin/log.c:518
 #, c-format
 msgid "Unknown type: %d"
 msgstr "未知类型:%d"
 
-#: builtin/log.c:602
+#: builtin/log.c:608
 msgid "format.headers without value"
 msgstr "format.headers 没有值"
 
-#: builtin/log.c:676
-msgid "name of output directory is too long"
-msgstr "输出目录名太长"
+#: builtin/log.c:682
+msgid "name of output directory is too long"
+msgstr "输出目录名太长"
+
+#: builtin/log.c:693
+#, c-format
+msgid "Cannot open patch file %s"
+msgstr "无法打开补丁文件 %s"
+
+#: builtin/log.c:707
+msgid "Need exactly one range."
+msgstr "只需要一个范围。"
+
+#: builtin/log.c:715
+msgid "Not a range."
+msgstr "不是一个范围。"
+
+#: builtin/log.c:789
+msgid "Cover letter needs email format"
+msgstr "信封需要邮件地址格式"
+
+#: builtin/log.c:862
+#, c-format
+msgid "insane in-reply-to: %s"
+msgstr "不正常的 in-reply-to:%s"
+
+#: builtin/log.c:890
+msgid "git format-patch [options] [<since> | <revision range>]"
+msgstr ""
+
+#: builtin/log.c:935
+msgid "Two output directories?"
+msgstr "两个输出目录?"
+
+#: builtin/log.c:1063
+msgid "use [PATCH n/m] even with a single patch"
+msgstr ""
+
+#: builtin/log.c:1066
+msgid "use [PATCH] even with multiple patches"
+msgstr ""
+
+#: builtin/log.c:1070
+msgid "print patches to standard out"
+msgstr ""
+
+#: builtin/log.c:1072
+msgid "generate a cover letter"
+msgstr ""
+
+#: builtin/log.c:1074
+msgid "use simple number sequence for output file names"
+msgstr ""
+
+#: builtin/log.c:1075
+msgid "sfx"
+msgstr ""
+
+#: builtin/log.c:1076
+msgid "use <sfx> instead of '.patch'"
+msgstr ""
+
+#: builtin/log.c:1078
+msgid "start numbering patches at <n> instead of 1"
+msgstr ""
+
+#: builtin/log.c:1080
+msgid "Use [<prefix>] instead of [PATCH]"
+msgstr ""
+
+#: builtin/log.c:1083
+msgid "store resulting files in <dir>"
+msgstr ""
+
+#: builtin/log.c:1086
+msgid "don't strip/add [PATCH]"
+msgstr ""
+
+#: builtin/log.c:1089
+msgid "don't output binary diffs"
+msgstr ""
+
+#: builtin/log.c:1091
+msgid "don't include a patch matching a commit upstream"
+msgstr ""
+
+#: builtin/log.c:1093
+msgid "show patch format instead of default (patch + stat)"
+msgstr ""
+
+#: builtin/log.c:1095
+#, fuzzy
+msgid "Messaging"
+msgstr "合并:"
+
+#  译者:注意保持句尾空格
+#: builtin/log.c:1096
+#, fuzzy
+msgid "header"
+msgstr "领先 "
+
+#: builtin/log.c:1097
+msgid "add email header"
+msgstr ""
+
+#: builtin/log.c:1098 builtin/log.c:1100
+msgid "email"
+msgstr ""
+
+#: builtin/log.c:1098
+msgid "add To: header"
+msgstr ""
+
+#: builtin/log.c:1100
+msgid "add Cc: header"
+msgstr ""
+
+#: builtin/log.c:1102
+msgid "message-id"
+msgstr ""
+
+#: builtin/log.c:1103
+msgid "make first mail a reply to <message-id>"
+msgstr ""
+
+#: builtin/log.c:1104 builtin/log.c:1107
+msgid "boundary"
+msgstr ""
 
-#: builtin/log.c:687
-#, c-format
-msgid "Cannot open patch file %s"
-msgstr "无法打开补丁文件 %s"
+#: builtin/log.c:1105
+msgid "attach the patch"
+msgstr ""
 
-#: builtin/log.c:701
-msgid "Need exactly one range."
-msgstr "只需要一个范围。"
+#: builtin/log.c:1108
+#, fuzzy
+msgid "inline the patch"
+msgstr "忽略补丁中的添加的文件"
 
-#: builtin/log.c:709
-msgid "Not a range."
-msgstr "不是一个范围。"
+#: builtin/log.c:1112
+msgid "enable message threading, styles: shallow, deep"
+msgstr ""
 
-#: builtin/log.c:786
-msgid "Cover letter needs email format"
-msgstr "信封需要邮件地址格式"
+#: builtin/log.c:1114
+msgid "signature"
+msgstr ""
 
-#: builtin/log.c:859
-#, c-format
-msgid "insane in-reply-to: %s"
-msgstr "不正常的 in-reply-to:%s"
+#: builtin/log.c:1115
+msgid "add a signature"
+msgstr ""
 
-#: builtin/log.c:932
-msgid "Two output directories?"
-msgstr "两个输出目录?"
+#: builtin/log.c:1117
+#, fuzzy
+msgid "don't print the patch filenames"
+msgstr "无法打开补丁文件 %s"
 
-#: builtin/log.c:1153
+#: builtin/log.c:1157
 #, c-format
 msgid "bogus committer info %s"
 msgstr "虚假的提交者信息 %s"
 
-#: builtin/log.c:1198
+#: builtin/log.c:1202
 msgid "-n and -k are mutually exclusive."
 msgstr "-n 和 -k 互斥。"
 
-#: builtin/log.c:1200
+#: builtin/log.c:1204
 msgid "--subject-prefix and -k are mutually exclusive."
 msgstr "--subject-prefix 和 -k 互斥。"
 
-#: builtin/log.c:1208
+#: builtin/log.c:1212
 msgid "--name-only does not make sense"
 msgstr "--name-only 无意义"
 
-#: builtin/log.c:1210
+#: builtin/log.c:1214
 msgid "--name-status does not make sense"
 msgstr "--name-status 无意义"
 
-#: builtin/log.c:1212
+#: builtin/log.c:1216
 msgid "--check does not make sense"
 msgstr "--check 无意义"
 
-#: builtin/log.c:1235
+#: builtin/log.c:1239
 msgid "standard output, or directory, which one?"
 msgstr "标准输出或目录,哪一个?"
 
-#: builtin/log.c:1237
+#: builtin/log.c:1241
 #, c-format
 msgid "Could not create directory '%s'"
 msgstr "不能创建目录 '%s'"
 
-#: builtin/log.c:1390
+#: builtin/log.c:1394
 msgid "Failed to create output files"
 msgstr "无法创建输出文件"
 
-#: builtin/log.c:1494
+#: builtin/log.c:1443
+msgid "git cherry [-v] [<upstream> [<head> [<limit>]]]"
+msgstr ""
+
+#: builtin/log.c:1498
 #, c-format
 msgid ""
 "Could not find a tracked remote branch, please specify <upstream> manually.\n"
 msgstr "不能找到跟踪的远程分支,请手工指定 <upstream>。\n"
 
-#: builtin/log.c:1510 builtin/log.c:1512 builtin/log.c:1524
+#: builtin/log.c:1511 builtin/log.c:1513 builtin/log.c:1525
 #, c-format
 msgid "Unknown commit %s"
 msgstr "未知提交 %s"
 
+#: builtin/ls-files.c:408
+#, fuzzy
+msgid "git ls-files [options] [<file>...]"
+msgstr "git apply [选项] [<补丁>...]"
+
+#: builtin/ls-files.c:463
+msgid "identify the file status with tags"
+msgstr ""
+
+#: builtin/ls-files.c:465
+msgid "use lowercase letters for 'assume unchanged' files"
+msgstr ""
+
+#: builtin/ls-files.c:467
+msgid "show cached files in the output (default)"
+msgstr ""
+
+#: builtin/ls-files.c:469
+#, fuzzy
+msgid "show deleted files in the output"
+msgstr "删除的文件 %s 仍有内容"
+
+#: builtin/ls-files.c:471
+msgid "show modified files in the output"
+msgstr ""
+
+#: builtin/ls-files.c:473
+msgid "show other files in the output"
+msgstr ""
+
+#: builtin/ls-files.c:475
+msgid "show ignored files in the output"
+msgstr ""
+
+#: builtin/ls-files.c:478
+msgid "show staged contents' object name in the output"
+msgstr ""
+
+#: builtin/ls-files.c:480
+msgid "show files on the filesystem that need to be removed"
+msgstr ""
+
+#: builtin/ls-files.c:482
+msgid "show 'other' directories' name only"
+msgstr ""
+
+#: builtin/ls-files.c:485
+#, fuzzy
+msgid "don't show empty directories"
+msgstr "两个输出目录?"
+
+#: builtin/ls-files.c:488
+msgid "show unmerged files in the output"
+msgstr ""
+
+#: builtin/ls-files.c:490
+msgid "show resolve-undo information"
+msgstr ""
+
+#: builtin/ls-files.c:492
+#, fuzzy
+msgid "skip files matching pattern"
+msgstr "输出和模式匹配的行"
+
+#: builtin/ls-files.c:495
+msgid "exclude patterns are read from <file>"
+msgstr ""
+
+#: builtin/ls-files.c:498
+msgid "read additional per-directory exclude patterns in <file>"
+msgstr ""
+
+#: builtin/ls-files.c:500
+msgid "add the standard git exclusions"
+msgstr ""
+
+#: builtin/ls-files.c:503
+msgid "make the output relative to the project top directory"
+msgstr ""
+
+#: builtin/ls-files.c:506
+msgid "if any <file> is not in the index, treat this as an error"
+msgstr ""
+
+#: builtin/ls-files.c:507
+msgid "tree-ish"
+msgstr ""
+
+#: builtin/ls-files.c:508
+msgid "pretend that paths removed since <tree-ish> are still present"
+msgstr ""
+
+#: builtin/ls-files.c:510
+msgid "show debugging data"
+msgstr ""
+
+#: builtin/ls-tree.c:27
+#, fuzzy
+msgid "git ls-tree [<options>] <tree-ish> [<path>...]"
+msgstr "git apply [选项] [<补丁>...]"
+
+#: builtin/ls-tree.c:125
+msgid "only show trees"
+msgstr ""
+
+#: builtin/ls-tree.c:127
+#, fuzzy
+msgid "recurse into subtrees"
+msgstr "变基到远程 %s"
+
+#: builtin/ls-tree.c:129
+msgid "show trees when recursing"
+msgstr ""
+
+#: builtin/ls-tree.c:132
+msgid "terminate entries with NUL byte"
+msgstr ""
+
+#: builtin/ls-tree.c:133
+#, fuzzy
+msgid "include object size"
+msgstr "提供了无效对象 '%s'。"
+
+#: builtin/ls-tree.c:135 builtin/ls-tree.c:137
+msgid "list only filenames"
+msgstr ""
+
+#: builtin/ls-tree.c:140
+msgid "use full path names"
+msgstr ""
+
+#: builtin/ls-tree.c:142
+msgid "list entire tree; not just current directory (implies --full-name)"
+msgstr ""
+
+#: builtin/merge.c:43
+#, fuzzy
+msgid "git merge [options] [<commit>...]"
+msgstr "git apply [选项] [<补丁>...]"
+
+#: builtin/merge.c:44
+msgid "git merge [options] <msg> HEAD <commit>"
+msgstr ""
+
+#: builtin/merge.c:45
+msgid "git merge --abort"
+msgstr ""
+
 #: builtin/merge.c:90
 msgid "switch `m' requires a value"
 msgstr "开关 `m' 需要一个值"
@@ -3388,6 +5779,71 @@ msgstr "可用的策略有:"
 msgid "Available custom strategies are:"
 msgstr "可用的自定义策略有:"
 
+#: builtin/merge.c:183
+msgid "do not show a diffstat at the end of the merge"
+msgstr ""
+
+#: builtin/merge.c:186
+msgid "show a diffstat at the end of the merge"
+msgstr ""
+
+#: builtin/merge.c:187
+msgid "(synonym to --stat)"
+msgstr ""
+
+#: builtin/merge.c:189
+msgid "add (at most <n>) entries from shortlog to merge commit message"
+msgstr ""
+
+#: builtin/merge.c:192
+#, fuzzy
+msgid "create a single commit instead of doing a merge"
+msgstr "在合并过程中不能做部分提交。"
+
+#: builtin/merge.c:194
+msgid "perform a commit if the merge succeeds (default)"
+msgstr ""
+
+#: builtin/merge.c:196
+#, fuzzy
+msgid "edit message before committing"
+msgstr "尚未暂存以备提交的变更:"
+
+#: builtin/merge.c:198
+#, fuzzy
+msgid "allow fast-forward (default)"
+msgstr "可快进"
+
+#: builtin/merge.c:200
+msgid "abort if fast-forward is not possible"
+msgstr ""
+
+#: builtin/merge.c:202 builtin/notes.c:867 builtin/revert.c:112
+msgid "strategy"
+msgstr ""
+
+#: builtin/merge.c:203
+#, fuzzy
+msgid "merge strategy to use"
+msgstr "尝试合并策略 %s...\n"
+
+#: builtin/merge.c:204
+msgid "option=value"
+msgstr ""
+
+#: builtin/merge.c:205
+msgid "option for selected merge strategy"
+msgstr ""
+
+#: builtin/merge.c:207
+msgid "merge commit message (for a non-fast-forward merge)"
+msgstr ""
+
+#: builtin/merge.c:211
+#, fuzzy
+msgid "abort the current in-progress merge"
+msgstr "无法保存当前索引状态"
+
 #: builtin/merge.c:240
 msgid "could not run stash."
 msgstr "不能进行进度保存。"
@@ -3428,53 +5884,49 @@ msgstr "完成 SQUASH_MSG"
 msgid "No merge message -- not updating HEAD\n"
 msgstr "无合并信息 -- 未更新 HEAD\n"
 
-#: builtin/merge.c:437
+#: builtin/merge.c:436
 #, c-format
 msgid "'%s' does not point to a commit"
 msgstr "'%s' 没有指向一个提交"
 
-#: builtin/merge.c:536
+#: builtin/merge.c:535
 #, c-format
 msgid "Bad branch.%s.mergeoptions string: %s"
 msgstr "坏的 branch.%s.mergeoptions 字符串:%s"
 
-#: builtin/merge.c:629
+#: builtin/merge.c:628
 msgid "git write-tree failed to write a tree"
 msgstr "git write-tree 无法写入一树对象"
 
-#: builtin/merge.c:679
+#: builtin/merge.c:678
 msgid "failed to read the cache"
 msgstr "无法读取缓存"
 
-#: builtin/merge.c:697
-msgid "Unable to write index."
-msgstr "不能写索引。"
-
-#: builtin/merge.c:710
+#: builtin/merge.c:709
 msgid "Not handling anything other than two heads merge."
 msgstr "不能处理两个头合并之外的任何操作。"
 
-#: builtin/merge.c:724
+#: builtin/merge.c:723
 #, c-format
 msgid "Unknown option for merge-recursive: -X%s"
 msgstr "merge-recursive 的未知选项:-X%s"
 
-#: builtin/merge.c:738
+#: builtin/merge.c:737
 #, c-format
 msgid "unable to write %s"
 msgstr "不能写 %s"
 
-#: builtin/merge.c:877
+#: builtin/merge.c:876
 #, c-format
 msgid "Could not read from '%s'"
 msgstr "不能从 '%s' 读取"
 
-#: builtin/merge.c:886
+#: builtin/merge.c:885
 #, c-format
 msgid "Not committing merge; use 'git commit' to complete the merge.\n"
 msgstr "未提交合并,使用 'git commit' 完成此次合并。\n"
 
-#: builtin/merge.c:892
+#: builtin/merge.c:891
 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"
@@ -3487,52 +5939,52 @@ msgstr ""
 "\n"
 "以 '#' 开头的行将被忽略,而且空提交说明将会终止提交。\n"
 
-#: builtin/merge.c:916
+#: builtin/merge.c:915
 msgid "Empty commit message."
 msgstr "空提交信息。"
 
-#: builtin/merge.c:928
+#: builtin/merge.c:927
 #, c-format
 msgid "Wonderful.\n"
 msgstr "太棒了。\n"
 
-#: builtin/merge.c:993
+#: builtin/merge.c:992
 #, c-format
 msgid "Automatic merge failed; fix conflicts and then commit the result.\n"
 msgstr "自动合并失败,修正冲突然后提交修正的结果。\n"
 
-#: builtin/merge.c:1009
+#: builtin/merge.c:1008
 #, c-format
 msgid "'%s' is not a commit"
 msgstr "'%s' 不是一个提交"
 
-#: builtin/merge.c:1050
+#: builtin/merge.c:1049
 msgid "No current branch."
 msgstr "没有当前分支。"
 
-#: builtin/merge.c:1052
+#: builtin/merge.c:1051
 msgid "No remote for the current branch."
 msgstr "当前分支没有对应的远程版本库。"
 
-#: builtin/merge.c:1054
+#: builtin/merge.c:1053
 msgid "No default upstream defined for the current branch."
 msgstr "当前分支没有定义默认的上游分支。"
 
-#: builtin/merge.c:1059
+#: builtin/merge.c:1058
 #, c-format
 msgid "No remote tracking branch for %s from %s"
 msgstr "%s 没有来自 %s 的远程跟踪分支"
 
-#: builtin/merge.c:1146 builtin/merge.c:1303
+#: builtin/merge.c:1145 builtin/merge.c:1302
 #, c-format
 msgid "%s - not something we can merge"
 msgstr "%s - 不能被合并"
 
-#: builtin/merge.c:1214
+#: builtin/merge.c:1213
 msgid "There is no merge to abort (MERGE_HEAD missing)."
 msgstr "没有要终止的合并(MERGE_HEAD 丢失)。"
 
-#: builtin/merge.c:1230 git-pull.sh:31
+#: builtin/merge.c:1229 git-pull.sh:31
 msgid ""
 "You have not concluded your merge (MERGE_HEAD exists).\n"
 "Please, commit your changes before you can merge."
@@ -3540,11 +5992,11 @@ msgstr ""
 "您尚未结束您的合并(存在 MERGE_HEAD)。\n"
 "请在合并前先提交您的修改。"
 
-#: builtin/merge.c:1233 git-pull.sh:34
+#: builtin/merge.c:1232 git-pull.sh:34
 msgid "You have not concluded your merge (MERGE_HEAD exists)."
 msgstr "您尚未结束您的合并(存在 MERGE_HEAD)。"
 
-#: builtin/merge.c:1237
+#: builtin/merge.c:1236
 msgid ""
 "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
 "Please, commit your changes before you can merge."
@@ -3552,83 +6004,184 @@ msgstr ""
 "您尚未结束您的拣选(存在 CHERRY_PICK_HEAD)。\n"
 "请在合并前先提交您的修改。"
 
-#: builtin/merge.c:1240
+#: builtin/merge.c:1239
 msgid "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)."
 msgstr "您尚未结束您的拣选(存在 CHERRY_PICK_HEAD)。"
 
-#: builtin/merge.c:1249
+#: builtin/merge.c:1248
 msgid "You cannot combine --squash with --no-ff."
-msgstr "æ\82¨ä¸\8dè\83½å°\86 --squash ä¸\8e --no-ff å\85±用。"
+msgstr "æ\82¨ä¸\8dè\83½å°\86 --squash ä¸\8e --no-ff å\90\8cæ\97¶ä½¿用。"
 
-#: builtin/merge.c:1254
+#: builtin/merge.c:1253
 msgid "You cannot combine --no-ff with --ff-only."
-msgstr "æ\82¨ä¸\8dè\83½å°\86 --no-ff ä¸\8e --ff-only å\85±用。"
+msgstr "æ\82¨ä¸\8dè\83½å°\86 --no-ff ä¸\8e --ff-only å\90\8cæ\97¶ä½¿用。"
 
-#: builtin/merge.c:1261
+#: builtin/merge.c:1260
 msgid "No commit specified and merge.defaultToUpstream not set."
 msgstr "未指定提交并且 merge.defaultToUpstream 未设置。"
 
-#: builtin/merge.c:1293
+#: builtin/merge.c:1292
 msgid "Can merge only exactly one commit into empty head"
 msgstr "只能将一个提交合并到空分支上"
 
-#: builtin/merge.c:1296
+#: builtin/merge.c:1295
 msgid "Squash commit into empty head not supported yet"
 msgstr "尚不支持到空分支的压缩提交"
 
-#: builtin/merge.c:1298
+#: builtin/merge.c:1297
 msgid "Non-fast-forward commit does not make sense into an empty head"
 msgstr "到空分支的非快进式提交没有意义"
 
-#: builtin/merge.c:1413
+#: builtin/merge.c:1412
 #, c-format
 msgid "Updating %s..%s\n"
 msgstr "更新 %s..%s\n"
 
-#: builtin/merge.c:1451
+#: builtin/merge.c:1450
 #, c-format
 msgid "Trying really trivial in-index merge...\n"
 msgstr "尝试非常小的索引内合并...\n"
 
-#: builtin/merge.c:1458
+#: builtin/merge.c:1457
 #, c-format
 msgid "Nope.\n"
 msgstr "无。\n"
 
-#: builtin/merge.c:1490
+#: builtin/merge.c:1489
 msgid "Not possible to fast-forward, aborting."
 msgstr "无法快进,终止。"
 
-#: builtin/merge.c:1513 builtin/merge.c:1592
+#: builtin/merge.c:1512 builtin/merge.c:1591
 #, c-format
 msgid "Rewinding the tree to pristine...\n"
 msgstr "将树回滚至原始状态...\n"
 
-#: builtin/merge.c:1517
+#: builtin/merge.c:1516
 #, c-format
 msgid "Trying merge strategy %s...\n"
 msgstr "尝试合并策略 %s...\n"
 
-#: builtin/merge.c:1583
+#: builtin/merge.c:1582
 #, c-format
 msgid "No merge strategy handled the merge.\n"
 msgstr "没有合并策略处理此合并。\n"
 
-#: builtin/merge.c:1585
+#: builtin/merge.c:1584
 #, c-format
 msgid "Merge with strategy %s failed.\n"
 msgstr "使用策略 %s 合并失败。\n"
 
-#: builtin/merge.c:1594
+#: builtin/merge.c:1593
 #, c-format
 msgid "Using the %s to prepare resolving by hand.\n"
 msgstr "使用 %s 以准备手工解决。\n"
 
-#: builtin/merge.c:1606
+#: builtin/merge.c:1605
 #, c-format
 msgid "Automatic merge went well; stopped before committing as requested\n"
 msgstr "自动合并进展顺利,按要求在提交前停止\n"
 
+#: builtin/merge-base.c:26
+msgid "git merge-base [-a|--all] <commit> <commit>..."
+msgstr ""
+
+#: builtin/merge-base.c:27
+msgid "git merge-base [-a|--all] --octopus <commit>..."
+msgstr ""
+
+#: builtin/merge-base.c:28
+msgid "git merge-base --independent <commit>..."
+msgstr ""
+
+#: builtin/merge-base.c:29
+msgid "git merge-base --is-ancestor <commit> <commit>"
+msgstr ""
+
+#: builtin/merge-base.c:98
+#, fuzzy
+msgid "output all common ancestors"
+msgstr "发现 %u 个共同祖先:"
+
+#: builtin/merge-base.c:99
+msgid "find ancestors for a single n-way merge"
+msgstr ""
+
+#: builtin/merge-base.c:100
+msgid "list revs not reachable from others"
+msgstr ""
+
+#: builtin/merge-base.c:102
+msgid "is the first one ancestor of the other?"
+msgstr ""
+
+#: builtin/merge-file.c:8
+msgid ""
+"git merge-file [options] [-L name1 [-L orig [-L name2]]] file1 orig_file "
+"file2"
+msgstr ""
+
+#: builtin/merge-file.c:33
+msgid "send results to standard output"
+msgstr ""
+
+#: builtin/merge-file.c:34
+msgid "use a diff3 based merge"
+msgstr ""
+
+#: builtin/merge-file.c:35
+msgid "for conflicts, use our version"
+msgstr ""
+
+#: builtin/merge-file.c:37
+msgid "for conflicts, use their version"
+msgstr ""
+
+#: builtin/merge-file.c:39
+msgid "for conflicts, use a union version"
+msgstr ""
+
+#: builtin/merge-file.c:42
+msgid "for conflicts, use this marker size"
+msgstr ""
+
+#: builtin/merge-file.c:43
+msgid "do not warn about conflicts"
+msgstr ""
+
+#: builtin/merge-file.c:45
+msgid "set labels for file1/orig_file/file2"
+msgstr ""
+
+#: builtin/mktree.c:67
+msgid "git mktree [-z] [--missing] [--batch]"
+msgstr ""
+
+#: builtin/mktree.c:153
+msgid "input is NUL terminated"
+msgstr ""
+
+#: builtin/mktree.c:154 builtin/write-tree.c:24
+#, fuzzy
+msgid "allow missing objects"
+msgstr "接收对象中"
+
+#: builtin/mktree.c:155
+msgid "allow creation of more than one tree"
+msgstr ""
+
+#: builtin/mv.c:14
+msgid "git mv [options] <source>... <destination>"
+msgstr ""
+
+#: builtin/mv.c:64
+msgid "force move/rename even if target exists"
+msgstr ""
+
+#: builtin/mv.c:65
+#, fuzzy
+msgid "skip move/rename errors"
+msgstr "程序错误"
+
 #: builtin/mv.c:108
 #, c-format
 msgid "Checking rename of '%s' to '%s'\n"
@@ -3672,24 +6225,169 @@ msgstr "覆盖 '%s'"
 msgid "Cannot overwrite"
 msgstr "不能覆盖"
 
-#: builtin/mv.c:187
-msgid "multiple sources for the same target"
-msgstr "同一目标具有多个源"
+#: builtin/mv.c:187
+msgid "multiple sources for the same target"
+msgstr "同一目标具有多个源"
+
+#: builtin/mv.c:202
+#, c-format
+msgid "%s, source=%s, destination=%s"
+msgstr "%s,源=%s,目标=%s"
+
+#: builtin/mv.c:212
+#, c-format
+msgid "Renaming %s to %s\n"
+msgstr "重命名 %s 至 %s\n"
+
+#: builtin/mv.c:215 builtin/remote.c:731
+#, c-format
+msgid "renaming '%s' failed"
+msgstr "重命名 '%s' 失败"
+
+#: builtin/name-rev.c:175
+#, fuzzy
+msgid "git name-rev [options] <commit>..."
+msgstr "git apply [选项] [<补丁>...]"
+
+#: builtin/name-rev.c:176
+msgid "git name-rev [options] --all"
+msgstr ""
+
+#: builtin/name-rev.c:177
+msgid "git name-rev [options] --stdin"
+msgstr ""
+
+#: builtin/name-rev.c:229
+msgid "print only names (no SHA-1)"
+msgstr ""
+
+#: builtin/name-rev.c:230
+msgid "only use tags to name the commits"
+msgstr ""
+
+#: builtin/name-rev.c:232
+#, fuzzy
+msgid "only use refs matching <pattern>"
+msgstr "输出和模式匹配的行"
+
+#: builtin/name-rev.c:234
+msgid "list all commits reachable from all refs"
+msgstr ""
+
+#: builtin/name-rev.c:235
+msgid "read from stdin"
+msgstr ""
+
+#: builtin/name-rev.c:236
+msgid "allow to print `undefined` names"
+msgstr ""
+
+#: builtin/notes.c:23
+msgid "git notes [--ref <notes_ref>] [list [<object>]]"
+msgstr ""
+
+#: builtin/notes.c:24
+msgid ""
+"git notes [--ref <notes_ref>] add [-f] [-m <msg> | -F <file> | (-c | -C) "
+"<object>] [<object>]"
+msgstr ""
+
+#: builtin/notes.c:25
+msgid "git notes [--ref <notes_ref>] copy [-f] <from-object> <to-object>"
+msgstr ""
+
+#: builtin/notes.c:26
+msgid ""
+"git notes [--ref <notes_ref>] append [-m <msg> | -F <file> | (-c | -C) "
+"<object>] [<object>]"
+msgstr ""
+
+#: builtin/notes.c:27
+msgid "git notes [--ref <notes_ref>] edit [<object>]"
+msgstr ""
+
+#: builtin/notes.c:28
+msgid "git notes [--ref <notes_ref>] show [<object>]"
+msgstr ""
+
+#: builtin/notes.c:29
+msgid ""
+"git notes [--ref <notes_ref>] merge [-v | -q] [-s <strategy> ] <notes_ref>"
+msgstr ""
+
+#: builtin/notes.c:30
+msgid "git notes merge --commit [-v | -q]"
+msgstr ""
+
+#: builtin/notes.c:31
+msgid "git notes merge --abort [-v | -q]"
+msgstr ""
+
+#: builtin/notes.c:32
+msgid "git notes [--ref <notes_ref>] remove [<object>...]"
+msgstr ""
+
+#: builtin/notes.c:33
+msgid "git notes [--ref <notes_ref>] prune [-n | -v]"
+msgstr ""
+
+#: builtin/notes.c:34
+msgid "git notes [--ref <notes_ref>] get-ref"
+msgstr ""
+
+#: builtin/notes.c:39
+msgid "git notes [list [<object>]]"
+msgstr ""
+
+#: builtin/notes.c:44
+#, fuzzy
+msgid "git notes add [<options>] [<object>]"
+msgstr "git apply [选项] [<补丁>...]"
+
+#: builtin/notes.c:49
+msgid "git notes copy [<options>] <from-object> <to-object>"
+msgstr ""
+
+#: builtin/notes.c:50
+msgid "git notes copy --stdin [<from-object> <to-object>]..."
+msgstr ""
+
+#: builtin/notes.c:55
+#, fuzzy
+msgid "git notes append [<options>] [<object>]"
+msgstr "git apply [选项] [<补丁>...]"
+
+#: builtin/notes.c:60
+msgid "git notes edit [<object>]"
+msgstr ""
+
+#: builtin/notes.c:65
+msgid "git notes show [<object>]"
+msgstr ""
+
+#: builtin/notes.c:70
+msgid "git notes merge [<options>] <notes_ref>"
+msgstr ""
+
+#: builtin/notes.c:71
+msgid "git notes merge --commit [<options>]"
+msgstr ""
 
-#: builtin/mv.c:202
-#, c-format
-msgid "%s, source=%s, destination=%s"
-msgstr "%s,源=%s,目标=%s"
+#: builtin/notes.c:72
+msgid "git notes merge --abort [<options>]"
+msgstr ""
 
-#: builtin/mv.c:212
-#, c-format
-msgid "Renaming %s to %s\n"
-msgstr "重命名 %s 至 %s\n"
+#: builtin/notes.c:77
+msgid "git notes remove [<object>]"
+msgstr ""
 
-#: builtin/mv.c:215 builtin/remote.c:731
-#, c-format
-msgid "renaming '%s' failed"
-msgstr "重命名 '%s' 失败"
+#: builtin/notes.c:82
+msgid "git notes prune [<options>]"
+msgstr ""
+
+#: builtin/notes.c:87
+msgid "git notes get-ref"
+msgstr ""
 
 #: builtin/notes.c:139
 #, c-format
@@ -3798,6 +6496,37 @@ msgstr "参数太多"
 msgid "No note found for object %s."
 msgstr "未发现对象 %s 的注解。"
 
+#: builtin/notes.c:535 builtin/notes.c:692
+#, fuzzy
+msgid "note contents as a string"
+msgstr "注解内容被留在文件 %s 中"
+
+#: builtin/notes.c:538 builtin/notes.c:695
+#, fuzzy
+msgid "note contents in a file"
+msgstr "无法存储索引文件"
+
+#: builtin/notes.c:540 builtin/notes.c:543 builtin/notes.c:697
+#: builtin/notes.c:700 builtin/tag.c:476
+#, fuzzy
+msgid "object"
+msgstr "坏对象 %s"
+
+#: builtin/notes.c:541 builtin/notes.c:698
+#, fuzzy
+msgid "reuse and edit specified note object"
+msgstr "不能写注解对象"
+
+#: builtin/notes.c:544 builtin/notes.c:701
+#, fuzzy
+msgid "reuse specified note object"
+msgstr "不能写注解对象"
+
+#: builtin/notes.c:546 builtin/notes.c:614
+#, fuzzy
+msgid "replace existing notes"
+msgstr "不能读取现存对象 %s"
+
 #: builtin/notes.c:580
 #, c-format
 msgid ""
@@ -3810,6 +6539,15 @@ msgstr "不能添加注解。发现对象 %s 已存在注解。使用 '-f' 覆
 msgid "Overwriting existing notes for object %s\n"
 msgstr "覆盖对象 %s 现存注解\n"
 
+#: builtin/notes.c:615
+#, fuzzy
+msgid "read objects from stdin"
+msgstr "坏对象 %s"
+
+#: builtin/notes.c:617
+msgid "load rewriting config for <command> (implies --stdin)"
+msgstr ""
+
 #: builtin/notes.c:635
 msgid "too few parameters"
 msgstr "参数太少"
@@ -3835,36 +6573,263 @@ msgstr ""
 "子命令 'edit' 的选项 -m/-F/-c/-C 已弃用。\n"
 "请换用 'git notes add -f -m/-F/-c/-C'。\n"
 
+#: builtin/notes.c:864
+#, fuzzy
+msgid "General options"
+msgstr "无效选项:%s"
+
+#: builtin/notes.c:866
+msgid "Merge options"
+msgstr ""
+
+#: builtin/notes.c:868
+msgid ""
+"resolve notes conflicts using the given strategy (manual/ours/theirs/union/"
+"cat_sort_uniq)"
+msgstr ""
+
+#: builtin/notes.c:870
+msgid "Committing unmerged notes"
+msgstr ""
+
+#: builtin/notes.c:872
+msgid "finalize notes merge by committing unmerged notes"
+msgstr ""
+
+#: builtin/notes.c:874
+msgid "Aborting notes merge resolution"
+msgstr ""
+
+#: builtin/notes.c:876
+#, fuzzy
+msgid "abort notes merge"
+msgstr "path '%s':无法合并"
+
 #: builtin/notes.c:971
 #, c-format
 msgid "Object %s has no note\n"
 msgstr "对象 %s 没有注解\n"
 
+#: builtin/notes.c:983
+msgid "attempt to remove non-existent note is not an error"
+msgstr ""
+
+#: builtin/notes.c:986
+#, fuzzy
+msgid "read object names from the standard input"
+msgstr "(正从标准输入中读取日志信息)\n"
+
+#: builtin/notes.c:1067
+msgid "notes_ref"
+msgstr ""
+
+#: builtin/notes.c:1068
+msgid "use notes from <notes_ref>"
+msgstr ""
+
 #: builtin/notes.c:1103 builtin/remote.c:1598
 #, c-format
 msgid "Unknown subcommand: %s"
 msgstr "未知子命令:%s"
 
-#: builtin/pack-objects.c:2337
+#: builtin/pack-objects.c:23
+msgid "git pack-objects --stdout [options...] [< ref-list | < object-list]"
+msgstr ""
+
+#: builtin/pack-objects.c:24
+msgid "git pack-objects [options...] base-name [< ref-list | < object-list]"
+msgstr ""
+
+#: builtin/pack-objects.c:183 builtin/pack-objects.c:186
+#, c-format
+msgid "deflate error (%d)"
+msgstr "压缩错误 (%d)"
+
+#: builtin/pack-objects.c:2398
 #, c-format
 msgid "unsupported index version %s"
 msgstr "不支持的索引版本 %s"
 
-#: builtin/pack-objects.c:2341
+#: builtin/pack-objects.c:2402
 #, c-format
 msgid "bad index version '%s'"
 msgstr "坏的索引版本 '%s'"
 
-#: builtin/pack-objects.c:2364
+#: builtin/pack-objects.c:2425
 #, c-format
 msgid "option %s does not accept negative form"
 msgstr "选项 %s 不接受否定格式"
 
-#: builtin/pack-objects.c:2368
+#: builtin/pack-objects.c:2429
 #, c-format
 msgid "unable to parse value '%s' for option %s"
 msgstr "不能解析选项 %1$s 的值 '%2$s'"
 
+#: builtin/pack-objects.c:2448
+msgid "do not show progress meter"
+msgstr ""
+
+#: builtin/pack-objects.c:2450
+msgid "show progress meter"
+msgstr ""
+
+#: builtin/pack-objects.c:2452
+msgid "show progress meter during object writing phase"
+msgstr ""
+
+#: builtin/pack-objects.c:2455
+msgid "similar to --all-progress when progress meter is shown"
+msgstr ""
+
+#: builtin/pack-objects.c:2456
+msgid "version[,offset]"
+msgstr ""
+
+#: builtin/pack-objects.c:2457
+msgid "write the pack index file in the specified idx format version"
+msgstr ""
+
+#: builtin/pack-objects.c:2460
+#, fuzzy
+msgid "maximum size of each output pack file"
+msgstr "无法创建输出文件"
+
+#: builtin/pack-objects.c:2462
+msgid "ignore borrowed objects from alternate object store"
+msgstr ""
+
+#: builtin/pack-objects.c:2464
+#, fuzzy
+msgid "ignore packed objects"
+msgstr "不能读取对象 %s"
+
+#: builtin/pack-objects.c:2466
+msgid "limit pack window by objects"
+msgstr ""
+
+#: builtin/pack-objects.c:2468
+msgid "limit pack window by memory in addition to object limit"
+msgstr ""
+
+#: builtin/pack-objects.c:2470
+msgid "maximum length of delta chain allowed in the resulting pack"
+msgstr ""
+
+#: builtin/pack-objects.c:2472
+#, fuzzy
+msgid "reuse existing deltas"
+msgstr "处理 delta 中"
+
+#: builtin/pack-objects.c:2474
+#, fuzzy
+msgid "reuse existing objects"
+msgstr "不能读取现存对象 %s"
+
+#: builtin/pack-objects.c:2476
+msgid "use OFS_DELTA objects"
+msgstr ""
+
+#: builtin/pack-objects.c:2478
+msgid "use threads when searching for best delta matches"
+msgstr ""
+
+#: builtin/pack-objects.c:2480
+msgid "do not create an empty pack output"
+msgstr ""
+
+#: builtin/pack-objects.c:2482
+#, fuzzy
+msgid "read revision arguments from standard input"
+msgstr "(正从标准输入中读取日志信息)\n"
+
+#: builtin/pack-objects.c:2484
+msgid "limit the objects to those that are not yet packed"
+msgstr ""
+
+#: builtin/pack-objects.c:2487
+msgid "include objects reachable from any reference"
+msgstr ""
+
+#: builtin/pack-objects.c:2490
+msgid "include objects referred by reflog entries"
+msgstr ""
+
+#: builtin/pack-objects.c:2493
+msgid "output pack to stdout"
+msgstr ""
+
+#: builtin/pack-objects.c:2495
+msgid "include tag objects that refer to objects to be packed"
+msgstr ""
+
+#: builtin/pack-objects.c:2497
+msgid "keep unreachable objects"
+msgstr ""
+
+#: builtin/pack-objects.c:2498 parse-options.h:141
+msgid "time"
+msgstr "时间"
+
+#: builtin/pack-objects.c:2499
+msgid "unpack unreachable objects newer than <time>"
+msgstr ""
+
+#: builtin/pack-objects.c:2502
+msgid "create thin packs"
+msgstr ""
+
+#: builtin/pack-objects.c:2504
+msgid "ignore packs that have companion .keep file"
+msgstr ""
+
+#: builtin/pack-objects.c:2506
+msgid "pack compression level"
+msgstr ""
+
+#: builtin/pack-objects.c:2508
+#, fuzzy
+msgid "do not hide commits by grafts"
+msgstr "不能写提交模版"
+
+#: builtin/pack-refs.c:6
+msgid "git pack-refs [options]"
+msgstr ""
+
+#: builtin/pack-refs.c:14
+msgid "pack everything"
+msgstr ""
+
+#: builtin/pack-refs.c:15
+msgid "prune loose refs (default)"
+msgstr ""
+
+#: builtin/prune-packed.c:7
+msgid "git prune-packed [-n|--dry-run] [-q|--quiet]"
+msgstr ""
+
+#: builtin/prune.c:12
+msgid "git prune [-n] [-v] [--expire <time>] [--] [<head>...]"
+msgstr ""
+
+#: builtin/prune.c:132
+#, fuzzy
+msgid "do not remove, show only"
+msgstr "不会删除 %s\n"
+
+#: builtin/prune.c:133
+#, fuzzy
+msgid "report pruned objects"
+msgstr "不能读取对象 %s"
+
+#: builtin/prune.c:136
+msgid "expire objects older than <time>"
+msgstr ""
+
+#: builtin/push.c:14
+#, fuzzy
+msgid "git push [<options>] [<repository> [<refspec>...]]"
+msgstr "git apply [选项] [<补丁>...]"
+
 #: builtin/push.c:45
 msgid "tag shorthand without <tag>"
 msgstr "tag 简写没有跟 <tag> 参数"
@@ -3947,12 +6912,44 @@ msgstr ""
 "您正推送至远程 '%s'(其并非当前分支 '%s' 的上游),\n"
 "而没有告诉我要推送什么、更新哪个远程分支。"
 
-#: builtin/push.c:174
+#  译者:字符串首行行首要添加“warning: ”字串,故此首行要较其余行短
+#: builtin/push.c:151
+msgid ""
+"push.default is unset; its implicit value is changing in\n"
+"Git 2.0 from 'matching' to 'simple'. To squelch this message\n"
+"and maintain the current behavior after the default changes, use:\n"
+"\n"
+"  git config --global push.default matching\n"
+"\n"
+"To squelch this message and adopt the new behavior now, use:\n"
+"\n"
+"  git config --global push.default simple\n"
+"\n"
+"See 'git help config' and search for 'push.default' for further "
+"information.\n"
+"(the 'simple' mode was introduced in Git 1.7.11. Use the similar mode\n"
+"'current' instead of 'simple' if you sometimes use older versions of Git)"
+msgstr ""
+"push.default 未设置,它的默认值将会在 Git 2.0 由 'matching'\n"
+"修改为 'simple'。若要不再显示本信息并在其默认值改变后维持当前使用习惯,\n"
+"进行如下设置:\n"
+"\n"
+"  git config --global push.default matching\n"
+"\n"
+"若要不再显示本信息并从现在开始采用新的使用习惯,设置:\n"
+"\n"
+"  git config --global push.default simple\n"
+"\n"
+"参见 'git help config' 并查找 'push.default' 以获取更多信息。\n"
+"('simple' 模式由 Git 1.7.11 版本引入。如果您有时要使用老版本的 Git,\n"
+"为保持兼容,请用 'current' 代替 'simple' 模式)"
+
+#: builtin/push.c:199
 msgid ""
 "You didn't specify any refspecs to push, and push.default is \"nothing\"."
 msgstr "您没有为推送指定任何引用表达式,并且 push.default 为 \"nothing\"。"
 
-#: builtin/push.c:181
+#: builtin/push.c:206
 msgid ""
 "Updates were rejected because the tip of your current branch is behind\n"
 "its remote counterpart. Merge the remote changes (e.g. 'git pull')\n"
@@ -3963,18 +6960,19 @@ msgstr ""
 "再次推送前,先与远程变更合并(如 'git pull')。详见\n"
 "'git push --help' 中的 'Note about fast-forwards' 小节。"
 
-#: builtin/push.c:187
+#: builtin/push.c:212
 msgid ""
 "Updates were rejected because a pushed branch tip is behind its remote\n"
 "counterpart. If you did not intend to push that branch, you may want to\n"
-"specify branches to push or set the 'push.default' configuration\n"
-"variable to 'current' or 'upstream' to push only the current branch."
+"specify branches to push or set the 'push.default' configuration variable\n"
+"to 'simple', 'current' or 'upstream' to push only the current branch."
 msgstr ""
 "更新被拒绝,因为推送的一个分支的最新提交落后于其对应的远程分支。\n"
 "如果您并非有意推送该分支,您可以在推送时指定要推送的分支,或者将\n"
-"配置变量 'push.default' 设置为 'current' 或 'upstream' 以便只推送当前分支。"
+"配置变量 'push.default' 设置为 'simple'、'current' 或 'upstream'\n"
+"以便只推送当前分支。"
 
-#: builtin/push.c:193
+#: builtin/push.c:218
 msgid ""
 "Updates were rejected because a pushed branch tip is behind its remote\n"
 "counterpart. Check out this branch and merge the remote changes\n"
@@ -3985,22 +6983,22 @@ msgstr ""
 "检出该分支并与远程变更合并(如 'git pull'),然后再推送。详见\n"
 "'git push --help' 中的 'Note about fast-forwards' 小节。"
 
-#: builtin/push.c:233
+#: builtin/push.c:258
 #, c-format
 msgid "Pushing to %s\n"
 msgstr "推送到 %s\n"
 
-#: builtin/push.c:237
+#: builtin/push.c:262
 #, c-format
 msgid "failed to push some refs to '%s'"
 msgstr "无法推送一些引用到 '%s'"
 
-#: builtin/push.c:269
+#: builtin/push.c:294
 #, c-format
 msgid "bad repository '%s'"
 msgstr "坏的版本库 '%s'"
 
-#: builtin/push.c:270
+#: builtin/push.c:295
 msgid ""
 "No configured push destination.\n"
 "Either specify the URL from the command-line or configure a remote "
@@ -4021,33 +7019,240 @@ msgstr ""
 "\n"
 "    git push <name>\n"
 
-#: builtin/push.c:285
+#: builtin/push.c:310
 msgid "--all and --tags are incompatible"
 msgstr "--all 和 --tags 不兼容"
 
-#: builtin/push.c:286
+#: builtin/push.c:311
 msgid "--all can't be combined with refspecs"
-msgstr "--all ä¸\8dè\83½å\92\8cå¼\95ç\94¨è¡¨è¾¾å¼\8få\85±用"
+msgstr "--all ä¸\8dè\83½å\92\8cå¼\95ç\94¨è¡¨è¾¾å¼\8få\90\8cæ\97¶ä½¿用"
 
-#: builtin/push.c:291
+#: builtin/push.c:316
 msgid "--mirror and --tags are incompatible"
 msgstr "--mirror 和 --tags 不兼容"
 
-#: builtin/push.c:292
+#: builtin/push.c:317
 msgid "--mirror can't be combined with refspecs"
-msgstr "--mirror ä¸\8dè\83½å\92\8cå¼\95ç\94¨è¡¨è¾¾å¼\8få\85±用"
+msgstr "--mirror ä¸\8dè\83½å\92\8cå¼\95ç\94¨è¡¨è¾¾å¼\8få\90\8cæ\97¶ä½¿用"
 
-#: builtin/push.c:297
+#: builtin/push.c:322
 msgid "--all and --mirror are incompatible"
 msgstr "--all 和 --mirror 不兼容"
 
-#: builtin/push.c:385
-msgid "--delete is incompatible with --all, --mirror and --tags"
-msgstr "--delete 与 --all、--mirror 及 --tags 不兼容"
+#: builtin/push.c:382
+#, fuzzy
+msgid "repository"
+msgstr "坏的版本库 '%s'"
+
+#: builtin/push.c:383
+msgid "push all refs"
+msgstr ""
+
+#: builtin/push.c:384
+msgid "mirror all refs"
+msgstr ""
+
+#: builtin/push.c:386
+#, fuzzy
+msgid "delete refs"
+msgstr "删除"
+
+#: builtin/push.c:387
+msgid "push tags (can't be used with --all or --mirror)"
+msgstr ""
+
+#: builtin/push.c:390
+#, fuzzy
+msgid "force updates"
+msgstr "强制更新"
+
+#: builtin/push.c:391
+msgid "check"
+msgstr ""
+
+#: builtin/push.c:392
+msgid "control recursive pushing of submodules"
+msgstr ""
+
+#: builtin/push.c:394
+msgid "use thin pack"
+msgstr ""
+
+#: builtin/push.c:395 builtin/push.c:396
+msgid "receive pack program"
+msgstr ""
+
+#: builtin/push.c:397
+msgid "set upstream for git pull/status"
+msgstr ""
+
+#: builtin/push.c:400
+msgid "prune locally removed refs"
+msgstr ""
+
+#: builtin/push.c:410
+msgid "--delete is incompatible with --all, --mirror and --tags"
+msgstr "--delete 与 --all、--mirror 及 --tags 不兼容"
+
+#: builtin/push.c:412
+msgid "--delete doesn't make sense without any refs"
+msgstr "--delete 未接任何引用没有意义"
+
+#: 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 ""
+
+#: builtin/read-tree.c:108
+#, fuzzy
+msgid "write resulting index to <file>"
+msgstr "损坏的索引文件"
+
+#: builtin/read-tree.c:111
+#, fuzzy
+msgid "only empty the index"
+msgstr "不能读取索引"
+
+#: builtin/read-tree.c:113
+#, fuzzy
+msgid "Merging"
+msgstr "合并:"
+
+#: builtin/read-tree.c:115
+msgid "perform a merge in addition to a read"
+msgstr ""
+
+#: builtin/read-tree.c:117
+msgid "3-way merge if no file level merging required"
+msgstr ""
+
+#: builtin/read-tree.c:119
+msgid "3-way merge in presence of adds and removes"
+msgstr ""
+
+#: builtin/read-tree.c:121
+msgid "same as -m, but discard unmerged entries"
+msgstr ""
+
+#: builtin/read-tree.c:122
+#, fuzzy
+msgid "<subdirectory>/"
+msgstr "目录/文件"
+
+#: builtin/read-tree.c:123
+msgid "read the tree into the index under <subdirectory>/"
+msgstr ""
+
+#: builtin/read-tree.c:126
+msgid "update working tree with merge result"
+msgstr ""
+
+#: builtin/read-tree.c:128
+#, fuzzy
+msgid "gitignore"
+msgstr "忽略的"
+
+#: builtin/read-tree.c:129
+msgid "allow explicitly ignored files to be overwritten"
+msgstr ""
+
+#: builtin/read-tree.c:132
+#, fuzzy
+msgid "don't check the working tree after merging"
+msgstr "显示工作区状态"
+
+#: builtin/read-tree.c:133
+msgid "don't update the index or the work tree"
+msgstr ""
+
+#: builtin/read-tree.c:135
+msgid "skip applying sparse checkout filter"
+msgstr ""
+
+#: builtin/read-tree.c:137
+msgid "debug unpack-trees"
+msgstr ""
+
+#: builtin/remote.c:11
+msgid "git remote [-v | --verbose]"
+msgstr ""
+
+#: builtin/remote.c:12
+msgid ""
+"git remote add [-t <branch>] [-m <master>] [-f] [--tags|--no-tags] [--"
+"mirror=<fetch|push>] <name> <url>"
+msgstr ""
+
+#: builtin/remote.c:13 builtin/remote.c:32
+msgid "git remote rename <old> <new>"
+msgstr ""
+
+#: builtin/remote.c:14 builtin/remote.c:37
+msgid "git remote remove <name>"
+msgstr ""
+
+#: builtin/remote.c:15
+msgid "git remote set-head <name> (-a | -d | <branch>)"
+msgstr ""
+
+#: builtin/remote.c:16
+msgid "git remote [-v | --verbose] show [-n] <name>"
+msgstr ""
+
+#: builtin/remote.c:17
+msgid "git remote prune [-n | --dry-run] <name>"
+msgstr ""
+
+#: builtin/remote.c:18
+msgid ""
+"git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]"
+msgstr ""
+
+#: builtin/remote.c:19
+msgid "git remote set-branches [--add] <name> <branch>..."
+msgstr ""
+
+#: builtin/remote.c:20 builtin/remote.c:68
+msgid "git remote set-url [--push] <name> <newurl> [<oldurl>]"
+msgstr ""
+
+#: builtin/remote.c:21 builtin/remote.c:69
+msgid "git remote set-url --add <name> <newurl>"
+msgstr ""
+
+#: builtin/remote.c:22 builtin/remote.c:70
+msgid "git remote set-url --delete <name> <url>"
+msgstr ""
+
+#: builtin/remote.c:27
+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 ""
+
+#: builtin/remote.c:48
+msgid "git remote set-branches --add <name> <branch>..."
+msgstr ""
+
+#: builtin/remote.c:53
+msgid "git remote show [<options>] <name>"
+msgstr ""
+
+#: builtin/remote.c:58
+msgid "git remote prune [<options>] <name>"
+msgstr ""
 
-#: builtin/push.c:387
-msgid "--delete doesn't make sense without any refs"
-msgstr "--delete 未接任何引用没有意义"
+#: builtin/remote.c:63
+msgid "git remote update [<options>] [<group> | <remote>]..."
+msgstr ""
 
 #: builtin/remote.c:98
 #, c-format
@@ -4067,13 +7272,43 @@ msgstr ""
 msgid "unknown mirror argument: %s"
 msgstr "未知的镜像参数:%s"
 
+#: builtin/remote.c:163
+#, fuzzy
+msgid "fetch the remote branches"
+msgstr "  远程分支:%s"
+
+#: builtin/remote.c:165
+msgid "import all tags and associated objects when fetching"
+msgstr ""
+
+#: builtin/remote.c:168
+msgid "or do not fetch any tag at all (--no-tags)"
+msgstr ""
+
+#: builtin/remote.c:170
+msgid "branch(es) to track"
+msgstr ""
+
+#: builtin/remote.c:171
+#, fuzzy
+msgid "master branch"
+msgstr "  远程分支:%s"
+
+#: builtin/remote.c:172
+msgid "push|fetch"
+msgstr ""
+
+#: builtin/remote.c:173
+msgid "set up remote as a mirror to push to or fetch from"
+msgstr ""
+
 #: builtin/remote.c:185
 msgid "specifying a master branch makes no sense with --mirror"
 msgstr "指定一个 master 分支并使用 --mirror 选项没有意义"
 
 #: builtin/remote.c:187
 msgid "specifying branches to track makes sense only with fetch mirrors"
-msgstr "æ\8c\87å®\9aè¦\81è·\9f踪ç\9a\84å\88\86æ\94¯å\8fªå\9c¨ä¸\8eè\8e·å\8f\96é\95\9cå\83\8få\85±用才有意义"
+msgstr "æ\8c\87å®\9aè¦\81è·\9f踪ç\9a\84å\88\86æ\94¯å\8fªå\9c¨ä¸\8eè\8e·å\8f\96é\95\9cå\83\8få\90\8cæ\97¶ä½¿用才有意义"
 
 #: builtin/remote.c:195 builtin/remote.c:646
 #, c-format
@@ -4259,6 +7494,11 @@ msgstr "    %-*s 强制推送至 %s"
 msgid "    %-*s pushes to %s"
 msgstr "    %-*s 推送至 %s"
 
+#: builtin/remote.c:1091
+#, fuzzy
+msgid "do not query remotes"
+msgstr "不会删除 %s\n"
+
 #: builtin/remote.c:1118
 #, c-format
 msgid "* remote %s"
@@ -4318,6 +7558,14 @@ msgid_plural "  Local refs configured for 'git push'%s:"
 msgstr[0] "  为 'git push' 配置的本地引用%s:"
 msgstr[1] "  为 'git push' 配置的本地引用%s:"
 
+#: builtin/remote.c:1199
+msgid "set refs/remotes/<name>/HEAD according to remote"
+msgstr ""
+
+#: builtin/remote.c:1201
+msgid "delete refs/remotes/<name>/HEAD"
+msgstr ""
+
 #: builtin/remote.c:1216
 msgid "Cannot determine remote HEAD"
 msgstr "无法确定远程 HEAD"
@@ -4373,15 +7621,37 @@ msgstr " * [将删除] %s"
 msgid " * [pruned] %s"
 msgstr " * [已删除] %s"
 
+#: builtin/remote.c:1321
+msgid "prune remotes after fetching"
+msgstr ""
+
 #: builtin/remote.c:1387 builtin/remote.c:1461
 #, c-format
 msgid "No such remote '%s'"
 msgstr "没有此远程 '%s'"
 
+#: builtin/remote.c:1407
+#, fuzzy
+msgid "add branch"
+msgstr "位于分支 "
+
 #: builtin/remote.c:1414
 msgid "no remote specified"
 msgstr "未指定远程"
 
+#: builtin/remote.c:1436
+msgid "manipulate push URLs"
+msgstr ""
+
+#: builtin/remote.c:1438
+msgid "add URL"
+msgstr ""
+
+#: builtin/remote.c:1440
+#, fuzzy
+msgid "delete URLs"
+msgstr "删除"
+
 #: builtin/remote.c:1447
 msgid "--add --delete doesn't make sense"
 msgstr "--add --delete 无意义"
@@ -4400,6 +7670,56 @@ msgstr "未找到此URL:%s"
 msgid "Will not delete all non-push URLs"
 msgstr "将不会删除所有非推送URL地址"
 
+#: builtin/remote.c:1569
+msgid "be verbose; must be placed before a subcommand"
+msgstr ""
+
+#: builtin/replace.c:17
+msgid "git replace [-f] <object> <replacement>"
+msgstr ""
+
+#: builtin/replace.c:18
+msgid "git replace -d <object>..."
+msgstr ""
+
+#: builtin/replace.c:19
+msgid "git replace -l [<pattern>]"
+msgstr ""
+
+#: builtin/replace.c:118
+msgid "list replace refs"
+msgstr ""
+
+#: builtin/replace.c:119
+msgid "delete replace refs"
+msgstr ""
+
+#: builtin/replace.c:120
+msgid "replace the ref if it exists"
+msgstr ""
+
+#: builtin/rerere.c:11
+msgid "git rerere [clear | forget path... | status | remaining | diff | gc]"
+msgstr ""
+
+#: builtin/rerere.c:56
+#, fuzzy
+msgid "register clean resolutions in index"
+msgstr "%s:已经存在于索引中"
+
+#: builtin/reset.c:25
+msgid ""
+"git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]"
+msgstr ""
+
+#: builtin/reset.c:26
+msgid "git reset [-q] <commit> [--] <paths>..."
+msgstr ""
+
+#: builtin/reset.c:27
+msgid "git reset --patch [<commit>] [--] [<paths>...]"
+msgstr ""
+
 #: builtin/reset.c:33
 msgid "mixed"
 msgstr "混杂"
@@ -4456,94 +7776,433 @@ msgstr "重置后撤出暂存区的变更:"
 msgid "Cannot do a %s reset in the middle of a merge."
 msgstr "在合并过程中不能做%s重置操作。"
 
-#: builtin/reset.c:297
+#: builtin/reset.c:238
+msgid "be quiet, only report errors"
+msgstr ""
+
+#: builtin/reset.c:240
+msgid "reset HEAD and index"
+msgstr ""
+
+#: builtin/reset.c:241
+msgid "reset only HEAD"
+msgstr ""
+
+#: builtin/reset.c:243 builtin/reset.c:245
+msgid "reset HEAD, index and working tree"
+msgstr ""
+
+#: builtin/reset.c:247
+msgid "reset HEAD but keep local changes"
+msgstr ""
+
+#: builtin/reset.c:303
 #, c-format
 msgid "Could not parse object '%s'."
 msgstr "不能解析对象 '%s'。"
 
-#: builtin/reset.c:302
+#: builtin/reset.c:308
 msgid "--patch is incompatible with --{hard,mixed,soft}"
 msgstr "--patch 与 --{hard,mixed,soft} 不兼容"
 
-#: builtin/reset.c:311
+#: builtin/reset.c:317
 msgid "--mixed with paths is deprecated; use 'git reset -- <paths>' instead."
-msgstr "--mixed 带路径已弃用,代之以 'git reset -- <paths>'。"
+msgstr "--mixed 带路径已弃用,而是用 'git reset -- <paths>'。"
+
+#  译者:汉字之间无空格,故删除%s前后空格
+#: builtin/reset.c:319
+#, c-format
+msgid "Cannot do %s reset with paths."
+msgstr "不能带路径进行%s重置。"
+
+#  译者:汉字之间无空格,故删除%s前后空格
+#: builtin/reset.c:331
+#, c-format
+msgid "%s reset is not allowed in a bare repository"
+msgstr "不能对裸版本库进行%s重置"
+
+#: builtin/reset.c:347
+#, c-format
+msgid "Could not reset index file to revision '%s'."
+msgstr "不能重置索引文件至版本 '%s'。"
+
+#: builtin/rev-parse.c:339
+#, fuzzy
+msgid "git rev-parse --parseopt [options] -- [<args>...]"
+msgstr "git apply [选项] [<补丁>...]"
+
+#: builtin/rev-parse.c:344
+msgid "keep the `--` passed as an arg"
+msgstr ""
+
+#: builtin/rev-parse.c:346
+msgid "stop parsing after the first non-option argument"
+msgstr ""
+
+#: 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 ""
+
+#: builtin/revert.c:22
+msgid "git revert [options] <commit-ish>"
+msgstr ""
+
+#: builtin/revert.c:23
+msgid "git revert <subcommand>"
+msgstr ""
+
+#: builtin/revert.c:28
+msgid "git cherry-pick [options] <commit-ish>"
+msgstr ""
+
+#: builtin/revert.c:29
+#, fuzzy
+msgid "git cherry-pick <subcommand>"
+msgstr "拣选失败"
+
+#: builtin/revert.c:70 builtin/revert.c:92
+#, c-format
+msgid "%s: %s cannot be used with %s"
+msgstr "%s:%s 不能和 %s 同时使用"
+
+#: builtin/revert.c:103
+msgid "end revert or cherry-pick sequence"
+msgstr ""
+
+#: builtin/revert.c:104
+msgid "resume revert or cherry-pick sequence"
+msgstr ""
+
+#: builtin/revert.c:105
+msgid "cancel revert or cherry-pick sequence"
+msgstr ""
+
+#: builtin/revert.c:106
+#, fuzzy
+msgid "don't automatically commit"
+msgstr "不能作为初始提交还原"
+
+#: builtin/revert.c:107
+#, fuzzy
+msgid "edit the commit message"
+msgstr "空提交信息。"
+
+#: builtin/revert.c:110
+msgid "parent number"
+msgstr ""
+
+#: builtin/revert.c:112
+#, fuzzy
+msgid "merge strategy"
+msgstr "尝试合并策略 %s...\n"
+
+#: builtin/revert.c:113
+#, fuzzy
+msgid "option"
+msgstr "动作"
+
+#: builtin/revert.c:114
+#, fuzzy
+msgid "option for merge strategy"
+msgstr "尝试合并策略 %s...\n"
+
+#: builtin/revert.c:125
+msgid "append commit name"
+msgstr ""
+
+#: builtin/revert.c:126
+#, fuzzy
+msgid "allow fast-forward"
+msgstr "(非快进式)"
+
+#: builtin/revert.c:127
+#, fuzzy
+msgid "preserve initially empty commits"
+msgstr "不能作为初始提交还原"
+
+#: builtin/revert.c:128
+#, fuzzy
+msgid "allow commits with empty messages"
+msgstr "提交说明为空"
+
+#: builtin/revert.c:129
+#, fuzzy
+msgid "keep redundant, empty commits"
+msgstr "合并未返回提交"
+
+#: builtin/revert.c:133
+msgid "program error"
+msgstr "程序错误"
+
+#: builtin/revert.c:223
+msgid "revert failed"
+msgstr "还原失败"
+
+#: builtin/revert.c:238
+msgid "cherry-pick failed"
+msgstr "拣选失败"
+
+#: builtin/rm.c:14
+#, fuzzy
+msgid "git rm [options] [--] <file>..."
+msgstr "git apply [选项] [<补丁>...]"
+
+#: builtin/rm.c:109
+#, c-format
+msgid ""
+"'%s' has staged content different from both the file and the HEAD\n"
+"(use -f to force removal)"
+msgstr ""
+"'%s' 暂存的内容和工作区及 HEAD 中的都不一样\n"
+"(使用 -f 强制删除)"
+
+#: builtin/rm.c:115
+#, c-format
+msgid ""
+"'%s' has changes staged in the index\n"
+"(use --cached to keep the file, or -f to force removal)"
+msgstr ""
+"'%s' 有变更已暂存至索引中\n"
+"(使用 --cached 保存文件,或用 -f 强制删除)"
+
+#: builtin/rm.c:119
+#, c-format
+msgid ""
+"'%s' has local modifications\n"
+"(use --cached to keep the file, or -f to force removal)"
+msgstr ""
+"'%s' 有本地修改\n"
+"(使用 --cached 保存文件,或用 -f 强制删除)"
+
+#: builtin/rm.c:134
+#, fuzzy
+msgid "do not list removed files"
+msgstr "无法还原修改的文件"
+
+#: builtin/rm.c:135
+#, fuzzy
+msgid "only remove from the index"
+msgstr "不能从索引中移除 %s"
+
+#: builtin/rm.c:136
+msgid "override the up-to-date check"
+msgstr ""
+
+#: builtin/rm.c:137
+msgid "allow recursive removal"
+msgstr ""
+
+#: builtin/rm.c:139
+msgid "exit with a zero status even if nothing matched"
+msgstr ""
+
+#: builtin/rm.c:194
+#, c-format
+msgid "not removing '%s' recursively without -r"
+msgstr "未提供 -r 选项不会递归删除 '%s'"
+
+#: builtin/rm.c:230
+#, c-format
+msgid "git rm: unable to remove %s"
+msgstr "git rm:不能删除 %s"
+
+#: builtin/shortlog.c:13
+msgid "git shortlog [-n] [-s] [-e] [-w] [rev-opts] [--] [<commit-id>... ]"
+msgstr ""
+
+#: builtin/shortlog.c:157
+#, c-format
+msgid "Missing author: %s"
+msgstr "缺少作者:%s"
+
+#: builtin/shortlog.c:253
+msgid "sort output according to the number of commits per author"
+msgstr ""
+
+#: builtin/shortlog.c:255
+msgid "Suppress commit descriptions, only provides commit count"
+msgstr ""
+
+#: builtin/shortlog.c:257
+msgid "Show the email address of each author"
+msgstr ""
+
+#: builtin/shortlog.c:258
+msgid "w[,i1[,i2]]"
+msgstr ""
+
+#: builtin/shortlog.c:259
+msgid "Linewrap output"
+msgstr ""
+
+#: 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 ""
+
+#: builtin/show-branch.c:10
+msgid "git show-branch (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]"
+msgstr ""
+
+#: builtin/show-branch.c:651
+#, fuzzy
+msgid "show remote-tracking and local branches"
+msgstr "%s 没有来自 %s 的远程跟踪分支"
+
+#: builtin/show-branch.c:653
+#, fuzzy
+msgid "show remote-tracking branches"
+msgstr "%s 没有来自 %s 的远程跟踪分支"
+
+#: builtin/show-branch.c:655
+msgid "color '*!+-' corresponding to the branch"
+msgstr ""
+
+#: builtin/show-branch.c:657
+msgid "show <n> more commits after the common ancestor"
+msgstr ""
+
+#: builtin/show-branch.c:659
+msgid "synonym to more=-1"
+msgstr ""
+
+#: builtin/show-branch.c:660
+msgid "suppress naming strings"
+msgstr ""
+
+#: builtin/show-branch.c:662
+#, fuzzy
+msgid "include the current branch"
+msgstr "没有当前分支。"
+
+#: builtin/show-branch.c:664
+#, fuzzy
+msgid "name commits with their object names"
+msgstr "不能写注解对象"
+
+#: builtin/show-branch.c:666
+msgid "show possible merge bases"
+msgstr ""
+
+#: builtin/show-branch.c:668
+msgid "show refs unreachable from any other ref"
+msgstr ""
+
+#: builtin/show-branch.c:670
+msgid "show commits in topological order"
+msgstr ""
+
+#: builtin/show-branch.c:672
+msgid "show only commits not on the first branch"
+msgstr ""
+
+#: builtin/show-branch.c:674
+msgid "show merges reachable from only one tip"
+msgstr ""
+
+#: builtin/show-branch.c:676
+msgid "show commits where no parent comes before its children"
+msgstr ""
+
+#: builtin/show-branch.c:678
+msgid "<n>[,<base>]"
+msgstr ""
+
+#: builtin/show-branch.c:679
+msgid "show <n> most recent ref-log entries starting at base"
+msgstr ""
+
+#: builtin/show-ref.c:10
+msgid ""
+"git show-ref [-q|--quiet] [--verify] [--head] [-d|--dereference] [-s|--hash"
+"[=<n>]] [--abbrev[=<n>]] [--tags] [--heads] [--] [pattern*] "
+msgstr ""
+
+#: builtin/show-ref.c:11
+msgid "git show-ref --exclude-existing[=pattern] < ref-list"
+msgstr ""
+
+#: builtin/show-ref.c:182
+#, fuzzy
+msgid "only show tags (can be combined with heads)"
+msgstr "--all 不能和引用表达式同时使用"
+
+#: builtin/show-ref.c:183
+#, fuzzy
+msgid "only show heads (can be combined with tags)"
+msgstr "--all 不能和引用表达式同时使用"
+
+#: builtin/show-ref.c:184
+msgid "stricter reference checking, requires exact ref path"
+msgstr ""
+
+#: builtin/show-ref.c:187 builtin/show-ref.c:189
+msgid "show the HEAD reference"
+msgstr ""
 
-#  译者:汉字之间无空格,故删除%s前后空格
-#: builtin/reset.c:313
-#, c-format
-msgid "Cannot do %s reset with paths."
-msgstr "不能带路径进行%s重置。"
+#: builtin/show-ref.c:191
+#, fuzzy
+msgid "dereference tags into object IDs"
+msgstr "引用不是一个树:%s"
 
-#  译者:汉字之间无空格,故删除%s前后空格
-#: builtin/reset.c:325
-#, c-format
-msgid "%s reset is not allowed in a bare repository"
-msgstr "不能对裸版本库进行%s重置"
+#: builtin/show-ref.c:193
+msgid "only show SHA1 hash using <n> digits"
+msgstr ""
 
-#: builtin/reset.c:341
-#, c-format
-msgid "Could not reset index file to revision '%s'."
-msgstr "不能重置索引文件至版本 '%s'。"
+#: builtin/show-ref.c:197
+msgid "do not print results to stdout (useful with --verify)"
+msgstr ""
 
-#: builtin/revert.c:70 builtin/revert.c:92
-#, c-format
-msgid "%s: %s cannot be used with %s"
-msgstr "%s:%s 不能和 %s 共用"
+#: builtin/show-ref.c:199
+msgid "show refs from stdin that aren't in local repository"
+msgstr ""
 
-#: builtin/revert.c:131
-msgid "program error"
-msgstr "程序错误"
+#: builtin/symbolic-ref.c:7
+msgid "git symbolic-ref [options] name [ref]"
+msgstr ""
 
-#: builtin/revert.c:221
-msgid "revert failed"
-msgstr "还原失败"
+#: builtin/symbolic-ref.c:38
+msgid "suppress error message for non-symbolic (detached) refs"
+msgstr ""
 
-#: builtin/revert.c:236
-msgid "cherry-pick failed"
-msgstr "拣选失败"
+#: builtin/symbolic-ref.c:39
+msgid "shorten ref output"
+msgstr ""
 
-#: builtin/rm.c:109
-#, c-format
-msgid ""
-"'%s' has staged content different from both the file and the HEAD\n"
-"(use -f to force removal)"
+#: builtin/symbolic-ref.c:40 builtin/update-ref.c:18
+msgid "reason"
 msgstr ""
-"'%s' 暂存的内容和工作区及 HEAD 中的都不一样\n"
-"(使用 -f 强制删除)"
 
-#: builtin/rm.c:115
-#, c-format
-msgid ""
-"'%s' has changes staged in the index\n"
-"(use --cached to keep the file, or -f to force removal)"
+#: builtin/symbolic-ref.c:40 builtin/update-ref.c:18
+msgid "reason of the update"
 msgstr ""
-"'%s' 有变更已暂存至索引中\n"
-"(使用 --cached 保存文件,或用 -f 强制删除)"
 
-#: builtin/rm.c:119
-#, c-format
+#: builtin/tag.c:22
 msgid ""
-"'%s' has local modifications\n"
-"(use --cached to keep the file, or -f to force removal)"
+"git tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]"
 msgstr ""
-"'%s' 有本地修改\n"
-"(使用 --cached 保存文件,或用 -f 强制删除)"
 
-#: builtin/rm.c:194
-#, c-format
-msgid "not removing '%s' recursively without -r"
-msgstr "未提供 -r 选项不会递归删除 '%s'"
+#: builtin/tag.c:23
+msgid "git tag -d <tagname>..."
+msgstr ""
 
-#: builtin/rm.c:230
-#, c-format
-msgid "git rm: unable to remove %s"
-msgstr "git rm:不能删除 %s"
+#: builtin/tag.c:24
+msgid ""
+"git tag -l [-n[<num>]] [--contains <commit>] [--points-at <object>] \n"
+"\t\t[<pattern>...]"
+msgstr ""
 
-#: builtin/shortlog.c:157
-#, c-format
-msgid "Missing author: %s"
-msgstr "缺少作者:%s"
+#: builtin/tag.c:26
+msgid "git tag -v <tagname>..."
+msgstr ""
 
 #: builtin/tag.c:60
 #, c-format
@@ -4633,21 +8292,81 @@ msgstr "开关 'points-at' 需要一个对象"
 msgid "malformed object name '%s'"
 msgstr "非法的对象名 '%s'"
 
+#: builtin/tag.c:447
+msgid "list tag names"
+msgstr ""
+
+#: builtin/tag.c:449
+msgid "print <n> lines of each tag message"
+msgstr ""
+
+#: builtin/tag.c:451
+#, fuzzy
+msgid "delete tags"
+msgstr "删除"
+
+#: builtin/tag.c:452
+msgid "verify tags"
+msgstr ""
+
+#: builtin/tag.c:454
+msgid "Tag creation options"
+msgstr ""
+
+#: builtin/tag.c:456
+#, fuzzy
+msgid "annotated tag, needs a message"
+msgstr "注释 tag %s 没有嵌入名称"
+
+#: builtin/tag.c:458
+#, fuzzy
+msgid "tag message"
+msgstr "无 tag 说明?"
+
+#: builtin/tag.c:460
+msgid "annotated and GPG-signed tag"
+msgstr ""
+
+#: builtin/tag.c:464
+#, fuzzy
+msgid "use another key to sign the tag"
+msgstr "无法签署 tag"
+
+#: builtin/tag.c:465
+msgid "replace the tag if exists"
+msgstr ""
+
+#: builtin/tag.c:466
+msgid "show tag list in columns"
+msgstr ""
+
+#: builtin/tag.c:468
+msgid "Tag listing options"
+msgstr ""
+
+#: builtin/tag.c:471
+msgid "print only tags that contain the commit"
+msgstr ""
+
+#: builtin/tag.c:477
+msgid "print only tags of the object"
+msgstr ""
+
 #: builtin/tag.c:506
 msgid "--column and -n are incompatible"
 msgstr "--column 和 -n 不兼容"
 
 #: builtin/tag.c:523
 msgid "-n option is only allowed with -l."
-msgstr "-n é\80\89项å\8fªå\85\81许å\92\8c -l å\85±用。"
+msgstr "-n é\80\89项å\8fªå\85\81许å\92\8c -l å\90\8cæ\97¶ä½¿用。"
 
 #: builtin/tag.c:525
 msgid "--contains option is only allowed with -l."
-msgstr "--contains é\80\89项å\8fªå\85\81许å\92\8c -l å\85±用。"
+msgstr "--contains é\80\89项å\8fªå\85\81许å\92\8c -l å\90\8cæ\97¶ä½¿用。"
 
 #: builtin/tag.c:527
 msgid "--points-at option is only allowed with -l."
-msgstr "--points-at é\80\89项å\8fªå\85\81许å\92\8c -l å\85±用。"
+msgstr "--points-at é\80\89项å\8fªå\85\81许å\92\8c -l å\90\8cæ\97¶ä½¿用。"
 
 #: builtin/tag.c:535
 msgid "only one -F or -m option is allowed."
@@ -4682,25 +8401,187 @@ msgstr "%s:不能更新引用"
 msgid "Updated tag '%s' (was %s)\n"
 msgstr "已更新tag '%s'(曾为 %s)\n"
 
-#: git.c:16
-msgid "See 'git help <command>' for more information on a specific command."
-msgstr "参见 'git help <command>' 以获得该特定命令的详细信息。"
+#: builtin/update-index.c:401
+#, fuzzy
+msgid "git update-index [options] [--] [<file>...]"
+msgstr "git apply [选项] [<补丁>...]"
 
-#: parse-options.h:133 parse-options.h:235
-msgid "n"
-msgstr "数字"
+#: builtin/update-index.c:717
+msgid "continue refresh even when index needs update"
+msgstr ""
 
-#: parse-options.h:141
-msgid "time"
-msgstr "时间"
+#: builtin/update-index.c:720
+msgid "refresh: ignore submodules"
+msgstr ""
 
-#: parse-options.h:149
-msgid "file"
-msgstr "文件"
+#: builtin/update-index.c:723
+#, fuzzy
+msgid "do not ignore new files"
+msgstr "无法存储索引文件"
 
-#: parse-options.h:151
-msgid "when"
-msgstr "何时"
+#: builtin/update-index.c:725
+msgid "let files replace directories and vice-versa"
+msgstr ""
+
+#: builtin/update-index.c:727
+msgid "notice files missing from worktree"
+msgstr ""
+
+#: builtin/update-index.c:729
+msgid "refresh even if index contains unmerged entries"
+msgstr ""
+
+#: builtin/update-index.c:732
+msgid "refresh stat information"
+msgstr ""
+
+#: builtin/update-index.c:736
+msgid "like --refresh, but ignore assume-unchanged setting"
+msgstr ""
+
+#: builtin/update-index.c:740
+msgid "<mode> <object> <path>"
+msgstr ""
+
+#: builtin/update-index.c:741
+#, fuzzy
+msgid "add the specified entry to the index"
+msgstr "添加文件内容至索引"
+
+#: builtin/update-index.c:745
+msgid "(+/-)x"
+msgstr ""
+
+#: builtin/update-index.c:746
+msgid "override the executable bit of the listed files"
+msgstr ""
+
+#: builtin/update-index.c:750
+msgid "mark files as \"not changing\""
+msgstr ""
+
+#: builtin/update-index.c:753
+msgid "clear assumed-unchanged bit"
+msgstr ""
+
+#: builtin/update-index.c:756
+msgid "mark files as \"index-only\""
+msgstr ""
+
+#: builtin/update-index.c:759
+msgid "clear skip-worktree bit"
+msgstr ""
+
+#: builtin/update-index.c:762
+msgid "add to index only; do not add content to object database"
+msgstr ""
+
+#: builtin/update-index.c:764
+msgid "remove named paths even if present in worktree"
+msgstr ""
+
+#: builtin/update-index.c:766
+msgid "with --stdin: input lines are terminated by null bytes"
+msgstr ""
+
+#: builtin/update-index.c:768
+#, fuzzy
+msgid "read list of paths to be updated from standard input"
+msgstr "(正从标准输入中读取日志信息)\n"
+
+#: builtin/update-index.c:772
+#, fuzzy
+msgid "add entries from standard input to the index"
+msgstr "不能从标准输入中读取日志信息"
+
+#: builtin/update-index.c:776
+msgid "repopulate stages #2 and #3 for the listed paths"
+msgstr ""
+
+#: builtin/update-index.c:780
+msgid "only update entries that differ from HEAD"
+msgstr ""
+
+#: builtin/update-index.c:784
+msgid "ignore files missing from worktree"
+msgstr ""
+
+#: builtin/update-index.c:787
+msgid "report actions to standard output"
+msgstr ""
+
+#: builtin/update-index.c:789
+msgid "(for porcelains) forget saved unresolved conflicts"
+msgstr ""
+
+#: builtin/update-index.c:793
+msgid "write index in this format"
+msgstr ""
+
+#: builtin/update-ref.c:7
+msgid "git update-ref [options] -d <refname> [<oldval>]"
+msgstr ""
+
+#: builtin/update-ref.c:8
+msgid "git update-ref [options]    <refname> <newval> [<oldval>]"
+msgstr ""
+
+#: builtin/update-ref.c:19
+msgid "delete the reference"
+msgstr ""
+
+#: builtin/update-ref.c:21
+msgid "update <refname> not the one it points to"
+msgstr ""
+
+#: builtin/update-server-info.c:6
+msgid "git update-server-info [--force]"
+msgstr ""
+
+#: builtin/update-server-info.c:14
+msgid "update the info files from scratch"
+msgstr ""
+
+#: builtin/verify-pack.c:56
+msgid "git verify-pack [-v|--verbose] [-s|--stat-only] <pack>..."
+msgstr ""
+
+#: builtin/verify-pack.c:66
+#, fuzzy
+msgid "verbose"
+msgstr "冗长输出"
+
+#: builtin/verify-pack.c:68
+msgid "show statistics only"
+msgstr ""
+
+#: builtin/verify-tag.c:17
+msgid "git verify-tag [-v|--verbose] <tag>..."
+msgstr ""
+
+#: builtin/verify-tag.c:73
+msgid "print tag contents"
+msgstr ""
+
+#: builtin/write-tree.c:13
+msgid "git write-tree [--missing-ok] [--prefix=<prefix>/]"
+msgstr ""
+
+#: builtin/write-tree.c:26
+msgid "<prefix>/"
+msgstr ""
+
+#: builtin/write-tree.c:27
+msgid "write tree object for a subdirectory <prefix>"
+msgstr ""
+
+#: builtin/write-tree.c:30
+msgid "only useful for debugging"
+msgstr ""
+
+#: git.c:16
+msgid "See 'git help <command>' for more information on a specific command."
+msgstr "参见 'git help <command>' 以获得该特定命令的详细信息。"
 
 #: parse-options.h:156
 msgid "no-op (backward compatibility)"
@@ -4810,15 +8691,14 @@ msgstr "您需要先设置你的提交者信息"
 msgid ""
 "You seem to have moved HEAD since the last 'am' failure.\n"
 "Not rewinding to ORIG_HEAD"
-msgstr ""
-"您好像在上一次 'am' 失败后移动了 HEAD。未回退至 ORIG_HEAD"
+msgstr "您好像在上一次 'am' 失败后移动了 HEAD。未回退至 ORIG_HEAD"
 
 #: git-am.sh:105
 #, sh-format
 msgid ""
-"When you have resolved this problem run \"$cmdline --resolved\".\n"
-"If you would prefer to skip this patch, instead run \"$cmdline --skip\".\n"
-"To restore the original branch and stop patching run \"$cmdline --abort\"."
+"When you have resolved this problem, run \"$cmdline --resolved\".\n"
+"If you prefer to skip this patch, run \"$cmdline --skip\" instead.\n"
+"To restore the original branch and stop patching, run \"$cmdline --abort\"."
 msgstr ""
 "当您解决了此问题后,执行 \"$cmdline --resolved\"。\n"
 "如果您想跳过此补丁,则执行 \"$cmdline --skip\"。\n"
@@ -4830,7 +8710,11 @@ msgstr "无法求助于三路合并。"
 
 #: git-am.sh:137
 msgid "Repository lacks necessary blobs to fall back on 3-way merge."
-msgstr "版本库缺乏必要的 blob 数据以进行三路合并。"
+msgstr "版本库缺乏必要的二进制对象(blob)以进行三路合并。"
+
+#: git-am.sh:139
+msgid "Using index info to reconstruct a base tree..."
+msgstr "更新索引信息以重建基树..."
 
 #: git-am.sh:154
 msgid ""
@@ -4838,48 +8722,56 @@ msgid ""
 "It does not apply to blobs recorded in its index."
 msgstr ""
 "您是否曾手动编辑过您的补丁?\n"
-"无法应用补丁到索引中的数据上。"
+"无法应用补丁到索引中的二进制对象(blob)上。"
 
 #: git-am.sh:163
 msgid "Falling back to patching base and 3-way merge..."
 msgstr "转而在基础版本上打补丁及进行三路合并..."
 
-#: git-am.sh:275
+#: git-am.sh:179
+msgid "Failed to merge in the changes."
+msgstr "无法合并变更。"
+
+#: git-am.sh:274
 msgid "Only one StGIT patch series can be applied at once"
 msgstr "一次只能有一个 StGIT 补丁队列被应用"
 
-#: git-am.sh:362
+#: git-am.sh:361
 #, sh-format
 msgid "Patch format $patch_format is not supported."
 msgstr "不支持 $patch_format 补丁格式。"
 
-#: git-am.sh:364
+#: git-am.sh:363
 msgid "Patch format detection failed."
 msgstr "补丁格式检测失败。"
 
-#: git-am.sh:418
-msgid "-d option is no longer supported.  Do not use."
-msgstr "不再支持 -d 选项。不要使用。"
+#: git-am.sh:389
+msgid ""
+"The -b/--binary option has been a no-op for long time, and\n"
+"it will be removed. Please do not use it anymore."
+msgstr ""
+"参数 -b/--binary 已经很长时间不做任何实质操作了,并且将被删除。\n"
+"请不要再使用它了。"
 
-#: git-am.sh:481
+#: git-am.sh:477
 #, sh-format
 msgid "previous rebase directory $dotest still exists but mbox given."
 msgstr "之前的变基目录 $dotest 仍然存在但给出了mbox。"
 
-#: git-am.sh:486
+#: git-am.sh:482
 msgid "Please make up your mind. --skip or --abort?"
 msgstr "请下决心。--skip 或是 --abort ?"
 
-#: git-am.sh:513
+#: git-am.sh:509
 msgid "Resolve operation not in progress, we are not resuming."
 msgstr "解决操作未进行,我们不会继续。"
 
-#: git-am.sh:579
+#: git-am.sh:575
 #, sh-format
 msgid "Dirty index: cannot apply patches (dirty: $files)"
 msgstr "脏的索引:不能应用补丁(脏文件:$files)"
 
-#: git-am.sh:671
+#: git-am.sh:679
 #, sh-format
 msgid ""
 "Patch is empty.  Was it split wrong?\n"
@@ -4890,15 +8782,15 @@ msgstr ""
 "如果您想要跳过这个补丁,执行 \"$cmdline --skip\"。\n"
 "要恢复原分支并停止打补丁,执行 \"$cmdline --abort\"。"
 
-#: git-am.sh:708
+#: git-am.sh:706
 msgid "Patch does not have a valid e-mail address."
 msgstr "补丁中没有一个有效的邮件地址。"
 
-#: git-am.sh:755
+#: git-am.sh:753
 msgid "cannot be interactive without stdin connected to a terminal."
 msgstr "标准输入没有和终端关联,不能进行交互式操作。"
 
-#: git-am.sh:759
+#: git-am.sh:757
 msgid "Commit Body is:"
 msgstr "提交内容为:"
 
@@ -4906,16 +8798,16 @@ msgstr "提交内容为:"
 #. TRANSLATORS: Make sure to include [y], [n], [e], [v] and [a]
 #. in your translation. The program will only accept English
 #. input at this point.
-#: git-am.sh:766
+#: git-am.sh:764
 msgid "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all "
 msgstr "应用?[y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all "
 
-#: git-am.sh:802
+#: git-am.sh:800
 #, sh-format
 msgid "Applying: $FIRSTLINE"
 msgstr "正应用:$FIRSTLINE"
 
-#: git-am.sh:823
+#: git-am.sh:821
 msgid ""
 "No changes - did you forget to use 'git add'?\n"
 "If there is nothing left to stage, chances are that something else\n"
@@ -4925,23 +8817,29 @@ msgstr ""
 "如果没有什么要添加到暂存区的,则很可能是其它提交已经引入了相同的变更。\n"
 "您也许想要跳过这个补丁。"
 
-#: git-am.sh:831
+#: git-am.sh:829
 msgid ""
 "You still have unmerged paths in your index\n"
 "did you forget to use 'git add'?"
-msgstr ""
-"您的索引中仍有未合并的路径。您是否忘了执行 'git add'?"
+msgstr "您的索引中仍有未合并的路径。您是否忘了执行 'git add'?"
 
-#: git-am.sh:847
+#: git-am.sh:845
 msgid "No changes -- Patch already applied."
 msgstr "没有变更 -- 补丁已经应用过。"
 
-#: git-am.sh:857
+#: git-am.sh:855
 #, sh-format
 msgid "Patch failed at $msgnum $FIRSTLINE"
 msgstr "补丁失败于 $msgnum $FIRSTLINE"
 
-#: git-am.sh:873
+#: git-am.sh:858
+#, sh-format
+msgid ""
+"The copy of the patch that failed is found in:\n"
+"   $dotest/patch"
+msgstr ""
+
+#: git-am.sh:876
 msgid "applying to an empty history"
 msgstr "正应用到一个空历史上"
 
@@ -5142,6 +9040,123 @@ msgstr "无法将多个分支合并到空分支"
 msgid "Cannot rebase onto multiple branches"
 msgstr "无法变基到多个分支"
 
+#: git-rebase.sh:52
+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"
+"To check out the original branch and stop rebasing, run \"git rebase --abort"
+"\"."
+msgstr ""
+"当您解决了此问题后,执行 \"git rebase --continue\"。\n"
+"如果您想跳过此补丁,则执行 \"git rebase --skip\"。\n"
+"要恢复原分支并停止变基,执行 \"git rebase --abort\"。"
+
+#: git-rebase.sh:159
+msgid "The pre-rebase hook refused to rebase."
+msgstr "钩子 pre-rebase 拒绝变基。"
+
+#: git-rebase.sh:164
+msgid "It looks like git-am is in progress. Cannot rebase."
+msgstr "似乎正处于在 git-am 的执行过程中。无法变基。"
+
+#: git-rebase.sh:295
+msgid "The --exec option must be used with the --interactive option"
+msgstr "选项 --exec 必须和选项 --interactive 同时使用"
+
+#: git-rebase.sh:300
+msgid "No rebase in progress?"
+msgstr "没有正在进行的变基?"
+
+#: git-rebase.sh:313
+msgid "Cannot read HEAD"
+msgstr "不能读取 HEAD"
+
+#: git-rebase.sh:316
+msgid ""
+"You must edit all merge conflicts and then\n"
+"mark them as resolved using git add"
+msgstr ""
+"您必须编辑所有的合并冲突,然后通过 git add\n"
+"命令将它们标记为已解决"
+
+#: git-rebase.sh:334
+#, sh-format
+msgid "Could not move back to $head_name"
+msgstr "无法移回 $head_name"
+
+#: git-rebase.sh:350
+#, sh-format
+msgid ""
+"It seems that there is already a $state_dir_base directory, and\n"
+"I wonder if you are in the middle of another rebase.  If that is the\n"
+"case, please try\n"
+"\t$cmd_live_rebase\n"
+"If that is not the case, please\n"
+"\t$cmd_clear_stale_rebase\n"
+"and run me again.  I am stopping in case you still have something\n"
+"valuable there."
+msgstr ""
+"好像已有一个 $state_dir_base 目录,我怀疑您正处于另外一个变基过程中。\n"
+"如果是这样,请尝试执行\n"
+"\t$cmd_live_rebase\n"
+"如果不是这样,请执行\n"
+"\t$cmd_clear_stale_rebase\n"
+"然后再重新执行变基。为避免您丢失重要数据,我已经停止当前操作。"
+
+#: git-rebase.sh:395
+#, sh-format
+msgid "invalid upstream $upstream_name"
+msgstr "无效的上游 $upstream_name"
+
+#: git-rebase.sh:419
+#, sh-format
+msgid "$onto_name: there are more than one merge bases"
+msgstr "$onto_name: 有一个以上的合并基准"
+
+#: git-rebase.sh:422 git-rebase.sh:426
+#, sh-format
+msgid "$onto_name: there is no merge base"
+msgstr "$onto_name: 没有合并基准"
+
+#: git-rebase.sh:431
+#, sh-format
+msgid "Does not point to a valid commit: $onto_name"
+msgstr "没有指向一个有效的提交:$onto_name"
+
+#: git-rebase.sh:454
+#, sh-format
+msgid "fatal: no such branch: $branch_name"
+msgstr "严重错误:无此分支:$branch_name"
+
+#: git-rebase.sh:474
+msgid "Please commit or stash them."
+msgstr "请提交或为它们保存进度。"
+
+#: git-rebase.sh:492
+#, sh-format
+msgid "Current branch $branch_name is up to date."
+msgstr "当前分支 $branch_name 是最新的。"
+
+#: git-rebase.sh:495
+#, sh-format
+msgid "Current branch $branch_name is up to date, rebase forced."
+msgstr "当前分支 $branch_name 是最新的,强制变基。"
+
+#: git-rebase.sh:506
+#, sh-format
+msgid "Changes from $mb to $onto:"
+msgstr "变更从 $mb 到 $onto:"
+
+#. Detach HEAD and reset the tree
+#: git-rebase.sh:515
+msgid "First, rewinding head to replay your work on top of it..."
+msgstr "首先,重置头指针以便在上面重放您的工作..."
+
+#: git-rebase.sh:523
+#, sh-format
+msgid "Fast-forwarded $branch_name to $onto_name."
+msgstr "快进 $branch_name 至 $onto_name。"
+
 #: git-stash.sh:51
 msgid "git stash clear with parameters is unimplemented"
 msgstr "git stash clear 不支持参数"
@@ -5249,59 +9264,59 @@ msgstr "不能保存索引树"
 msgid "Cannot unstage modified files"
 msgstr "无法还原修改的文件"
 
-#: git-stash.sh:474
+#: git-stash.sh:475
 msgid "Index was not unstashed."
 msgstr "索引的进度没有被恢复。"
 
-#: git-stash.sh:491
+#: git-stash.sh:492
 #, sh-format
 msgid "Dropped ${REV} ($s)"
 msgstr "丢弃了 ${REV} ($s)"
 
-#: git-stash.sh:492
+#: git-stash.sh:493
 #, sh-format
 msgid "${REV}: Could not drop stash entry"
 msgstr "${REV}:不能丢弃进度条目"
 
-#: git-stash.sh:499
+#: git-stash.sh:500
 msgid "No branch name specified"
 msgstr "未指定分支名"
 
-#: git-stash.sh:570
+#: git-stash.sh:571
 msgid "(To restore them type \"git stash apply\")"
 msgstr "(为恢复数据输入 \"git stash apply\")"
 
-#: git-submodule.sh:56
+#: git-submodule.sh:88
 #, sh-format
 msgid "cannot strip one component off url '$remoteurl'"
 msgstr "无法从 url '$remoteurl' 剥离一个组件"
 
-#: git-submodule.sh:109
+#: git-submodule.sh:167
 #, sh-format
 msgid "No submodule mapping found in .gitmodules for path '$sm_path'"
 msgstr "未在 .gitmodules 中发现路径 '$sm_path' 的子模组映射"
 
-#: git-submodule.sh:150
+#: git-submodule.sh:211
 #, sh-format
 msgid "Clone of '$url' into submodule path '$sm_path' failed"
 msgstr "无法克隆 '$url' 到子模组路径 '$sm_path'"
 
-#: git-submodule.sh:160
+#: git-submodule.sh:223
 #, sh-format
 msgid "Gitdir '$a' is part of the submodule path '$b' or vice versa"
 msgstr "Gitdir '$a' 在子模组路径 '$b' 之下或者相反"
 
-#: git-submodule.sh:249
+#: git-submodule.sh:312
 #, sh-format
 msgid "repo URL: '$repo' must be absolute or begin with ./|../"
 msgstr "版本库URL:'$repo' 必须是绝对路径或以 ./|../ 起始"
 
-#: git-submodule.sh:266
+#: git-submodule.sh:329
 #, sh-format
 msgid "'$sm_path' already exists in the index"
 msgstr "'$sm_path' 已经存在于索引中"
 
-#: git-submodule.sh:270
+#: git-submodule.sh:333
 #, sh-format
 msgid ""
 "The following path is ignored by one of your .gitignore files:\n"
@@ -5312,62 +9327,62 @@ msgstr ""
 "$sm_path\n"
 "如果您确实想添加它,使用 -f 参数。"
 
-#: git-submodule.sh:281
+#: git-submodule.sh:344
 #, sh-format
 msgid "Adding existing repo at '$sm_path' to the index"
 msgstr "添加位于 '$sm_path' 的现存版本库到索引"
 
-#: git-submodule.sh:283
+#: git-submodule.sh:346
 #, sh-format
 msgid "'$sm_path' already exists and is not a valid git repo"
 msgstr "'$sm_path' 已存在且不是一个有效的 git 版本库"
 
-#: git-submodule.sh:297
+#: git-submodule.sh:360
 #, sh-format
 msgid "Unable to checkout submodule '$sm_path'"
 msgstr "不能检出子模组 '$sm_path'"
 
-#: git-submodule.sh:302
+#: git-submodule.sh:365
 #, sh-format
 msgid "Failed to add submodule '$sm_path'"
 msgstr "无法添加子模组 '$sm_path'"
 
-#: git-submodule.sh:307
+#: git-submodule.sh:370
 #, sh-format
 msgid "Failed to register submodule '$sm_path'"
 msgstr "无法注册子模组 '$sm_path'"
 
-#: git-submodule.sh:349
+#: git-submodule.sh:413
 #, sh-format
 msgid "Entering '$prefix$sm_path'"
 msgstr "正在进入 '$prefix$sm_path'"
 
-#: git-submodule.sh:363
+#: git-submodule.sh:427
 #, sh-format
 msgid "Stopping at '$sm_path'; script returned non-zero status."
 msgstr "停止于 '$sm_path',脚本返回非零值。"
 
-#: git-submodule.sh:406
+#: git-submodule.sh:471
 #, sh-format
 msgid "No url found for submodule path '$sm_path' in .gitmodules"
 msgstr "在 .gitmodules 中未找到子模组路径 '$sm_path' 的 url"
 
-#: git-submodule.sh:415
+#: git-submodule.sh:480
 #, sh-format
 msgid "Failed to register url for submodule path '$sm_path'"
 msgstr "无法为子模组路径 '$sm_path' 注册 url"
 
-#: git-submodule.sh:417
+#: git-submodule.sh:482
 #, sh-format
 msgid "Submodule '$name' ($url) registered for path '$sm_path'"
 msgstr "子模组 '$name' ($url) 已为路径 '$sm_path' 注册"
 
-#: git-submodule.sh:425
+#: git-submodule.sh:490
 #, sh-format
 msgid "Failed to register update mode for submodule path '$sm_path'"
 msgstr "无法为子模组路径 '$sm_path' 注册更新模式"
 
-#: git-submodule.sh:524
+#: git-submodule.sh:590
 #, sh-format
 msgid ""
 "Submodule path '$sm_path' not initialized\n"
@@ -5376,96 +9391,130 @@ msgstr ""
 "子模组路径 '$sm_path' 没有初始化\n"
 "也许您想用 'update --init'?"
 
-#: git-submodule.sh:537
+#: git-submodule.sh:603
 #, sh-format
 msgid "Unable to find current revision in submodule path '$sm_path'"
 msgstr "无法在子模组路径 '$sm_path' 中找到当前版本"
 
-#: git-submodule.sh:556
+#: git-submodule.sh:622
 #, sh-format
 msgid "Unable to fetch in submodule path '$sm_path'"
 msgstr "无法在子模组路径 '$sm_path' 中获取"
 
-#: git-submodule.sh:570
+#: git-submodule.sh:636
 #, sh-format
 msgid "Unable to rebase '$sha1' in submodule path '$sm_path'"
 msgstr "无法在子模组路径 '$sm_path' 中变基 '$sha1'"
 
-#: git-submodule.sh:571
+#: git-submodule.sh:637
 #, sh-format
 msgid "Submodule path '$sm_path': rebased into '$sha1'"
 msgstr "子模组路径 '$sm_path':变基至 '$sha1'"
 
-#: git-submodule.sh:576
+#: git-submodule.sh:642
 #, sh-format
 msgid "Unable to merge '$sha1' in submodule path '$sm_path'"
 msgstr "无法合并 '$sha1' 到子模组路径 '$sm_path' 中"
 
-#: git-submodule.sh:577
+#: git-submodule.sh:643
 #, sh-format
 msgid "Submodule path '$sm_path': merged in '$sha1'"
 msgstr "子模组路径 '$sm_path':已合并入 '$sha1'"
 
-#: git-submodule.sh:582
+#: git-submodule.sh:648
 #, sh-format
 msgid "Unable to checkout '$sha1' in submodule path '$sm_path'"
 msgstr "无法在子模组路径 '$sm_path' 中检出 '$sha1'"
 
-#: git-submodule.sh:583
+#: git-submodule.sh:649
 #, sh-format
 msgid "Submodule path '$sm_path': checked out '$sha1'"
 msgstr "子模组路径 '$sm_path':检出 '$sha1'"
 
-#: git-submodule.sh:605 git-submodule.sh:928
+#: git-submodule.sh:671 git-submodule.sh:995
 #, sh-format
 msgid "Failed to recurse into submodule path '$sm_path'"
 msgstr "无法递归进子模组路径 '$sm_path'"
 
-#: git-submodule.sh:713
-msgid "--cached cannot be used with --files"
-msgstr "--cached 不能和 --files 共用"
+#: git-submodule.sh:779
+msgid "The --cached option cannot be used with the --files option"
+msgstr "选项 --cached 不能和选项 --files 同时使用"
 
 #. unexpected type
-#: git-submodule.sh:753
+#: git-submodule.sh:819
 #, sh-format
 msgid "unexpected mode $mod_dst"
 msgstr "意外的模式 $mod_dst"
 
 #  译者:注意保持前导空格
-#: git-submodule.sh:771
+#: git-submodule.sh:837
 #, sh-format
 msgid "  Warn: $name doesn't contain commit $sha1_src"
 msgstr "  警告:$name 未包含提交 $sha1_src"
 
 #  译者:注意保持前导空格
-#: git-submodule.sh:774
+#: git-submodule.sh:840
 #, sh-format
 msgid "  Warn: $name doesn't contain commit $sha1_dst"
 msgstr "  警告:$name 未包含提交 $sha1_dst"
 
 #  译者:注意保持前导空格
-#: git-submodule.sh:777
+#: git-submodule.sh:843
 #, sh-format
 msgid "  Warn: $name doesn't contain commits $sha1_src and $sha1_dst"
 msgstr "  警告:$name 未包含提交 $sha1_src 和 $sha1_dst"
 
-#: git-submodule.sh:802
+#: git-submodule.sh:868
 msgid "blob"
-msgstr "blob"
-
-#: git-submodule.sh:803
-msgid "submodule"
-msgstr "子模组"
+msgstr "二进制对象"
 
-#: git-submodule.sh:840
+#: git-submodule.sh:906
 msgid "# Submodules changed but not updated:"
 msgstr "# 子模组已修改但尚未更新:"
 
-#: git-submodule.sh:842
+#: git-submodule.sh:908
 msgid "# Submodule changes to be committed:"
 msgstr "要提交的子模组变更:"
 
-#: git-submodule.sh:974
+#: git-submodule.sh:1054
 #, sh-format
 msgid "Synchronizing submodule url for '$name'"
 msgstr "为 '$name' 同步子模组 url"
+
+#  译者:中文字符串拼接,可删除前导空格
+#~ msgid " (use \"git add\" to track)"
+#~ msgstr "(使用 \"git add\" 建立跟踪)"
+
+#~ msgid "-B cannot be used with -b"
+#~ msgstr "-B 不能和 -b 同时使用"
+
+#~ msgid "--patch is incompatible with all other options"
+#~ msgstr "--patch 选项和其他选项不兼容"
+
+#~ msgid "--detach cannot be used with -b/-B/--orphan"
+#~ msgstr "--detach 不能和 -b/-B/--orphan 同时使用"
+
+#~ msgid "--detach cannot be used with -t"
+#~ msgstr "--detach 不能和 -t 同时使用"
+
+#~ msgid "--orphan and -b|-B are mutually exclusive"
+#~ msgstr "--orphan 和 -b|-B 互斥"
+
+#~ msgid "--orphan cannot be used with -t"
+#~ msgstr "--orphan 不能和 -t 同时使用"
+
+#~ msgid "git checkout: -f and -m are incompatible"
+#~ msgstr "git checkout:-f 和 -m 不兼容"
+
+#~ msgid ""
+#~ "git checkout: updating paths is incompatible with switching branches."
+#~ msgstr "git checkout:更新路径和切换分支不兼容。"
+
+#~ msgid "diff setup failed"
+#~ msgstr "diff 设置失败"
+
+#~ msgid "merge-recursive: disk full?"
+#~ msgstr "merge-recursive:磁盘已满?"
+
+#~ msgid "diff_setup_done failed"
+#~ msgstr "diff_setup_done 失败"
index d8543e4d42f0cf7f8850751806cc40bc05578117..fda78bc353afcfd4d01864f2a13158d9c9c55173 100644 (file)
 
 static struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really);
 
+/* Mask for the name length in ce_flags in the on-disk index */
+
+#define CE_NAMEMASK  (0x0fff)
+
 /* Index extensions.
  *
  * The first letter should be 'A'..'Z' for extensions that are not
@@ -54,8 +58,8 @@ void rename_index_entry_at(struct index_state *istate, int nr, const char *new_n
 
        new = xmalloc(cache_entry_size(namelen));
        copy_cache_entry(new, old);
-       new->ce_flags &= ~(CE_STATE_MASK | CE_NAMEMASK);
-       new->ce_flags |= (namelen >= CE_NAMEMASK ? CE_NAMEMASK : namelen);
+       new->ce_flags &= ~CE_STATE_MASK;
+       new->ce_namelen = namelen;
        memcpy(new->name, new_name, namelen + 1);
 
        cache_tree_invalidate_path(istate->cache_tree, old->name);
@@ -395,17 +399,10 @@ int df_name_compare(const char *name1, int len1, int mode1,
        return c1 - c2;
 }
 
-int cache_name_compare(const char *name1, int flags1, const char *name2, int flags2)
+int cache_name_stage_compare(const char *name1, int len1, int stage1, const char *name2, int len2, int stage2)
 {
-       int len1, len2, len, cmp;
-
-       len1 = flags1 & CE_NAMEMASK;
-       if (CE_NAMEMASK <= len1)
-               len1 = strlen(name1 + CE_NAMEMASK) + CE_NAMEMASK;
-       len2 = flags2 & CE_NAMEMASK;
-       if (CE_NAMEMASK <= len2)
-               len2 = strlen(name2 + CE_NAMEMASK) + CE_NAMEMASK;
-       len = len1 < len2 ? len1 : len2;
+       int len = len1 < len2 ? len1 : len2;
+       int cmp;
 
        cmp = memcmp(name1, name2, len);
        if (cmp)
@@ -415,18 +412,19 @@ int cache_name_compare(const char *name1, int flags1, const char *name2, int fla
        if (len1 > len2)
                return 1;
 
-       /* Compare stages  */
-       flags1 &= CE_STAGEMASK;
-       flags2 &= CE_STAGEMASK;
-
-       if (flags1 < flags2)
+       if (stage1 < stage2)
                return -1;
-       if (flags1 > flags2)
+       if (stage1 > stage2)
                return 1;
        return 0;
 }
 
-int index_name_pos(const struct index_state *istate, const char *name, int namelen)
+int cache_name_compare(const char *name1, int len1, const char *name2, int len2)
+{
+       return cache_name_stage_compare(name1, len1, 0, name2, len2, 0);
+}
+
+static int index_name_stage_pos(const struct index_state *istate, const char *name, int namelen, int stage)
 {
        int first, last;
 
@@ -435,7 +433,7 @@ int index_name_pos(const struct index_state *istate, const char *name, int namel
        while (last > first) {
                int next = (last + first) >> 1;
                struct cache_entry *ce = istate->cache[next];
-               int cmp = cache_name_compare(name, namelen, ce->name, ce->ce_flags);
+               int cmp = cache_name_stage_compare(name, namelen, stage, ce->name, ce_namelen(ce), ce_stage(ce));
                if (!cmp)
                        return next;
                if (cmp < 0) {
@@ -447,6 +445,11 @@ int index_name_pos(const struct index_state *istate, const char *name, int namel
        return -first-1;
 }
 
+int index_name_pos(const struct index_state *istate, const char *name, int namelen)
+{
+       return index_name_stage_pos(istate, name, namelen, 0);
+}
+
 /* Remove entry, return true if there are more entries to go.. */
 int remove_index_entry_at(struct index_state *istate, int pos)
 {
@@ -586,7 +589,7 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
        size = cache_entry_size(namelen);
        ce = xcalloc(1, size);
        memcpy(ce->name, path, namelen);
-       ce->ce_flags = namelen;
+       ce->ce_namelen = namelen;
        if (!intent_only)
                fill_stat_cache_info(ce, st);
        else
@@ -688,7 +691,8 @@ struct cache_entry *make_cache_entry(unsigned int mode,
 
        hashcpy(ce->sha1, sha1);
        memcpy(ce->name, path, len);
-       ce->ce_flags = create_ce_flags(len, stage);
+       ce->ce_flags = create_ce_flags(stage);
+       ce->ce_namelen = len;
        ce->ce_mode = create_ce_mode(mode);
 
        if (refresh)
@@ -825,7 +829,7 @@ static int has_dir_name(struct index_state *istate,
                }
                len = slash - name;
 
-               pos = index_name_pos(istate, name, create_ce_flags(len, stage));
+               pos = index_name_stage_pos(istate, name, len, stage);
                if (pos >= 0) {
                        /*
                         * Found one, but not so fast.  This could
@@ -915,7 +919,7 @@ static int add_index_entry_with_check(struct index_state *istate, struct cache_e
        int new_only = option & ADD_CACHE_NEW_ONLY;
 
        cache_tree_invalidate_path(istate->cache_tree, ce->name);
-       pos = index_name_pos(istate, ce->name, ce->ce_flags);
+       pos = index_name_stage_pos(istate, ce->name, ce_namelen(ce), ce_stage(ce));
 
        /* existing match? Just replace it. */
        if (pos >= 0) {
@@ -947,7 +951,7 @@ static int add_index_entry_with_check(struct index_state *istate, struct cache_e
                if (!ok_to_replace)
                        return error("'%s' appears as both a file and as a directory",
                                     ce->name);
-               pos = index_name_pos(istate, ce->name, ce->ce_flags);
+               pos = index_name_stage_pos(istate, ce->name, ce_namelen(ce), ce_stage(ce));
                pos = -pos-1;
        }
        return pos + 1;
@@ -1124,7 +1128,7 @@ int refresh_index(struct index_state *istate, unsigned int flags, const char **p
                        continue;
 
                if (pathspec &&
-                   !match_pathspec(pathspec, ce->name, strlen(ce->name), 0, seen))
+                   !match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, seen))
                        filtered = 1;
 
                if (ce_stage(ce)) {
@@ -1324,7 +1328,8 @@ static struct cache_entry *cache_entry_from_ondisk(struct ondisk_cache_entry *on
        ce->ce_uid   = ntoh_l(ondisk->uid);
        ce->ce_gid   = ntoh_l(ondisk->gid);
        ce->ce_size  = ntoh_l(ondisk->size);
-       ce->ce_flags = flags;
+       ce->ce_flags = flags & ~CE_NAMEMASK;
+       ce->ce_namelen = len;
        hashcpy(ce->sha1, ondisk->sha1);
        memcpy(ce->name, name, len);
        ce->name[len] = '\0';
@@ -1647,6 +1652,8 @@ static void ce_smudge_racily_clean_entry(struct cache_entry *ce)
 static char *copy_cache_entry_to_ondisk(struct ondisk_cache_entry *ondisk,
                                       struct cache_entry *ce)
 {
+       short flags;
+
        ondisk->ctime.sec = htonl(ce->ce_ctime.sec);
        ondisk->mtime.sec = htonl(ce->ce_mtime.sec);
        ondisk->ctime.nsec = htonl(ce->ce_ctime.nsec);
@@ -1658,7 +1665,10 @@ static char *copy_cache_entry_to_ondisk(struct ondisk_cache_entry *ondisk,
        ondisk->gid  = htonl(ce->ce_gid);
        ondisk->size = htonl(ce->ce_size);
        hashcpy(ondisk->sha1, ce->sha1);
-       ondisk->flags = htons(ce->ce_flags);
+
+       flags = ce->ce_flags;
+       flags |= (ce_namelen(ce) >= CE_NAMEMASK ? CE_NAMEMASK : ce_namelen(ce));
+       ondisk->flags = htons(flags);
        if (ce->ce_flags & CE_EXTENDED) {
                struct ondisk_cache_entry_extended *ondisk2;
                ondisk2 = (struct ondisk_cache_entry_extended *)ondisk;
@@ -1844,11 +1854,12 @@ int read_index_unmerged(struct index_state *istate)
                if (!ce_stage(ce))
                        continue;
                unmerged = 1;
-               len = strlen(ce->name);
+               len = ce_namelen(ce);
                size = cache_entry_size(len);
                new_ce = xcalloc(1, size);
                memcpy(new_ce->name, ce->name, len);
-               new_ce->ce_flags = create_ce_flags(len, 0) | CE_CONFLICTED;
+               new_ce->ce_flags = create_ce_flags(0) | CE_CONFLICTED;
+               new_ce->ce_namelen = len;
                new_ce->ce_mode = ce->ce_mode;
                if (add_index_entry(istate, new_ce, 0))
                        return error("%s: cannot drop to stage #0",
diff --git a/refs.c b/refs.c
index da74a2b29a20a2c94fef61641e35980007c1ab95..726c53c540a94c6ac994aa768c1ffb355ca4538e 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;
@@ -1753,26 +1762,18 @@ 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
index 3ec474fc631eb3b433b3cadbd74aed4b83cba724..278fecdd9bd00bf0df0a3d1f35777546794bc92f 100644 (file)
@@ -95,15 +95,16 @@ static struct discovery* discover_refs(const char *service)
        struct strbuf buffer = STRBUF_INIT;
        struct discovery *last = last_discovery;
        char *refs_url;
-       int http_ret, is_http = 0, proto_git_candidate = 1;
+       int http_ret, maybe_smart = 0;
 
        if (last && !strcmp(service, last->service))
                return last;
        free_discovery(last);
 
        strbuf_addf(&buffer, "%sinfo/refs", url);
-       if (!prefixcmp(url, "http://") || !prefixcmp(url, "https://")) {
-               is_http = 1;
+       if ((!prefixcmp(url, "http://") || !prefixcmp(url, "https://")) &&
+            git_env_bool("GIT_SMART_HTTP", 1)) {
+               maybe_smart = 1;
                if (!strchr(url, '?'))
                        strbuf_addch(&buffer, '?');
                else
@@ -113,19 +114,6 @@ static struct discovery* discover_refs(const char *service)
        refs_url = strbuf_detach(&buffer, NULL);
 
        http_ret = http_get_strbuf(refs_url, &buffer, HTTP_NO_CACHE);
-
-       /* try again with "plain" url (no ? or & appended) */
-       if (http_ret != HTTP_OK && http_ret != HTTP_NOAUTH) {
-               free(refs_url);
-               strbuf_reset(&buffer);
-
-               proto_git_candidate = 0;
-               strbuf_addf(&buffer, "%sinfo/refs", url);
-               refs_url = strbuf_detach(&buffer, NULL);
-
-               http_ret = http_get_strbuf(refs_url, &buffer, HTTP_NO_CACHE);
-       }
-
        switch (http_ret) {
        case HTTP_OK:
                break;
@@ -144,8 +132,7 @@ static struct discovery* discover_refs(const char *service)
        last->buf_alloc = strbuf_detach(&buffer, &last->len);
        last->buf = last->buf_alloc;
 
-       if (is_http && proto_git_candidate
-               && 5 <= last->len && last->buf[4] == '#') {
+       if (maybe_smart && 5 <= last->len && last->buf[4] == '#') {
                /* smart HTTP response; validate that the service
                 * pkt-line matches our request.
                 */
@@ -369,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);
+       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);
@@ -393,7 +380,7 @@ static int probe_rpc(struct rpc_state *rpc)
        curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 0);
        curl_easy_setopt(slot->curl, CURLOPT_POST, 1);
        curl_easy_setopt(slot->curl, CURLOPT_URL, rpc->service_url);
-       curl_easy_setopt(slot->curl, CURLOPT_ENCODING, "");
+       curl_easy_setopt(slot->curl, CURLOPT_ENCODING, NULL);
        curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, "0000");
        curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE, 4);
        curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, headers);
@@ -444,16 +431,17 @@ 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);
        curl_easy_setopt(slot->curl, CURLOPT_POST, 1);
        curl_easy_setopt(slot->curl, CURLOPT_URL, rpc->service_url);
-       curl_easy_setopt(slot->curl, CURLOPT_ENCODING, "");
-
-       headers = curl_slist_append(headers, rpc->hdr_content_type);
-       headers = curl_slist_append(headers, rpc->hdr_accept);
-       headers = curl_slist_append(headers, "Expect:");
+       curl_easy_setopt(slot->curl, CURLOPT_ENCODING, "gzip");
 
        if (large_request) {
                /* The request body is large and the size cannot be predicted.
@@ -528,9 +516,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 && !use_gzip)
+               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..51fba05
--- /dev/null
@@ -0,0 +1,342 @@
+#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;
+               }
+               msg += len + 1;
+       }
+       return 0;
+}
+
+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 651c5def92e3f864a99ed7e97d008aa04cce3782..a6a5cd57bef4aaf204f1bad293c18b5af6f57f53 100644 (file)
--- a/rerere.c
+++ b/rerere.c
@@ -25,7 +25,7 @@ const char *rerere_path(const char *hex, const char *file)
        return git_path("rr-cache/%s/%s", hex, file);
 }
 
-int has_rerere_resolution(const char *hex)
+static int has_rerere_resolution(const char *hex)
 {
        struct stat st;
        return !stat(rerere_path(hex, "postimage"), &st);
@@ -544,13 +544,13 @@ static int do_plain_rerere(struct string_list *rr, int fd)
 
                if (has_rerere_resolution(name)) {
                        if (!merge(name, path)) {
-                               if (rerere_autoupdate)
+                               const char *msg;
+                               if (rerere_autoupdate) {
                                        string_list_insert(&update, path);
-                               fprintf(stderr,
-                                       "%s '%s' using previous resolution.\n",
-                                       rerere_autoupdate
-                                       ? "Staged" : "Resolved",
-                                       path);
+                                       msg = "Staged '%s' using previous resolution.\n";
+                               } else
+                                       msg = "Resolved '%s' using previous resolution.\n";
+                               fprintf(stderr, msg, path);
                                goto mark_resolved;
                        }
                }
index fcd8bc10ba587d023d174d68020a185eab0f8d40..156d2aad804527d5ae766b5381f3b5e0d2176580 100644 (file)
--- a/rerere.h
+++ b/rerere.h
@@ -16,7 +16,6 @@ extern void *RERERE_RESOLVED;
 extern int setup_rerere(struct string_list *, int);
 extern int rerere(int);
 extern const char *rerere_path(const char *hex, const char *file);
-extern int has_rerere_resolution(const char *hex);
 extern int rerere_forget(const char **);
 extern int rerere_remaining(struct string_list *);
 extern void rerere_clear(struct string_list *);
index 72104962d36b9672fd9dfc6ec850c99ccfc3803c..d7d621cdbf224f5a2bc1780e9602dcd3d08c1d57 100644 (file)
@@ -1002,7 +1002,7 @@ static int add_parents_only(struct rev_info *revs, const char *arg_, int flags)
                flags ^= UNINTERESTING;
                arg++;
        }
-       if (get_sha1(arg, sha1))
+       if (get_sha1_committish(arg, sha1))
                return 0;
        while (1) {
                it = get_reference(revs, arg, sha1, 0);
@@ -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);
@@ -1116,16 +1116,16 @@ static void prepare_show_merge(struct rev_info *revs)
        revs->limited = 1;
 }
 
-int handle_revision_arg(const char *arg_, struct rev_info *revs,
-                       int flags,
-                       int cant_be_filename)
+int handle_revision_arg(const char *arg_, struct rev_info *revs, int flags, unsigned revarg_opt)
 {
-       unsigned mode;
+       struct object_context oc;
        char *dotdot;
        struct object *object;
        unsigned char sha1[20];
        int local_flags;
        const char *arg = arg_;
+       int cant_be_filename = revarg_opt & REVARG_CANNOT_BE_FILENAME;
+       unsigned get_sha1_flags = 0;
 
        dotdot = strstr(arg, "..");
        if (dotdot) {
@@ -1155,8 +1155,8 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs,
                                return -1;
                        }
                }
-               if (!get_sha1(this, from_sha1) &&
-                   !get_sha1(next, sha1)) {
+               if (!get_sha1_committish(this, from_sha1) &&
+                   !get_sha1_committish(next, sha1)) {
                        struct commit *a, *b;
                        struct commit_list *exclude;
 
@@ -1215,13 +1215,17 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs,
                local_flags = UNINTERESTING;
                arg++;
        }
-       if (get_sha1_with_mode(arg, sha1, &mode))
+
+       if (revarg_opt & REVARG_COMMITTISH)
+               get_sha1_flags = GET_SHA1_COMMITTISH;
+
+       if (get_sha1_with_context(arg, get_sha1_flags, sha1, &oc))
                return revs->ignore_missing ? 0 : -1;
        if (!cant_be_filename)
                verify_non_filename(revs->prefix, arg);
        object = get_reference(revs, arg, sha1, flags ^ local_flags);
        add_rev_cmdline(revs, object, arg_, REV_CMD_REV, flags ^ local_flags);
-       add_pending_object_with_mode(revs, object, arg, mode);
+       add_pending_object_with_mode(revs, object, arg, oc.mode);
        return 0;
 }
 
@@ -1271,7 +1275,7 @@ static void read_revisions_from_stdin(struct rev_info *revs,
                        }
                        die("options not supported in --stdin mode");
                }
-               if (handle_revision_arg(sb.buf, revs, 0, 1))
+               if (handle_revision_arg(sb.buf, revs, 0, REVARG_CANNOT_BE_FILENAME))
                        die("bad revision '%s'", sb.buf);
        }
        if (seen_dashdash)
@@ -1308,7 +1312,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
            !strcmp(arg, "--no-walk") || !strcmp(arg, "--do-walk") ||
            !strcmp(arg, "--bisect") || !prefixcmp(arg, "--glob=") ||
            !prefixcmp(arg, "--branches=") || !prefixcmp(arg, "--tags=") ||
-           !prefixcmp(arg, "--remotes="))
+           !prefixcmp(arg, "--remotes=") || !prefixcmp(arg, "--no-walk="))
        {
                unkv[(*unkc)++] = arg;
                return 1;
@@ -1591,16 +1595,25 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
        } else if ((argcount = parse_long_opt("committer", argv, &optarg))) {
                add_header_grep(revs, GREP_HEADER_COMMITTER, optarg);
                return argcount;
+       } else if ((argcount = parse_long_opt("grep-reflog", argv, &optarg))) {
+               add_header_grep(revs, GREP_HEADER_REFLOG, optarg);
+               return argcount;
        } else if ((argcount = parse_long_opt("grep", argv, &optarg))) {
                add_message_grep(revs, optarg);
                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))) {
@@ -1703,7 +1716,18 @@ static int handle_revision_pseudo_opt(const char *submodule,
        } else if (!strcmp(arg, "--not")) {
                *flags ^= UNINTERESTING;
        } else if (!strcmp(arg, "--no-walk")) {
-               revs->no_walk = 1;
+               revs->no_walk = REVISION_WALK_NO_WALK_SORTED;
+       } else if (!prefixcmp(arg, "--no-walk=")) {
+               /*
+                * Detached form ("--no-walk X" as opposed to "--no-walk=X")
+                * not allowed, since the argument is optional.
+                */
+               if (!strcmp(arg + 10, "sorted"))
+                       revs->no_walk = REVISION_WALK_NO_WALK_SORTED;
+               else if (!strcmp(arg + 10, "unsorted"))
+                       revs->no_walk = REVISION_WALK_NO_WALK_UNSORTED;
+               else
+                       return error("invalid argument to --no-walk");
        } else if (!strcmp(arg, "--do-walk")) {
                revs->no_walk = 0;
        } else {
@@ -1722,7 +1746,7 @@ static int handle_revision_pseudo_opt(const char *submodule,
  */
 int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct setup_revision_opt *opt)
 {
-       int i, flags, left, seen_dashdash, read_from_stdin, got_rev_arg = 0;
+       int i, flags, left, seen_dashdash, read_from_stdin, got_rev_arg = 0, revarg_opt;
        struct cmdline_pathspec prune_data;
        const char *submodule = NULL;
 
@@ -1750,6 +1774,9 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
 
        /* Second, deal with arguments and options */
        flags = 0;
+       revarg_opt = opt ? opt->revarg_opt : 0;
+       if (seen_dashdash)
+               revarg_opt |= REVARG_CANNOT_BE_FILENAME;
        read_from_stdin = 0;
        for (left = i = 1; i < argc; i++) {
                const char *arg = argv[i];
@@ -1785,7 +1812,8 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
                        continue;
                }
 
-               if (handle_revision_arg(arg, revs, flags, seen_dashdash)) {
+
+               if (handle_revision_arg(arg, revs, flags, revarg_opt)) {
                        int j;
                        if (seen_dashdash || *arg == '^')
                                die("bad revision '%s'", arg);
@@ -1836,11 +1864,11 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
        if (revs->def && !revs->pending.nr && !got_rev_arg) {
                unsigned char sha1[20];
                struct object *object;
-               unsigned mode;
-               if (get_sha1_with_mode(revs->def, sha1, &mode))
+               struct object_context oc;
+               if (get_sha1_with_context(revs->def, 0, sha1, &oc))
                        die("bad default revision '%s'", revs->def);
                object = get_reference(revs, revs->def, sha1, 0);
-               add_pending_object_with_mode(revs, object, revs->def, mode);
+               add_pending_object_with_mode(revs, object, revs->def, oc.mode);
        }
 
        /* Did the user ask for any diff output? Run the diff! */
@@ -1869,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)
@@ -1884,6 +1914,8 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
 
        if (revs->reflog_info && revs->graph)
                die("cannot combine --walk-reflogs with --graph");
+       if (!revs->reflog_info && revs->grep_filter.use_reflog_filter)
+               die("cannot use --grep-reflog without --walk-reflogs");
 
        return left;
 }
@@ -2121,10 +2153,11 @@ int prepare_revision_walk(struct rev_info *revs)
                }
                e++;
        }
-       commit_list_sort_by_date(&revs->commits);
        if (!revs->leak_pending)
                free(list);
 
+       if (revs->no_walk != REVISION_WALK_NO_WALK_UNSORTED)
+               commit_list_sort_by_date(&revs->commits);
        if (revs->no_walk)
                return 0;
        if (revs->limited)
@@ -2188,10 +2221,38 @@ static int rewrite_parents(struct rev_info *revs, struct commit *commit)
 
 static int commit_match(struct commit *commit, struct rev_info *opt)
 {
+       int retval;
+       struct strbuf buf = STRBUF_INIT;
        if (!opt->grep_filter.pattern_list && !opt->grep_filter.header_list)
                return 1;
-       return grep_buffer(&opt->grep_filter,
-                          commit->buffer, strlen(commit->buffer));
+
+       /* Prepend "fake" headers as needed */
+       if (opt->grep_filter.use_reflog_filter) {
+               strbuf_addstr(&buf, "reflog ");
+               get_reflog_message(&buf, opt->reflog_info);
+               strbuf_addch(&buf, '\n');
+       }
+
+       /* Copy the commit to temporary if we are using "fake" headers */
+       if (buf.len)
+               strbuf_addstr(&buf, commit->buffer);
+
+       /* Append "fake" message parts as needed */
+       if (opt->show_notes) {
+               if (!buf.len)
+                       strbuf_addstr(&buf, commit->buffer);
+               format_display_notes(commit->object.sha1, &buf,
+                                    get_log_output_encoding(), 0);
+       }
+
+       /* Find either in the commit object, or in the temporary */
+       if (buf.len)
+               retval = grep_buffer(&opt->grep_filter, buf.buf, buf.len);
+       else
+               retval = grep_buffer(&opt->grep_filter,
+                                    commit->buffer, strlen(commit->buffer));
+       strbuf_release(&buf);
+       return retval;
 }
 
 static inline int want_ancestry(struct rev_info *revs)
@@ -2374,29 +2435,28 @@ static struct commit *get_revision_internal(struct rev_info *revs)
        }
 
        /*
-        * Now pick up what they want to give us
+        * If our max_count counter has reached zero, then we are done. We
+        * don't simply return NULL because we still might need to show
+        * boundary commits. But we want to avoid calling get_revision_1, which
+        * might do a considerable amount of work finding the next commit only
+        * for us to throw it away.
+        *
+        * If it is non-zero, then either we don't have a max_count at all
+        * (-1), or it is still counting, in which case we decrement.
         */
-       c = get_revision_1(revs);
-       if (c) {
-               while (0 < revs->skip_count) {
-                       revs->skip_count--;
-                       c = get_revision_1(revs);
-                       if (!c)
-                               break;
+       if (revs->max_count) {
+               c = get_revision_1(revs);
+               if (c) {
+                       while (0 < revs->skip_count) {
+                               revs->skip_count--;
+                               c = get_revision_1(revs);
+                               if (!c)
+                                       break;
+                       }
                }
-       }
 
-       /*
-        * Check the max_count.
-        */
-       switch (revs->max_count) {
-       case -1:
-               break;
-       case 0:
-               c = NULL;
-               break;
-       default:
-               revs->max_count--;
+               if (revs->max_count > 0)
+                       revs->max_count--;
        }
 
        if (c)
index 863f4f64543bd9f9e830e7c9567def23e906c7d9..a95bd0b3f3026068046d469a74d1a2d85e50e314 100644 (file)
@@ -41,6 +41,10 @@ struct rev_cmdline_info {
        } *rev;
 };
 
+#define REVISION_WALK_WALK 0
+#define REVISION_WALK_NO_WALK_SORTED 1
+#define REVISION_WALK_NO_WALK_UNSORTED 2
+
 struct rev_info {
        /* Starting list */
        struct commit_list *commits;
@@ -62,7 +66,7 @@ struct rev_info {
        /* Traversal flags */
        unsigned int    dense:1,
                        prune:1,
-                       no_walk:1,
+                       no_walk:2,
                        show_all:1,
                        remove_empty_trees:1,
                        simplify_history:1,
@@ -184,6 +188,7 @@ struct setup_revision_opt {
        void (*tweak)(struct rev_info *, struct setup_revision_opt *);
        const char *submodule;
        int assume_dashdash;
+       unsigned revarg_opt;
 };
 
 extern void init_revisions(struct rev_info *revs, const char *prefix);
@@ -191,7 +196,9 @@ extern int setup_revisions(int argc, const char **argv, struct rev_info *revs, s
 extern void parse_revision_opt(struct rev_info *revs, struct parse_opt_ctx_t *ctx,
                                 const struct option *options,
                                 const char * const usagestr[]);
-extern int handle_revision_arg(const char *arg, struct rev_info *revs,int flags,int cant_be_filename);
+#define REVARG_CANNOT_BE_FILENAME 01
+#define REVARG_COMMITTISH 02
+extern int handle_revision_arg(const char *arg, struct rev_info *revs, int flags, unsigned revarg_opt);
 
 extern void reset_revision_walk(void);
 extern int prepare_revision_walk(struct rev_info *revs);
index f9922b9ecc8e4956e19d7143bb6cb6ef4d97abf8..3b982e4d55274ebe87c5751fa198bee53e371d9b 100644 (file)
@@ -53,13 +53,14 @@ static void mark_child_for_cleanup(pid_t pid)
 
 static void clear_child_for_cleanup(pid_t pid)
 {
-       struct child_to_clean **last, *p;
+       struct child_to_clean **pp;
 
-       last = &children_to_clean;
-       for (p = children_to_clean; p; p = p->next) {
-               if (p->pid == pid) {
-                       *last = p->next;
-                       free(p);
+       for (pp = &children_to_clean; *pp; pp = &(*pp)->next) {
+               struct child_to_clean *clean_me = *pp;
+
+               if (clean_me->pid == pid) {
+                       *pp = clean_me->next;
+                       free(clean_me);
                        return;
                }
        }
@@ -396,16 +397,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) {
index 44f7d2bd42ddcf2d65722b7e54bea69645d167a2..850c638f19a2b6776c0311db28371b18438f207a 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 *);
index bf078f274bfe23997fcd1bc8c2a1c958f39ac9fe..e3723d20956719d2cba13ee6c6890ff1a8cfd21a 100644 (file)
@@ -17,7 +17,9 @@
 
 #define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
 
-void remove_sequencer_state(void)
+const char sign_off_header[] = "Signed-off-by: ";
+
+static void remove_sequencer_state(void)
 {
        struct strbuf seq_dir = STRBUF_INIT;
 
@@ -233,6 +235,9 @@ static int do_recursive_merge(struct commit *base, struct commit *next,
                die(_("%s: Unable to write new index file"), action_name(opts));
        rollback_lock_file(&index_lock);
 
+       if (opts->signoff)
+               append_signoff(msgbuf, 0);
+
        if (!clean) {
                int i;
                strbuf_addstr(msgbuf, "\nConflicts:\n");
@@ -311,6 +316,9 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,
        if (allow_empty)
                argv_array_push(&array, "--allow-empty");
 
+       if (opts->allow_empty_message)
+               argv_array_push(&array, "--allow-empty-message");
+
        rc = run_command_v_opt(array.argv, RUN_GIT_CMD);
        argv_array_clear(&array);
        return rc;
@@ -543,7 +551,11 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
 
 static void prepare_revs(struct replay_opts *opts)
 {
-       if (opts->action != REPLAY_REVERT)
+       /*
+        * picking (but not reverting) ranges (but not individual revisions)
+        * should be done in reverse
+        */
+       if (opts->action == REPLAY_PICK && !opts->revs->no_walk)
                opts->revs->reverse ^= 1;
 
        if (prepare_revision_walk(opts->revs))
@@ -1004,3 +1016,63 @@ int sequencer_pick_revisions(struct replay_opts *opts)
        save_opts(opts);
        return pick_commits(todo_list, opts);
 }
+
+static int ends_rfc2822_footer(struct strbuf *sb, int ignore_footer)
+{
+       int ch;
+       int hit = 0;
+       int i, j, k;
+       int len = sb->len - ignore_footer;
+       int first = 1;
+       const char *buf = sb->buf;
+
+       for (i = len - 1; i > 0; i--) {
+               if (hit && buf[i] == '\n')
+                       break;
+               hit = (buf[i] == '\n');
+       }
+
+       while (i < len - 1 && buf[i] == '\n')
+               i++;
+
+       for (; i < len; i = k) {
+               for (k = i; k < len && buf[k] != '\n'; k++)
+                       ; /* do nothing */
+               k++;
+
+               if ((buf[k] == ' ' || buf[k] == '\t') && !first)
+                       continue;
+
+               first = 0;
+
+               for (j = 0; i + j < len; j++) {
+                       ch = buf[i + j];
+                       if (ch == ':')
+                               break;
+                       if (isalnum(ch) ||
+                           (ch == '-'))
+                               continue;
+                       return 0;
+               }
+       }
+       return 1;
+}
+
+void append_signoff(struct strbuf *msgbuf, int ignore_footer)
+{
+       struct strbuf sob = STRBUF_INIT;
+       int i;
+
+       strbuf_addstr(&sob, sign_off_header);
+       strbuf_addstr(&sob, fmt_name(getenv("GIT_COMMITTER_NAME"),
+                               getenv("GIT_COMMITTER_EMAIL")));
+       strbuf_addch(&sob, '\n');
+       for (i = msgbuf->len - 1 - ignore_footer; i > 0 && msgbuf->buf[i - 1] != '\n'; i--)
+               ; /* do nothing */
+       if (prefixcmp(msgbuf->buf + i, sob.buf)) {
+               if (!i || !ends_rfc2822_footer(msgbuf, ignore_footer))
+                       strbuf_splice(msgbuf, msgbuf->len - ignore_footer, 0, "\n", 1);
+               strbuf_splice(msgbuf, msgbuf->len - ignore_footer, 0, sob.buf, sob.len);
+       }
+       strbuf_release(&sob);
+}
index aa5f17cc3079f39000e9d7526d24354a027daabd..9d57d57524d411c54d55346a5ecff67bc256595c 100644 (file)
@@ -30,6 +30,7 @@ struct replay_opts {
        int allow_ff;
        int allow_rerere_auto;
        int allow_empty;
+       int allow_empty_message;
        int keep_redundant_commits;
 
        int mainline;
@@ -43,9 +44,10 @@ struct replay_opts {
        struct rev_info *revs;
 };
 
-/* Removes SEQ_DIR. */
-extern void remove_sequencer_state(void);
-
 int sequencer_pick_revisions(struct replay_opts *opts);
 
+extern const char sign_off_header[];
+
+void append_signoff(struct strbuf *msgbuf, int ignore_footer);
+
 #endif
diff --git a/setup.c b/setup.c
index 7663a4cbb2e3d179c3a16d647733da7bf89a3e2d..3a1b2fd45580cad7ecd55efa755872efc81075ad 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -77,9 +77,6 @@ static void NORETURN die_verify_filename(const char *prefix,
                                         const char *arg,
                                         int diagnose_misspelt_rev)
 {
-       unsigned char sha1[20];
-       unsigned mode;
-
        if (!diagnose_misspelt_rev)
                die("%s: no such path in the working tree.\n"
                    "Use 'git <command> -- <path>...' to specify paths that do not exist locally.",
@@ -88,11 +85,10 @@ static void NORETURN die_verify_filename(const char *prefix,
         * Saying "'(icase)foo' does not exist in the index" when the
         * user gave us ":(icase)foo" is just stupid.  A magic pathspec
         * begins with a colon and is followed by a non-alnum; do not
-        * let get_sha1_with_mode_1(only_to_die=1) to even trigger.
+        * let maybe_die_on_misspelt_object_name() even trigger.
         */
        if (!(arg[0] == ':' && !isalnum(arg[1])))
-               /* try a detailed diagnostic ... */
-               get_sha1_with_mode_1(arg, sha1, &mode, 1, prefix);
+               maybe_die_on_misspelt_object_name(arg, prefix);
 
        /* ... or fall back the most general message. */
        die("ambiguous argument '%s': unknown revision or path not in the working tree.\n"
index b2f47f98fbba26ff7cab4c8651f4c4097e933f84..6f4a2246c9a912d06cf1a6995e07bf2008ec749d 100644 (file)
@@ -14,7 +14,7 @@ static int void_hashcmp(const void *a, const void *b)
        return hashcmp(a, b);
 }
 
-void sha1_array_sort(struct sha1_array *array)
+static void sha1_array_sort(struct sha1_array *array)
 {
        qsort(array->sha1, array->nr, sizeof(*array->sha1), void_hashcmp);
        array->sorted = 1;
index 4499b5dad40924e9be2b6aacd73153326e6d11ec..72bb33bec6c173633c2b5cd04db57b562fa23a9e 100644 (file)
@@ -11,7 +11,6 @@ struct sha1_array {
 #define SHA1_ARRAY_INIT { NULL, 0, 0, 0 }
 
 void sha1_array_append(struct sha1_array *array, const unsigned char *sha1);
-void sha1_array_sort(struct sha1_array *array);
 int sha1_array_lookup(struct sha1_array *array, const unsigned char *sha1);
 void sha1_array_clear(struct sha1_array *array);
 
index af5cfbde63aed41d95ac7318d064d3012832d2c5..9152974642986de2307ec4ed6beda4efa49e8383 100644 (file)
@@ -731,6 +731,24 @@ void free_pack_by_name(const char *pack_name)
        }
 }
 
+static unsigned int get_max_fd_limit(void)
+{
+#ifdef RLIMIT_NOFILE
+       struct rlimit lim;
+
+       if (getrlimit(RLIMIT_NOFILE, &lim))
+               die_errno("cannot get RLIMIT_NOFILE");
+
+       return lim.rlim_cur;
+#elif defined(_SC_OPEN_MAX)
+       return sysconf(_SC_OPEN_MAX);
+#elif defined(OPEN_MAX)
+       return OPEN_MAX;
+#else
+       return 1; /* see the caller ;-) */
+#endif
+}
+
 /*
  * Do not call this directly as this leaks p->pack_fd on error return;
  * call open_packed_git() instead.
@@ -747,13 +765,7 @@ static int open_packed_git_1(struct packed_git *p)
                return error("packfile %s index unavailable", p->pack_name);
 
        if (!pack_max_fds) {
-               struct rlimit lim;
-               unsigned int max_fds;
-
-               if (getrlimit(RLIMIT_NOFILE, &lim))
-                       die_errno("cannot get RLIMIT_NOFILE");
-
-               max_fds = lim.rlim_cur;
+               unsigned int max_fds = get_max_fd_limit();
 
                /* Save 3 for stdin/stdout/stderr, 22 for work */
                if (25 < max_fds)
index 5d81ea0564c8d90b417eb8ec5ed8c32baa2c3ea3..95003c77ea9a0ee240d60bc7958bb48245b14ad4 100644 (file)
@@ -9,14 +9,82 @@
 
 static int get_sha1_oneline(const char *, unsigned char *, struct commit_list *);
 
-static int find_short_object_filename(int len, const char *name, unsigned char *sha1)
+typedef int (*disambiguate_hint_fn)(const unsigned char *, void *);
+
+struct disambiguate_state {
+       disambiguate_hint_fn fn;
+       void *cb_data;
+       unsigned char candidate[20];
+       unsigned candidate_exists:1;
+       unsigned candidate_checked:1;
+       unsigned candidate_ok:1;
+       unsigned disambiguate_fn_used:1;
+       unsigned ambiguous:1;
+       unsigned always_call_fn:1;
+};
+
+static void update_candidates(struct disambiguate_state *ds, const unsigned char *current)
+{
+       if (ds->always_call_fn) {
+               ds->ambiguous = ds->fn(current, ds->cb_data) ? 1 : 0;
+               return;
+       }
+       if (!ds->candidate_exists) {
+               /* this is the first candidate */
+               hashcpy(ds->candidate, current);
+               ds->candidate_exists = 1;
+               return;
+       } else if (!hashcmp(ds->candidate, current)) {
+               /* the same as what we already have seen */
+               return;
+       }
+
+       if (!ds->fn) {
+               /* cannot disambiguate between ds->candidate and current */
+               ds->ambiguous = 1;
+               return;
+       }
+
+       if (!ds->candidate_checked) {
+               ds->candidate_ok = ds->fn(ds->candidate, ds->cb_data);
+               ds->disambiguate_fn_used = 1;
+               ds->candidate_checked = 1;
+       }
+
+       if (!ds->candidate_ok) {
+               /* discard the candidate; we know it does not satisify fn */
+               hashcpy(ds->candidate, current);
+               ds->candidate_checked = 0;
+               return;
+       }
+
+       /* if we reach this point, we know ds->candidate satisfies fn */
+       if (ds->fn(current, ds->cb_data)) {
+               /*
+                * if both current and candidate satisfy fn, we cannot
+                * disambiguate.
+                */
+               ds->candidate_ok = 0;
+               ds->ambiguous = 1;
+       }
+
+       /* otherwise, current can be discarded and candidate is still good */
+}
+
+static void find_short_object_filename(int len, const char *hex_pfx, struct disambiguate_state *ds)
 {
        struct alternate_object_database *alt;
        char hex[40];
-       int found = 0;
        static struct alternate_object_database *fakeent;
 
        if (!fakeent) {
+               /*
+                * Create a "fake" alternate object database that
+                * points to our own object database, to make it
+                * easier to get a temporary working space in
+                * alt->name/alt->base while iterating over the
+                * object databases including our own.
+                */
                const char *objdir = get_object_directory();
                int objdir_len = strlen(objdir);
                int entlen = objdir_len + 43;
@@ -27,33 +95,28 @@ static int find_short_object_filename(int len, const char *name, unsigned char *
        }
        fakeent->next = alt_odb_list;
 
-       sprintf(hex, "%.2s", name);
-       for (alt = fakeent; alt && found < 2; alt = alt->next) {
+       sprintf(hex, "%.2s", hex_pfx);
+       for (alt = fakeent; alt && !ds->ambiguous; alt = alt->next) {
                struct dirent *de;
                DIR *dir;
-               sprintf(alt->name, "%.2s/", name);
+               sprintf(alt->name, "%.2s/", hex_pfx);
                dir = opendir(alt->base);
                if (!dir)
                        continue;
-               while ((de = readdir(dir)) != NULL) {
+
+               while (!ds->ambiguous && (de = readdir(dir)) != NULL) {
+                       unsigned char sha1[20];
+
                        if (strlen(de->d_name) != 38)
                                continue;
-                       if (memcmp(de->d_name, name + 2, len - 2))
+                       if (memcmp(de->d_name, hex_pfx + 2, len - 2))
                                continue;
-                       if (!found) {
-                               memcpy(hex + 2, de->d_name, 38);
-                               found++;
-                       }
-                       else if (memcmp(hex + 2, de->d_name, 38)) {
-                               found = 2;
-                               break;
-                       }
+                       memcpy(hex + 2, de->d_name, 38);
+                       if (!get_sha1_hex(hex, sha1))
+                               update_candidates(ds, sha1);
                }
                closedir(dir);
        }
-       if (found == 1)
-               return get_sha1_hex(hex, sha1) == 0;
-       return found;
 }
 
 static int match_sha(unsigned len, const unsigned char *a, const unsigned char *b)
@@ -71,103 +134,157 @@ static int match_sha(unsigned len, const unsigned char *a, const unsigned char *
        return 1;
 }
 
-static int find_short_packed_object(int len, const unsigned char *match, unsigned char *sha1)
+static void unique_in_pack(int len,
+                         const unsigned char *bin_pfx,
+                          struct packed_git *p,
+                          struct disambiguate_state *ds)
 {
-       struct packed_git *p;
-       const unsigned char *found_sha1 = NULL;
-       int found = 0;
-
-       prepare_packed_git();
-       for (p = packed_git; p && found < 2; p = p->next) {
-               uint32_t num, last;
-               uint32_t first = 0;
-               open_pack_index(p);
-               num = p->num_objects;
-               last = num;
-               while (first < last) {
-                       uint32_t mid = (first + last) / 2;
-                       const unsigned char *now;
-                       int cmp;
-
-                       now = nth_packed_object_sha1(p, mid);
-                       cmp = hashcmp(match, now);
-                       if (!cmp) {
-                               first = mid;
-                               break;
-                       }
-                       if (cmp > 0) {
-                               first = mid+1;
-                               continue;
-                       }
-                       last = mid;
+       uint32_t num, last, i, first = 0;
+       const unsigned char *current = NULL;
+
+       open_pack_index(p);
+       num = p->num_objects;
+       last = num;
+       while (first < last) {
+               uint32_t mid = (first + last) / 2;
+               const unsigned char *current;
+               int cmp;
+
+               current = nth_packed_object_sha1(p, mid);
+               cmp = hashcmp(bin_pfx, current);
+               if (!cmp) {
+                       first = mid;
+                       break;
                }
-               if (first < num) {
-                       const unsigned char *now, *next;
-                      now = nth_packed_object_sha1(p, first);
-                       if (match_sha(len, match, now)) {
-                               next = nth_packed_object_sha1(p, first+1);
-                              if (!next|| !match_sha(len, match, next)) {
-                                       /* unique within this pack */
-                                       if (!found) {
-                                               found_sha1 = now;
-                                               found++;
-                                       }
-                                       else if (hashcmp(found_sha1, now)) {
-                                               found = 2;
-                                               break;
-                                       }
-                               }
-                               else {
-                                       /* not even unique within this pack */
-                                       found = 2;
-                                       break;
-                               }
-                       }
+               if (cmp > 0) {
+                       first = mid+1;
+                       continue;
                }
+               last = mid;
+       }
+
+       /*
+        * At this point, "first" is the location of the lowest object
+        * with an object name that could match "bin_pfx".  See if we have
+        * 0, 1 or more objects that actually match(es).
+        */
+       for (i = first; i < num && !ds->ambiguous; i++) {
+               current = nth_packed_object_sha1(p, i);
+               if (!match_sha(len, bin_pfx, current))
+                       break;
+               update_candidates(ds, current);
        }
-       if (found == 1)
-               hashcpy(sha1, found_sha1);
-       return found;
+}
+
+static void find_short_packed_object(int len, const unsigned char *bin_pfx,
+                                    struct disambiguate_state *ds)
+{
+       struct packed_git *p;
+
+       prepare_packed_git();
+       for (p = packed_git; p && !ds->ambiguous; p = p->next)
+               unique_in_pack(len, bin_pfx, p, ds);
 }
 
 #define SHORT_NAME_NOT_FOUND (-1)
 #define SHORT_NAME_AMBIGUOUS (-2)
 
-static int find_unique_short_object(int len, char *canonical,
-                                   unsigned char *res, unsigned char *sha1)
+static int finish_object_disambiguation(struct disambiguate_state *ds,
+                                       unsigned char *sha1)
 {
-       int has_unpacked, has_packed;
-       unsigned char unpacked_sha1[20], packed_sha1[20];
+       if (ds->ambiguous)
+               return SHORT_NAME_AMBIGUOUS;
 
-       prepare_alt_odb();
-       has_unpacked = find_short_object_filename(len, canonical, unpacked_sha1);
-       has_packed = find_short_packed_object(len, res, packed_sha1);
-       if (!has_unpacked && !has_packed)
+       if (!ds->candidate_exists)
                return SHORT_NAME_NOT_FOUND;
-       if (1 < has_unpacked || 1 < has_packed)
+
+       if (!ds->candidate_checked)
+               /*
+                * If this is the only candidate, there is no point
+                * calling the disambiguation hint callback.
+                *
+                * On the other hand, if the current candidate
+                * replaced an earlier candidate that did _not_ pass
+                * the disambiguation hint callback, then we do have
+                * more than one objects that match the short name
+                * given, so we should make sure this one matches;
+                * otherwise, if we discovered this one and the one
+                * that we previously discarded in the reverse order,
+                * we would end up showing different results in the
+                * same repository!
+                */
+               ds->candidate_ok = (!ds->disambiguate_fn_used ||
+                                   ds->fn(ds->candidate, ds->cb_data));
+
+       if (!ds->candidate_ok)
                return SHORT_NAME_AMBIGUOUS;
-       if (has_unpacked != has_packed) {
-               hashcpy(sha1, (has_packed ? packed_sha1 : unpacked_sha1));
+
+       hashcpy(sha1, ds->candidate);
+       return 0;
+}
+
+static int disambiguate_commit_only(const unsigned char *sha1, void *cb_data_unused)
+{
+       int kind = sha1_object_info(sha1, NULL);
+       return kind == OBJ_COMMIT;
+}
+
+static int disambiguate_committish_only(const unsigned char *sha1, void *cb_data_unused)
+{
+       struct object *obj;
+       int kind;
+
+       kind = sha1_object_info(sha1, NULL);
+       if (kind == OBJ_COMMIT)
+               return 1;
+       if (kind != OBJ_TAG)
                return 0;
-       }
-       /* Both have unique ones -- do they match? */
-       if (hashcmp(packed_sha1, unpacked_sha1))
-               return SHORT_NAME_AMBIGUOUS;
-       hashcpy(sha1, packed_sha1);
+
+       /* We need to do this the hard way... */
+       obj = deref_tag(lookup_object(sha1), NULL, 0);
+       if (obj && obj->type == OBJ_COMMIT)
+               return 1;
        return 0;
 }
 
-static int get_short_sha1(const char *name, int len, unsigned char *sha1,
-                         int quietly)
+static int disambiguate_tree_only(const unsigned char *sha1, void *cb_data_unused)
 {
-       int i, status;
-       char canonical[40];
-       unsigned char res[20];
+       int kind = sha1_object_info(sha1, NULL);
+       return kind == OBJ_TREE;
+}
 
-       if (len < MINIMUM_ABBREV || len > 40)
-               return -1;
-       hashclr(res);
-       memset(canonical, 'x', 40);
+static int disambiguate_treeish_only(const unsigned char *sha1, void *cb_data_unused)
+{
+       struct object *obj;
+       int kind;
+
+       kind = sha1_object_info(sha1, NULL);
+       if (kind == OBJ_TREE || kind == OBJ_COMMIT)
+               return 1;
+       if (kind != OBJ_TAG)
+               return 0;
+
+       /* We need to do this the hard way... */
+       obj = deref_tag(lookup_object(sha1), NULL, 0);
+       if (obj && (obj->type == OBJ_TREE || obj->type == OBJ_COMMIT))
+               return 1;
+       return 0;
+}
+
+static int disambiguate_blob_only(const unsigned char *sha1, void *cb_data_unused)
+{
+       int kind = sha1_object_info(sha1, NULL);
+       return kind == OBJ_BLOB;
+}
+
+static int prepare_prefixes(const char *name, int len,
+                           unsigned char *bin_pfx,
+                           char *hex_pfx)
+{
+       int i;
+
+       hashclr(bin_pfx);
+       memset(hex_pfx, 'x', 40);
        for (i = 0; i < len ;i++) {
                unsigned char c = name[i];
                unsigned char val;
@@ -181,18 +298,76 @@ static int get_short_sha1(const char *name, int len, unsigned char *sha1,
                }
                else
                        return -1;
-               canonical[i] = c;
+               hex_pfx[i] = c;
                if (!(i & 1))
                        val <<= 4;
-               res[i >> 1] |= val;
+               bin_pfx[i >> 1] |= val;
        }
+       return 0;
+}
+
+static int get_short_sha1(const char *name, int len, unsigned char *sha1,
+                         unsigned flags)
+{
+       int status;
+       char hex_pfx[40];
+       unsigned char bin_pfx[20];
+       struct disambiguate_state ds;
+       int quietly = !!(flags & GET_SHA1_QUIETLY);
+
+       if (len < MINIMUM_ABBREV || len > 40)
+               return -1;
+       if (prepare_prefixes(name, len, bin_pfx, hex_pfx) < 0)
+               return -1;
+
+       prepare_alt_odb();
+
+       memset(&ds, 0, sizeof(ds));
+       if (flags & GET_SHA1_COMMIT)
+               ds.fn = disambiguate_commit_only;
+       else if (flags & GET_SHA1_COMMITTISH)
+               ds.fn = disambiguate_committish_only;
+       else if (flags & GET_SHA1_TREE)
+               ds.fn = disambiguate_tree_only;
+       else if (flags & GET_SHA1_TREEISH)
+               ds.fn = disambiguate_treeish_only;
+       else if (flags & GET_SHA1_BLOB)
+               ds.fn = disambiguate_blob_only;
+
+       find_short_object_filename(len, hex_pfx, &ds);
+       find_short_packed_object(len, bin_pfx, &ds);
+       status = finish_object_disambiguation(&ds, sha1);
 
-       status = find_unique_short_object(i, canonical, res, sha1);
        if (!quietly && (status == SHORT_NAME_AMBIGUOUS))
-               return error("short SHA1 %.*s is ambiguous.", len, canonical);
+               return error("short SHA1 %.*s is ambiguous.", len, hex_pfx);
        return status;
 }
 
+
+int for_each_abbrev(const char *prefix, each_abbrev_fn fn, void *cb_data)
+{
+       char hex_pfx[40];
+       unsigned char bin_pfx[20];
+       struct disambiguate_state ds;
+       int len = strlen(prefix);
+
+       if (len < MINIMUM_ABBREV || len > 40)
+               return -1;
+       if (prepare_prefixes(prefix, len, bin_pfx, hex_pfx) < 0)
+               return -1;
+
+       prepare_alt_odb();
+
+       memset(&ds, 0, sizeof(ds));
+       ds.always_call_fn = 1;
+       ds.cb_data = cb_data;
+       ds.fn = fn;
+
+       find_short_object_filename(len, hex_pfx, &ds);
+       find_short_packed_object(len, bin_pfx, &ds);
+       return ds.ambiguous;
+}
+
 const char *find_unique_abbrev(const unsigned char *sha1, int len)
 {
        int status, exists;
@@ -204,7 +379,7 @@ const char *find_unique_abbrev(const unsigned char *sha1, int len)
                return hex;
        while (len < 40) {
                unsigned char sha1_ret[20];
-               status = get_short_sha1(hex, len, sha1_ret, 1);
+               status = get_short_sha1(hex, len, sha1_ret, GET_SHA1_QUIETLY);
                if (exists
                    ? !status
                    : status == SHORT_NAME_NOT_FOUND) {
@@ -255,7 +430,7 @@ static inline int upstream_mark(const char *string, int len)
        return 0;
 }
 
-static int get_sha1_1(const char *name, int len, unsigned char *sha1);
+static int get_sha1_1(const char *name, int len, unsigned char *sha1, unsigned lookup_flags);
 
 static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
 {
@@ -292,7 +467,7 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
                ret = interpret_branch_name(str+at, &buf);
                if (ret > 0) {
                        /* substitute this branch name and restart */
-                       return get_sha1_1(buf.buf, buf.len, sha1);
+                       return get_sha1_1(buf.buf, buf.len, sha1, 0);
                } else if (ret == 0) {
                        return -1;
                }
@@ -362,7 +537,7 @@ static int get_parent(const char *name, int len,
                      unsigned char *result, int idx)
 {
        unsigned char sha1[20];
-       int ret = get_sha1_1(name, len, sha1);
+       int ret = get_sha1_1(name, len, sha1, GET_SHA1_COMMITTISH);
        struct commit *commit;
        struct commit_list *p;
 
@@ -395,7 +570,7 @@ static int get_nth_ancestor(const char *name, int len,
        struct commit *commit;
        int ret;
 
-       ret = get_sha1_1(name, len, sha1);
+       ret = get_sha1_1(name, len, sha1, GET_SHA1_COMMITTISH);
        if (ret)
                return ret;
        commit = lookup_commit_reference(sha1);
@@ -441,6 +616,7 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)
        unsigned char outer[20];
        const char *sp;
        unsigned int expected_type = 0;
+       unsigned lookup_flags = 0;
        struct object *o;
 
        /*
@@ -476,7 +652,10 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)
        else
                return -1;
 
-       if (get_sha1_1(name, sp - name - 2, outer))
+       if (expected_type == OBJ_COMMIT)
+               lookup_flags = GET_SHA1_COMMITTISH;
+
+       if (get_sha1_1(name, sp - name - 2, outer, lookup_flags))
                return -1;
 
        o = parse_object(outer);
@@ -525,6 +704,7 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)
 static int get_describe_name(const char *name, int len, unsigned char *sha1)
 {
        const char *cp;
+       unsigned flags = GET_SHA1_QUIETLY | GET_SHA1_COMMIT;
 
        for (cp = name + len - 1; name + 2 <= cp; cp--) {
                char ch = *cp;
@@ -535,14 +715,14 @@ static int get_describe_name(const char *name, int len, unsigned char *sha1)
                        if (ch == 'g' && cp[-1] == '-') {
                                cp++;
                                len -= cp - name;
-                               return get_short_sha1(cp, len, sha1, 1);
+                               return get_short_sha1(cp, len, sha1, flags);
                        }
                }
        }
        return -1;
 }
 
-static int get_sha1_1(const char *name, int len, unsigned char *sha1)
+static int get_sha1_1(const char *name, int len, unsigned char *sha1, unsigned lookup_flags)
 {
        int ret, has_suffix;
        const char *cp;
@@ -587,7 +767,7 @@ static int get_sha1_1(const char *name, int len, unsigned char *sha1)
        if (!ret)
                return 0;
 
-       return get_short_sha1(name, len, sha1, 0);
+       return get_short_sha1(name, len, sha1, lookup_flags);
 }
 
 /*
@@ -769,7 +949,7 @@ int get_sha1_mb(const char *name, unsigned char *sha1)
                struct strbuf sb;
                strbuf_init(&sb, dots - name);
                strbuf_add(&sb, name, dots - name);
-               st = get_sha1(sb.buf, sha1_tmp);
+               st = get_sha1_committish(sb.buf, sha1_tmp);
                strbuf_release(&sb);
        }
        if (st)
@@ -778,7 +958,7 @@ int get_sha1_mb(const char *name, unsigned char *sha1)
        if (!one)
                return -1;
 
-       if (get_sha1(dots[3] ? (dots + 3) : "HEAD", sha1_tmp))
+       if (get_sha1_committish(dots[3] ? (dots + 3) : "HEAD", sha1_tmp))
                return -1;
        two = lookup_commit_reference_gently(sha1_tmp, 0);
        if (!two)
@@ -905,7 +1085,52 @@ int strbuf_check_branch_ref(struct strbuf *sb, const char *name)
 int get_sha1(const char *name, unsigned char *sha1)
 {
        struct object_context unused;
-       return get_sha1_with_context(name, sha1, &unused);
+       return get_sha1_with_context(name, 0, sha1, &unused);
+}
+
+/*
+ * Many callers know that the user meant to name a committish by
+ * syntactical positions where the object name appears.  Calling this
+ * function allows the machinery to disambiguate shorter-than-unique
+ * abbreviated object names between committish and others.
+ *
+ * Note that this does NOT error out when the named object is not a
+ * committish. It is merely to give a hint to the disambiguation
+ * machinery.
+ */
+int get_sha1_committish(const char *name, unsigned char *sha1)
+{
+       struct object_context unused;
+       return get_sha1_with_context(name, GET_SHA1_COMMITTISH,
+                                    sha1, &unused);
+}
+
+int get_sha1_treeish(const char *name, unsigned char *sha1)
+{
+       struct object_context unused;
+       return get_sha1_with_context(name, GET_SHA1_TREEISH,
+                                    sha1, &unused);
+}
+
+int get_sha1_commit(const char *name, unsigned char *sha1)
+{
+       struct object_context unused;
+       return get_sha1_with_context(name, GET_SHA1_COMMIT,
+                                    sha1, &unused);
+}
+
+int get_sha1_tree(const char *name, unsigned char *sha1)
+{
+       struct object_context unused;
+       return get_sha1_with_context(name, GET_SHA1_TREE,
+                                    sha1, &unused);
+}
+
+int get_sha1_blob(const char *name, unsigned char *sha1)
+{
+       struct object_context unused;
+       return get_sha1_with_context(name, GET_SHA1_BLOB,
+                                    sha1, &unused);
 }
 
 /* Must be called only when object_name:filename doesn't exist. */
@@ -1004,16 +1229,6 @@ static void diagnose_invalid_index_path(int stage,
 }
 
 
-int get_sha1_with_mode_1(const char *name, unsigned char *sha1, unsigned *mode,
-                        int only_to_die, const char *prefix)
-{
-       struct object_context oc;
-       int ret;
-       ret = get_sha1_with_context_1(name, sha1, &oc, only_to_die, prefix);
-       *mode = oc.mode;
-       return ret;
-}
-
 static char *resolve_relative_path(const char *rel)
 {
        if (prefixcmp(rel, "./") && prefixcmp(rel, "../"))
@@ -1031,20 +1246,24 @@ static char *resolve_relative_path(const char *rel)
                           rel);
 }
 
-int get_sha1_with_context_1(const char *name, unsigned char *sha1,
-                           struct object_context *oc,
-                           int only_to_die, const char *prefix)
+static int get_sha1_with_context_1(const char *name,
+                                  unsigned flags,
+                                  const char *prefix,
+                                  unsigned char *sha1,
+                                  struct object_context *oc)
 {
        int ret, bracket_depth;
        int namelen = strlen(name);
        const char *cp;
+       int only_to_die = flags & GET_SHA1_ONLY_TO_DIE;
 
        memset(oc, 0, sizeof(*oc));
        oc->mode = S_IFINVALID;
-       ret = get_sha1_1(name, namelen, sha1);
+       ret = get_sha1_1(name, namelen, sha1, flags);
        if (!ret)
                return ret;
-       /* sha1:path --> object name of path in ent sha1
+       /*
+        * sha1:path --> object name of path in ent sha1
         * :path -> object name of absolute path in index
         * :./path -> object name of path relative to cwd in index
         * :[0-3]:path -> object name of path in index at stage
@@ -1119,7 +1338,7 @@ int get_sha1_with_context_1(const char *name, unsigned char *sha1,
                        strncpy(object_name, name, cp-name);
                        object_name[cp-name] = '\0';
                }
-               if (!get_sha1_1(name, cp-name, tree_sha1)) {
+               if (!get_sha1_1(name, cp-name, tree_sha1, GET_SHA1_TREEISH)) {
                        const char *filename = cp+1;
                        char *new_filename = NULL;
 
@@ -1146,3 +1365,22 @@ int get_sha1_with_context_1(const char *name, unsigned char *sha1,
        }
        return ret;
 }
+
+/*
+ * Call this function when you know "name" given by the end user must
+ * name an object but it doesn't; the function _may_ die with a better
+ * diagnostic message than "no such object 'name'", e.g. "Path 'doc' does not
+ * exist in 'HEAD'" when given "HEAD:doc", or it may return in which case
+ * you have a chance to diagnose the error further.
+ */
+void maybe_die_on_misspelt_object_name(const char *name, const char *prefix)
+{
+       struct object_context oc;
+       unsigned char sha1[20];
+       get_sha1_with_context_1(name, GET_SHA1_ONLY_TO_DIE, prefix, sha1, &oc);
+}
+
+int get_sha1_with_context(const char *str, unsigned flags, unsigned char *sha1, struct object_context *orc)
+{
+       return get_sha1_with_context_1(str, flags, NULL, sha1, orc);
+}
index ec88266718879ebcf89ab95b4c89f83004467869..4b9e30cadcd1ff45e7d4f23b210b22006445da91 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);
@@ -445,8 +447,8 @@ static int is_rfc3986_unreserved(char ch)
                ch == '-' || ch == '_' || ch == '.' || ch == '~';
 }
 
-void strbuf_add_urlencode(struct strbuf *sb, const char *s, size_t len,
-                         int reserved)
+static void strbuf_add_urlencode(struct strbuf *sb, const char *s, size_t len,
+                                int reserved)
 {
        strbuf_grow(sb, len);
        while (len--) {
@@ -465,15 +467,6 @@ void strbuf_addstr_urlencode(struct strbuf *sb, const char *s,
        strbuf_add_urlencode(sb, s, strlen(s), reserved);
 }
 
-void strbuf_addf_ln(struct strbuf *sb, const char *fmt, ...)
-{
-       va_list ap;
-       va_start(ap, fmt);
-       strbuf_vaddf(sb, fmt, ap);
-       va_end(ap);
-       strbuf_addch(sb, '\n');
-}
-
 int printf_ln(const char *fmt, ...)
 {
        int ret;
index b888d405db492c9851696cf6efe66e33d5e1dca8..be941ee481a735dcc73e3821c93e8ee682478d18 100644 (file)
--- a/strbuf.h
+++ b/strbuf.h
@@ -99,8 +99,6 @@ __attribute__((format (printf,2,3)))
 extern void strbuf_addf(struct strbuf *sb, const char *fmt, ...);
 __attribute__((format (printf,2,0)))
 extern void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap);
-__attribute__((format (printf,2,3)))
-extern void strbuf_addf_ln(struct strbuf *sb, const char *fmt, ...);
 
 extern void strbuf_add_lines(struct strbuf *sb, const char *prefix, const char *buf, size_t size);
 
@@ -126,8 +124,6 @@ extern int launch_editor(const char *path, struct strbuf *buffer, const char *co
 extern int strbuf_branchname(struct strbuf *sb, const char *name);
 extern int strbuf_check_branch_ref(struct strbuf *sb, const char *name);
 
-extern void strbuf_add_urlencode(struct strbuf *, const char *, size_t,
-                                int reserved);
 extern void strbuf_addstr_urlencode(struct strbuf *, const char *,
                                    int reserved);
 
index d9810aba421cbbc844b45ea5ca713a480a699eb2..c54b816244f69614c67c532d20719081a4b34bd4 100644 (file)
@@ -92,6 +92,23 @@ struct string_list_item *string_list_lookup(struct string_list *list, const char
        return list->items + i;
 }
 
+void string_list_remove_duplicates(struct string_list *list, int free_util)
+{
+       if (list->nr > 1) {
+               int src, dst;
+               for (src = dst = 1; src < list->nr; src++) {
+                       if (!strcmp(list->items[dst - 1].string, list->items[src].string)) {
+                               if (list->strdup_strings)
+                                       free(list->items[src].string);
+                               if (free_util)
+                                       free(list->items[src].util);
+                       } else
+                               list->items[dst++] = list->items[src];
+               }
+               list->nr = dst;
+       }
+}
+
 int for_each_string_list(struct string_list *list,
                         string_list_each_func_t fn, void *cb_data)
 {
@@ -102,6 +119,43 @@ int for_each_string_list(struct string_list *list,
        return ret;
 }
 
+void filter_string_list(struct string_list *list, int free_util,
+                       string_list_each_func_t want, void *cb_data)
+{
+       int src, dst = 0;
+       for (src = 0; src < list->nr; src++) {
+               if (want(&list->items[src], cb_data)) {
+                       list->items[dst++] = list->items[src];
+               } else {
+                       if (list->strdup_strings)
+                               free(list->items[src].string);
+                       if (free_util)
+                               free(list->items[src].util);
+               }
+       }
+       list->nr = dst;
+}
+
+char *string_list_longest_prefix(const struct string_list *prefixes,
+                                const char *string)
+{
+       int i, max_len = -1;
+       char *retval = NULL;
+
+       for (i = 0; i < prefixes->nr; i++) {
+               char *prefix = prefixes->items[i].string;
+               if (!prefixcmp(string, prefix)) {
+                       int len = strlen(prefix);
+                       if (len > max_len) {
+                               retval = prefix;
+                               max_len = len;
+                       }
+               }
+       }
+
+       return retval;
+}
+
 void string_list_clear(struct string_list *list, int free_util)
 {
        if (list->items) {
@@ -148,13 +202,23 @@ void print_string_list(const struct string_list *p, const char *text)
                printf("%s:%p\n", p->items[i].string, p->items[i].util);
 }
 
-struct string_list_item *string_list_append(struct string_list *list, const char *string)
+struct string_list_item *string_list_append_nodup(struct string_list *list,
+                                                 char *string)
 {
+       struct string_list_item *retval;
        ALLOC_GROW(list->items, list->nr + 1, list->alloc);
-       list->items[list->nr].string =
-               list->strdup_strings ? xstrdup(string) : (char *)string;
-       list->items[list->nr].util = NULL;
-       return list->items + list->nr++;
+       retval = &list->items[list->nr++];
+       retval->string = string;
+       retval->util = NULL;
+       return retval;
+}
+
+struct string_list_item *string_list_append(struct string_list *list,
+                                           const char *string)
+{
+       return string_list_append_nodup(
+                       list,
+                       list->strdup_strings ? xstrdup(string) : (char *)string);
 }
 
 static int cmp_items(const void *a, const void *b)
@@ -194,3 +258,56 @@ void unsorted_string_list_delete_item(struct string_list *list, int i, int free_
        list->items[i] = list->items[list->nr-1];
        list->nr--;
 }
+
+int string_list_split(struct string_list *list, const char *string,
+                     int delim, int maxsplit)
+{
+       int count = 0;
+       const char *p = string, *end;
+
+       if (!list->strdup_strings)
+               die("internal error in string_list_split(): "
+                   "list->strdup_strings must be set");
+       for (;;) {
+               count++;
+               if (maxsplit >= 0 && count > maxsplit) {
+                       string_list_append(list, p);
+                       return count;
+               }
+               end = strchr(p, delim);
+               if (end) {
+                       string_list_append_nodup(list, xmemdupz(p, end - p));
+                       p = end + 1;
+               } else {
+                       string_list_append(list, p);
+                       return count;
+               }
+       }
+}
+
+int string_list_split_in_place(struct string_list *list, char *string,
+                              int delim, int maxsplit)
+{
+       int count = 0;
+       char *p = string, *end;
+
+       if (list->strdup_strings)
+               die("internal error in string_list_split_in_place(): "
+                   "list->strdup_strings must not be set");
+       for (;;) {
+               count++;
+               if (maxsplit >= 0 && count > maxsplit) {
+                       string_list_append(list, p);
+                       return count;
+               }
+               end = strchr(p, delim);
+               if (end) {
+                       *end = '\0';
+                       string_list_append(list, p);
+                       p = end + 1;
+               } else {
+                       string_list_append(list, p);
+                       return count;
+               }
+       }
+}
index 0684cb73bfd27846182479a4e192d682a44f201a..5efd07b44e020428326ff32ff258449ec347861f 100644 (file)
@@ -29,6 +29,24 @@ int for_each_string_list(struct string_list *list,
 #define for_each_string_list_item(item,list) \
        for (item = (list)->items; item < (list)->items + (list)->nr; ++item)
 
+/*
+ * Apply want to each item in list, retaining only the ones for which
+ * the function returns true.  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.
+ */
+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).
+ */
+char *string_list_longest_prefix(const struct string_list *prefixes, const char *string);
+
+
 /* Use these functions only on sorted lists: */
 int string_list_has_string(const struct string_list *list, const char *string);
 int string_list_find_insert_index(const struct string_list *list, const char *string,
@@ -38,11 +56,64 @@ struct string_list_item *string_list_insert_at_index(struct string_list *list,
                                                     int insert_at, const char *string);
 struct string_list_item *string_list_lookup(struct string_list *list, const char *string);
 
+/*
+ * Remove all but the first of consecutive entries with the same
+ * string value.  If free_util is true, call free() on the util
+ * members of any items that have to be deleted.
+ */
+void string_list_remove_duplicates(struct string_list *sorted_list, int free_util);
+
+
 /* Use these functions only on unsorted lists: */
+
+/*
+ * Add string to the end of list.  If list->strdup_string is set, then
+ * string is copied; otherwise the new string_list_entry refers to the
+ * input string.
+ */
 struct string_list_item *string_list_append(struct string_list *list, const char *string);
+
+/*
+ * Like string_list_append(), except string is never copied.  When
+ * list->strdup_strings is set, this function can be used to hand
+ * ownership of a malloc()ed string to list without making an extra
+ * copy.
+ */
+struct string_list_item *string_list_append_nodup(struct string_list *list, char *string);
+
 void sort_string_list(struct string_list *list);
 int unsorted_string_list_has_string(struct string_list *list, const char *string);
 struct string_list_item *unsorted_string_list_lookup(struct string_list *list,
                                                     const char *string);
+
 void unsorted_string_list_delete_item(struct string_list *list, int i, int free_util);
+
+/*
+ * Split string into substrings on character delim and append the
+ * substrings to list.  The input string is not modified.
+ * list->strdup_strings must be set, as new memory needs to be
+ * allocated to hold the substrings.  If maxsplit is non-negative,
+ * then split at most maxsplit times.  Return the number of substrings
+ * appended to list.
+ *
+ * Examples:
+ *   string_list_split(l, "foo:bar:baz", ':', -1) -> ["foo", "bar", "baz"]
+ *   string_list_split(l, "foo:bar:baz", ':', 0) -> ["foo:bar:baz"]
+ *   string_list_split(l, "foo:bar:baz", ':', 1) -> ["foo", "bar:baz"]
+ *   string_list_split(l, "foo:bar:", ':', -1) -> ["foo", "bar", ""]
+ *   string_list_split(l, "", ':', -1) -> [""]
+ *   string_list_split(l, ":", ':', -1) -> ["", ""]
+ */
+int string_list_split(struct string_list *list, const char *string,
+                     int delim, int maxsplit);
+
+/*
+ * Like string_list_split(), except that string is split in-place: the
+ * delimiter characters in string are overwritten with NULs, and the
+ * new string_list_items point into string (which therefore must not
+ * be modified or freed while the string_list is in use).
+ * list->strdup_strings must *not* be set.
+ */
+int string_list_split_in_place(struct string_list *list, char *string,
+                              int delim, int maxsplit);
 #endif /* STRING_LIST_H */
index 19dc6a6c0d5cf7d9a4c80c61e160290b4462665d..e3e0b455eae925996aa8ecf8bf931edd0638d1cc 100644 (file)
@@ -588,13 +588,13 @@ static void calculate_changed_submodule_paths(void)
        initialized_fetch_ref_tips = 0;
 }
 
-int fetch_populated_submodules(int num_options, const char **options,
+int fetch_populated_submodules(const struct argv_array *options,
                               const char *prefix, int command_line_option,
                               int quiet)
 {
-       int i, result = 0, argc = 0, default_argc;
+       int i, result = 0;
        struct child_process cp;
-       const char **argv;
+       struct argv_array argv = ARGV_ARRAY_INIT;
        struct string_list_item *name_for_path;
        const char *work_tree = get_git_work_tree();
        if (!work_tree)
@@ -604,17 +604,13 @@ int fetch_populated_submodules(int num_options, const char **options,
                if (read_cache() < 0)
                        die("index file corrupt");
 
-       /* 6: "fetch" (options) --recurse-submodules-default default "--submodule-prefix" prefix NULL */
-       argv = xcalloc(num_options + 6, sizeof(const char *));
-       argv[argc++] = "fetch";
-       for (i = 0; i < num_options; i++)
-               argv[argc++] = options[i];
-       argv[argc++] = "--recurse-submodules-default";
-       default_argc = argc++;
-       argv[argc++] = "--submodule-prefix";
+       argv_array_push(&argv, "fetch");
+       for (i = 0; i < options->argc; i++)
+               argv_array_push(&argv, options->argv[i]);
+       argv_array_push(&argv, "--recurse-submodules-default");
+       /* default value, "--submodule-prefix" and its value are added later */
 
        memset(&cp, 0, sizeof(cp));
-       cp.argv = argv;
        cp.env = local_repo_env;
        cp.git_cmd = 1;
        cp.no_stdin = 1;
@@ -674,16 +670,21 @@ int fetch_populated_submodules(int num_options, const char **options,
                        if (!quiet)
                                printf("Fetching submodule %s%s\n", prefix, ce->name);
                        cp.dir = submodule_path.buf;
-                       argv[default_argc] = default_argv;
-                       argv[argc] = submodule_prefix.buf;
+                       argv_array_push(&argv, default_argv);
+                       argv_array_push(&argv, "--submodule-prefix");
+                       argv_array_push(&argv, submodule_prefix.buf);
+                       cp.argv = argv.argv;
                        if (run_command(&cp))
                                result = 1;
+                       argv_array_pop(&argv);
+                       argv_array_pop(&argv);
+                       argv_array_pop(&argv);
                }
                strbuf_release(&submodule_path);
                strbuf_release(&submodule_git_dir);
                strbuf_release(&submodule_prefix);
        }
-       free(argv);
+       argv_array_clear(&argv);
 out:
        string_list_clear(&changed_submodule_paths, 1);
        return result;
@@ -758,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)
 {
@@ -788,7 +869,7 @@ static int find_first_merges(struct object_array *result, const char *path,
                die("revision walk setup failed");
        while ((commit = get_revision(&revs)) != NULL) {
                struct object *o = &(commit->object);
-               if (in_merge_bases(b, &commit, 1))
+               if (in_merge_bases(b, commit))
                        add_object_array(o, NULL, &merges);
        }
        reset_revision_walk();
@@ -803,7 +884,7 @@ static int find_first_merges(struct object_array *result, const char *path,
                contains_another = 0;
                for (j = 0; j < merges.nr; j++) {
                        struct commit *m2 = (struct commit *) merges.objects[j].item;
-                       if (i != j && in_merge_bases(m2, &m1, 1)) {
+                       if (i != j && in_merge_bases(m2, m1)) {
                                contains_another = 1;
                                break;
                        }
@@ -865,18 +946,18 @@ int merge_submodule(unsigned char result[20], const char *path,
        }
 
        /* check whether both changes are forward */
-       if (!in_merge_bases(commit_base, &commit_a, 1) ||
-           !in_merge_bases(commit_base, &commit_b, 1)) {
+       if (!in_merge_bases(commit_base, commit_a) ||
+           !in_merge_bases(commit_base, commit_b)) {
                MERGE_WARNING(path, "commits don't follow merge-base");
                return 0;
        }
 
        /* Case #1: a is contained in b or vice versa */
-       if (in_merge_bases(commit_a, &commit_b, 1)) {
+       if (in_merge_bases(commit_a, commit_b)) {
                hashcpy(result, b);
                return 1;
        }
-       if (in_merge_bases(commit_b, &commit_a, 1)) {
+       if (in_merge_bases(commit_b, commit_a)) {
                hashcpy(result, a);
                return 1;
        }
index e105b0ebe6c06a03af7f82bdfbc9beb66377544f..f2e8271fc68c3b1e78d200e2af374a77f253f1ee 100644 (file)
@@ -2,6 +2,7 @@
 #define SUBMODULE_H
 
 struct diff_options;
+struct argv_array;
 
 enum {
        RECURSE_SUBMODULES_ON_DEMAND = -1,
@@ -23,10 +24,12 @@ void show_submodule_summary(FILE *f, const char *path,
                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]);
-int fetch_populated_submodules(int num_options, const char **options,
+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 290036744bcfd390f91e75db49bf620bb12c12ea..c2b41a85013eec87a412badc4097f364d547726d 100644 (file)
@@ -1,5 +1,8 @@
 #include "cache.h"
 
+static int threaded_check_leading_path(struct cache_def *cache, const char *name, int len);
+static int threaded_has_dirs_only_path(struct cache_def *cache, const char *name, int len, int prefix_len);
+
 /*
  * Returns the length (on a path component basis) of the longest
  * common prefix match of 'name_a' and 'name_b'.
@@ -231,7 +234,7 @@ int check_leading_path(const char *name, int len)
  * Return path length if leading path exists and is neither a
  * directory nor a symlink.
  */
-int threaded_check_leading_path(struct cache_def *cache, const char *name, int len)
+static int threaded_check_leading_path(struct cache_def *cache, const char *name, int len)
 {
        int flags;
        int match_len = lstat_cache_matchlen(cache, name, len, &flags,
@@ -263,7 +266,7 @@ int has_dirs_only_path(const char *name, int len, int prefix_len)
  * 'prefix_len', thus we then allow for symlinks in the prefix part as
  * long as those points to real existing directories.
  */
-int threaded_has_dirs_only_path(struct cache_def *cache, const char *name, int len, int prefix_len)
+static int threaded_has_dirs_only_path(struct cache_def *cache, const char *name, int len, int prefix_len)
 {
        return lstat_cache(cache, name, len,
                           FL_DIR|FL_FULLPATH, prefix_len) &
diff --git a/t/Git-SVN/00compile.t b/t/Git-SVN/00compile.t
new file mode 100644 (file)
index 0000000..c92fee4
--- /dev/null
@@ -0,0 +1,14 @@
+#!/usr/bin/env perl
+
+use strict;
+use warnings;
+
+use Test::More tests => 7;
+
+require_ok 'Git::SVN';
+require_ok 'Git::SVN::Utils';
+require_ok 'Git::SVN::Ra';
+require_ok 'Git::SVN::Log';
+require_ok 'Git::SVN::Migration';
+require_ok 'Git::IndexInfo';
+require_ok 'Git::SVN::GlobSpec';
diff --git a/t/Git-SVN/Utils/add_path_to_url.t b/t/Git-SVN/Utils/add_path_to_url.t
new file mode 100644 (file)
index 0000000..bfbd878
--- /dev/null
@@ -0,0 +1,27 @@
+#!/usr/bin/env perl
+
+use strict;
+use warnings;
+
+use Test::More 'no_plan';
+
+use Git::SVN::Utils qw(
+       add_path_to_url
+);
+
+# A reference cannot be a hash key, so we use an array.
+my @tests = (
+       ["http://x.com", "bar"]                 => 'http://x.com/bar',
+       ["http://x.com", ""]                    => 'http://x.com',
+       ["http://x.com/foo/", undef]            => 'http://x.com/foo/',
+       ["http://x.com/foo/", "/bar/baz/"]      => 'http://x.com/foo/bar/baz/',
+       ["http://x.com", 'per%cent']            => 'http://x.com/per%25cent',
+);
+
+while(@tests) {
+       my($have, $want) = splice @tests, 0, 2;
+
+       my $args = join ", ", map { qq['$_'] } map { defined($_) ? $_ : 'undef' } @$have;
+       my $name = "add_path_to_url($args) eq $want";
+       is add_path_to_url(@$have), $want, $name;
+}
diff --git a/t/Git-SVN/Utils/can_compress.t b/t/Git-SVN/Utils/can_compress.t
new file mode 100644 (file)
index 0000000..d7b49b8
--- /dev/null
@@ -0,0 +1,11 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Test::More 'no_plan';
+
+use Git::SVN::Utils qw(can_compress);
+
+# !! is the "convert this to boolean" operator.
+is !!can_compress(), !!eval { require Compress::Zlib };
diff --git a/t/Git-SVN/Utils/canonicalize_url.t b/t/Git-SVN/Utils/canonicalize_url.t
new file mode 100644 (file)
index 0000000..05795ab
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/env perl
+
+# Test our own home rolled URL canonicalizer.  Test the private one
+# directly because we can't predict what the SVN API is doing to do.
+
+use strict;
+use warnings;
+
+use Test::More 'no_plan';
+
+use Git::SVN::Utils;
+my $canonicalize_url = \&Git::SVN::Utils::_canonicalize_url_ourselves;
+
+my %tests = (
+       "http://x.com"                  => "http://x.com",
+       "http://x.com/"                 => "http://x.com",
+       "http://x.com/foo/bar"          => "http://x.com/foo/bar",
+       "http://x.com//foo//bar//"      => "http://x.com/foo/bar",
+       "http://x.com/  /%/"            => "http://x.com/%20%20/%25",
+);
+
+for my $arg (keys %tests) {
+       my $want = $tests{$arg};
+
+       is $canonicalize_url->($arg), $want, "canonicalize_url('$arg') => $want";
+}
diff --git a/t/Git-SVN/Utils/collapse_dotdot.t b/t/Git-SVN/Utils/collapse_dotdot.t
new file mode 100644 (file)
index 0000000..1da1cce
--- /dev/null
@@ -0,0 +1,23 @@
+#!/usr/bin/env perl
+
+use strict;
+use warnings;
+
+use Test::More 'no_plan';
+
+use Git::SVN::Utils;
+my $collapse_dotdot = \&Git::SVN::Utils::_collapse_dotdot;
+
+my %tests = (
+       "foo/bar/baz"                   => "foo/bar/baz",
+       ".."                            => "..",
+       "foo/.."                        => "",
+       "/foo/bar/../../baz"            => "/baz",
+       "deeply/.././deeply/nested"     => "./deeply/nested",
+);
+
+for my $arg (keys %tests) {
+       my $want = $tests{$arg};
+
+       is $collapse_dotdot->($arg), $want, "_collapse_dotdot('$arg') => $want";
+}
diff --git a/t/Git-SVN/Utils/fatal.t b/t/Git-SVN/Utils/fatal.t
new file mode 100644 (file)
index 0000000..49e1438
--- /dev/null
@@ -0,0 +1,34 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Test::More 'no_plan';
+
+BEGIN {
+       # Override exit at BEGIN time before Git::SVN::Utils is loaded
+       # so it will see our local exit later.
+       *CORE::GLOBAL::exit = sub(;$) {
+       return @_ ? CORE::exit($_[0]) : CORE::exit();
+       };
+}
+
+use Git::SVN::Utils qw(fatal);
+
+# fatal()
+{
+       # Capture the exit code and prevent exit.
+       my $exit_status;
+       no warnings 'redefine';
+       local *CORE::GLOBAL::exit = sub { $exit_status = $_[0] || 0 };
+
+       # Trap fatal's message to STDERR
+       my $stderr;
+       close STDERR;
+       ok open STDERR, ">", \$stderr;
+
+       fatal "Some", "Stuff", "Happened";
+
+       is $stderr, "Some Stuff Happened\n";
+       is $exit_status, 1;
+}
diff --git a/t/Git-SVN/Utils/join_paths.t b/t/Git-SVN/Utils/join_paths.t
new file mode 100644 (file)
index 0000000..d4488e7
--- /dev/null
@@ -0,0 +1,32 @@
+#!/usr/bin/env perl
+
+use strict;
+use warnings;
+
+use Test::More 'no_plan';
+
+use Git::SVN::Utils qw(
+       join_paths
+);
+
+# A reference cannot be a hash key, so we use an array.
+my @tests = (
+       []                                      => '',
+       ["/x.com", "bar"]                       => '/x.com/bar',
+       ["x.com", ""]                           => 'x.com',
+       ["/x.com/foo/", undef, "bar"]           => '/x.com/foo/bar',
+       ["x.com/foo/", "/bar/baz/"]             => 'x.com/foo/bar/baz/',
+       ["foo", "bar"]                          => 'foo/bar',
+       ["/foo/bar", "baz", "/biff"]            => '/foo/bar/baz/biff',
+       ["", undef, "."]                        => '.',
+       []                                      => '',
+
+);
+
+while(@tests) {
+       my($have, $want) = splice @tests, 0, 2;
+
+       my $args = join ", ", map { qq['$_'] } map { defined($_) ? $_ : 'undef' } @$have;
+       my $name = "join_paths($args) eq '$want'";
+       is join_paths(@$have), $want, $name;
+}
index 4c3ea25e6649007c9dde7ae4570d6311824051b6..e4128e5769722473f7fd1024fdf8a5100bd8ccf6 100644 (file)
--- a/t/README
+++ b/t/README
@@ -625,6 +625,15 @@ use these, and "test_set_prereq" for how to define your own.
    Git was compiled with USE_LIBPCRE=YesPlease. Wrap any tests
    that use git-grep --perl-regexp or git-grep -P in these.
 
+ - CASE_INSENSITIVE_FS
+
+   Test is run on a case insensitive file system.
+
+ - UTF8_NFD_TO_NFC
+
+   Test is run on a filesystem which converts decomposed utf-8 (nfd)
+   to precomposed utf-8 (nfc).
+
 Tips for Writing Tests
 ----------------------
 
diff --git a/t/lib-bash.sh b/t/lib-bash.sh
new file mode 100644 (file)
index 0000000..11397f7
--- /dev/null
@@ -0,0 +1,18 @@
+#!/bin/sh
+#
+# Ensures that tests are run under Bash; primarily intended for running tests
+# of the completion script.
+
+if test -n "$BASH" && test -z "$POSIXLY_CORRECT"; then
+       # we are in full-on bash mode
+       true
+elif type bash >/dev/null 2>&1; then
+       # execute in full-on bash mode
+       unset POSIXLY_CORRECT
+       exec bash "$0" "$@"
+else
+       echo '1..0 #SKIP skipping bash completion tests; bash not available'
+       exit 0
+fi
+
+. ./test-lib.sh
index 4a37cd79e585e86572b5bc6f127bbee33af998b3..3c43ff11b305c5d533323c1ed9520ac52d0cfbe3 100755 (executable)
@@ -4,10 +4,24 @@
 # stdout and stderr should be provided on stdin,
 # separated by "--".
 check() {
+       credential_opts=
+       credential_cmd=$1
+       shift
+       for arg in "$@"; do
+               credential_opts="$credential_opts -c credential.helper='$arg'"
+       done
        read_chunk >stdin &&
        read_chunk >expect-stdout &&
        read_chunk >expect-stderr &&
-       test-credential "$@" <stdin >stdout 2>stderr &&
+       if ! eval "git $credential_opts credential $credential_cmd <stdin >stdout 2>stderr"; then
+               echo "git credential failed with code $?" &&
+               cat stderr &&
+               false
+       fi &&
+       if test_have_prereq MINGW
+       then
+               dos2unix -q stderr
+       fi &&
        test_cmp expect-stdout stdout &&
        test_cmp expect-stderr stderr
 }
@@ -41,7 +55,7 @@ reject() {
                echo protocol=$2
                echo host=$3
                echo username=$4
-       ) | test-credential reject $1
+       ) | git -c credential.helper=$1 credential reject
 }
 
 helper_test() {
@@ -52,6 +66,8 @@ helper_test() {
                protocol=https
                host=example.com
                --
+               protocol=https
+               host=example.com
                username=askpass-username
                password=askpass-password
                --
@@ -74,6 +90,8 @@ helper_test() {
                protocol=https
                host=example.com
                --
+               protocol=https
+               host=example.com
                username=store-user
                password=store-pass
                --
@@ -85,6 +103,8 @@ helper_test() {
                protocol=http
                host=example.com
                --
+               protocol=http
+               host=example.com
                username=askpass-username
                password=askpass-password
                --
@@ -98,6 +118,8 @@ helper_test() {
                protocol=https
                host=other.tld
                --
+               protocol=https
+               host=other.tld
                username=askpass-username
                password=askpass-password
                --
@@ -112,6 +134,8 @@ helper_test() {
                host=example.com
                username=other
                --
+               protocol=https
+               host=example.com
                username=other
                password=askpass-password
                --
@@ -133,6 +157,9 @@ helper_test() {
                host=path.tld
                path=bar.git
                --
+               protocol=http
+               host=path.tld
+               path=bar.git
                username=askpass-username
                password=askpass-password
                --
@@ -150,6 +177,8 @@ helper_test() {
                protocol=https
                host=example.com
                --
+               protocol=https
+               host=example.com
                username=askpass-username
                password=askpass-password
                --
@@ -176,6 +205,8 @@ helper_test() {
                host=example.com
                username=user1
                --
+               protocol=https
+               host=example.com
                username=user1
                password=pass1
                EOF
@@ -184,6 +215,8 @@ helper_test() {
                host=example.com
                username=user2
                --
+               protocol=https
+               host=example.com
                username=user2
                password=pass2
                EOF
@@ -200,6 +233,8 @@ helper_test() {
                host=example.com
                username=user1
                --
+               protocol=https
+               host=example.com
                username=user1
                password=askpass-password
                --
@@ -213,6 +248,8 @@ helper_test() {
                host=example.com
                username=user2
                --
+               protocol=https
+               host=example.com
                username=user2
                password=pass2
                EOF
@@ -234,6 +271,8 @@ helper_test_timeout() {
                protocol=https
                host=timeout.tld
                --
+               protocol=https
+               host=timeout.tld
                username=askpass-username
                password=askpass-password
                --
index 121e38002bc73807649ebcc5df2799f6f35a9c67..7061dce7e5de2f67e60fe6c42c40519f29cad4a1 100644 (file)
@@ -2,6 +2,10 @@
 # Library code for git p4 tests
 #
 
+# p4 tests never use the top-level repo; always build/clone into
+# a subdirectory called "$git"
+TEST_NO_CREATE_REPO=NoThanks
+
 . ./test-lib.sh
 
 if ! test_have_prereq PYTHON; then
@@ -22,28 +26,54 @@ testid=${this_test#t}
 git_p4_test_start=9800
 P4DPORT=$((10669 + ($testid - $git_p4_test_start)))
 
-export P4PORT=localhost:$P4DPORT
-export P4CLIENT=client
-export P4EDITOR=:
+P4PORT=localhost:$P4DPORT
+P4CLIENT=client
+P4EDITOR=:
+export P4PORT P4CLIENT P4EDITOR
 
 db="$TRASH_DIRECTORY/db"
-cli="$TRASH_DIRECTORY/cli"
+cli=$(test-path-utils real_path "$TRASH_DIRECTORY/cli")
 git="$TRASH_DIRECTORY/git"
 pidfile="$TRASH_DIRECTORY/p4d.pid"
 
 start_p4d() {
        mkdir -p "$db" "$cli" "$git" &&
+       rm -f "$pidfile" &&
        (
                p4d -q -r "$db" -p $P4DPORT &
                echo $! >"$pidfile"
        ) &&
-       for i in 1 2 3 4 5 ; do
-               p4 info >/dev/null 2>&1 && break || true &&
-               echo waiting for p4d to start &&
+
+       # This gives p4d a long time to start up, as it can be
+       # quite slow depending on the machine.  Set this environment
+       # variable to something smaller to fail faster in, say,
+       # an automated test setup.  If the p4d process dies, that
+       # will be caught with the "kill -0" check below.
+       i=${P4D_START_PATIENCE:-300}
+       pid=$(cat "$pidfile")
+       ready=
+       while test $i -gt 0
+       do
+               # succeed when p4 client commands start to work
+               if p4 info >/dev/null 2>&1
+               then
+                       ready=true
+                       break
+               fi
+               # fail if p4d died
+               kill -0 $pid 2>/dev/null || break
+               echo waiting for p4d to start
                sleep 1
-       done &&
-       # complain if it never started
-       p4 info >/dev/null &&
+               i=$(( $i - 1 ))
+       done
+
+       if test -z "$ready"
+       then
+               # p4d failed to start
+               return 1
+       fi
+
+       # build a client
        (
                cd "$cli" &&
                p4 client -i <<-EOF
@@ -53,6 +83,7 @@ start_p4d() {
                View: //depot/... //client/...
                EOF
        )
+       return 0
 }
 
 kill_p4d() {
@@ -69,5 +100,36 @@ kill_p4d() {
 }
 
 cleanup_git() {
-       rm -rf "$git"
+       rm -rf "$git" &&
+       mkdir "$git"
+}
+
+marshal_dump() {
+       what=$1 &&
+       line=${2:-1} &&
+       cat >"$TRASH_DIRECTORY/marshal-dump.py" <<-EOF &&
+       import marshal
+       import sys
+       for i in range($line):
+           d = marshal.load(sys.stdin)
+       print d['$what']
+       EOF
+       "$PYTHON_PATH" "$TRASH_DIRECTORY/marshal-dump.py"
+}
+
+#
+# Construct a client with this list of View lines
+#
+client_view() {
+       (
+               cat <<-EOF &&
+               Client: client
+               Description: client
+               Root: $cli
+               View:
+               EOF
+               for arg ; do
+                       printf "\t$arg\n"
+               done
+       ) | p4 client -i
 }
index 0f31ef9be487759829c141031f8925167b135537..02f442bfadbb1239785a456cddc50223da4f3834 100644 (file)
@@ -43,6 +43,10 @@ TEST_PATH="$TEST_DIRECTORY"/lib-httpd
 HTTPD_ROOT_PATH="$PWD"/httpd
 HTTPD_DOCUMENT_ROOT_PATH=$HTTPD_ROOT_PATH/www
 
+# hack to suppress apache PassEnv warnings
+GIT_VALGRIND=$GIT_VALGRIND; export GIT_VALGRIND
+GIT_VALGRIND_OPTIONS=$GIT_VALGRIND_OPTIONS; export GIT_VALGRIND_OPTIONS
+
 if ! test -x "$LIB_HTTPD_PATH"
 then
        skip_all="skipping test, no web server found at '$LIB_HTTPD_PATH'"
index ec8618dfde3b106c79f1d056bc0ed085075fc8c8..49d5d877ceeeba3738b0939f14d059c2a75ff3ae 100644 (file)
@@ -42,6 +42,9 @@ ErrorLog error.log
 </IfModule>
 </IfVersion>
 
+PassEnv GIT_VALGRIND
+PassEnv GIT_VALGRIND_OPTIONS
+
 Alias /dumb/ www/
 Alias /auth/dumb/ www/auth/dumb/
 
@@ -60,7 +63,7 @@ Alias /auth/dumb/ www/auth/dumb/
 </LocationMatch>
 ScriptAliasMatch /smart_*[^/]*/(.*) ${GIT_EXEC_PATH}/git-http-backend/$1
 <Directory ${GIT_EXEC_PATH}>
-       Options None
+       Options FollowSymlinks
 </Directory>
 <Files ${GIT_EXEC_PATH}/git-http-backend>
        Options ExecCGI
index 50f5cc1ed901e5abd7839dcb58ff94aa96a9c641..982eb8e3a949a74e5c26a952a33364c25f6f5b74 100644 (file)
@@ -1,2 +1,3 @@
-build/
-test-results/
+/build/
+/test-results/
+/trash directory*/
index a1361e530c60609a52948dd0fd35642d57f84486..a816fbcb7618bb8cdbf1f74a4fd2295923c02ea3 100644 (file)
@@ -42,6 +42,7 @@ else
 fi
 
 TEST_NO_CREATE_REPO=t
+TEST_NO_MALLOC_CHECK=t
 
 . ../test-lib.sh
 
index ccb5435b2a7dd4724f3bc8e0b0186f248dbad448..08677df10e9d2a4c87fbe1e5d24eb836b1117e64 100755 (executable)
@@ -18,16 +18,6 @@ swapping compression and hashing order, the person who is making the
 modification *should* take notice and update the test vectors here.
 '
 
-################################################################
-# It appears that people try to run tests without building...
-
-../git >/dev/null
-if test $? != 1
-then
-       echo >&2 'You do not seem to have built git yet.'
-       exit 1
-fi
-
 . ./test-lib.sh
 
 ################################################################
@@ -450,24 +440,6 @@ test_expect_success 'update-index D/F conflict' '
        test $numpath0 = 1
 '
 
-test_expect_success SYMLINKS 'real path works as expected' '
-       mkdir first &&
-       ln -s ../.git first/.git &&
-       mkdir second &&
-       ln -s ../first second/other &&
-       mkdir third &&
-       dir="$(cd .git; pwd -P)" &&
-       dir2=third/../second/other/.git &&
-       test "$dir" = "$(test-path-utils real_path $dir2)" &&
-       file="$dir"/index &&
-       test "$file" = "$(test-path-utils real_path $dir2/index)" &&
-       basename=blub &&
-       test "$dir/$basename" = "$(cd .git && test-path-utils real_path "$basename")" &&
-       ln -s ../first/file .git/syml &&
-       sym="$(cd first; pwd -P)"/file &&
-       test "$sym" = "$(test-path-utils real_path "$dir2/syml")"
-'
-
 test_expect_success 'very long name in the index handled sanely' '
 
        a=a && # 1
index 51f3045ba4bde549b06ea669b1877f0e2db7c401..807b8b88e215df5ce39504b1858be8694499727d 100755 (executable)
@@ -123,16 +123,6 @@ test_expect_success 'attribute matching is case insensitive when core.ignorecase
 
 '
 
-test_expect_success 'check whether FS is case-insensitive' '
-       mkdir junk &&
-       echo good >junk/CamelCase &&
-       echo bad >junk/camelcase &&
-       if test "$(cat junk/CamelCase)" != good
-       then
-               test_set_prereq CASE_INSENSITIVE_FS
-       fi
-'
-
 test_expect_success CASE_INSENSITIVE_FS 'additional case insensitivity tests' '
        test_must_fail attr_check a/B/D/g "a/b/d/*" "-c core.ignorecase=0" &&
        test_must_fail attr_check A/B/D/NO "a/b/d/*" "-c core.ignorecase=0" &&
@@ -206,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
index 1d29810a7a94dad15645869c2f4f015a470fa622..e53cf6d36d573c3d758f0005c95aa4a364df82b1 100755 (executable)
@@ -11,7 +11,7 @@ check_show() {
        echo "$t -> $2" >expect
        test_expect_${3:-success} "relative date ($2)" "
        test-date show $t >actual &&
-       test_cmp expect actual
+       test_i18ncmp expect actual
        "
 }
 
index e3f354a45e382dbaa9de4557aa9310fa21eb626b..244a43c9201a3d81d0931f5f127bd2dcfd068eba 100755 (executable)
@@ -51,7 +51,7 @@ EOF
 test_expect_success 'test help' '
        test_must_fail test-parse-options -h > output 2> output.err &&
        test ! -s output.err &&
-       test_cmp expect output
+       test_i18ncmp expect output
 '
 
 mv expect expect.err
@@ -79,6 +79,17 @@ check() {
        test_cmp expect output
 }
 
+check_i18n() {
+       what="$1" &&
+       shift &&
+       expect="$1" &&
+       shift &&
+       sed "s/^$what .*/$what $expect/" <expect.template >expect &&
+       test-parse-options $* >output 2>output.err &&
+       test ! -s output.err &&
+       test_i18ncmp expect output
+}
+
 check_unknown() {
        case "$1" in
        --*)
@@ -92,6 +103,19 @@ check_unknown() {
        test_cmp expect output.err
 }
 
+check_unknown_i18n() {
+       case "$1" in
+       --*)
+               echo error: unknown option \`${1#--}\' >expect ;;
+       -*)
+               echo error: unknown switch \`${1#-}\' >expect ;;
+       esac &&
+       cat expect.err >>expect &&
+       test_must_fail test-parse-options $* >output 2>output.err &&
+       test ! -s output &&
+       test_i18ncmp expect output.err
+}
+
 test_expect_success 'OPT_BOOL() #1' 'check boolean: 1 --yes'
 test_expect_success 'OPT_BOOL() #2' 'check boolean: 1 --no-doubt'
 test_expect_success 'OPT_BOOL() #3' 'check boolean: 1 -D'
@@ -104,8 +128,8 @@ test_expect_success 'OPT_BOOL() is idempotent #2' 'check boolean: 1 -DB'
 test_expect_success 'OPT_BOOL() negation #1' 'check boolean: 0 -D --no-yes'
 test_expect_success 'OPT_BOOL() negation #2' 'check boolean: 0 -D --no-no-doubt'
 
-test_expect_success 'OPT_BOOL() no negation #1' 'check_unknown --fear'
-test_expect_success 'OPT_BOOL() no negation #2' 'check_unknown --no-no-fear'
+test_expect_success 'OPT_BOOL() no negation #1' 'check_unknown_i18n --fear'
+test_expect_success 'OPT_BOOL() no negation #2' 'check_unknown_i18n --no-no-fear'
 
 test_expect_success 'OPT_BOOL() positivation' 'check boolean: 0 -D --doubt'
 
@@ -310,8 +334,8 @@ EOF
 
 test_expect_success 'OPT_CALLBACK() and callback errors work' '
        test_must_fail test-parse-options --no-length > output 2> output.err &&
-       test_cmp expect output &&
-       test_cmp expect.err output.err
+       test_i18ncmp expect output &&
+       test_i18ncmp expect.err output.err
 '
 
 cat > expect <<EOF
index 1542cf6a1313963fccdf42702c620be9e05f7143..78816d9d935df478f5cdf93e06fae26cc5488910 100755 (executable)
@@ -7,48 +7,26 @@ test_description='Various filesystem issues'
 auml=$(printf '\303\244')
 aumlcdiar=$(printf '\141\314\210')
 
-case_insensitive=
-unibad=
-no_symlinks=
-test_expect_success 'see what we expect' '
-
-       test_case=test_expect_success &&
-       test_unicode=test_expect_success &&
-       mkdir junk &&
-       echo good >junk/CamelCase &&
-       echo bad >junk/camelcase &&
-       if test "$(cat junk/CamelCase)" != good
-       then
-               test_case=test_expect_failure &&
-               case_insensitive=t
-       fi &&
-       rm -fr junk &&
-       mkdir junk &&
-       >junk/"$auml" &&
-       case "$(cd junk && echo *)" in
-       "$aumlcdiar")
-               test_unicode=test_expect_failure &&
-               unibad=t
-               ;;
-       *)      ;;
-       esac &&
-       rm -fr junk &&
-       {
-               ln -s x y 2> /dev/null &&
-               test -h y 2> /dev/null ||
-               no_symlinks=1 &&
-               rm -f y
-       }
-'
-
-test "$case_insensitive" &&
+if test_have_prereq CASE_INSENSITIVE_FS
+then
        say "will test on a case insensitive filesystem"
-test "$unibad" &&
+       test_case=test_expect_failure
+else
+       test_case=test_expect_success
+fi
+
+if test_have_prereq UTF8_NFD_TO_NFC
+then
        say "will test on a unicode corrupting filesystem"
-test "$no_symlinks" &&
+       test_unicode=test_expect_failure
+else
+       test_unicode=test_expect_success
+fi
+
+test_have_prereq SYMLINKS ||
        say "will test on a filesystem lacking symbolic links"
 
-if test "$case_insensitive"
+if test_have_prereq CASE_INSENSITIVE_FS
 then
 test_expect_success "detection of case insensitive filesystem during repo init" '
 
@@ -62,18 +40,18 @@ test_expect_success "detection of case insensitive filesystem during repo init"
 '
 fi
 
-if test "$no_symlinks"
+if test_have_prereq SYMLINKS
 then
 test_expect_success "detection of filesystem w/o symlink support during repo init" '
 
-       v=$(git config --bool core.symlinks) &&
-       test "$v" = false
+       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" '
 
-       test_must_fail git config --bool core.symlinks ||
-       test "$(git config --bool core.symlinks)" = true
+       v=$(git config --bool core.symlinks) &&
+       test "$v" = false
 '
 fi
 
index 53cf1f8dc4acad959fdec359b738387aeb126b1e..4ef2345982fe0e0c175ed67edcb20b04c81b9680 100755 (executable)
@@ -139,4 +139,63 @@ test_expect_success 'strip_path_suffix' '
        test c:/msysgit = $(test-path-utils strip_path_suffix \
                c:/msysgit/libexec//git-core libexec/git-core)
 '
+
+test_expect_success 'absolute path rejects the empty string' '
+       test_must_fail test-path-utils absolute_path ""
+'
+
+test_expect_success 'real path rejects the empty string' '
+       test_must_fail test-path-utils real_path ""
+'
+
+test_expect_success POSIX 'real path works on absolute paths 1' '
+       nopath="hopefully-absent-path" &&
+       test "/" = "$(test-path-utils real_path "/")" &&
+       test "/$nopath" = "$(test-path-utils real_path "/$nopath")"
+'
+
+test_expect_success 'real path works on absolute paths 2' '
+       nopath="hopefully-absent-path" &&
+       # Find an existing top-level directory for the remaining tests:
+       d=$(pwd -P | sed -e "s|^\([^/]*/[^/]*\)/.*|\1|") &&
+       test "$d" = "$(test-path-utils real_path "$d")" &&
+       test "$d/$nopath" = "$(test-path-utils real_path "$d/$nopath")"
+'
+
+test_expect_success POSIX 'real path removes extra leading slashes' '
+       nopath="hopefully-absent-path" &&
+       test "/" = "$(test-path-utils real_path "///")" &&
+       test "/$nopath" = "$(test-path-utils real_path "///$nopath")" &&
+       # Find an existing top-level directory for the remaining tests:
+       d=$(pwd -P | sed -e "s|^\([^/]*/[^/]*\)/.*|\1|") &&
+       test "$d" = "$(test-path-utils real_path "//$d")" &&
+       test "$d/$nopath" = "$(test-path-utils real_path "//$d/$nopath")"
+'
+
+test_expect_success 'real path removes other extra slashes' '
+       nopath="hopefully-absent-path" &&
+       # Find an existing top-level directory for the remaining tests:
+       d=$(pwd -P | sed -e "s|^\([^/]*/[^/]*\)/.*|\1|") &&
+       test "$d" = "$(test-path-utils real_path "$d///")" &&
+       test "$d/$nopath" = "$(test-path-utils real_path "$d///$nopath")"
+'
+
+test_expect_success SYMLINKS 'real path works on symlinks' '
+       mkdir first &&
+       ln -s ../.git first/.git &&
+       mkdir second &&
+       ln -s ../first second/other &&
+       mkdir third &&
+       dir="$(cd .git; pwd -P)" &&
+       dir2=third/../second/other/.git &&
+       test "$dir" = "$(test-path-utils real_path $dir2)" &&
+       file="$dir"/index &&
+       test "$file" = "$(test-path-utils real_path $dir2/index)" &&
+       basename=blub &&
+       test "$dir/$basename" = "$(cd .git && test-path-utils real_path "$basename")" &&
+       ln -s ../first/file .git/syml &&
+       sym="$(cd first; pwd -P)"/file &&
+       test "$sym" = "$(test-path-utils real_path "$dir2/syml")"
+'
+
 test_done
diff --git a/t/t0063-string-list.sh b/t/t0063-string-list.sh
new file mode 100755 (executable)
index 0000000..41c8826
--- /dev/null
@@ -0,0 +1,121 @@
+#!/bin/sh
+#
+# Copyright (c) 2012 Michael Haggerty
+#
+
+test_description='Test string list functionality'
+
+. ./test-lib.sh
+
+test_split () {
+       cat >expected &&
+       test_expect_success "split $1 at $2, max $3" "
+               test-string-list split '$1' '$2' '$3' >actual &&
+               test_cmp expected actual &&
+               test-string-list split_in_place '$1' '$2' '$3' >actual &&
+               test_cmp expected actual
+       "
+}
+
+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"
+[1]: "bar"
+[2]: "baz"
+EOF
+
+test_split "foo:bar:baz" ":" "0" <<EOF
+1
+[0]: "foo:bar:baz"
+EOF
+
+test_split "foo:bar:baz" ":" "1" <<EOF
+2
+[0]: "foo"
+[1]: "bar:baz"
+EOF
+
+test_split "foo:bar:baz" ":" "2" <<EOF
+3
+[0]: "foo"
+[1]: "bar"
+[2]: "baz"
+EOF
+
+test_split "foo:bar:" ":" "-1" <<EOF
+3
+[0]: "foo"
+[1]: "bar"
+[2]: ""
+EOF
+
+test_split "" ":" "-1" <<EOF
+1
+[0]: ""
+EOF
+
+test_split ":" ":" "-1" <<EOF
+2
+[0]: ""
+[1]: ""
+EOF
+
+test_expect_success "test filter_string_list" '
+       test "x-" = "x$(test-string-list filter - y)" &&
+       test "x-" = "x$(test-string-list filter no y)" &&
+       test yes = "$(test-string-list filter yes y)" &&
+       test yes = "$(test-string-list filter no:yes y)" &&
+       test yes = "$(test-string-list filter yes:no y)" &&
+       test y1:y2 = "$(test-string-list filter y1:y2 y)" &&
+       test y2:y1 = "$(test-string-list filter y2:y1 y)" &&
+       test "x-" = "x$(test-string-list filter x1:x2 y)"
+'
+
+test_expect_success "test remove_duplicates" '
+       test "x-" = "x$(test-string-list remove_duplicates -)" &&
+       test "x" = "x$(test-string-list remove_duplicates "")" &&
+       test a = "$(test-string-list remove_duplicates a)" &&
+       test a = "$(test-string-list remove_duplicates a:a)" &&
+       test a = "$(test-string-list remove_duplicates a:a:a:a:a)" &&
+       test a:b = "$(test-string-list remove_duplicates a:b)" &&
+       test a:b = "$(test-string-list remove_duplicates a:a:b)" &&
+       test a:b = "$(test-string-list remove_duplicates a:b:b)" &&
+       test a:b:c = "$(test-string-list remove_duplicates a:b:c)" &&
+       test a:b:c = "$(test-string-list remove_duplicates a:a:b:c)" &&
+       test a:b:c = "$(test-string-list remove_duplicates a:b:b:c)" &&
+       test a:b:c = "$(test-string-list remove_duplicates a:b:c:c)" &&
+       test a:b:c = "$(test-string-list remove_duplicates a:a:b:b:c:c)" &&
+       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 52b1c27c2c9d3c6111447df4fa241b724f0e6ee1..5d80a985fb709b2cd278f45555fcdeccf45ebb10 100755 (executable)
@@ -51,16 +51,16 @@ test_expect_success 'eval_gettext: our eval_gettext() fallback can interpolate v
 test_expect_success 'eval_gettext: our eval_gettext() fallback can interpolate variables with spaces' '
     cmdline="git am" &&
     export cmdline;
-    printf "When you have resolved this problem run git am --resolved." >expect &&
-    eval_gettext "When you have resolved this problem run \$cmdline --resolved." >actual
+    printf "When you have resolved this problem, run git am --resolved." >expect &&
+    eval_gettext "When you have resolved this problem, run \$cmdline --resolved." >actual
     test_i18ncmp expect actual
 '
 
 test_expect_success 'eval_gettext: our eval_gettext() fallback can interpolate variables with spaces and quotes' '
     cmdline="git am" &&
     export cmdline;
-    printf "When you have resolved this problem run \"git am --resolved\"." >expect &&
-    eval_gettext "When you have resolved this problem run \"\$cmdline --resolved\"." >actual
+    printf "When you have resolved this problem, run \"git am --resolved\"." >expect &&
+    eval_gettext "When you have resolved this problem, run \"\$cmdline --resolved\"." >actual
     test_i18ncmp expect actual
 '
 
index 20e28e34e7dc63aaf9ee9c6bdabcf311e0240615..538ea5fb1c27bf5e4f9c4a0268f219f5d6d6e9c5 100755 (executable)
@@ -82,6 +82,9 @@ test_expect_success 'credential_fill passes along metadata' '
        host=example.com
        path=foo.git
        --
+       protocol=ftp
+       host=example.com
+       path=foo.git
        username=one
        password=two
        --
@@ -213,6 +216,8 @@ test_expect_success 'match configured credential' '
        host=example.com
        path=repo.git
        --
+       protocol=https
+       host=example.com
        username=foo
        password=bar
        --
@@ -225,6 +230,8 @@ test_expect_success 'do not match configured credential' '
        protocol=https
        host=bar
        --
+       protocol=https
+       host=bar
        username=askpass-username
        password=askpass-password
        --
@@ -239,6 +246,8 @@ test_expect_success 'pull username from config' '
        protocol=https
        host=example.com
        --
+       protocol=https
+       host=example.com
        username=foo
        password=askpass-password
        --
@@ -252,6 +261,8 @@ test_expect_success 'http paths can be part of context' '
        host=example.com
        path=foo.git
        --
+       protocol=https
+       host=example.com
        username=foo
        password=bar
        --
@@ -265,6 +276,9 @@ test_expect_success 'http paths can be part of context' '
        host=example.com
        path=foo.git
        --
+       protocol=https
+       host=example.com
+       path=foo.git
        username=foo
        password=bar
        --
index 55ed955ceffee9184b5822054697f58e7d0ef6a4..fd105280092b7f655f5c48f09b2e8f5e0ee6d351 100755 (executable)
@@ -130,10 +130,27 @@ test_expect_success 'git-show a large file' '
 
 '
 
+test_expect_success 'index-pack' '
+       git clone file://"`pwd`"/.git foo &&
+       GIT_DIR=non-existent git index-pack --strict --verify foo/.git/objects/pack/*.pack
+'
+
 test_expect_success 'repack' '
        git repack -ad
 '
 
+test_expect_success 'pack-objects with large loose object' '
+       SHA1=`git hash-object huge` &&
+       test_create_repo loose &&
+       echo $SHA1 | git pack-objects --stdout |
+               GIT_ALLOC_LIMIT=0 GIT_DIR=loose/.git git unpack-objects &&
+       echo $SHA1 | GIT_DIR=loose/.git git pack-objects pack &&
+       test_create_repo packed &&
+       mv pack-* packed/.git/objects/pack &&
+       GIT_DIR=packed/.git git cat-file blob $SHA1 >actual &&
+       cmp huge actual
+'
+
 test_expect_success 'tar achiving' '
        git archive --format=tar HEAD >/dev/null
 '
index a3b77239f48ade053c3514c9ba65cd72286d0783..f8457f9d14c90349b0d3b09a3f695cbfafc3cbbf 100755 (executable)
@@ -47,6 +47,7 @@ test_expect_success \
 
 
 test_expect_success 'flags and then non flags' '
+       test_tick &&
        echo comment text |
        git commit-tree $(cat treeid) >commitid &&
        echo comment text |
index a477453e2ef8ffedafb2dd05e00f507cd112bc97..e127f35db9d12dba84cbf0503628ab5d9a3fc24f 100755 (executable)
@@ -391,7 +391,7 @@ test_expect_success 'get bool variable with empty value' \
 
 test_expect_success 'no arguments, but no crash' '
        test_must_fail git config >output 2>&1 &&
-       grep usage output
+       test_i18ngrep usage output
 '
 
 cat > .git/config << EOF
index 2b962cfda70d998e9c2799cf8fc720b330cd118a..79045abb5171691246167a42eec6bf18fbeb0b76 100755 (executable)
@@ -14,16 +14,15 @@ umask 077
 # We need an arbitrary other user give permission to using ACLs. root
 # is a good candidate: exists on all unices, and it has permission
 # anyway, so we don't create a security hole running the testsuite.
-
-setfacl_out="$(setfacl -m u:root:rwx . 2>&1)"
-setfacl_ret=$?
-
-if test $setfacl_ret != 0
-then
-       say "Unable to use setfacl (output: '$setfacl_out'; return code: '$setfacl_ret')"
-else
-       test_set_prereq SETFACL
-fi
+test_expect_success 'checking for a working acl setup' '
+       if setfacl -m d:m:rwx -m u:root:rwx . &&
+          getfacl . | grep user:root:rwx &&
+          touch should-have-readable-acl &&
+          getfacl should-have-readable-acl | egrep "mask::?rw-"
+       then
+               test_set_prereq SETFACL
+       fi
+'
 
 if test -z "$LOGNAME"
 then
diff --git a/t/t1306-xdg-files.sh b/t/t1306-xdg-files.sh
new file mode 100755 (executable)
index 0000000..8b14ab1
--- /dev/null
@@ -0,0 +1,197 @@
+#!/bin/sh
+#
+# Copyright (c) 2012 Valentin Duperray, Lucien Kong, Franck Jonas,
+#                   Thomas Nguy, Khoi Nguyen
+#                   Grenoble INP Ensimag
+#
+
+test_description='Compatibility with $XDG_CONFIG_HOME/git/ files'
+
+. ./test-lib.sh
+
+test_expect_success 'read config: xdg file exists and ~/.gitconfig doesn'\''t' '
+       mkdir -p .config/git &&
+       echo "[alias]" >.config/git/config &&
+       echo "  myalias = !echo in_config" >>.config/git/config &&
+       echo in_config >expected &&
+       git myalias >actual &&
+       test_cmp expected actual
+'
+
+
+test_expect_success 'read config: xdg file exists and ~/.gitconfig exists' '
+       >.gitconfig &&
+       echo "[alias]" >.gitconfig &&
+       echo "  myalias = !echo in_gitconfig" >>.gitconfig &&
+       echo in_gitconfig >expected &&
+       git myalias >actual &&
+       test_cmp expected actual
+'
+
+
+test_expect_success 'read with --get: xdg file exists and ~/.gitconfig doesn'\''t' '
+       rm .gitconfig &&
+       echo "[user]" >.config/git/config &&
+       echo "  name = read_config" >>.config/git/config &&
+       echo read_config >expected &&
+       git config --get user.name >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success '"$XDG_CONFIG_HOME overrides $HOME/.config/git' '
+       mkdir -p "$HOME"/xdg/git &&
+       echo "[user]name = in_xdg" >"$HOME"/xdg/git/config &&
+       echo in_xdg >expected &&
+       XDG_CONFIG_HOME="$HOME"/xdg git config --get-all user.name >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success 'read with --get: xdg file exists and ~/.gitconfig exists' '
+       >.gitconfig &&
+       echo "[user]" >.gitconfig &&
+       echo "  name = read_gitconfig" >>.gitconfig &&
+       echo read_gitconfig >expected &&
+       git config --get user.name >actual &&
+       test_cmp expected actual
+'
+
+
+test_expect_success 'read with --list: xdg file exists and ~/.gitconfig doesn'\''t' '
+       rm .gitconfig &&
+       echo user.name=read_config >expected &&
+       git config --global --list >actual &&
+       test_cmp expected actual
+'
+
+
+test_expect_success 'read with --list: xdg file exists and ~/.gitconfig exists' '
+       >.gitconfig &&
+       echo "[user]" >.gitconfig &&
+       echo "  name = read_gitconfig" >>.gitconfig &&
+       echo user.name=read_gitconfig >expected &&
+       git config --global --list >actual &&
+       test_cmp expected actual
+'
+
+
+test_expect_success 'Setup' '
+       git init git &&
+       cd git &&
+       echo foo >to_be_excluded
+'
+
+
+test_expect_success 'Exclusion of a file in the XDG ignore file' '
+       mkdir -p "$HOME"/.config/git/ &&
+       echo to_be_excluded >"$HOME"/.config/git/ignore &&
+       test_must_fail git add to_be_excluded
+'
+
+test_expect_success '$XDG_CONFIG_HOME overrides $HOME/.config/git/ignore' '
+       mkdir -p "$HOME"/xdg/git &&
+       echo content >excluded_by_xdg_only &&
+       echo excluded_by_xdg_only >"$HOME"/xdg/git/ignore &&
+       test_when_finished "git read-tree --empty" &&
+       (XDG_CONFIG_HOME="$HOME/xdg" &&
+        export XDG_CONFIG_HOME &&
+        git add to_be_excluded &&
+        test_must_fail git add excluded_by_xdg_only
+       )
+'
+
+test_expect_success 'Exclusion in both XDG and local ignore files' '
+       echo to_be_excluded >.gitignore &&
+       test_must_fail git add to_be_excluded
+'
+
+
+test_expect_success 'Exclusion in a non-XDG global ignore file' '
+       rm .gitignore &&
+       echo >"$HOME"/.config/git/ignore &&
+       echo to_be_excluded >"$HOME"/my_gitignore &&
+       git config core.excludesfile "$HOME"/my_gitignore &&
+       test_must_fail git add to_be_excluded
+'
+
+test_expect_success 'Checking XDG ignore file when HOME is unset' '
+       >expected &&
+       (sane_unset HOME &&
+        git config --unset core.excludesfile &&
+        git ls-files --exclude-standard --ignored >actual) &&
+       test_cmp expected actual
+'
+
+test_expect_success 'Checking attributes in the XDG attributes file' '
+       echo foo >f &&
+       git check-attr -a f >actual &&
+       test_line_count -eq 0 actual &&
+       echo "f attr_f" >"$HOME"/.config/git/attributes &&
+       echo "f: attr_f: set" >expected &&
+       git check-attr -a f >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success 'Checking XDG attributes when HOME is unset' '
+       >expected &&
+       (sane_unset HOME &&
+        git check-attr -a f >actual) &&
+       test_cmp expected actual
+'
+
+test_expect_success '$XDG_CONFIG_HOME overrides $HOME/.config/git/attributes' '
+       mkdir -p "$HOME"/xdg/git &&
+       echo "f attr_f=xdg" >"$HOME"/xdg/git/attributes &&
+       echo "f: attr_f: xdg" >expected &&
+       XDG_CONFIG_HOME="$HOME/xdg" git check-attr -a f >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success 'Checking attributes in both XDG and local attributes files' '
+       echo "f -attr_f" >.gitattributes &&
+       echo "f: attr_f: unset" >expected &&
+       git check-attr -a f >actual &&
+       test_cmp expected actual
+'
+
+
+test_expect_success 'Checking attributes in a non-XDG global attributes file' '
+       test_might_fail rm .gitattributes &&
+       echo "f attr_f=test" >"$HOME"/my_gitattributes &&
+       git config core.attributesfile "$HOME"/my_gitattributes &&
+       echo "f: attr_f: test" >expected &&
+       git check-attr -a f >actual &&
+       test_cmp expected actual
+'
+
+
+test_expect_success 'write: xdg file exists and ~/.gitconfig doesn'\''t' '
+       mkdir -p "$HOME"/.config/git &&
+       >"$HOME"/.config/git/config &&
+       test_might_fail rm "$HOME"/.gitconfig &&
+       git config --global user.name "write_config" &&
+       echo "[user]" >expected &&
+       echo "  name = write_config" >>expected &&
+       test_cmp expected "$HOME"/.config/git/config
+'
+
+
+test_expect_success 'write: xdg file exists and ~/.gitconfig exists' '
+       >"$HOME"/.gitconfig &&
+       git config --global user.name "write_gitconfig" &&
+       echo "[user]" >expected &&
+       echo "  name = write_gitconfig" >>expected &&
+       test_cmp expected "$HOME"/.gitconfig
+'
+
+
+test_expect_success 'write: ~/.config/git/ exists and config file doesn'\''t' '
+       test_might_fail rm "$HOME"/.gitconfig &&
+       test_might_fail rm "$HOME"/.config/git/config &&
+       git config --global user.name "write_gitconfig" &&
+       echo "[user]" >expected &&
+       echo "  name = write_gitconfig" >>expected &&
+       test_cmp expected "$HOME"/.gitconfig
+'
+
+
+test_done
index bf7a2cd6fb649e3b210b537d4d25312ba2921f16..08aa24ca15a377826b9e1cdad73fb232853aea7f 100755 (executable)
@@ -177,9 +177,7 @@ test_expect_success 'tag pointing to something else than its type' '
        test_when_finished "remove_object $tag" &&
        echo $tag >.git/refs/tags/wrong &&
        test_when_finished "git update-ref -d refs/tags/wrong" &&
-       test_must_fail git fsck --tags 2>out &&
-       cat out &&
-       grep "error in tag.*broken links" out
+       test_must_fail git fsck --tags
 '
 
 test_expect_success 'cleaned up' '
index 1efd7f76ddea8dbd788032c5a9076270d1159825..13c88c9aae7f7177cbff278cf5e587f86acb11e7 100755 (executable)
@@ -41,7 +41,7 @@ EOF
 
 test_expect_success 'test --parseopt help output' '
        test_expect_code 129 git rev-parse --parseopt -- -h > output < optionspec &&
-       test_cmp expect output
+       test_i18ncmp expect output
 '
 
 cat > expect <<EOF
diff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh
new file mode 100755 (executable)
index 0000000..6b3d797
--- /dev/null
@@ -0,0 +1,264 @@
+#!/bin/sh
+
+test_description='object name disambiguation
+
+Create blobs, trees, commits and a tag that all share the same
+prefix, and make sure "git rev-parse" can take advantage of
+type information to disambiguate short object names that are
+not necessarily unique.
+
+The final history used in the test has five commits, with the bottom
+one tagged as v1.0.0.  They all have one regular file each.
+
+  +-------------------------------------------+
+  |                                           |
+  |           .-------b3wettvi---- ad2uee     |
+  |          /                   /            |
+  |  a2onsxbvj---czy8f73t--ioiley5o           |
+  |                                           |
+  +-------------------------------------------+
+
+'
+
+. ./test-lib.sh
+
+test_expect_success 'blob and tree' '
+       test_tick &&
+       (
+               for i in 0 1 2 3 4 5 6 7 8 9
+               do
+                       echo $i
+               done
+               echo
+               echo b1rwzyc3
+       ) >a0blgqsjc &&
+
+       # create one blob 0000000000b36
+       git add a0blgqsjc &&
+
+       # create one tree 0000000000cdc
+       git write-tree
+'
+
+test_expect_success 'warn ambiguity when no candidate matches type hint' '
+       test_must_fail git rev-parse --verify 000000000^{commit} 2>actual &&
+       grep "short SHA1 000000000 is ambiguous" actual
+'
+
+test_expect_success 'disambiguate tree-ish' '
+       # feed tree-ish in an unambiguous way
+       git rev-parse --verify 0000000000cdc:a0blgqsjc &&
+
+       # ambiguous at the object name level, but there is only one
+       # such tree-ish (the other is a blob)
+       git rev-parse --verify 000000000:a0blgqsjc
+'
+
+test_expect_success 'disambiguate blob' '
+       sed -e "s/|$//" >patch <<-EOF &&
+       diff --git a/frotz b/frotz
+       index 000000000..ffffff 100644
+       --- a/frotz
+       +++ b/frotz
+       @@ -10,3 +10,4 @@
+        9
+        |
+        b1rwzyc3
+       +irwry
+       EOF
+       (
+               GIT_INDEX_FILE=frotz &&
+               export GIT_INDEX_FILE &&
+               git apply --build-fake-ancestor frotz patch &&
+               git cat-file blob :frotz >actual
+       ) &&
+       test_cmp a0blgqsjc actual
+'
+
+test_expect_success 'disambiguate tree' '
+       commit=$(echo "d7xm" | git commit-tree 000000000) &&
+       test $(git rev-parse $commit^{tree}) = $(git rev-parse 0000000000cdc)
+'
+
+test_expect_success 'first commit' '
+       # create one commit 0000000000e4f
+       git commit -m a2onsxbvj
+'
+
+test_expect_success 'disambiguate commit-ish' '
+       # feed commit-ish in an unambiguous way
+       git rev-parse --verify 0000000000e4f^{commit} &&
+
+       # ambiguous at the object name level, but there is only one
+       # such commit (the others are tree and blob)
+       git rev-parse --verify 000000000^{commit} &&
+
+       # likewise
+       git rev-parse --verify 000000000^0
+'
+
+test_expect_success 'disambiguate commit' '
+       commit=$(echo "hoaxj" | git commit-tree 0000000000cdc -p 000000000) &&
+       test $(git rev-parse $commit^) = $(git rev-parse 0000000000e4f)
+'
+
+test_expect_success 'log name1..name2 takes only commit-ishes on both ends' '
+       git log 000000000..000000000 &&
+       git log ..000000000 &&
+       git log 000000000.. &&
+       git log 000000000...000000000 &&
+       git log ...000000000 &&
+       git log 000000000...
+'
+
+test_expect_success 'rev-parse name1..name2 takes only commit-ishes on both ends' '
+       git rev-parse 000000000..000000000 &&
+       git rev-parse ..000000000 &&
+       git rev-parse 000000000..
+'
+
+test_expect_success 'git log takes only commit-ish' '
+       git log 000000000
+'
+
+test_expect_success 'git reset takes only commit-ish' '
+       git reset 000000000
+'
+
+test_expect_success 'first tag' '
+       # create one tag 0000000000f8f
+       git tag -a -m j7cp83um v1.0.0
+'
+
+test_expect_failure 'two semi-ambiguous commit-ish' '
+       # Once the parser becomes ultra-smart, it could notice that
+       # 110282 before ^{commit} name many different objects, but
+       # that only two (HEAD and v1.0.0 tag) can be peeled to commit,
+       # and that peeling them down to commit yield the same commit
+       # without ambiguity.
+       git rev-parse --verify 110282^{commit} &&
+
+       # likewise
+       git log 000000000..000000000 &&
+       git log ..000000000 &&
+       git log 000000000.. &&
+       git log 000000000...000000000 &&
+       git log ...000000000 &&
+       git log 000000000...
+'
+
+test_expect_failure 'three semi-ambiguous tree-ish' '
+       # Likewise for tree-ish.  HEAD, v1.0.0 and HEAD^{tree} share
+       # the prefix but peeling them to tree yields the same thing
+       git rev-parse --verify 000000000^{tree}
+'
+
+test_expect_success 'parse describe name' '
+       # feed an unambiguous describe name
+       git rev-parse --verify v1.0.0-0-g0000000000e4f &&
+
+       # ambiguous at the object name level, but there is only one
+       # such commit (others are blob, tree and tag)
+       git rev-parse --verify v1.0.0-0-g000000000
+'
+
+test_expect_success 'more history' '
+       # commit 0000000000043
+       git mv a0blgqsjc d12cr3h8t &&
+       echo h62xsjeu >>d12cr3h8t &&
+       git add d12cr3h8t &&
+
+       test_tick &&
+       git commit -m czy8f73t &&
+
+       # commit 00000000008ec
+       git mv d12cr3h8t j000jmpzn &&
+       echo j08bekfvt >>j000jmpzn &&
+       git add j000jmpzn &&
+
+       test_tick &&
+       git commit -m ioiley5o &&
+
+       # commit 0000000005b0
+       git checkout v1.0.0^0 &&
+       git mv a0blgqsjc f5518nwu &&
+
+       for i in h62xsjeu j08bekfvt kg7xflhm
+       do
+               echo $i
+       done >>f5518nwu &&
+       git add f5518nwu &&
+
+       test_tick &&
+       git commit -m b3wettvi &&
+       side=$(git rev-parse HEAD) &&
+
+       # commit 000000000066
+       git checkout master &&
+
+       # If you use recursive, merge will fail and you will need to
+       # clean up a0blgqsjc as well.  If you use resolve, merge will
+       # succeed.
+       test_might_fail git merge --no-commit -s recursive $side &&
+       git rm -f f5518nwu j000jmpzn &&
+
+       test_might_fail git rm -f a0blgqsjc &&
+       (
+               git cat-file blob $side:f5518nwu
+               echo j3l0i9s6
+       ) >ab2gs879 &&
+       git add ab2gs879 &&
+
+       test_tick &&
+       git commit -m ad2uee
+
+'
+
+test_expect_failure 'parse describe name taking advantage of generation' '
+       # ambiguous at the object name level, but there is only one
+       # such commit at generation 0
+       git rev-parse --verify v1.0.0-0-g000000000 &&
+
+       # likewise for generation 2 and 4
+       git rev-parse --verify v1.0.0-2-g000000000 &&
+       git rev-parse --verify v1.0.0-4-g000000000
+'
+
+# Note: because rev-parse does not even try to disambiguate based on
+# the generation number, this test currently succeeds for a wrong
+# reason.  When it learns to use the generation number, the previous
+# test should succeed, and also this test should fail because the
+# describe name used in the test with generation number can name two
+# commits.  Make sure that such a future enhancement does not randomly
+# pick one.
+test_expect_success 'parse describe name not ignoring ambiguity' '
+       # ambiguous at the object name level, and there are two such
+       # commits at generation 1
+       test_must_fail git rev-parse --verify v1.0.0-1-g000000000
+'
+
+test_expect_success 'ambiguous commit-ish' '
+       # Now there are many commits that begin with the
+       # common prefix, none of these should pick one at
+       # random.  They all should result in ambiguity errors.
+       test_must_fail git rev-parse --verify 110282^{commit} &&
+
+       # likewise
+       test_must_fail git log 000000000..000000000 &&
+       test_must_fail git log ..000000000 &&
+       test_must_fail git log 000000000.. &&
+       test_must_fail git log 000000000...000000000 &&
+       test_must_fail git log ...000000000 &&
+       test_must_fail git log 000000000...
+'
+
+test_expect_success 'rev-parse --disambiguate' '
+       # The test creates 16 objects that share the prefix and two
+       # commits created by commit-tree in earlier tests share a
+       # different prefix.
+       git rev-parse --disambiguate=000000000 >actual &&
+       test $(wc -l <actual) = 16 &&
+       test "$(sed -e "s/^\(.........\).*/\1/" actual | sort -u)" = 000000000
+'
+
+test_done
index b8559838b176ec8fa3c1d4acb71ae42ac71056c6..57cbdfe9bce93ddd33df08fec506be93e362db58 100755 (executable)
@@ -7,7 +7,7 @@ test_description='basic checkout-index tests
 
 test_expect_success 'checkout-index --gobbledegook' '
        test_expect_code 129 git checkout-index --gobbledegook 2>err &&
-       grep "[Uu]sage" err
+       test_i18ngrep "[Uu]sage" err
 '
 
 test_expect_success 'checkout-index -h in broken repository' '
@@ -18,7 +18,7 @@ test_expect_success 'checkout-index -h in broken repository' '
                >.git/index &&
                test_expect_code 129 git checkout-index -h >usage 2>&1
        ) &&
-       grep "[Uu]sage" broken/usage
+       test_i18ngrep "[Uu]sage" broken/usage
 '
 
 test_done
index 0dbbb00d740da8b1e62325c7daea659bb97eb399..a6405d318d322b9e1f49e4762570a2c1f5371726 100755 (executable)
@@ -15,7 +15,7 @@ test_expect_success 'update-index --nonsense fails' '
 
 test_expect_success 'update-index --nonsense dumps usage' '
        test_expect_code 129 git update-index --nonsense 2>err &&
-       grep "[Uu]sage: git update-index" err
+       test_i18ngrep "[Uu]sage: git update-index" err
 '
 
 test_expect_success 'update-index -h with corrupt index' '
@@ -26,7 +26,7 @@ test_expect_success 'update-index -h with corrupt index' '
                >.git/index &&
                test_expect_code 129 git update-index -h >usage 2>&1
        ) &&
-       grep "[Uu]sage: git update-index" broken/usage
+       test_i18ngrep "[Uu]sage: git update-index" broken/usage
 '
 
 test_expect_success '--cacheinfo does not accept blob null sha1' '
index c8fe9782672c0e6ba2f0fd0c1b708fc980263182..dc2f0458fd0e74a3dcb4769517f5cde2606eb6f2 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 490e052875806849e9cbaa54958f1d8d02f5e8f2..8d9bc3c2af6ad84c006010ee7be65146107c2259 100755 (executable)
@@ -22,7 +22,7 @@ test_expect_success 'ls-files with nonexistent path' '
 
 test_expect_success 'ls-files with nonsense option' '
        test_expect_code 129 git ls-files --nonsense 2>actual &&
-       grep "[Uu]sage: git ls-files" actual
+       test_i18ngrep "[Uu]sage: git ls-files" actual
 '
 
 test_expect_success 'ls-files -h in corrupt repository' '
@@ -33,7 +33,7 @@ test_expect_success 'ls-files -h in corrupt repository' '
                >.git/index &&
                test_expect_code 129 git ls-files -h >usage 2>&1
        ) &&
-       grep "[Uu]sage: git ls-files " broken/usage
+       test_i18ngrep "[Uu]sage: git ls-files " broken/usage
 '
 
 test_done
index a17f8b2a407c2de2bf81d8a858957da409f1c980..80e6be39d7b76d8e5daa6cad24a22a80a42e8eff 100755 (executable)
@@ -31,7 +31,7 @@ test_expect_success 'branch -h in broken repository' '
                >.git/refs/heads/master &&
                test_expect_code 129 git branch -h >usage 2>&1
        ) &&
-       grep "[Uu]sage" broken/usage
+       test_i18ngrep "[Uu]sage" broken/usage
 '
 
 test_expect_success \
@@ -74,7 +74,7 @@ test_expect_success \
 test_expect_success \
     'git branch -m dumps usage' \
        'test_expect_code 129 git branch -m 2>err &&
-       grep "[Uu]sage: git branch" err'
+       test_i18ngrep "[Uu]sage: git branch" err'
 
 test_expect_success \
     'git branch -m m m/m should work' \
@@ -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 &&
@@ -369,6 +388,76 @@ test_expect_success \
     'git tag foobar &&
      test_must_fail git branch --track my11 foobar'
 
+test_expect_success 'use --set-upstream-to modify HEAD' \
+    'test_config branch.master.remote foo &&
+     test_config branch.master.merge foo &&
+     git branch my12
+     git branch --set-upstream-to my12 &&
+     test "$(git config branch.master.remote)" = "." &&
+     test "$(git config branch.master.merge)" = "refs/heads/my12"'
+
+test_expect_success 'use --set-upstream-to modify a particular branch' \
+    'git branch my13
+     git branch --set-upstream-to master my13 &&
+     test "$(git config branch.my13.remote)" = "." &&
+     test "$(git config branch.my13.merge)" = "refs/heads/master"'
+
+test_expect_success '--unset-upstream should fail if given a non-existent branch' \
+    'test_must_fail git branch --unset-upstream i-dont-exist'
+
+test_expect_success 'test --unset-upstream on HEAD' \
+    'git branch my14
+     test_config branch.master.remote foo &&
+     test_config branch.master.merge foo &&
+     git branch --set-upstream-to my14 &&
+     git branch --unset-upstream &&
+     test_must_fail git config branch.master.remote &&
+     test_must_fail git config branch.master.merge &&
+     # fail for a branch without upstream set
+     test_must_fail git branch --unset-upstream
+'
+
+test_expect_success 'test --unset-upstream on a particular branch' \
+    'git branch my15
+     git branch --set-upstream-to master my14 &&
+     git branch --unset-upstream my14 &&
+     test_must_fail git config branch.my14.remote &&
+     test_must_fail git config branch.my14.merge'
+
+test_expect_success '--set-upstream shows message when creating a new branch that exists as remote-tracking' \
+    'git update-ref refs/remotes/origin/master HEAD &&
+     git branch --set-upstream origin/master 2>actual &&
+     test_when_finished git update-ref -d refs/remotes/origin/master &&
+     test_when_finished git branch -d origin/master &&
+     cat >expected <<EOF &&
+The --set-upstream flag is deprecated and will be removed. Consider using --track or --set-upstream-to
+
+If you wanted to make '"'master'"' track '"'origin/master'"', do this:
+
+    git branch -d origin/master
+    git branch --set-upstream-to origin/master
+EOF
+     test_cmp expected actual
+'
+
+test_expect_success '--set-upstream with two args only shows the deprecation message' \
+    'git branch --set-upstream master my13 2>actual &&
+     test_when_finished git branch --unset-upstream master &&
+     cat >expected <<EOF &&
+The --set-upstream flag is deprecated and will be removed. Consider using --track or --set-upstream-to
+EOF
+     test_cmp expected actual
+'
+
+test_expect_success '--set-upstream with one arg only shows the deprecation message if the branch existed' \
+    'git branch --set-upstream my13 2>actual &&
+     test_when_finished git branch --unset-upstream my13 &&
+     cat >expected <<EOF &&
+The --set-upstream flag is deprecated and will be removed. Consider using --track or --set-upstream-to
+EOF
+     test_cmp expected actual
+'
+
 # Keep this test last, as it changes the current branch
 cat >expect <<EOF
 $_z40 $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000        branch: Created from master
index 1f35e55ee3be1b2bbdb8aa9f3248f6fe5ebf46cb..7480d6e7c2a8d14c5f75875d47eefe96ca9c5010 100755 (executable)
@@ -11,6 +11,16 @@ tree, index, and tree objects.
 
 . ./test-lib.sh
 
+HT='   '
+
+echo 2>/dev/null > "Name with an${HT}HT"
+if ! test -f "Name with an${HT}HT"
+then
+       # since FAT/NTFS does not allow tabs in filenames, skip this test
+       skip_all='Your filesystem does not allow tabs in filenames'
+       test_done
+fi
+
 p0='no-funny'
 p1='tabs       ," (dq) and spaces'
 p2='just space'
@@ -23,21 +33,9 @@ test_expect_success 'setup' '
        EOF
 
        { cat "$p0" >"$p1" || :; } &&
-       { echo "Foo Bar Baz" >"$p2" || :; } &&
-
-       if test -f "$p1" && cmp "$p0" "$p1"
-       then
-               test_set_prereq TABS_IN_FILENAMES
-       fi
+       { echo "Foo Bar Baz" >"$p2" || :; }
 '
 
-if ! test_have_prereq TABS_IN_FILENAMES
-then
-       # since FAT/NTFS does not allow tabs in filenames, skip this test
-       skip_all='Your filesystem does not allow tabs in filenames'
-       test_done
-fi
-
 test_expect_success 'setup: populate index and tree' '
        git update-index --add "$p0" "$p2" &&
        t0=$(git write-tree)
index 7788ae02adca18ab1d1f8cf7b76243fbf56377ae..1de0ebda25c1034fc1b343a8f0e3da9c2c7f8c6e 100755 (executable)
@@ -68,24 +68,24 @@ test_expect_success 'rebase against master' '
 
 test_expect_success 'rebase against master twice' '
        git rebase master >out &&
-       grep "Current branch my-topic-branch is up to date" out
+       test_i18ngrep "Current branch my-topic-branch is up to date" out
 '
 
 test_expect_success 'rebase against master twice with --force' '
        git rebase --force-rebase master >out &&
-       grep "Current branch my-topic-branch is up to date, rebase forced" out
+       test_i18ngrep "Current branch my-topic-branch is up to date, rebase forced" out
 '
 
 test_expect_success 'rebase against master twice from another branch' '
        git checkout my-topic-branch^ &&
        git rebase master my-topic-branch >out &&
-       grep "Current branch my-topic-branch is up to date" out
+       test_i18ngrep "Current branch my-topic-branch is up to date" out
 '
 
 test_expect_success 'rebase fast-forward to master' '
        git checkout my-topic-branch^ &&
        git rebase my-topic-branch >out &&
-       grep "Fast-forwarded HEAD to my-topic-branch" out
+       test_i18ngrep "Fast-forwarded HEAD to my-topic-branch" out
 '
 
 test_expect_success 'the rebase operation should not have destroyed author information' '
index 025c1c610efee9562343b34a9c815f34f51ed9ac..32fdc9938e1dc29d9a1c6c1dd54379ee33644561 100755 (executable)
@@ -118,6 +118,17 @@ test_expect_success 'rebase -i with the exec command checks tree cleanness' '
        git rebase --continue
 '
 
+test_expect_success 'rebase -i with exec of inexistent command' '
+       git checkout master &&
+       test_when_finished "git rebase --abort" &&
+       (
+       FAKE_LINES="exec_this-command-does-not-exist 1" &&
+       export FAKE_LINES &&
+       test_must_fail git rebase -i HEAD^ >actual 2>&1
+       ) &&
+       ! grep "Maybe git-rebase is broken" actual
+'
+
 test_expect_success 'no changes are a nop' '
        git checkout branch2 &&
        git rebase -i F &&
@@ -755,4 +766,178 @@ test_expect_success 'rebase-i history with funny messages' '
        test_cmp expect actual
 '
 
+
+test_expect_success 'prepare for rebase -i --exec' '
+       git checkout master &&
+       git checkout -b execute &&
+       test_commit one_exec main.txt one_exec &&
+       test_commit two_exec main.txt two_exec &&
+       test_commit three_exec main.txt three_exec
+'
+
+
+test_expect_success 'running "git rebase -i --exec git show HEAD"' '
+       git rebase -i --exec "git show HEAD" HEAD~2 >actual &&
+       (
+               FAKE_LINES="1 exec_git_show_HEAD 2 exec_git_show_HEAD" &&
+               export FAKE_LINES &&
+               git rebase -i HEAD~2 >expect
+       ) &&
+       sed -e "1,9d" expect >expected &&
+       test_cmp expected actual
+'
+
+
+test_expect_success 'running "git rebase --exec git show HEAD -i"' '
+       git reset --hard execute &&
+       git rebase --exec "git show HEAD" -i HEAD~2 >actual &&
+       (
+               FAKE_LINES="1 exec_git_show_HEAD 2 exec_git_show_HEAD" &&
+               export FAKE_LINES &&
+               git rebase -i HEAD~2 >expect
+       ) &&
+       sed -e "1,9d" expect >expected &&
+       test_cmp expected actual
+'
+
+
+test_expect_success 'running "git rebase -ix git show HEAD"' '
+       git reset --hard execute &&
+       git rebase -ix "git show HEAD" HEAD~2 >actual &&
+       (
+               FAKE_LINES="1 exec_git_show_HEAD 2 exec_git_show_HEAD" &&
+               export FAKE_LINES &&
+               git rebase -i HEAD~2 >expect
+       ) &&
+       sed -e "1,9d" expect >expected &&
+       test_cmp expected actual
+'
+
+
+test_expect_success 'rebase -ix with several <CMD>' '
+       git reset --hard execute &&
+       git rebase -ix "git show HEAD; pwd" HEAD~2 >actual &&
+       (
+               FAKE_LINES="1 exec_git_show_HEAD;_pwd 2 exec_git_show_HEAD;_pwd" &&
+               export FAKE_LINES &&
+               git rebase -i HEAD~2 >expect
+       ) &&
+       sed -e "1,9d" expect >expected &&
+       test_cmp expected actual
+'
+
+
+test_expect_success 'rebase -ix with several instances of --exec' '
+       git reset --hard execute &&
+       git rebase -i --exec "git show HEAD" --exec "pwd" HEAD~2 >actual &&
+       (
+               FAKE_LINES="1 exec_git_show_HEAD exec_pwd 2
+                               exec_git_show_HEAD exec_pwd" &&
+               export FAKE_LINES &&
+               git rebase -i HEAD~2 >expect
+       ) &&
+       sed -e "1,11d" expect >expected &&
+       test_cmp expected actual
+'
+
+
+test_expect_success 'rebase -ix with --autosquash' '
+       git reset --hard execute &&
+       git checkout -b autosquash &&
+       echo second >second.txt &&
+       git add second.txt &&
+       git commit -m "fixup! two_exec" &&
+       echo bis >bis.txt &&
+       git add bis.txt &&
+       git commit -m "fixup! two_exec" &&
+       (
+               git checkout -b autosquash_actual &&
+               git rebase -i --exec "git show HEAD" --autosquash HEAD~4 >actual
+       ) &&
+       git checkout autosquash &&
+       (
+               git checkout -b autosquash_expected &&
+               FAKE_LINES="1 fixup 3 fixup 4 exec_git_show_HEAD 2 exec_git_show_HEAD" &&
+               export FAKE_LINES &&
+               git rebase -i HEAD~4 >expect
+       ) &&
+       sed -e "1,13d" expect >expected &&
+       test_cmp expected actual
+'
+
+
+test_expect_success 'rebase --exec without -i shows error message' '
+       git reset --hard execute &&
+       test_must_fail git rebase --exec "git show HEAD" HEAD~2 2>actual &&
+       echo "The --exec option must be used with the --interactive option" >expected &&
+       test_i18ncmp expected actual
+'
+
+
+test_expect_success 'rebase -i --exec without <CMD>' '
+       git reset --hard execute &&
+       test_must_fail git rebase -i --exec 2>tmp &&
+       sed -e "1d" tmp >actual &&
+       test_must_fail git rebase -h >expected &&
+       test_cmp expected actual &&
+       git checkout master
+'
+
+test_expect_success 'rebase -i --root re-order and drop commits' '
+       git checkout E &&
+       FAKE_LINES="3 1 2 5" git rebase -i --root &&
+       test E = $(git cat-file commit HEAD | sed -ne \$p) &&
+       test B = $(git cat-file commit HEAD^ | sed -ne \$p) &&
+       test A = $(git cat-file commit HEAD^^ | sed -ne \$p) &&
+       test C = $(git cat-file commit HEAD^^^ | sed -ne \$p) &&
+       test 0 = $(git cat-file commit HEAD^^^ | grep -c ^parent\ )
+'
+
+test_expect_success 'rebase -i --root retain root commit author and message' '
+       git checkout A &&
+       echo B >file7 &&
+       git add file7 &&
+       GIT_AUTHOR_NAME="Twerp Snog" git commit -m "different author" &&
+       FAKE_LINES="2" git rebase -i --root &&
+       git cat-file commit HEAD | grep -q "^author Twerp Snog" &&
+       git cat-file commit HEAD | grep -q "^different author$"
+'
+
+test_expect_success 'rebase -i --root temporary sentinel commit' '
+       git checkout B &&
+       (
+               FAKE_LINES="2" &&
+               export FAKE_LINES &&
+               test_must_fail git rebase -i --root
+       ) &&
+       git cat-file commit HEAD | grep "^tree 4b825dc642cb" &&
+       git rebase --abort
+'
+
+test_expect_success 'rebase -i --root fixup root commit' '
+       git checkout B &&
+       FAKE_LINES="1 fixup 2" git rebase -i --root &&
+       test A = $(git cat-file commit HEAD | sed -ne \$p) &&
+       test B = $(git show HEAD:file1) &&
+       test 0 = $(git cat-file commit HEAD | grep -c ^parent\ )
+'
+
+test_expect_success 'rebase --edit-todo does not works on non-interactive rebase' '
+       git reset --hard &&
+       git checkout conflict-branch &&
+       test_must_fail git rebase --onto HEAD~2 HEAD~ &&
+       test_must_fail git rebase --edit-todo &&
+       git rebase --abort
+'
+
+test_expect_success 'rebase --edit-todo can be used to modify todo' '
+       git reset --hard &&
+       git checkout no-conflict-branch^0 &&
+       FAKE_LINES="edit 1 2 3" git rebase -i HEAD~3 &&
+       FAKE_LINES="2 1" git rebase --edit-todo &&
+       git rebase --continue
+       test M = $(git cat-file commit HEAD^ | sed -ne \$p) &&
+       test L = $(git cat-file commit HEAD | sed -ne \$p)
+'
+
 test_done
index e5ad67c643ffee9b79fce813673732faa950714f..19eddadcf734951b22246c6dd0a16d517f111b5b 100755 (executable)
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-test_description='rebase should not insist on git message convention'
+test_description='rebase should handle arbitrary git message'
 
 . ./test-lib.sh
 
@@ -12,6 +12,11 @@ It has two paragraphs, but its first paragraph is not friendly
 to oneline summary format.
 EOF
 
+cat >G <<\EOF
+commit log message containing a diff
+EOF
+
+
 test_expect_success setup '
 
        >file1 &&
@@ -19,8 +24,9 @@ test_expect_success setup '
        git add file1 file2 &&
        test_tick &&
        git commit -m "Initial commit" &&
+       git branch diff-in-message
 
-       git checkout -b side &&
+       git checkout -b multi-line-subject &&
        cat F >file2 &&
        git add file2 &&
        test_tick &&
@@ -28,6 +34,17 @@ test_expect_success setup '
 
        git cat-file commit HEAD | sed -e "1,/^\$/d" >F0 &&
 
+       git checkout diff-in-message &&
+       echo "commit log message containing a diff" >G &&
+       echo "" >>G
+       cat G >file2 &&
+       git add file2 &&
+       git diff --cached >>G &&
+       test_tick &&
+       git commit -F G &&
+
+       git cat-file commit HEAD | sed -e "1,/^\$/d" >G0 &&
+
        git checkout master &&
 
        echo One >file1 &&
@@ -36,13 +53,20 @@ test_expect_success setup '
        git commit -m "Second commit"
 '
 
-test_expect_success rebase '
+test_expect_success 'rebase commit with multi-line subject' '
 
-       git rebase master side &&
+       git rebase master multi-line-subject &&
        git cat-file commit HEAD | sed -e "1,/^\$/d" >F1 &&
 
        test_cmp F0 F1 &&
        test_cmp F F0
 '
 
+test_expect_success 'rebase commit with diff in message' '
+       git rebase master diff-in-message &&
+       git cat-file commit HEAD | sed -e "1,/^$/d" >G1 &&
+       test_cmp G0 G1 &&
+       test_cmp G G0
+'
+
 test_done
index 6898377910f9fce8ccc73fba7b8140dff53d7ec6..e6a9a0d436f3a28a7de6eaadd7f1f223ae740c64 100755 (executable)
@@ -62,9 +62,16 @@ test_expect_success 'rebase -n overrides config rebase.stat config' '
         ! grep "^ fileX |  *1 +$" diffstat.txt
 '
 
+# Output to stderr:
+#
+#     "Does not point to a valid commit: invalid-ref"
+#
+# NEEDSWORK: This "grep" is fine in real non-C locales, but
+# GETTEXT_POISON poisons the refname along with the enclosing
+# error message.
 test_expect_success 'rebase --onto outputs the invalid ref' '
        test_must_fail git rebase --onto invalid-ref HEAD HEAD 2>err &&
-       grep "invalid-ref" err
+       test_i18ngrep "invalid-ref" err
 '
 
 test_done
index 086c91c7b47aa2fa7b593f4f9b2f84f6b7ba3724..0b521057283bf106da8ce55f25f61c7ec7e3ad35 100755 (executable)
@@ -22,8 +22,9 @@ test_expect_success 'prepare repository' '
        test_commit 4 B
 '
 
-test_expect_success 'rebase --root expects --onto' '
-       test_must_fail git rebase --root
+test_expect_success 'rebase --root fails with too many args' '
+       git checkout -B fail other &&
+       test_must_fail git rebase --onto master --root fail fail
 '
 
 test_expect_success 'setup pre-rebase hook' '
@@ -42,7 +43,7 @@ cat > expect <<EOF
 EOF
 
 test_expect_success 'rebase --root --onto <newbase>' '
-       git checkout -b work &&
+       git checkout -b work other &&
        git rebase --root --onto master &&
        git log --pretty=tformat:"%s" > rebased &&
        test_cmp expect rebased
index 595d2ff990ad3305f47977431c0b7d102ca3866b..34c86e5de69468fe7618383e556d1711cc49b0bb 100755 (executable)
@@ -47,7 +47,7 @@ test_expect_success 'cherry-pick --nonsense' '
        git diff --exit-code HEAD &&
        test_must_fail git cherry-pick --nonsense 2>msg &&
        git diff --exit-code HEAD "$pos" &&
-       grep '[Uu]sage:' msg
+       test_i18ngrep '[Uu]sage:' msg
 '
 
 test_expect_success 'revert --nonsense' '
@@ -56,7 +56,7 @@ test_expect_success 'revert --nonsense' '
        git diff --exit-code HEAD &&
        test_must_fail git revert --nonsense 2>msg &&
        git diff --exit-code HEAD "$pos" &&
-       grep '[Uu]sage:' msg
+       test_i18ngrep '[Uu]sage:' msg
 '
 
 test_expect_success 'cherry-pick after renaming branch' '
index 5a1340cee69f344613c09b7d4a3f3f7bebd6719e..a0c6e30d805e6e71b9fec4311a6ede298b6265b4 100755 (executable)
@@ -53,6 +53,11 @@ test_expect_success 'index lockfile was removed' '
 
 '
 
+test_expect_success 'cherry-pick a commit with an empty message with --allow-empty-message' '
+       git checkout -f master &&
+       git cherry-pick --allow-empty-message empty-branch
+'
+
 test_expect_success 'cherry pick an empty non-ff commit without --allow-empty' '
        git checkout master &&
        echo fourth >>file2 &&
index 0c81b3c427af47f0b0ef73170372ef9df70b4ade..c82f7210c4ca10e35d9d2000aa8da2d10194a6c6 100755 (executable)
@@ -30,6 +30,7 @@ test_expect_success setup '
        test_commit initial foo a &&
        test_commit base foo b &&
        test_commit picked foo c &&
+       test_commit --signoff picked-signed foo d &&
        git config advice.detachedhead false
 
 '
@@ -340,4 +341,35 @@ test_expect_success 'revert conflict, diff3 -m style' '
        test_cmp expected actual
 '
 
+test_expect_success 'failed cherry-pick does not forget -s' '
+       pristine_detach initial &&
+       test_must_fail git cherry-pick -s picked &&
+       test_i18ngrep -e "Signed-off-by" .git/MERGE_MSG
+'
+
+test_expect_success 'commit after failed cherry-pick does not add duplicated -s' '
+       pristine_detach initial &&
+       test_must_fail git cherry-pick -s picked-signed &&
+       git commit -a -s &&
+       test $(git show -s |grep -c "Signed-off-by") = 1
+'
+
+test_expect_success 'commit after failed cherry-pick adds -s at the right place' '
+       pristine_detach initial &&
+       test_must_fail git cherry-pick picked &&
+       git commit -a -s &&
+       pwd &&
+       cat <<EOF > expected &&
+picked
+
+Signed-off-by: C O Mitter <committer@example.com>
+
+Conflicts:
+       foo
+EOF
+
+       git show -s --pretty=format:%B > actual &&
+       test_cmp expected actual
+'
+
 test_done
index 75f7ff4f2fe21e86e0a26fe5a6c2119bef38404c..340afc760de030879fff496dca3db8432a6b992b 100755 (executable)
@@ -44,6 +44,21 @@ test_expect_success 'cherry-pick first..fourth works' '
        check_head_differs_from fourth
 '
 
+test_expect_success 'cherry-pick three one two works' '
+       git checkout -f first &&
+       test_commit one &&
+       test_commit two &&
+       test_commit three &&
+       git checkout -f master &&
+       git reset --hard first &&
+       git cherry-pick three one two &&
+       git diff --quiet three &&
+       git diff --quiet HEAD three &&
+       test "$(git log --reverse --format=%s first..)" = "three
+one
+two"
+'
+
 test_expect_success 'output to keep user entertained during multi-pick' '
        cat <<-\EOF >expected &&
        [master OBJID] second
index f4e6450d6a88ae0abd158e52634c47a23872ad2c..b5fb527b2e686d158a6e7d53d6246b9e66f80a7b 100755 (executable)
@@ -410,7 +410,7 @@ test_expect_success '--continue respects -x in first commit in multi-pick' '
        grep "cherry picked from.*$picked" msg
 '
 
-test_expect_success '--signoff is not automatically propagated to resolved conflict' '
+test_expect_failure '--signoff is automatically propagated to resolved conflict' '
        pristine_detach initial &&
        test_expect_code 1 git cherry-pick --signoff base..anotherpick &&
        echo "c" >foo &&
@@ -428,7 +428,7 @@ test_expect_success '--signoff is not automatically propagated to resolved confl
        grep "Signed-off-by:" anotherpick_msg
 '
 
-test_expect_success '--signoff dropped for implicit commit of resolution, multi-pick case' '
+test_expect_failure '--signoff dropped for implicit commit of resolution, multi-pick case' '
        pristine_detach initial &&
        test_must_fail git cherry-pick -s picked anotherpick &&
        echo c >foo &&
@@ -441,7 +441,7 @@ test_expect_success '--signoff dropped for implicit commit of resolution, multi-
        ! grep Signed-off-by: msg
 '
 
-test_expect_success 'sign-off needs to be reaffirmed after conflict resolution, single-pick case' '
+test_expect_failure 'sign-off needs to be reaffirmed after conflict resolution, single-pick case' '
        pristine_detach initial &&
        test_must_fail git cherry-pick -s picked &&
        echo c >foo &&
index 9fd28bcf3435f831fa24285dd703c82b8396d635..97254e8d337ff066f633ece5d1a7c8a59108e703 100755 (executable)
@@ -262,4 +262,347 @@ 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 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 -a ../.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 -a ../.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 -a ../../.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 534ee08a44b9d8501b234f228302e9a266d67f8c..892f5678441b3c9065f743d9fe9f071334420831 100755 (executable)
@@ -16,9 +16,8 @@ echo foo 2>/dev/null > "Name and an${HT}HT"
 if ! test -f "Name and an${HT}HT"
 then
        # FAT/NTFS does not allow tabs in filenames
-       say 'Your filesystem does not allow tabs in filenames'
-else
-       test_set_prereq TABS_IN_FILENAMES
+       skip_all='Your filesystem does not allow tabs in filenames'
+       test_done
 fi
 
 for_each_name () {
@@ -31,7 +30,7 @@ for_each_name () {
        done
 }
 
-test_expect_success TABS_IN_FILENAMES 'setup' '
+test_expect_success 'setup' '
 
        mkdir "$FN" &&
        for_each_name "echo initial >\"\$name\"" &&
@@ -45,7 +44,7 @@ test_expect_success TABS_IN_FILENAMES 'setup' '
 
 '
 
-test_expect_success TABS_IN_FILENAMES 'setup expected files' '
+test_expect_success 'setup expected files' '
 cat >expect.quoted <<\EOF &&
 Name
 "Name and a\nLF"
@@ -75,74 +74,74 @@ With SP in it
 EOF
 '
 
-test_expect_success TABS_IN_FILENAMES 'check fully quoted output from ls-files' '
+test_expect_success 'check fully quoted output from ls-files' '
 
        git ls-files >current && test_cmp expect.quoted current
 
 '
 
-test_expect_success TABS_IN_FILENAMES 'check fully quoted output from diff-files' '
+test_expect_success 'check fully quoted output from diff-files' '
 
        git diff --name-only >current &&
        test_cmp expect.quoted current
 
 '
 
-test_expect_success TABS_IN_FILENAMES 'check fully quoted output from diff-index' '
+test_expect_success 'check fully quoted output from diff-index' '
 
        git diff --name-only HEAD >current &&
        test_cmp expect.quoted current
 
 '
 
-test_expect_success TABS_IN_FILENAMES 'check fully quoted output from diff-tree' '
+test_expect_success 'check fully quoted output from diff-tree' '
 
        git diff --name-only HEAD^ HEAD >current &&
        test_cmp expect.quoted current
 
 '
 
-test_expect_success TABS_IN_FILENAMES 'check fully quoted output from ls-tree' '
+test_expect_success 'check fully quoted output from ls-tree' '
 
        git ls-tree --name-only -r HEAD >current &&
        test_cmp expect.quoted current
 
 '
 
-test_expect_success TABS_IN_FILENAMES 'setting core.quotepath' '
+test_expect_success 'setting core.quotepath' '
 
        git config --bool core.quotepath false
 
 '
 
-test_expect_success TABS_IN_FILENAMES 'check fully quoted output from ls-files' '
+test_expect_success 'check fully quoted output from ls-files' '
 
        git ls-files >current && test_cmp expect.raw current
 
 '
 
-test_expect_success TABS_IN_FILENAMES 'check fully quoted output from diff-files' '
+test_expect_success 'check fully quoted output from diff-files' '
 
        git diff --name-only >current &&
        test_cmp expect.raw current
 
 '
 
-test_expect_success TABS_IN_FILENAMES 'check fully quoted output from diff-index' '
+test_expect_success 'check fully quoted output from diff-index' '
 
        git diff --name-only HEAD >current &&
        test_cmp expect.raw current
 
 '
 
-test_expect_success TABS_IN_FILENAMES 'check fully quoted output from diff-tree' '
+test_expect_success 'check fully quoted output from diff-tree' '
 
        git diff --name-only HEAD^ HEAD >current &&
        test_cmp expect.raw current
 
 '
 
-test_expect_success TABS_IN_FILENAMES 'check fully quoted output from ls-tree' '
+test_expect_success 'check fully quoted output from ls-tree' '
 
        git ls-tree --name-only -r HEAD >current &&
        test_cmp expect.raw current
index cd042633ba5ec36be89507d25254b32a8f0b98ae..5dfbda7491aceaa64215ac94bdd416f9b93f55d3 100755 (executable)
@@ -610,7 +610,7 @@ test_expect_success 'stash apply shows status same as git status (relative to cu
                git stash apply
        ) |
        sed -e 1,2d >actual && # drop "Saved..." and "HEAD is now..."
-       test_cmp expect actual
+       test_i18ncmp expect actual
 '
 
 cat > expect << EOF
diff --git a/t/t3910-mac-os-precompose.sh b/t/t3910-mac-os-precompose.sh
new file mode 100755 (executable)
index 0000000..5fe57c5
--- /dev/null
@@ -0,0 +1,153 @@
+#!/bin/sh
+#
+# Copyright (c) 2012 Torsten Bögershausen
+#
+
+test_description='utf-8 decomposed (nfd) converted to precomposed (nfc)'
+
+. ./test-lib.sh
+
+if ! test_have_prereq UTF8_NFD_TO_NFC
+then
+       skip_all="filesystem does not corrupt utf-8"
+       test_done
+fi
+
+# create utf-8 variables
+Adiarnfc=`printf '\303\204'`
+Adiarnfd=`printf 'A\314\210'`
+
+Odiarnfc=`printf '\303\226'`
+Odiarnfd=`printf 'O\314\210'`
+AEligatu=`printf '\303\206'`
+Invalidu=`printf '\303\377'`
+
+
+#Create a string with 255 bytes (decomposed)
+Alongd=$Adiarnfd$Adiarnfd$Adiarnfd$Adiarnfd$Adiarnfd$Adiarnfd$Adiarnfd #21 Byte
+Alongd=$Alongd$Alongd$Alongd                                           #63 Byte
+Alongd=$Alongd$Alongd$Alongd$Alongd$Adiarnfd                           #255 Byte
+
+#Create a string with 254 bytes (precomposed)
+Alongc=$AEligatu$AEligatu$AEligatu$AEligatu$AEligatu #10 Byte
+Alongc=$Alongc$Alongc$Alongc$Alongc$Alongc           #50 Byte
+Alongc=$Alongc$Alongc$Alongc$Alongc$Alongc           #250 Byte
+Alongc=$Alongc$AEligatu$AEligatu                     #254 Byte
+
+test_expect_success "detect if nfd needed" '
+       precomposeunicode=`git config core.precomposeunicode` &&
+       test "$precomposeunicode" = false &&
+       git config core.precomposeunicode true
+'
+test_expect_success "setup" '
+       >x &&
+       git add x &&
+       git commit -m "1st commit" &&
+       git rm x &&
+       git commit -m "rm x"
+'
+test_expect_success "setup case mac" '
+       git checkout -b mac_os
+'
+# This will test nfd2nfc in readdir()
+test_expect_success "add file Adiarnfc" '
+       echo f.Adiarnfc >f.$Adiarnfc &&
+       git add f.$Adiarnfc &&
+       git commit -m "add f.$Adiarnfc"
+'
+# This will test nfd2nfc in git stage()
+test_expect_success "stage file d.Adiarnfd/f.Adiarnfd" '
+       mkdir d.$Adiarnfd &&
+       echo d.$Adiarnfd/f.$Adiarnfd >d.$Adiarnfd/f.$Adiarnfd &&
+       git stage d.$Adiarnfd/f.$Adiarnfd &&
+       git commit -m "add d.$Adiarnfd/f.$Adiarnfd"
+'
+test_expect_success "add link Adiarnfc" '
+       ln -s d.$Adiarnfd/f.$Adiarnfd l.$Adiarnfc &&
+       git add l.$Adiarnfc &&
+       git commit -m "add l.Adiarnfc"
+'
+# This will test git log
+test_expect_success "git log f.Adiar" '
+       git log f.$Adiarnfc > f.Adiarnfc.log &&
+       git log f.$Adiarnfd > f.Adiarnfd.log &&
+       test -s f.Adiarnfc.log &&
+       test -s f.Adiarnfd.log &&
+       test_cmp f.Adiarnfc.log f.Adiarnfd.log &&
+       rm f.Adiarnfc.log f.Adiarnfd.log
+'
+# This will test git ls-files
+test_expect_success "git lsfiles f.Adiar" '
+       git ls-files f.$Adiarnfc > f.Adiarnfc.log &&
+       git ls-files f.$Adiarnfd > f.Adiarnfd.log &&
+       test -s f.Adiarnfc.log &&
+       test -s f.Adiarnfd.log &&
+       test_cmp f.Adiarnfc.log f.Adiarnfd.log &&
+       rm f.Adiarnfc.log f.Adiarnfd.log
+'
+# This will test git mv
+test_expect_success "git mv" '
+       git mv f.$Adiarnfd f.$Odiarnfc &&
+       git mv d.$Adiarnfd d.$Odiarnfc &&
+       git mv l.$Adiarnfd l.$Odiarnfc &&
+       git commit -m "mv Adiarnfd Odiarnfc"
+'
+# Files can be checked out as nfc
+# And the link has been corrected from nfd to nfc
+test_expect_success "git checkout nfc" '
+       rm f.$Odiarnfc &&
+       git checkout f.$Odiarnfc
+'
+# Make it possible to checkout files with their NFD names
+test_expect_success "git checkout file nfd" '
+       rm -f f.* &&
+       git checkout f.$Odiarnfd
+'
+# Make it possible to checkout links with their NFD names
+test_expect_success "git checkout link nfd" '
+       rm l.* &&
+       git checkout l.$Odiarnfd
+'
+test_expect_success "setup case mac2" '
+       git checkout master &&
+       git reset --hard &&
+       git checkout -b mac_os_2
+'
+# This will test nfd2nfc in git commit
+test_expect_success "commit file d2.Adiarnfd/f.Adiarnfd" '
+       mkdir d2.$Adiarnfd &&
+       echo d2.$Adiarnfd/f.$Adiarnfd >d2.$Adiarnfd/f.$Adiarnfd &&
+       git add d2.$Adiarnfd/f.$Adiarnfd &&
+       git commit -m "add d2.$Adiarnfd/f.$Adiarnfd" -- d2.$Adiarnfd/f.$Adiarnfd
+'
+test_expect_success "setup for long decomposed filename" '
+       git checkout master &&
+       git reset --hard &&
+       git checkout -b mac_os_long_nfd_fn
+'
+test_expect_success "Add long decomposed filename" '
+       echo longd >$Alongd &&
+       git add * &&
+       git commit -m "Long filename"
+'
+test_expect_success "setup for long precomposed filename" '
+       git checkout master &&
+       git reset --hard &&
+       git checkout -b mac_os_long_nfc_fn
+'
+test_expect_success "Add long precomposed filename" '
+       echo longc >$Alongc &&
+       git add * &&
+       git commit -m "Long filename"
+'
+# Test if the global core.precomposeunicode stops autosensing
+# Must be the last test case
+test_expect_success "respect git config --global core.precomposeunicode" '
+       git config --global core.precomposeunicode true &&
+       rm -rf .git &&
+       git init &&
+       precomposeunicode=`git config core.precomposeunicode` &&
+       test "$precomposeunicode" = "true"
+'
+
+test_done
index 7a3e1f9a24e4be3759c29acc632fc461ede2b74b..3d4b1ba23f9eacec4e1bcd29345cc7d3943badce 100755 (executable)
@@ -36,24 +36,24 @@ test_expect_success '--stat output after text chmod' '
        test_chmod -x rezrov &&
        echo " 0 files changed" >expect &&
        git diff HEAD --stat >actual &&
-       test_cmp expect actual
+       test_i18ncmp expect actual
 '
 
 test_expect_success '--shortstat output after text chmod' '
        git diff HEAD --shortstat >actual &&
-       test_cmp expect 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_cmp expect actual
+       test_i18ncmp expect actual
 '
 
 test_expect_success '--shortstat output after binary chmod' '
        git diff HEAD --shortstat >actual &&
-       test_cmp expect actual
+       test_i18ncmp expect actual
 '
 
 test_done
index 6cebb3951bc7f4e9b772efed052c485d82d1a68d..1215ae544b6915fe2cc6df4d193c8f3a805beba1 100755 (executable)
@@ -15,13 +15,14 @@ cat >expect.binary-numstat <<\EOF
 -      -       d
 EOF
 
-test_expect_success 'prepare repository' \
-       'echo AIT >a && echo BIT >b && echo CIT >c && echo DIT >d &&
-        git update-index --add a b c d &&
-        echo git >a &&
-        cat "$TEST_DIRECTORY"/test-binary-1.png >b &&
-        echo git >c &&
-        cat b b >d'
+test_expect_success 'prepare repository' '
+       echo AIT >a && echo BIT >b && echo CIT >c && echo DIT >d &&
+       git update-index --add a b c d &&
+       echo git >a &&
+       cat "$TEST_DIRECTORY"/test-binary-1.png >b &&
+       echo git >c &&
+       cat b b >d
+'
 
 cat > expected <<\EOF
  a |    2 +-
@@ -30,16 +31,16 @@ cat > expected <<\EOF
  d |  Bin
  4 files changed, 2 insertions(+), 2 deletions(-)
 EOF
-test_expect_success '"apply --stat" output for binary file change' '
+test_expect_success 'apply --stat output for binary file change' '
        git diff >diff &&
        git apply --stat --summary <diff >current &&
        test_i18ncmp expected current
 '
 
 test_expect_success 'diff --shortstat output for binary file change' '
-       echo " 4 files changed, 2 insertions(+), 2 deletions(-)" >expected &&
+       tail -n 1 expected >expect &&
        git diff --shortstat >current &&
-       test_i18ncmp expected current
+       test_i18ncmp expect current
 '
 
 test_expect_success 'diff --shortstat output for binary file change only' '
@@ -62,49 +63,42 @@ test_expect_success 'apply --numstat understands diff --binary format' '
 
 # apply needs to be able to skip the binary material correctly
 # in order to report the line number of a corrupt patch.
-test_expect_success 'apply detecting corrupt patch correctly' \
-       'git diff | sed -e 's/-CIT/xCIT/' >broken &&
-        if git apply --stat --summary broken 2>detected
-        then
-               echo unhappy - should have detected an error
-               (exit 1)
-        else
-               echo happy
-        fi &&
-        detected=`cat detected` &&
-        detected=`expr "$detected" : "fatal.*at line \\([0-9]*\\)\$"` &&
-        detected=`sed -ne "${detected}p" broken` &&
-        test "$detected" = xCIT'
-
-test_expect_success 'apply detecting corrupt patch correctly' \
-       'git diff --binary | sed -e 's/-CIT/xCIT/' >broken &&
-        if git apply --stat --summary broken 2>detected
-        then
-               echo unhappy - should have detected an error
-               (exit 1)
-        else
-               echo happy
-        fi &&
-        detected=`cat detected` &&
-        detected=`expr "$detected" : "fatal.*at line \\([0-9]*\\)\$"` &&
-        detected=`sed -ne "${detected}p" broken` &&
-        test "$detected" = xCIT'
+test_expect_success C_LOCALE_OUTPUT 'apply detecting corrupt patch correctly' '
+       git diff >output &&
+       sed -e "s/-CIT/xCIT/" <output >broken &&
+       test_must_fail git apply --stat --summary broken 2>detected &&
+       detected=`cat detected` &&
+       detected=`expr "$detected" : "fatal.*at line \\([0-9]*\\)\$"` &&
+       detected=`sed -ne "${detected}p" broken` &&
+       test "$detected" = xCIT
+'
+
+test_expect_success C_LOCALE_OUTPUT 'apply detecting corrupt patch correctly' '
+       git diff --binary | sed -e "s/-CIT/xCIT/" >broken &&
+       test_must_fail git apply --stat --summary broken 2>detected &&
+       detected=`cat detected` &&
+       detected=`expr "$detected" : "fatal.*at line \\([0-9]*\\)\$"` &&
+       detected=`sed -ne "${detected}p" broken` &&
+       test "$detected" = xCIT
+'
 
 test_expect_success 'initial commit' 'git commit -a -m initial'
 
 # Try removal (b), modification (d), and creation (e).
-test_expect_success 'diff-index with --binary' \
-       'echo AIT >a && mv b e && echo CIT >c && cat e >d &&
-        git update-index --add --remove a b c d e &&
-        tree0=`git write-tree` &&
-        git diff --cached --binary >current &&
-        git apply --stat --summary current'
-
-test_expect_success 'apply binary patch' \
-       'git reset --hard &&
-        git apply --binary --index <current &&
-        tree1=`git write-tree` &&
-        test "$tree1" = "$tree0"'
+test_expect_success 'diff-index with --binary' '
+       echo AIT >a && mv b e && echo CIT >c && cat e >d &&
+       git update-index --add --remove a b c d e &&
+       tree0=`git write-tree` &&
+       git diff --cached --binary >current &&
+       git apply --stat --summary current
+'
+
+test_expect_success 'apply binary patch' '
+       git reset --hard &&
+       git apply --binary --index <current &&
+       tree1=`git write-tree` &&
+       test "$tree1" = "$tree0"
+'
 
 test_expect_success 'diff --no-index with binary creation' '
        echo Q | q_to_nul >binary &&
@@ -125,7 +119,7 @@ cat >expect <<EOF
 EOF
 
 test_expect_success 'diff --stat with binary files and big change count' '
-       echo X | dd of=binfile bs=1k seek=1 &&
+       printf "\01\00%1024d" 1 >binfile &&
        git add binfile &&
        i=0 &&
        while test $i -lt 10000; do
index 97b81778cb8c9f3c06b551b1f7031c944ced70d0..cd543ecc5429dc175750971f4b593e327ab3fcee 100755 (executable)
@@ -13,14 +13,12 @@ P1='pathname        with HT'
 P2='pathname with SP'
 P3='pathname
 with LF'
-if : 2>/dev/null >"$P1" && test -f "$P1" && rm -f "$P1"
-then
-       test_set_prereq TABS_IN_FILENAMES
-else
-       say 'Your filesystem does not allow tabs in filenames'
-fi
+echo 2>/dev/null >"$P1" && test -f "$P1" && rm -f "$P1" || {
+       skip_all='Your filesystem does not allow tabs in filenames'
+       test_done
+}
 
-test_expect_success TABS_IN_FILENAMES setup '
+test_expect_success setup '
        echo P0.0 >"$P0.0" &&
        echo P0.1 >"$P0.1" &&
        echo P0.2 >"$P0.2" &&
@@ -40,7 +38,7 @@ test_expect_success TABS_IN_FILENAMES setup '
        :
 '
 
-test_expect_success TABS_IN_FILENAMES 'setup expected files' '
+test_expect_success 'setup expected files' '
 cat >expect <<\EOF
  rename pathname.1 => "Rpathname\twith HT.0" (100%)
  rename pathname.3 => "Rpathname\nwith LF.0" (100%)
@@ -52,12 +50,12 @@ cat >expect <<\EOF
 EOF
 '
 
-test_expect_success TABS_IN_FILENAMES 'git diff --summary -M HEAD' '
+test_expect_success 'git diff --summary -M HEAD' '
        git diff --summary -M HEAD >actual &&
        test_cmp expect actual
 '
 
-test_expect_success TABS_IN_FILENAMES 'git diff --numstat -M HEAD' '
+test_expect_success 'git diff --numstat -M HEAD' '
        cat >expect <<-\EOF &&
        0       0       pathname.1 => "Rpathname\twith HT.0"
        0       0       pathname.3 => "Rpathname\nwith LF.0"
@@ -71,7 +69,7 @@ test_expect_success TABS_IN_FILENAMES 'git diff --numstat -M HEAD' '
        test_cmp expect actual
 '
 
-test_expect_success TABS_IN_FILENAMES 'git diff --stat -M HEAD' '
+test_expect_success 'git diff --stat -M HEAD' '
        cat >expect <<-\EOF &&
         pathname.1 => "Rpathname\twith HT.0"            | 0
         pathname.3 => "Rpathname\nwith LF.0"            | 0
index 4bd2a1c838e9a522c4376860e726455d3cdb92b0..082d3e83bddf242fb02f5124fd52d125520af6b8 100755 (executable)
@@ -105,7 +105,7 @@ test_expect_funcname () {
        grep "^@@.*@@ $1" diff
 }
 
-for p in bibtex cpp csharp fortran html java matlab objc pascal perl php python ruby tex
+for p in ada bibtex cpp csharp fortran html java matlab objc pascal perl php python ruby tex
 do
        test_expect_success "builtin $p pattern compiles" '
                echo "*.java diff=$p" >.gitattributes &&
index 30d42cb3bfd856a7d920119f1c4226c408a8f82f..40ab333a8a4849d620e1d41a75f611921f83055a 100755 (executable)
@@ -298,6 +298,7 @@ test_expect_success 'unset default driver' '
        test_unconfig diff.wordregex
 '
 
+test_language_driver ada
 test_language_driver bibtex
 test_language_driver cpp
 test_language_driver csharp
diff --git a/t/t4034/ada/expect b/t/t4034/ada/expect
new file mode 100644 (file)
index 0000000..be2376e
--- /dev/null
@@ -0,0 +1,27 @@
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index d96fdd1..df21bb0 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
+<CYAN>@@ -1,13 +1,13 @@<RESET>
+Ada.Text_IO.Put_Line("Hello World<RED>!<RESET><GREEN>?<RESET>");
+1 1e<RED>-<RESET>10 16#FE12#E2 3.141_592 '<RED>x<RESET><GREEN>y<RESET>'
+<RED>a<RESET><GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>**<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>(<RED>b<RESET><GREEN>y<RESET>)
+<RED>a<RESET><GREEN>x<RESET>:=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>/= <RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>,<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>=><RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>..<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET><><RED>b<RESET><GREEN>y<RESET>
diff --git a/t/t4034/ada/post b/t/t4034/ada/post
new file mode 100644 (file)
index 0000000..df21bb0
--- /dev/null
@@ -0,0 +1,13 @@
+Ada.Text_IO.Put_Line("Hello World?");
+1 1e10 16#FE12#E2 3.141_592 'y'
+x+y x-y
+x*y x/y
+x**y
+x(y)
+x:=y
+x=y x/= y
+x<y x<=y x>y x>=y
+x,y
+x=>y
+x..y
+x<>y
diff --git a/t/t4034/ada/pre b/t/t4034/ada/pre
new file mode 100644 (file)
index 0000000..d96fdd1
--- /dev/null
@@ -0,0 +1,13 @@
+Ada.Text_IO.Put_Line("Hello World!");
+1 1e-10 16#FE12#E2 3.141_592 'x'
+a+b a-b
+a*b a/b
+a**b
+a(b)
+a:=b
+a=b a/= b
+a<b a<=b a>b a>=b
+a,b
+a=>b
+a..b
+a<>b
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
diff --git a/t/t4108-apply-threeway.sh b/t/t4108-apply-threeway.sh
new file mode 100755 (executable)
index 0000000..fa5d4ef
--- /dev/null
@@ -0,0 +1,157 @@
+#!/bin/sh
+
+test_description='git apply --3way'
+
+. ./test-lib.sh
+
+create_file () {
+       for i
+       do
+               echo "$i"
+       done
+}
+
+sanitize_conflicted_diff () {
+       sed -e '
+               /^index /d
+               s/^\(+[<>][<>][<>][<>]*\) .*/\1/
+       '
+}
+
+test_expect_success setup '
+       test_tick &&
+       create_file >one 1 2 3 4 5 6 7 &&
+       cat one >two &&
+       git add one two &&
+       git commit -m initial &&
+
+       git branch side &&
+
+       test_tick &&
+       create_file >one 1 two 3 4 5 six 7 &&
+       create_file >two 1 two 3 4 5 6 7 &&
+       git commit -a -m master &&
+
+       git checkout side &&
+       create_file >one 1 2 3 4 five 6 7 &&
+       create_file >two 1 2 3 4 five 6 7 &&
+       git commit -a -m side &&
+
+       git checkout master
+'
+
+test_expect_success 'apply without --3way' '
+       git diff side^ side >P.diff &&
+
+       # should fail to apply
+       git reset --hard &&
+       git checkout master^0 &&
+       test_must_fail git apply --index P.diff &&
+       # should leave things intact
+       git diff-files --exit-code &&
+       git diff-index --exit-code --cached HEAD
+'
+
+test_expect_success 'apply with --3way' '
+       # Merging side should be similar to applying this patch
+       git diff ...side >P.diff &&
+
+       # The corresponding conflicted merge
+       git reset --hard &&
+       git checkout master^0 &&
+       test_must_fail git merge --no-commit side &&
+       git ls-files -s >expect.ls &&
+       git diff HEAD | sanitize_conflicted_diff >expect.diff &&
+
+       # should fail to apply
+       git reset --hard &&
+       git checkout master^0 &&
+       test_must_fail git apply --index --3way P.diff &&
+       git ls-files -s >actual.ls &&
+       git diff HEAD | sanitize_conflicted_diff >actual.diff &&
+
+       # The result should resemble the corresponding merge
+       test_cmp expect.ls actual.ls &&
+       test_cmp expect.diff actual.diff
+'
+
+test_expect_success 'apply with --3way with rerere enabled' '
+       git config rerere.enabled true &&
+
+       # Merging side should be similar to applying this patch
+       git diff ...side >P.diff &&
+
+       # The corresponding conflicted merge
+       git reset --hard &&
+       git checkout master^0 &&
+       test_must_fail git merge --no-commit side &&
+
+       # Manually resolve and record the resolution
+       create_file 1 two 3 4 five six 7 >one &&
+       git rerere &&
+       cat one >expect &&
+
+       # should fail to apply
+       git reset --hard &&
+       git checkout master^0 &&
+       test_must_fail git apply --index --3way P.diff &&
+
+       # but rerere should have replayed the recorded resolution
+       test_cmp expect one
+'
+
+test_expect_success 'apply -3 with add/add conflict setup' '
+       git reset --hard &&
+
+       git checkout -b adder &&
+       create_file 1 2 3 4 5 6 7 >three &&
+       create_file 1 2 3 4 5 6 7 >four &&
+       git add three four &&
+       git commit -m "add three and four" &&
+
+       git checkout -b another adder^ &&
+       create_file 1 2 3 4 5 6 7 >three &&
+       create_file 1 2 3 four 5 6 7 >four &&
+       git add three four &&
+       git commit -m "add three and four" &&
+
+       # Merging another should be similar to applying this patch
+       git diff adder...another >P.diff &&
+
+       git checkout adder^0 &&
+       test_must_fail git merge --no-commit another &&
+       git ls-files -s >expect.ls &&
+       git diff HEAD | sanitize_conflicted_diff >expect.diff
+'
+
+test_expect_success 'apply -3 with add/add conflict' '
+       # should fail to apply ...
+       git reset --hard &&
+       git checkout adder^0 &&
+       test_must_fail git apply --index --3way P.diff &&
+       # ... and leave conflicts in the index and in the working tree
+       git ls-files -s >actual.ls &&
+       git diff HEAD | sanitize_conflicted_diff >actual.diff &&
+
+       # The result should resemble the corresponding merge
+       test_cmp expect.ls actual.ls &&
+       test_cmp expect.diff actual.diff
+'
+
+test_expect_success 'apply -3 with add/add conflict (dirty working tree)' '
+       # should fail to apply ...
+       git reset --hard &&
+       git checkout adder^0 &&
+       echo >>four &&
+       cat four >four.save &&
+       cat three >three.save &&
+       git ls-files -s >expect.ls &&
+       test_must_fail git apply --index --3way P.diff &&
+       # ... and should not touch anything
+       git ls-files -s >actual.ls &&
+       test_cmp expect.ls actual.ls &&
+       test_cmp four.save four &&
+       test_cmp three.save three
+'
+
+test_done
index e9ccd161ee96a5bdbb4bf77de406ea51dacfb5de..8e15ecbdfdb497fcaa077fd1e6b3f882c9a46cb4 100755 (executable)
@@ -46,6 +46,14 @@ test_expect_success setup '
        cat file1 >saved.file1
 '
 
+test_expect_success 'apply --reject is incompatible with --3way' '
+       test_when_finished "cat saved.file1 >file1" &&
+       git diff >patch.0 &&
+       git checkout file1 &&
+       test_must_fail git apply --reject --3way patch.0 &&
+       git diff --exit-code
+'
+
 test_expect_success 'apply without --reject should fail' '
 
        if git apply patch.1
index a33d510bf6b27a6bb2c640cfc9d11f462cbdf7a6..c5fecdfed43dc5682307dd0fdb66ddd78dece056 100755 (executable)
@@ -32,7 +32,7 @@ test_expect_success 'apply git diff with -p2' '
 test_expect_success 'apply with too large -p' '
        cp file1.saved file1 &&
        test_must_fail git apply --stat -p3 patch.file 2>err &&
-       grep "removing 3 leading" err
+       test_i18ngrep "removing 3 leading" err
 '
 
 test_expect_success 'apply (-p2) traditional diff with funny filenames' '
@@ -54,7 +54,7 @@ test_expect_success 'apply (-p2) traditional diff with funny filenames' '
 test_expect_success 'apply with too large -p and fancy filename' '
        cp file1.saved file1 &&
        test_must_fail git apply --stat -p3 patch.escaped 2>err &&
-       grep "removing 3 leading" err
+       test_i18ngrep "removing 3 leading" err
 '
 
 test_expect_success 'apply (-p2) diff, mode change only' '
index 94da99075c55c790aae7a260ff6c4964f950c47c..2ecb4216b7179ef836836d90a5f76f5e4349ca23 100755 (executable)
@@ -30,9 +30,9 @@ EOF
 
 test_expect_success 'apply diff with inconsistent filenames in headers' '
        test_must_fail git apply bad1.patch 2>err &&
-       grep "inconsistent new filename" err &&
+       test_i18ngrep "inconsistent new filename" err &&
        test_must_fail git apply bad2.patch 2>err &&
-       grep "inconsistent old filename" err
+       test_i18ngrep "inconsistent old filename" err
 '
 
 test_done
index 3ab670d36aea890e07827b14486e4c49de83bdb5..7f6666fcd3ffd6dfe53ed72cedcbabfe5a626ed8 100755 (executable)
@@ -382,13 +382,13 @@ test_expect_success 'rerere --no-no-rerere-autoupdate' '
        git update-index --index-info <failedmerge &&
        cp file3.conflict file3 &&
        test_must_fail git rerere --no-no-rerere-autoupdate 2>err &&
-       grep [Uu]sage err &&
+       test_i18ngrep [Uu]sage err &&
        test_must_fail git update-index --refresh
 '
 
 test_expect_success 'rerere -h' '
        test_must_fail git rerere -h >help &&
-       grep [Uu]sage help
+       test_i18ngrep [Uu]sage help
 '
 
 test_done
index 37023e30ea7c747f7dd92efebd2195127e94103a..a343bf6c629f8e6acaf7559d3168a97fcce9d286 100755 (executable)
@@ -178,11 +178,21 @@ test_expect_success 'git log --no-walk <commits> sorts by commit time' '
        test_cmp expect actual
 '
 
+test_expect_success 'git log --no-walk=sorted <commits> sorts by commit time' '
+       git log --no-walk=sorted --oneline 5d31159 804a787 394ef78 > actual &&
+       test_cmp expect actual
+'
+
 cat > expect << EOF
 5d31159 fourth
 804a787 sixth
 394ef78 fifth
 EOF
+test_expect_success 'git log --no-walk=unsorted <commits> leaves list of commits as given' '
+       git log --no-walk=unsorted --oneline 5d31159 804a787 394ef78 > actual &&
+       test_cmp expect actual
+'
+
 test_expect_success 'git show <commits> leaves list of commits as given' '
        git show --oneline -s 5d31159 804a787 394ef78 > actual &&
        test_cmp expect actual
@@ -220,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
@@ -803,7 +819,7 @@ sanitize_output () {
 test_expect_success 'log --graph with diff and stats' '
        git log --graph --pretty=short --stat -p >actual &&
        sanitize_output >actual.sanitized <actual &&
-       test_cmp expect actual.sanitized
+       test_i18ncmp expect actual.sanitized
 '
 
 test_expect_success 'dotdot is a parent directory' '
index 4afd77815f6bf698d4b865bad2300706d2a8e0fc..2c45de7aeaf2872873685ce9d055a7579161d875 100755 (executable)
@@ -88,7 +88,7 @@ test_expect_success 'NUL separation with --stat' '
        stat1_part=$(git diff --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_cmp expected actual
+       test_i18ncmp expected actual
 '
 
 test_expect_failure 'NUL termination with --stat' '
@@ -96,7 +96,7 @@ test_expect_failure 'NUL termination with --stat' '
        stat1_part=$(git diff --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_cmp expected actual
+       test_i18ncmp expected actual
 '
 
 test_done
index 81904d9ec8d341399b534c5d576262439d0e1ad6..3e64a7a65da86410dd0236975bef9bd0013a6405 100755 (executable)
@@ -11,7 +11,7 @@ test_expect_success 'split sample box' \
        'git mailsplit -o. "$TEST_DIRECTORY"/t5100/sample.mbox >last &&
        last=`cat last` &&
        echo total is $last &&
-       test `cat last` = 16'
+       test `cat last` = 17'
 
 check_mailinfo () {
        mail=$1 opt=$2
diff --git a/t/t5100/info0017 b/t/t5100/info0017
new file mode 100644 (file)
index 0000000..d2bc89f
--- /dev/null
@@ -0,0 +1,5 @@
+Author: A U Thor
+Email: a.u.thor@example.com
+Subject: A E I O U
+Date: Mon, 17 Sep 2012 14:23:44 -0700
+
diff --git a/t/t5100/msg0017 b/t/t5100/msg0017
new file mode 100644 (file)
index 0000000..2ee0900
--- /dev/null
@@ -0,0 +1,2 @@
+New content here
+
diff --git a/t/t5100/patch0017 b/t/t5100/patch0017
new file mode 100644 (file)
index 0000000..35cf84c
--- /dev/null
@@ -0,0 +1,6 @@
+diff --git a/foo b/foo
+index e69de29..d95f3ad 100644
+--- a/foo
++++ b/foo
+@@ -0,0 +1 @@
++New content
index 34a09a0fc1c0ca9d1e68ed8bbf56e592c54e7227..8b2ae064c36b969ca20324154cea66bf26739de6 100644 (file)
@@ -683,3 +683,19 @@ index e69de29..d95f3ad 100644
 @@ -0,0 +1 @@
 +content
 
+From nobody Mon Sep 17 00:00:00 2001
+From: A U Thor <a.u.thor@example.com>
+Subject: A E I O U
+Date: Mon, 17 Sep 2012 14:23:44 -0700
+MIME-Version: 1.0
+Content-Type: text/plain; charset="iso-2022-jp"
+Content-type: text/plain; charset="UTF-8"
+
+New content here
+
+diff --git a/foo b/foo
+index e69de29..d95f3ad 100644
+--- a/foo
++++ b/foo
+@@ -0,0 +1 @@
++New content
index 4fd69a19ebab07cc0ca784b63a7f02ddd613f306..a07c871797d22e1da4b2d3904cab024a7bef37b4 100755 (executable)
@@ -416,6 +416,11 @@ test_expect_success \
 test_expect_success \
     'make sure index-pack detects the SHA1 collision' \
     'test_must_fail git index-pack -o bad.idx test-3.pack 2>msg &&
-     grep "SHA1 COLLISION FOUND" msg'
+     test_i18ngrep "SHA1 COLLISION FOUND" msg'
+
+test_expect_success \
+    'make sure index-pack detects the SHA1 collision (large blobs)' \
+    'test_must_fail git -c core.bigfilethreshold=1 index-pack -o bad.idx test-3.pack 2>msg &&
+     test_i18ngrep "SHA1 COLLISION FOUND" msg'
 
 test_done
index 250c720c14602bdf21e6a7200437b13fe6feaca3..129fc88bd28e8ea85e81310aec860df808949447 100755 (executable)
@@ -159,7 +159,7 @@ test_expect_success 'receive-pack runs auto-gc in remote repo' '
            git commit -a -m "Second commit" &&
            git repack
        ) &&
-       cp -a parent child &&
+       cp -R parent child &&
        (
            # Set the child to auto-pack if more than one pack exists
            cd child &&
@@ -174,8 +174,7 @@ test_expect_success 'receive-pack runs auto-gc in remote repo' '
            cd parent &&
            echo "Even more text" >>file.txt &&
            git commit -a -m "Third commit" &&
-           git send-pack ../child HEAD:refs/heads/test_auto_gc >output 2>&1 &&
-           grep "Auto packing the repository for optimum performance." output
+           git send-pack ../child HEAD:refs/heads/test_auto_gc
        ) &&
        test ! -e child/.git/objects/tmp_test_object
 '
index e80a2af348565a0a3d001ef28cb76427acfee495..6322e8ade8436dc4e66b9874638e7ca6b7d222b3 100755 (executable)
@@ -391,10 +391,55 @@ test_expect_success 'fetch mixed refs from cmdline and stdin' '
 test_expect_success 'test duplicate refs from stdin' '
        (
        cd client &&
-       test_must_fail git fetch-pack --stdin --no-progress .. <../input.dup
+       git fetch-pack --stdin --no-progress .. <../input.dup
        ) >output &&
        cut -d " " -f 2 <output | sort >actual &&
        test_cmp expect actual
 '
 
+test_expect_success 'set up tests of missing reference' '
+       cat >expect-error <<-\EOF
+       error: no such remote ref refs/heads/xyzzy
+       EOF
+'
+
+test_expect_success 'test lonely missing ref' '
+       (
+               cd client &&
+               test_must_fail git fetch-pack --no-progress .. refs/heads/xyzzy
+       ) >/dev/null 2>error-m &&
+       test_cmp expect-error error-m
+'
+
+test_expect_success 'test missing ref after existing' '
+       (
+               cd client &&
+               test_must_fail git fetch-pack --no-progress .. refs/heads/A refs/heads/xyzzy
+       ) >/dev/null 2>error-em &&
+       test_cmp expect-error error-em
+'
+
+test_expect_success 'test missing ref before existing' '
+       (
+               cd client &&
+               test_must_fail git fetch-pack --no-progress .. refs/heads/xyzzy refs/heads/A
+       ) >/dev/null 2>error-me &&
+       test_cmp expect-error error-me
+'
+
+test_expect_success 'test --all, --depth, and explicit head' '
+       (
+               cd client &&
+               git fetch-pack --no-progress --all --depth=1 .. refs/heads/A
+       ) >out-adh 2>error-adh
+'
+
+test_expect_success 'test --all, --depth, and explicit tag' '
+       git tag OLDTAG refs/heads/B~5 &&
+       (
+               cd client &&
+               git fetch-pack --no-progress --all --depth=1 .. refs/tags/OLDTAG
+       ) >out-adt 2>error-adt
+'
+
 test_done
index 35ec294d9a56d5fc6b22ee2a39166325352bd639..69ee13c8bebbdb1303378288597420cdf70b7b88 100755 (executable)
@@ -89,7 +89,7 @@ test_expect_success 'push with !receive.fsckobjects' '
 
 cat >exp <<EOF
 To dst
-!      refs/heads/master:refs/heads/test       [remote rejected] (n/a (unpacker error))
+!      refs/heads/master:refs/heads/test       [remote rejected] (unpacker error)
 EOF
 
 test_expect_success 'push with receive.fsckobjects' '
index e8af615e6dcdf365416ef9f71825c17a0d601186..ccc55ebf4bf10d4782bf2ff32910ed6eeec040f6 100755 (executable)
@@ -52,7 +52,7 @@ test_expect_success setup '
 
 '
 
-test_expect_success 'remote information for the origin' '
+test_expect_success C_LOCALE_OUTPUT 'remote information for the origin' '
 (
        cd test &&
        tokens_match origin "$(git remote)" &&
@@ -66,8 +66,6 @@ test_expect_success 'add another remote' '
        cd test &&
        git remote add -f second ../two &&
        tokens_match "origin second" "$(git remote)" &&
-       check_remote_track origin master side &&
-       check_remote_track second master side another &&
        check_tracking_branch second master side another &&
        git for-each-ref "--format=%(refname)" refs/remotes |
        sed -e "/^refs\/remotes\/origin\//d" \
@@ -77,6 +75,14 @@ test_expect_success 'add another remote' '
 )
 '
 
+test_expect_success C_LOCALE_OUTPUT 'check remote tracking' '
+(
+       cd test &&
+       check_remote_track origin master side &&
+       check_remote_track second master side another
+)
+'
+
 test_expect_success 'remote forces tracking branches' '
 (
        cd test &&
@@ -95,7 +101,7 @@ test_expect_success 'remove remote' '
 )
 '
 
-test_expect_success 'remove remote' '
+test_expect_success C_LOCALE_OUTPUT 'remove remote' '
 (
        cd test &&
        tokens_match origin "$(git remote)" &&
@@ -125,14 +131,14 @@ EOF
        } &&
        git tag footag &&
        git config --add remote.oops.fetch "+refs/*:refs/*" &&
-       git remote rm oops 2>actual1 &&
+       git remote remove oops 2>actual1 &&
        git branch foobranch &&
        git config --add remote.oops.fetch "+refs/*:refs/*" &&
        git remote rm oops 2>actual2 &&
        git branch -d foobranch &&
        git tag -d footag &&
-       test_cmp expect1 actual1 &&
-       test_cmp expect2 actual2
+       test_i18ncmp expect1 actual1 &&
+       test_i18ncmp expect2 actual2
 )
 '
 
@@ -192,7 +198,7 @@ test_expect_success 'show' '
         git config --add remote.two.push refs/heads/master:refs/heads/another &&
         git remote show origin two > output &&
         git branch -d rebase octopus &&
-        test_cmp expect output)
+        test_i18ncmp expect output)
 '
 
 cat > test/expect << EOF
@@ -217,7 +223,7 @@ test_expect_success 'show -n' '
         cd test &&
         git remote show -n origin > output &&
         mv ../one.unreachable ../one &&
-        test_cmp expect output)
+        test_i18ncmp expect output)
 '
 
 test_expect_success 'prune' '
@@ -255,7 +261,7 @@ EOF
 test_expect_success 'set-head --auto fails w/multiple HEADs' '
        (cd test &&
         test_must_fail git remote set-head --auto two >output 2>&1 &&
-       test_cmp expect output)
+       test_i18ncmp expect output)
 '
 
 cat >test/expect <<EOF
@@ -285,7 +291,7 @@ test_expect_success 'prune --dry-run' '
         test_must_fail git rev-parse refs/remotes/origin/side &&
        (cd ../one &&
         git branch -m side side2) &&
-        test_cmp expect output)
+        test_i18ncmp expect output)
 '
 
 test_expect_success 'add --mirror && prune' '
@@ -672,7 +678,7 @@ test_expect_success 'migrate a remote from named file in $GIT_DIR/remotes' '
        git clone one five &&
        origin_url=$(pwd)/one &&
        (cd five &&
-        git remote rm origin &&
+        git remote remove origin &&
         mkdir -p .git/remotes &&
         cat ../remotes_origin > .git/remotes/origin &&
         git remote rename origin origin &&
@@ -705,7 +711,7 @@ test_expect_success 'remote prune to cause a dangling symref' '
                cd seven &&
                git remote prune origin
        ) >err 2>&1 &&
-       grep "has become dangling" err &&
+       test_i18ngrep "has become dangling" err &&
 
        : And the dangling symref will not cause other annoying errors &&
        (
index 6764d511ce08cf62da2c257bf5fe50cabaf2f03c..d16e5d384a8966bc04e9fde6e92bd41818526aab 100755 (executable)
@@ -87,17 +87,15 @@ test_expect_success 'use branch.<name>.remote if possible' '
 test_expect_success 'confuses pattern as remote when no remote specified' '
        cat >exp <<-\EOF &&
        fatal: '\''refs*master'\'' does not appear to be a git repository
-       fatal: The remote end hung up unexpectedly
+       fatal: Could not read from remote repository.
+
+       Please make sure you have the correct access rights
+       and the repository exists.
        EOF
        #
-       # Do not expect "git ls-remote <pattern>" to work; ls-remote, correctly,
-       # confuses <pattern> for <remote>. Although ugly, this behaviour is akin
-       # to the confusion of refspecs for remotes by git-fetch and git-push,
-       # eg:
-       #
-       #   $ git fetch branch
-       #
-
+       # Do not expect "git ls-remote <pattern>" to work; ls-remote needs
+       # <remote> if you want to feed <pattern>, just like you cannot say
+       # fetch <branch>.
        # We could just as easily have used "master"; the "*" emphasizes its
        # role as a pattern.
        test_must_fail git ls-remote refs*master >actual 2>&1 &&
index 227dd56137c469311209ebda43cb89f9734c6e68..0f8140957f8080f4a9f3283a1cfef7f3798ae454 100755 (executable)
@@ -151,4 +151,34 @@ test_expect_success 'git fetch --multiple (ignoring skipFetchAll)' '
         test_cmp ../expect output)
 '
 
+test_expect_success 'git fetch --all --no-tags' '
+       >expect &&
+       git clone one test5 &&
+       git clone test5 test6 &&
+       (cd test5 && git tag test-tag) &&
+       (
+               cd test6 &&
+               git fetch --all --no-tags &&
+               git tag >output
+       ) &&
+       test_cmp expect test6/output
+'
+
+test_expect_success 'git fetch --all --tags' '
+       echo test-tag >expect &&
+       git clone one test7 &&
+       git clone test7 test8 &&
+       (
+               cd test7 &&
+               test_commit test-tag &&
+               git reset --hard HEAD^
+       ) &&
+       (
+               cd test8 &&
+               git fetch --all --tags &&
+               git tag >output
+       ) &&
+       test_cmp expect test8/output
+'
+
 test_done
index 6b2a5f4a65659b7fcfcd9d096a0b43473e1cf1d6..c983d3694c74cf6de6b7bd9a74c28d41462171f0 100755 (executable)
@@ -35,8 +35,8 @@ test_expect_success 'upload-pack fails due to error in pack-objects packing' '
        printf "0032want %s\n00000009done\n0000" \
                $(git rev-parse HEAD) >input &&
        test_must_fail git upload-pack . <input >/dev/null 2>output.err &&
-       grep "unable to read" output.err &&
-       grep "pack-objects died" output.err
+       test_i18ngrep "unable to read" output.err &&
+       test_i18ngrep "pack-objects died" output.err
 '
 
 test_expect_success 'corrupt repo differently' '
index f141f2d1da3ca8186ccc7a742bddd06f2e7f8970..01d0d95b4d6476f691f650cc413fa7156caee88b 100755 (executable)
@@ -109,7 +109,7 @@ test_expect_success 'http-push fetches packed objects' '
        # By reset, we force git to retrieve the packed object
        (cd "$ROOT_PATH"/test_repo_clone_packed &&
         git reset --hard HEAD^ &&
-        git remote rm origin &&
+        git remote remove origin &&
         git reflog expire --expire=0 --all &&
         git prune &&
         git push -f -v $HTTPD_URL/dumb/test_repo_packed.git master)
index ef6d6b6e4e1a06e31780cf2a4261a632f5779987..4b4b4a604f3075dec1056b31da5cccc0c4ed5a9a 100755 (executable)
@@ -66,7 +66,10 @@ test_expect_success 'no empty path components' '
 
 test_expect_success 'clone remote repository' '
        rm -rf test_repo_clone &&
-       git clone $HTTPD_URL/smart/test_repo.git test_repo_clone
+       git clone $HTTPD_URL/smart/test_repo.git test_repo_clone &&
+       (
+               cd test_repo_clone && git config push.default matching
+       )
 '
 
 test_expect_success 'push to remote repository (standard)' '
index 16ef0419e9e4ea8d42aebd63c5bc5ec7f63d3732..80d20c876bbac0b00d388d511da555a29e827dbc 100755 (executable)
@@ -22,7 +22,7 @@ test_expect_success 'setup repository' '
 '
 
 test_expect_success 'create http-accessible bare repository with loose objects' '
-       cp -a .git "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
+       cp -R .git "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
        (cd "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
         git config core.bare true &&
         mkdir -p hooks &&
index 2db5c3564181818efdf885188d7cc597024c6f12..5060879d6d93d1f10a1db690bd42c19ee5ec1ae4 100755 (executable)
@@ -32,13 +32,14 @@ setup_askpass_helper
 cat >exp <<EOF
 > GET /smart/repo.git/info/refs?service=git-upload-pack HTTP/1.1
 > Accept: */*
+> Accept-Encoding: gzip
 > Pragma: no-cache
 < HTTP/1.1 200 OK
 < Pragma: no-cache
 < Cache-Control: no-cache, max-age=0, must-revalidate
 < Content-Type: application/x-git-upload-pack-advertisement
 > POST /smart/repo.git/git-upload-pack HTTP/1.1
-> Accept-Encoding: deflate, gzip
+> Accept-Encoding: gzip
 > Content-Type: application/x-git-upload-pack-request
 > Accept: application/x-git-upload-pack-result
 > Content-Length: xxx
@@ -129,6 +130,18 @@ test_expect_success 'clone from auth-only-for-push repository' '
        test_cmp expect actual
 '
 
+test_expect_success 'disable dumb http on server' '
+       git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/repo.git" \
+               config http.getanyfile false
+'
+
+test_expect_success 'GIT_SMART_HTTP can disable smart http' '
+       (GIT_SMART_HTTP=0 &&
+        export GIT_SMART_HTTP &&
+        cd clone &&
+        test_must_fail git fetch)
+'
+
 test -n "$GIT_TEST_LONG" && test_set_prereq EXPENSIVE
 
 test_expect_success EXPENSIVE 'create 50,000 tags in the repo' '
index c6feca44e3677c416bfe4841fda5205b2133f7bc..7ff6e0e16cbeb014c1ea551392a63beca2dbc386 100755 (executable)
@@ -124,4 +124,14 @@ test_expect_success 'cloning non-git directory fails' '
        test_must_fail git clone not-a-git-repo not-a-git-repo-clone
 '
 
+test_expect_success 'cloning file:// does not hardlink' '
+       git clone --bare file://"$(pwd)"/a non-local &&
+       ! repo_is_hardlinked non-local
+'
+
+test_expect_success 'cloning a local path with --no-local does not hardlink' '
+       git clone --bare --no-local a force-nonlocal &&
+       ! repo_is_hardlinked force-nonlocal
+'
+
 test_done
diff --git a/t/t5709-clone-refspec.sh b/t/t5709-clone-refspec.sh
new file mode 100755 (executable)
index 0000000..6f1ea98
--- /dev/null
@@ -0,0 +1,156 @@
+#!/bin/sh
+
+test_description='test refspec written by clone-command'
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+       # Make two branches, "master" and "side"
+       echo one >file &&
+       git add file &&
+       git commit -m one &&
+       echo two >file &&
+       git commit -a -m two &&
+       git tag two &&
+       echo three >file &&
+       git commit -a -m three &&
+       git checkout -b side &&
+       echo four >file &&
+       git commit -a -m four &&
+       git checkout master &&
+
+       # default clone
+       git clone . dir_all &&
+
+       # default --single that follows HEAD=master
+       git clone --single-branch . dir_master &&
+
+       # default --single that follows HEAD=side
+       git checkout side &&
+       git clone --single-branch . dir_side &&
+
+       # explicit --single that follows side
+       git checkout master &&
+       git clone --single-branch --branch side . dir_side2 &&
+
+       # default --single with --mirror
+       git clone --single-branch --mirror . dir_mirror &&
+
+       # default --single with --branch and --mirror
+       git clone --single-branch --mirror --branch side . dir_mirror_side &&
+
+       # --single that does not know what branch to follow
+       git checkout two^ &&
+       git clone --single-branch . dir_detached &&
+
+       # explicit --single with tag
+       git clone --single-branch --branch two . dir_tag &&
+
+       # advance both "master" and "side" branches
+       git checkout side &&
+       echo five >file &&
+       git commit -a -m five &&
+       git checkout master &&
+       echo six >file &&
+       git commit -a -m six &&
+
+       # update tag
+       git tag -d two && git tag two
+'
+
+test_expect_success 'by default all branches will be kept updated' '
+       (
+               cd dir_all && git fetch &&
+               git for-each-ref refs/remotes/origin |
+               sed -e "/HEAD$/d" \
+                   -e "s|/remotes/origin/|/heads/|" >../actual
+       ) &&
+       # follow both master and side
+       git for-each-ref refs/heads >expect &&
+       test_cmp expect actual
+'
+
+test_expect_success 'by default no tags will be kept updated' '
+       (
+               cd dir_all && git fetch &&
+               git for-each-ref refs/tags >../actual
+       ) &&
+       git for-each-ref refs/tags >expect &&
+       test_must_fail test_cmp expect actual
+'
+
+test_expect_success '--single-branch while HEAD pointing at master' '
+       (
+               cd dir_master && git fetch &&
+               git for-each-ref refs/remotes/origin |
+               sed -e "/HEAD$/d" \
+                   -e "s|/remotes/origin/|/heads/|" >../actual
+       ) &&
+       # only follow master
+       git for-each-ref refs/heads/master >expect &&
+       test_cmp expect actual
+'
+
+test_expect_success '--single-branch while HEAD pointing at side' '
+       (
+               cd dir_side && git fetch &&
+               git for-each-ref refs/remotes/origin |
+               sed -e "/HEAD$/d" \
+                   -e "s|/remotes/origin/|/heads/|" >../actual
+       ) &&
+       # only follow side
+       git for-each-ref refs/heads/side >expect &&
+       test_cmp expect actual
+'
+
+test_expect_success '--single-branch with explicit --branch side' '
+       (
+               cd dir_side2 && git fetch &&
+               git for-each-ref refs/remotes/origin |
+               sed -e "/HEAD$/d" \
+                   -e "s|/remotes/origin/|/heads/|" >../actual
+       ) &&
+       # only follow side
+       git for-each-ref refs/heads/side >expect &&
+       test_cmp expect actual
+'
+
+test_expect_success '--single-branch with explicit --branch with tag fetches updated tag' '
+       (
+               cd dir_tag && git fetch &&
+               git for-each-ref refs/tags >../actual
+       ) &&
+       git for-each-ref refs/tags >expect &&
+       test_cmp expect actual
+'
+
+test_expect_success '--single-branch with --mirror' '
+       (
+               cd dir_mirror && git fetch &&
+               git for-each-ref refs > ../actual
+       ) &&
+       git for-each-ref refs >expect &&
+       test_cmp expect actual
+'
+
+test_expect_success '--single-branch with explicit --branch and --mirror' '
+       (
+               cd dir_mirror_side && git fetch &&
+               git for-each-ref refs > ../actual
+       ) &&
+       git for-each-ref refs >expect &&
+       test_cmp expect actual
+'
+
+test_expect_success '--single-branch with detached' '
+       (
+               cd dir_detached && git fetch &&
+               git for-each-ref refs/remotes/origin |
+               sed -e "/HEAD$/d" \
+                   -e "s|/remotes/origin/|/heads/|" >../actual
+       )
+       # nothing
+       >expect &&
+       test_cmp expect actual
+'
+
+test_done
index 57023345100d3c04f9bfb1b2a701c53b6e55deed..e7dc668cef22719a778fb0447534466b88aaa245 100755 (executable)
@@ -76,7 +76,7 @@ test_expect_success 'pushing to local repo' '
 # git-remote-testgit, but is too slow to leave in for general use.
 : test_expect_success 'racily pushing to local repo' '
        test_when_finished "rm -rf server2 localclone2" &&
-       cp -a server server2 &&
+       cp -R server server2 &&
        git clone "testgit::${PWD}/server2" localclone2 &&
        (cd localclone2 &&
        echo content >>file &&
index 1104249182074c1a987905e1661356ff8da7580c..c680f789a7028f5300a4665ca068c9a7e87bb22a 100755 (executable)
@@ -242,10 +242,10 @@ test_expect_success 'merge of identical changes in a renamed file' '
        rm -f A M N &&
        git reset --hard &&
        git checkout change+rename &&
-       GIT_MERGE_VERBOSITY=3 git merge change | grep "^Skipped B" &&
+       GIT_MERGE_VERBOSITY=3 git merge change | test_i18ngrep "^Skipped B" &&
        git reset --hard HEAD^ &&
        git checkout change &&
-       GIT_MERGE_VERBOSITY=3 git merge change+rename | grep "^Skipped B"
+       GIT_MERGE_VERBOSITY=3 git merge change+rename | test_i18ngrep "^Skipped B"
 '
 
 test_expect_success 'setup for rename + d/f conflicts' '
@@ -303,9 +303,9 @@ test_expect_success 'Rename+D/F conflict; renamed file merges but dir in way' '
        git checkout -q renamed-file-has-no-conflicts^0 &&
        test_must_fail git merge --strategy=recursive dir-in-way >output &&
 
-       grep "CONFLICT (modify/delete): dir/file-in-the-way" output &&
-       grep "Auto-merging dir" output &&
-       grep "Adding as dir~HEAD instead" output &&
+       test_i18ngrep "CONFLICT (modify/delete): dir/file-in-the-way" output &&
+       test_i18ngrep "Auto-merging dir" output &&
+       test_i18ngrep "Adding as dir~HEAD instead" output &&
 
        test 3 -eq "$(git ls-files -u | wc -l)" &&
        test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
@@ -325,9 +325,9 @@ test_expect_success 'Same as previous, but merged other way' '
        test_must_fail git merge --strategy=recursive renamed-file-has-no-conflicts >output 2>errors &&
 
        ! grep "error: refusing to lose untracked file at" errors &&
-       grep "CONFLICT (modify/delete): dir/file-in-the-way" output &&
-       grep "Auto-merging dir" output &&
-       grep "Adding as dir~renamed-file-has-no-conflicts instead" output &&
+       test_i18ngrep "CONFLICT (modify/delete): dir/file-in-the-way" output &&
+       test_i18ngrep "Auto-merging dir" output &&
+       test_i18ngrep "Adding as dir~renamed-file-has-no-conflicts instead" output &&
 
        test 3 -eq "$(git ls-files -u | wc -l)" &&
        test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
index 2cf42c73f14ef5069d096fb29e67dac571227cfe..3889eca4ae8524cd62eaf45b4d7a2394e53da429 100755 (executable)
@@ -53,7 +53,19 @@ test_expect_success 'recursive favouring ours' '
        ! grep 1 file
 '
 
-test_expect_success 'pull with -X' '
+test_expect_success 'binary file with -Xours/-Xtheirs' '
+       echo file binary >.gitattributes &&
+
+       git reset --hard master &&
+       git merge -s recursive -X theirs side &&
+       git diff --exit-code side HEAD -- file &&
+
+       git reset --hard master &&
+       git merge -s recursive -X ours side &&
+       git diff --exit-code master HEAD -- file
+'
+
+test_expect_success 'pull passes -X to underlying merge' '
        git reset --hard master && git pull -s recursive -Xours . side &&
        git reset --hard master && git pull -s recursive -X ours . side &&
        git reset --hard master && git pull -s recursive -Xtheirs . side &&
index 466fa3804bc8a840d994e9d2e9092f599cc87eab..411550d2b6e9085c5e7f93c25effec7b130f0401 100755 (executable)
@@ -380,7 +380,7 @@ test_expect_success 'handle rename/rename (2to1) conflict correctly' '
        git checkout B^0 &&
 
        test_must_fail git merge -s recursive C^0 >out &&
-       grep "CONFLICT (rename/rename)" out &&
+       test_i18ngrep "CONFLICT (rename/rename)" out &&
 
        test 2 -eq $(git ls-files -s | wc -l) &&
        test 2 -eq $(git ls-files -u | wc -l) &&
index 82f363993712d2c0de44de6285f956b46e1ceaf2..b1a63655f98dfc8d19c1a80f86652654cd9cade6 100755 (executable)
@@ -11,7 +11,7 @@ test_expect_success 'gc empty repository' '
 
 test_expect_success 'gc --gobbledegook' '
        test_expect_code 129 git gc --nonsense 2>err &&
-       grep "[Uu]sage: git gc" err
+       test_i18ngrep "[Uu]sage: git gc" err
 '
 
 test_expect_success 'gc -h with invalid configuration' '
@@ -22,7 +22,7 @@ test_expect_success 'gc -h with invalid configuration' '
                echo "[gc] pruneexpire = CORRUPT" >>.git/config &&
                test_expect_code 129 git gc -h >usage 2>&1
        ) &&
-       grep "[Uu]sage" broken/usage
+       test_i18ngrep "[Uu]sage" broken/usage
 '
 
 test_done
index 4d13e10de1f2594ab304b3a2b7b5905d75d6ff84..1e7a209efa715bc52d14d7f653ecfc13ffb5301f 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 fd6410fc7149ed381d4d09120089859281e40696..26f831984d603a959e2141641269268a2f0d78c8 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 &&
index b8cb4906aa7de022543b594399b6fa9a83ffc847..f4f38a5e7387694e16ff6f4a54020843630c2ac7 100755 (executable)
@@ -30,6 +30,9 @@ test_expect_success 'Report new path with conflict' '
 
 cat >expect <<EOF
 # On branch side
+# You have unmerged paths.
+#   (fix conflicts and run "git commit")
+#
 # Unmerged paths:
 #   (use "git add/rm <file>..." as appropriate to mark resolution)
 #
@@ -118,4 +121,97 @@ test_expect_success 'git diff-index --cached -C shows 2 copies + 1 unmerged' '
        test_cmp expected actual
 '
 
+
+test_expect_success 'status when conflicts with add and rm advice (deleted by them)' '
+       git reset --hard &&
+       git checkout master &&
+       test_commit init main.txt init &&
+       git checkout -b second_branch &&
+       git rm main.txt &&
+       git commit -m "main.txt deleted on second_branch" &&
+       test_commit second conflict.txt second &&
+       git checkout master &&
+       test_commit on_second main.txt on_second &&
+       test_commit master conflict.txt master &&
+       test_must_fail git merge second_branch &&
+       cat >expected <<-\EOF &&
+       # On branch master
+       # You have unmerged paths.
+       #   (fix conflicts and run "git commit")
+       #
+       # Unmerged paths:
+       #   (use "git add/rm <file>..." as appropriate to mark resolution)
+       #
+       #       both added:         conflict.txt
+       #       deleted by them:    main.txt
+       #
+       no changes added to commit (use "git add" and/or "git commit -a")
+       EOF
+       git status --untracked-files=no >actual &&
+       test_i18ncmp expected actual
+'
+
+
+test_expect_success 'prepare for conflicts' '
+       git reset --hard &&
+       git checkout -b conflict &&
+       test_commit one main.txt one &&
+       git branch conflict_second &&
+       git mv main.txt sub_master.txt &&
+       git commit -m "main.txt renamed in sub_master.txt" &&
+       git checkout conflict_second &&
+       git mv main.txt sub_second.txt &&
+       git commit -m "main.txt renamed in sub_second.txt"
+'
+
+
+test_expect_success 'status when conflicts with add and rm advice (both deleted)' '
+       test_must_fail git merge conflict &&
+       cat >expected <<-\EOF &&
+       # On branch conflict_second
+       # You have unmerged paths.
+       #   (fix conflicts and run "git commit")
+       #
+       # Unmerged paths:
+       #   (use "git add/rm <file>..." as appropriate to mark resolution)
+       #
+       #       both deleted:       main.txt
+       #       added by them:      sub_master.txt
+       #       added by us:        sub_second.txt
+       #
+       no changes added to commit (use "git add" and/or "git commit -a")
+       EOF
+       git status --untracked-files=no >actual &&
+       test_i18ncmp expected actual
+'
+
+
+test_expect_success 'status when conflicts with only rm advice (both deleted)' '
+       git reset --hard conflict_second &&
+       test_must_fail git merge conflict &&
+       git add sub_master.txt &&
+       git add sub_second.txt &&
+       cat >expected <<-\EOF &&
+       # On branch conflict_second
+       # You have unmerged paths.
+       #   (fix conflicts and run "git commit")
+       #
+       # Changes to be committed:
+       #
+       #       new file:   sub_master.txt
+       #
+       # Unmerged paths:
+       #   (use "git rm <file>..." to mark resolution)
+       #
+       #       both deleted:       main.txt
+       #
+       # Untracked files not listed (use -u option to show untracked files)
+       EOF
+       git status --untracked-files=no >actual &&
+       test_i18ncmp expected actual &&
+       git reset --hard &&
+       git checkout master
+'
+
+
 test_done
index 0278f48396e0d22d434b421b2f74cf05244a17a3..de7d45352e001d3c1b2c7f24361dc38dd9e0ea0a 100755 (executable)
@@ -438,8 +438,8 @@ test_expect_success 'moving to a commit without submodule does not leave empty d
        git checkout second
 '
 
-test_expect_success 'submodule <invalid-path> warns' '
-       test_failure_with_unknown_submodule
+test_expect_success 'submodule <invalid-subcommand> fails' '
+       test_must_fail git submodule no-such-subcommand
 '
 
 test_expect_success 'add submodules without specifying an explicit path' '
@@ -501,21 +501,72 @@ test_expect_success 'set up for relative path tests' '
                git add sub &&
                git config -f .gitmodules submodule.sub.path sub &&
                git config -f .gitmodules submodule.sub.url ../subrepo &&
-               cp .git/config pristine-.git-config
+               cp .git/config pristine-.git-config &&
+               cp .gitmodules pristine-.gitmodules
        )
 '
 
-test_expect_success 'relative path works with URL' '
+test_expect_success '../subrepo works with URL - ssh://hostname/repo' '
        (
                cd reltest &&
                cp pristine-.git-config .git/config &&
+               cp pristine-.gitmodules .gitmodules &&
                git config remote.origin.url ssh://hostname/repo &&
                git submodule init &&
                test "$(git config submodule.sub.url)" = ssh://hostname/subrepo
        )
 '
 
-test_expect_success 'relative path works with user@host:path' '
+test_expect_success '../subrepo works with port-qualified URL - ssh://hostname:22/repo' '
+       (
+               cd reltest &&
+               cp pristine-.git-config .git/config &&
+               cp pristine-.gitmodules .gitmodules &&
+               git config remote.origin.url ssh://hostname:22/repo &&
+               git submodule init &&
+               test "$(git config submodule.sub.url)" = ssh://hostname:22/subrepo
+       )
+'
+
+# About the choice of the path in the next test:
+# - double-slash side-steps path mangling issues on Windows
+# - it is still an absolute local path
+# - there cannot be a server with a blank in its name just in case the
+#   path is used erroneously to access a //server/share style path
+test_expect_success '../subrepo path works with local path - //somewhere else/repo' '
+       (
+               cd reltest &&
+               cp pristine-.git-config .git/config &&
+               cp pristine-.gitmodules .gitmodules &&
+               git config remote.origin.url "//somewhere else/repo" &&
+               git submodule init &&
+               test "$(git config submodule.sub.url)" = "//somewhere else/subrepo"
+       )
+'
+
+test_expect_success '../subrepo works with file URL - file:///tmp/repo' '
+       (
+               cd reltest &&
+               cp pristine-.git-config .git/config &&
+               cp pristine-.gitmodules .gitmodules &&
+               git config remote.origin.url file:///tmp/repo &&
+               git submodule init &&
+               test "$(git config submodule.sub.url)" = file:///tmp/subrepo
+       )
+'
+
+test_expect_success '../subrepo works with helper URL- helper:://hostname/repo' '
+       (
+               cd reltest &&
+               cp pristine-.git-config .git/config &&
+               cp pristine-.gitmodules .gitmodules &&
+               git config remote.origin.url helper:://hostname/repo &&
+               git submodule init &&
+               test "$(git config submodule.sub.url)" = helper:://hostname/subrepo
+       )
+'
+
+test_expect_success '../subrepo works with scp-style URL - user@host:repo' '
        (
                cd reltest &&
                cp pristine-.git-config .git/config &&
@@ -525,6 +576,98 @@ test_expect_success 'relative path works with user@host:path' '
        )
 '
 
+test_expect_success '../subrepo works with scp-style URL - user@host:path/to/repo' '
+       (
+               cd reltest &&
+               cp pristine-.git-config .git/config &&
+               cp pristine-.gitmodules .gitmodules &&
+               git config remote.origin.url user@host:path/to/repo &&
+               git submodule init &&
+               test "$(git config submodule.sub.url)" = user@host:path/to/subrepo
+       )
+'
+
+test_expect_success '../subrepo works with relative local path - foo' '
+       (
+               cd reltest &&
+               cp pristine-.git-config .git/config &&
+               cp pristine-.gitmodules .gitmodules &&
+               git config remote.origin.url foo &&
+               # actual: fails with an error
+               git submodule init &&
+               test "$(git config submodule.sub.url)" = subrepo
+       )
+'
+
+test_expect_success '../subrepo works with relative local path - foo/bar' '
+       (
+               cd reltest &&
+               cp pristine-.git-config .git/config &&
+               cp pristine-.gitmodules .gitmodules &&
+               git config remote.origin.url foo/bar &&
+               git submodule init &&
+               test "$(git config submodule.sub.url)" = foo/subrepo
+       )
+'
+
+test_expect_success '../subrepo works with relative local path - ./foo' '
+       (
+               cd reltest &&
+               cp pristine-.git-config .git/config &&
+               cp pristine-.gitmodules .gitmodules &&
+               git config remote.origin.url ./foo &&
+               git submodule init &&
+               test "$(git config submodule.sub.url)" = subrepo
+       )
+'
+
+test_expect_success '../subrepo works with relative local path - ./foo/bar' '
+       (
+               cd reltest &&
+               cp pristine-.git-config .git/config &&
+               cp pristine-.gitmodules .gitmodules &&
+               git config remote.origin.url ./foo/bar &&
+               git submodule init &&
+               test "$(git config submodule.sub.url)" = foo/subrepo
+       )
+'
+
+test_expect_success '../subrepo works with relative local path - ../foo' '
+       (
+               cd reltest &&
+               cp pristine-.git-config .git/config &&
+               cp pristine-.gitmodules .gitmodules &&
+               git config remote.origin.url ../foo &&
+               git submodule init &&
+               test "$(git config submodule.sub.url)" = ../subrepo
+       )
+'
+
+test_expect_success '../subrepo works with relative local path - ../foo/bar' '
+       (
+               cd reltest &&
+               cp pristine-.git-config .git/config &&
+               cp pristine-.gitmodules .gitmodules &&
+               git config remote.origin.url ../foo/bar &&
+               git submodule init &&
+               test "$(git config submodule.sub.url)" = ../foo/subrepo
+       )
+'
+
+test_expect_success '../bar/a/b/c works with relative local path - ../foo/bar.git' '
+       (
+               cd reltest &&
+               cp pristine-.git-config .git/config &&
+               cp pristine-.gitmodules .gitmodules &&
+               mkdir -p a/b/c &&
+               (cd a/b/c; git init) &&
+               git config remote.origin.url ../foo/bar.git &&
+               git submodule add ../bar/a/b/c ./a/b/c &&
+               git submodule init &&
+               test "$(git config submodule.a/b/c.url)" = ../foo/bar/a/b/c
+       )
+'
+
 test_expect_success 'moving the superproject does not break submodules' '
        (
                cd addtest &&
@@ -538,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 3620215c1f84b8e184b470c92b9a01c15fd75dc2..524d5c1b21a507c5ed16edc52fb9353792b83f28 100755 (executable)
@@ -26,7 +26,9 @@ test_expect_success setup '
        (cd super-clone && git submodule update --init) &&
        git clone super empty-clone &&
        (cd empty-clone && git submodule init) &&
-       git clone super top-only-clone
+       git clone super top-only-clone &&
+       git clone super relative-clone &&
+       (cd relative-clone && git submodule update --init)
 '
 
 test_expect_success 'change submodule' '
@@ -86,4 +88,90 @@ test_expect_success '"git submodule sync" should not vivify uninteresting submod
        )
 '
 
+test_expect_success '"git submodule sync" handles origin URL of the form foo' '
+       (cd relative-clone &&
+        git remote set-url origin foo &&
+        git submodule sync &&
+       (cd submodule &&
+        #actual fails with: "cannot strip off url foo
+        test "$(git config remote.origin.url)" = "../submodule"
+       )
+       )
+'
+
+test_expect_success '"git submodule sync" handles origin URL of the form foo/bar' '
+       (cd relative-clone &&
+        git remote set-url origin foo/bar &&
+        git submodule sync &&
+       (cd submodule &&
+        #actual foo/submodule
+        test "$(git config remote.origin.url)" = "../foo/submodule"
+       )
+       )
+'
+
+test_expect_success '"git submodule sync" handles origin URL of the form ./foo' '
+       (cd relative-clone &&
+        git remote set-url origin ./foo &&
+        git submodule sync &&
+       (cd submodule &&
+        #actual ./submodule
+        test "$(git config remote.origin.url)" = "../submodule"
+       )
+       )
+'
+
+test_expect_success '"git submodule sync" handles origin URL of the form ./foo/bar' '
+       (cd relative-clone &&
+        git remote set-url origin ./foo/bar &&
+        git submodule sync &&
+       (cd submodule &&
+        #actual ./foo/submodule
+        test "$(git config remote.origin.url)" = "../foo/submodule"
+       )
+       )
+'
+
+test_expect_success '"git submodule sync" handles origin URL of the form ../foo' '
+       (cd relative-clone &&
+        git remote set-url origin ../foo &&
+        git submodule sync &&
+       (cd submodule &&
+        #actual ../submodule
+        test "$(git config remote.origin.url)" = "../../submodule"
+       )
+       )
+'
+
+test_expect_success '"git submodule sync" handles origin URL of the form ../foo/bar' '
+       (cd relative-clone &&
+        git remote set-url origin ../foo/bar &&
+        git submodule sync &&
+       (cd submodule &&
+        #actual ../foo/submodule
+        test "$(git config remote.origin.url)" = "../../foo/submodule"
+       )
+       )
+'
+
+test_expect_success '"git submodule sync" handles origin URL of the form ../foo/bar with deeply nested submodule' '
+       (cd relative-clone &&
+        git remote set-url origin ../foo/bar &&
+        mkdir -p a/b/c &&
+        ( cd a/b/c &&
+          git init &&
+          :> .gitignore &&
+          git add .gitignore &&
+          test_tick &&
+          git commit -m "initial commit" ) &&
+        git submodule add ../bar/a/b/c ./a/b/c &&
+        git submodule sync &&
+       (cd a/b/c &&
+        #actual ../foo/bar/a/b/c
+        test "$(git config remote.origin.url)" = "../../../../foo/bar/a/b/c"
+       )
+       )
+'
+
+
 test_done
index 15426530e49ef2e42cda2528f4a72a784eb40cd9..feaec6cdf4b8c7eac348ea1de61887c93c69244d 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
        )
 '
 
diff --git a/t/t7409-submodule-detached-worktree.sh b/t/t7409-submodule-detached-worktree.sh
new file mode 100755 (executable)
index 0000000..2fec13d
--- /dev/null
@@ -0,0 +1,78 @@
+#!/bin/sh
+#
+# Copyright (c) 2012 Daniel Graña
+#
+
+test_description='Test submodules on detached working tree
+
+This test verifies that "git submodule" initialization, update and addition works
+on detahced working trees
+'
+
+TEST_NO_CREATE_REPO=1
+. ./test-lib.sh
+
+test_expect_success 'submodule on detached working tree' '
+       git init --bare remote &&
+       test_create_repo bundle1 &&
+       (
+               cd bundle1 &&
+               test_commit "shoot" &&
+               git rev-parse --verify HEAD >../expect
+       ) &&
+       mkdir home &&
+       (
+               cd home &&
+               export GIT_WORK_TREE="$(pwd)" GIT_DIR="$(pwd)/.dotfiles" &&
+               git clone --bare ../remote .dotfiles &&
+               git submodule add ../bundle1 .vim/bundle/sogood &&
+               test_commit "sogood" &&
+               (
+                       unset GIT_WORK_TREE GIT_DIR &&
+                       cd .vim/bundle/sogood &&
+                       git rev-parse --verify HEAD >actual &&
+                       test_cmp ../../../../expect actual
+               ) &&
+               git push origin master
+       ) &&
+       mkdir home2 &&
+       (
+               cd home2 &&
+               git clone --bare ../remote .dotfiles &&
+               export GIT_WORK_TREE="$(pwd)" GIT_DIR="$(pwd)/.dotfiles" &&
+               git checkout master &&
+               git submodule update --init &&
+               (
+                       unset GIT_WORK_TREE GIT_DIR &&
+                       cd .vim/bundle/sogood &&
+                       git rev-parse --verify HEAD >actual &&
+                       test_cmp ../../../../expect actual
+               )
+       )
+'
+
+test_expect_success 'submodule on detached working pointed by core.worktree' '
+       mkdir home3 &&
+       (
+               cd home3 &&
+               export GIT_DIR="$(pwd)/.dotfiles" &&
+               git clone --bare ../remote "$GIT_DIR" &&
+               git config core.bare false &&
+               git config core.worktree .. &&
+               git checkout master &&
+               git submodule add ../bundle1 .vim/bundle/dupe &&
+               test_commit "dupe" &&
+               git push origin master
+       ) &&
+       (
+               cd home &&
+               export GIT_DIR="$(pwd)/.dotfiles" &&
+               git config core.bare false &&
+               git config core.worktree .. &&
+               git pull &&
+               git submodule update --init &&
+               test -f .vim/bundle/dupe/shoot.t
+       )
+'
+
+test_done
index 181456aa9a80893e93477302516a7f00594eba85..deb187eb7b4277a43f46e73c1d85012b728ce14a 100755 (executable)
@@ -235,44 +235,56 @@ test_expect_success 'cleanup commit messages (strip,-F,-e): output' '
        test_i18ncmp expect actual
 '
 
-echo "#
-# Author:    $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL>
-#" >> expect
-
-test_expect_success 'author different from committer' '
+test_expect_success 'message shows author when it is not equal to committer' '
        echo >>negative &&
-       test_might_fail git commit -e -m "sample" &&
-       head -n 7 .git/COMMIT_EDITMSG >actual &&
-       test_i18ncmp expect actual
+       git commit -e -m "sample" -a &&
+       test_i18ngrep \
+         "^# Author: *A U Thor <author@example.com>\$" \
+         .git/COMMIT_EDITMSG
 '
 
-mv expect expect.tmp
-sed '$d' < expect.tmp > expect
-rm -f expect.tmp
-echo "# Committer:
-#" >> expect
+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 'committer is automatic' '
+test_expect_success AUTOIDENT 'message shows committer when it is automatic' '
 
        echo >>negative &&
        (
                sane_unset GIT_COMMITTER_EMAIL &&
                sane_unset GIT_COMMITTER_NAME &&
-               # must fail because there is no change
-               test_must_fail git commit -e -m "sample"
+               git commit -e -m "sample" -a
        ) &&
-       head -n 8 .git/COMMIT_EDITMSG | \
-       sed "s/^# Committer: .*/# Committer:/" >actual
-       test_i18ncmp expect actual
+       # the ident is calculated from the system, so we cannot
+       # check the actual value, only that it is there
+       test_i18ngrep "^# Committer: " .git/COMMIT_EDITMSG
 '
 
-pwd=`pwd`
-cat >> .git/FAKE_EDITOR << EOF
-#! /bin/sh
-echo editor started > "$pwd/.git/result"
+write_script .git/FAKE_EDITOR <<EOF
+echo editor started > "$(pwd)/.git/result"
 exit 0
 EOF
-chmod +x .git/FAKE_EDITOR
+
+test_expect_success NOAUTOIDENT 'do not fire editor when committer is bogus' '
+       >.git/result
+       >expect &&
+
+       echo >>negative &&
+       (
+               sane_unset GIT_COMMITTER_EMAIL &&
+               sane_unset GIT_COMMITTER_NAME &&
+               GIT_EDITOR="\"$(pwd)/.git/FAKE_EDITOR\"" &&
+               export GIT_EDITOR &&
+               test_must_fail git commit -e -m sample -a
+       ) &&
+       test_cmp expect .git/result
+'
 
 test_expect_success 'do not fire editor in the presence of conflicts' '
 
@@ -293,16 +305,14 @@ test_expect_success 'do not fire editor in the presence of conflicts' '
        test_must_fail git cherry-pick -n master &&
        echo "editor not started" >.git/result &&
        (
-               GIT_EDITOR="$(pwd)/.git/FAKE_EDITOR" &&
+               GIT_EDITOR="\"$(pwd)/.git/FAKE_EDITOR\"" &&
                export GIT_EDITOR &&
                test_must_fail git commit
        ) &&
        test "$(cat .git/result)" = "editor not started"
 '
 
-pwd=`pwd`
-cat >.git/FAKE_EDITOR <<EOF
-#! $SHELL_PATH
+write_script .git/FAKE_EDITOR <<EOF
 # kill -TERM command added below.
 EOF
 
@@ -339,13 +349,12 @@ test_expect_success 'A single-liner subject with a token plus colon is not a foo
 
 '
 
-cat >.git/FAKE_EDITOR <<EOF
-#!$SHELL_PATH
-mv "\$1" "\$1.orig"
+write_script .git/FAKE_EDITOR <<\EOF
+mv "$1" "$1.orig"
 (
        echo message
-       cat "\$1.orig"
-) >"\$1"
+       cat "$1.orig"
+) >"$1"
 EOF
 
 echo '## Custom template' >template
index c206f4777a36a28687def873bd9fe60ed322fbbc..e313ef196ed91a6ad12c70b147e2309af8fb4bfd 100755 (executable)
@@ -80,7 +80,7 @@ test_expect_success 'status --column' '
 #      dir1/untracked dir2/untracked untracked
 #      dir2/modified  output
 EOF
-       test_cmp expect output
+       test_i18ncmp expect output
 '
 
 cat >expect <<\EOF
diff --git a/t/t7512-status-help.sh b/t/t7512-status-help.sh
new file mode 100755 (executable)
index 0000000..b3f6eb9
--- /dev/null
@@ -0,0 +1,649 @@
+#!/bin/sh
+#
+# Copyright (c) 2012 Valentin Duperray, Lucien Kong, Franck Jonas,
+#                   Thomas Nguy, Khoi Nguyen
+#                   Grenoble INP Ensimag
+#
+
+test_description='git status advices'
+
+. ./test-lib.sh
+
+. "$TEST_DIRECTORY"/lib-rebase.sh
+
+set_fake_editor
+
+test_expect_success 'prepare for conflicts' '
+       test_commit init main.txt init &&
+       git branch conflicts &&
+       test_commit on_master main.txt on_master &&
+       git checkout conflicts &&
+       test_commit on_conflicts main.txt on_conflicts
+'
+
+
+test_expect_success 'status when conflicts unresolved' '
+       test_must_fail git merge master &&
+       cat >expected <<-\EOF &&
+       # On branch conflicts
+       # You have unmerged paths.
+       #   (fix conflicts and run "git commit")
+       #
+       # Unmerged paths:
+       #   (use "git add <file>..." to mark resolution)
+       #
+       #       both modified:      main.txt
+       #
+       no changes added to commit (use "git add" and/or "git commit -a")
+       EOF
+       git status --untracked-files=no >actual &&
+       test_i18ncmp expected actual
+'
+
+
+test_expect_success 'status when conflicts resolved before commit' '
+       git reset --hard conflicts &&
+       test_must_fail git merge master &&
+       echo one >main.txt &&
+       git add main.txt &&
+       cat >expected <<-\EOF &&
+       # On branch conflicts
+       # All conflicts fixed but you are still merging.
+       #   (use "git commit" to conclude merge)
+       #
+       # Changes to be committed:
+       #
+       #       modified:   main.txt
+       #
+       # Untracked files not listed (use -u option to show untracked files)
+       EOF
+       git status --untracked-files=no >actual &&
+       test_i18ncmp expected actual
+'
+
+
+test_expect_success 'prepare for rebase conflicts' '
+       git reset --hard master &&
+       git checkout -b rebase_conflicts &&
+       test_commit one_rebase main.txt one &&
+       test_commit two_rebase main.txt two &&
+       test_commit three_rebase main.txt three
+'
+
+
+test_expect_success 'status when rebase in progress before resolving conflicts' '
+       test_when_finished "git rebase --abort" &&
+       test_must_fail git rebase HEAD^ --onto HEAD^^ &&
+       cat >expected <<-\EOF &&
+       # Not currently on any branch.
+       # You are currently rebasing.
+       #   (fix conflicts and then run "git rebase --continue")
+       #   (use "git rebase --skip" to skip this patch)
+       #   (use "git rebase --abort" to check out the original branch)
+       #
+       # Unmerged paths:
+       #   (use "git reset HEAD <file>..." to unstage)
+       #   (use "git add <file>..." to mark resolution)
+       #
+       #       both modified:      main.txt
+       #
+       no changes added to commit (use "git add" and/or "git commit -a")
+       EOF
+       git status --untracked-files=no >actual &&
+       test_i18ncmp expected actual
+'
+
+
+test_expect_success 'status when rebase in progress before rebase --continue' '
+       git reset --hard rebase_conflicts &&
+       test_when_finished "git rebase --abort" &&
+       test_must_fail git rebase HEAD^ --onto HEAD^^ &&
+       echo three >main.txt &&
+       git add main.txt &&
+       cat >expected <<-\EOF &&
+       # Not currently on any branch.
+       # You are currently rebasing.
+       #   (all conflicts fixed: run "git rebase --continue")
+       #
+       # Changes to be committed:
+       #   (use "git reset HEAD <file>..." to unstage)
+       #
+       #       modified:   main.txt
+       #
+       # Untracked files not listed (use -u option to show untracked files)
+       EOF
+       git status --untracked-files=no >actual &&
+       test_i18ncmp expected actual
+'
+
+
+test_expect_success 'prepare for rebase_i_conflicts' '
+       git reset --hard master &&
+       git checkout -b rebase_i_conflicts &&
+       test_commit one_unmerge main.txt one_unmerge &&
+       git branch rebase_i_conflicts_second &&
+       test_commit one_master main.txt one_master &&
+       git checkout rebase_i_conflicts_second &&
+       test_commit one_second main.txt one_second
+'
+
+
+test_expect_success 'status during rebase -i when conflicts unresolved' '
+       test_when_finished "git rebase --abort" &&
+       test_must_fail git rebase -i rebase_i_conflicts &&
+       cat >expected <<-\EOF &&
+       # Not currently on any branch.
+       # You are currently rebasing.
+       #   (fix conflicts and then run "git rebase --continue")
+       #   (use "git rebase --skip" to skip this patch)
+       #   (use "git rebase --abort" to check out the original branch)
+       #
+       # Unmerged paths:
+       #   (use "git reset HEAD <file>..." to unstage)
+       #   (use "git add <file>..." to mark resolution)
+       #
+       #       both modified:      main.txt
+       #
+       no changes added to commit (use "git add" and/or "git commit -a")
+       EOF
+       git status --untracked-files=no >actual &&
+       test_i18ncmp expected actual
+'
+
+
+test_expect_success 'status during rebase -i after resolving conflicts' '
+       git reset --hard rebase_i_conflicts_second &&
+       test_when_finished "git rebase --abort" &&
+       test_must_fail git rebase -i rebase_i_conflicts &&
+       git add main.txt &&
+       cat >expected <<-\EOF &&
+       # Not currently on any branch.
+       # You are currently rebasing.
+       #   (all conflicts fixed: run "git rebase --continue")
+       #
+       # Changes to be committed:
+       #   (use "git reset HEAD <file>..." to unstage)
+       #
+       #       modified:   main.txt
+       #
+       # Untracked files not listed (use -u option to show untracked files)
+       EOF
+       git status --untracked-files=no >actual &&
+       test_i18ncmp expected actual
+'
+
+
+test_expect_success 'status when rebasing -i in edit mode' '
+       git reset --hard master &&
+       git checkout -b rebase_i_edit &&
+       test_commit one_rebase_i main.txt one &&
+       test_commit two_rebase_i main.txt two &&
+       test_commit three_rebase_i main.txt three &&
+       FAKE_LINES="1 edit 2" &&
+       export FAKE_LINES &&
+       test_when_finished "git rebase --abort" &&
+       git rebase -i HEAD~2 &&
+       cat >expected <<-\EOF &&
+       # Not currently on any branch.
+       # You are currently editing a commit during a rebase.
+       #   (use "git commit --amend" to amend the current commit)
+       #   (use "git rebase --continue" once you are satisfied with your changes)
+       #
+       nothing to commit (use -u to show untracked files)
+       EOF
+       git status --untracked-files=no >actual &&
+       test_i18ncmp expected actual
+'
+
+
+test_expect_success 'status when splitting a commit' '
+       git reset --hard master &&
+       git checkout -b split_commit &&
+       test_commit one_split main.txt one &&
+       test_commit two_split main.txt two &&
+       test_commit three_split main.txt three &&
+       test_commit four_split main.txt four &&
+       FAKE_LINES="1 edit 2 3" &&
+       export FAKE_LINES &&
+       test_when_finished "git rebase --abort" &&
+       git rebase -i HEAD~3 &&
+       git reset HEAD^ &&
+       cat >expected <<-\EOF &&
+       # Not currently on any branch.
+       # You are currently splitting a commit during a rebase.
+       #   (Once your working directory is clean, run "git rebase --continue")
+       #
+       # Changes not staged for commit:
+       #   (use "git add <file>..." to update what will be committed)
+       #   (use "git checkout -- <file>..." to discard changes in working directory)
+       #
+       #       modified:   main.txt
+       #
+       no changes added to commit (use "git add" and/or "git commit -a")
+       EOF
+       git status --untracked-files=no >actual &&
+       test_i18ncmp expected actual
+'
+
+
+test_expect_success 'status after editing the last commit with --amend during a rebase -i' '
+       git reset --hard master &&
+       git checkout -b amend_last &&
+       test_commit one_amend main.txt one &&
+       test_commit two_amend main.txt two &&
+       test_commit three_amend main.txt three &&
+       test_commit four_amend main.txt four &&
+       FAKE_LINES="1 2 edit 3" &&
+       export FAKE_LINES &&
+       test_when_finished "git rebase --abort" &&
+       git rebase -i HEAD~3 &&
+       git commit --amend -m "foo" &&
+       cat >expected <<-\EOF &&
+       # Not currently on any branch.
+       # You are currently editing a commit during a rebase.
+       #   (use "git commit --amend" to amend the current commit)
+       #   (use "git rebase --continue" once you are satisfied with your changes)
+       #
+       nothing to commit (use -u to show untracked files)
+       EOF
+       git status --untracked-files=no >actual &&
+       test_i18ncmp expected actual
+'
+
+
+test_expect_success 'prepare for several edits' '
+       git reset --hard master &&
+       git checkout -b several_edits &&
+       test_commit one_edits main.txt one &&
+       test_commit two_edits main.txt two &&
+       test_commit three_edits main.txt three &&
+       test_commit four_edits main.txt four
+'
+
+
+test_expect_success 'status: (continue first edit) second edit' '
+       FAKE_LINES="edit 1 edit 2 3" &&
+       export FAKE_LINES &&
+       test_when_finished "git rebase --abort" &&
+       git rebase -i HEAD~3 &&
+       git rebase --continue &&
+       cat >expected <<-\EOF &&
+       # Not currently on any branch.
+       # You are currently editing a commit during a rebase.
+       #   (use "git commit --amend" to amend the current commit)
+       #   (use "git rebase --continue" once you are satisfied with your changes)
+       #
+       nothing to commit (use -u to show untracked files)
+       EOF
+       git status --untracked-files=no >actual &&
+       test_i18ncmp expected actual
+'
+
+
+test_expect_success 'status: (continue first edit) second edit and split' '
+       git reset --hard several_edits &&
+       FAKE_LINES="edit 1 edit 2 3" &&
+       export FAKE_LINES &&
+       test_when_finished "git rebase --abort" &&
+       git rebase -i HEAD~3 &&
+       git rebase --continue &&
+       git reset HEAD^ &&
+       cat >expected <<-\EOF &&
+       # Not currently on any branch.
+       # You are currently splitting a commit during a rebase.
+       #   (Once your working directory is clean, run "git rebase --continue")
+       #
+       # Changes not staged for commit:
+       #   (use "git add <file>..." to update what will be committed)
+       #   (use "git checkout -- <file>..." to discard changes in working directory)
+       #
+       #       modified:   main.txt
+       #
+       no changes added to commit (use "git add" and/or "git commit -a")
+       EOF
+       git status --untracked-files=no >actual &&
+       test_i18ncmp expected actual
+'
+
+
+test_expect_success 'status: (continue first edit) second edit and amend' '
+       git reset --hard several_edits &&
+       FAKE_LINES="edit 1 edit 2 3" &&
+       export FAKE_LINES &&
+       test_when_finished "git rebase --abort" &&
+       git rebase -i HEAD~3 &&
+       git rebase --continue &&
+       git commit --amend -m "foo" &&
+       cat >expected <<-\EOF &&
+       # Not currently on any branch.
+       # You are currently editing a commit during a rebase.
+       #   (use "git commit --amend" to amend the current commit)
+       #   (use "git rebase --continue" once you are satisfied with your changes)
+       #
+       nothing to commit (use -u to show untracked files)
+       EOF
+       git status --untracked-files=no >actual &&
+       test_i18ncmp expected actual
+'
+
+
+test_expect_success 'status: (amend first edit) second edit' '
+       git reset --hard several_edits &&
+       FAKE_LINES="edit 1 edit 2 3" &&
+       export FAKE_LINES &&
+       test_when_finished "git rebase --abort" &&
+       git rebase -i HEAD~3 &&
+       git commit --amend -m "a" &&
+       git rebase --continue &&
+       cat >expected <<-\EOF &&
+       # Not currently on any branch.
+       # You are currently editing a commit during a rebase.
+       #   (use "git commit --amend" to amend the current commit)
+       #   (use "git rebase --continue" once you are satisfied with your changes)
+       #
+       nothing to commit (use -u to show untracked files)
+       EOF
+       git status --untracked-files=no >actual &&
+       test_i18ncmp expected actual
+'
+
+
+test_expect_success 'status: (amend first edit) second edit and split' '
+       git reset --hard several_edits &&
+       FAKE_LINES="edit 1 edit 2 3" &&
+       export FAKE_LINES &&
+       test_when_finished "git rebase --abort" &&
+       git rebase -i HEAD~3 &&
+       git commit --amend -m "b" &&
+       git rebase --continue &&
+       git reset HEAD^ &&
+       cat >expected <<-\EOF &&
+       # Not currently on any branch.
+       # You are currently splitting a commit during a rebase.
+       #   (Once your working directory is clean, run "git rebase --continue")
+       #
+       # Changes not staged for commit:
+       #   (use "git add <file>..." to update what will be committed)
+       #   (use "git checkout -- <file>..." to discard changes in working directory)
+       #
+       #       modified:   main.txt
+       #
+       no changes added to commit (use "git add" and/or "git commit -a")
+       EOF
+       git status --untracked-files=no >actual &&
+       test_i18ncmp expected actual
+'
+
+
+test_expect_success 'status: (amend first edit) second edit and amend' '
+       git reset --hard several_edits &&
+       FAKE_LINES="edit 1 edit 2 3" &&
+       export FAKE_LINES &&
+       test_when_finished "git rebase --abort" &&
+       git rebase -i HEAD~3 &&
+       git commit --amend -m "c" &&
+       git rebase --continue &&
+       git commit --amend -m "d" &&
+       cat >expected <<-\EOF &&
+       # Not currently on any branch.
+       # You are currently editing a commit during a rebase.
+       #   (use "git commit --amend" to amend the current commit)
+       #   (use "git rebase --continue" once you are satisfied with your changes)
+       #
+       nothing to commit (use -u to show untracked files)
+       EOF
+       git status --untracked-files=no >actual &&
+       test_i18ncmp expected actual
+'
+
+
+test_expect_success 'status: (split first edit) second edit' '
+       git reset --hard several_edits &&
+       FAKE_LINES="edit 1 edit 2 3" &&
+       export FAKE_LINES &&
+       test_when_finished "git rebase --abort" &&
+       git rebase -i HEAD~3 &&
+       git reset HEAD^ &&
+       git add main.txt &&
+       git commit -m "e" &&
+       git rebase --continue &&
+       cat >expected <<-\EOF &&
+       # Not currently on any branch.
+       # You are currently editing a commit during a rebase.
+       #   (use "git commit --amend" to amend the current commit)
+       #   (use "git rebase --continue" once you are satisfied with your changes)
+       #
+       nothing to commit (use -u to show untracked files)
+       EOF
+       git status --untracked-files=no >actual &&
+       test_i18ncmp expected actual
+'
+
+
+test_expect_success 'status: (split first edit) second edit and split' '
+       git reset --hard several_edits &&
+       FAKE_LINES="edit 1 edit 2 3" &&
+       export FAKE_LINES &&
+       test_when_finished "git rebase --abort" &&
+       git rebase -i HEAD~3 &&
+       git reset HEAD^ &&
+       git add main.txt &&
+       git commit --amend -m "f" &&
+       git rebase --continue &&
+       git reset HEAD^ &&
+       cat >expected <<-\EOF &&
+       # Not currently on any branch.
+       # You are currently splitting a commit during a rebase.
+       #   (Once your working directory is clean, run "git rebase --continue")
+       #
+       # Changes not staged for commit:
+       #   (use "git add <file>..." to update what will be committed)
+       #   (use "git checkout -- <file>..." to discard changes in working directory)
+       #
+       #       modified:   main.txt
+       #
+       no changes added to commit (use "git add" and/or "git commit -a")
+       EOF
+       git status --untracked-files=no >actual &&
+       test_i18ncmp expected actual
+'
+
+
+test_expect_success 'status: (split first edit) second edit and amend' '
+       git reset --hard several_edits &&
+       FAKE_LINES="edit 1 edit 2 3" &&
+       export FAKE_LINES &&
+       test_when_finished "git rebase --abort" &&
+       git rebase -i HEAD~3 &&
+       git reset HEAD^ &&
+       git add main.txt &&
+       git commit --amend -m "g" &&
+       git rebase --continue &&
+       git commit --amend -m "h" &&
+       cat >expected <<-\EOF &&
+       # Not currently on any branch.
+       # You are currently editing a commit during a rebase.
+       #   (use "git commit --amend" to amend the current commit)
+       #   (use "git rebase --continue" once you are satisfied with your changes)
+       #
+       nothing to commit (use -u to show untracked files)
+       EOF
+       git status --untracked-files=no >actual &&
+       test_i18ncmp expected actual
+'
+
+
+test_expect_success 'prepare am_session' '
+       git reset --hard master &&
+       git checkout -b am_session &&
+       test_commit one_am one.txt "one" &&
+       test_commit two_am two.txt "two" &&
+       test_commit three_am three.txt "three"
+'
+
+
+test_expect_success 'status in an am session: file already exists' '
+       git checkout -b am_already_exists &&
+       test_when_finished "rm Maildir/* && git am --abort" &&
+       git format-patch -1 -oMaildir &&
+       test_must_fail git am Maildir/*.patch &&
+       cat >expected <<-\EOF &&
+       # On branch am_already_exists
+       # You are in the middle of an am session.
+       #   (fix conflicts and then run "git am --resolved")
+       #   (use "git am --skip" to skip this patch)
+       #   (use "git am --abort" to restore the original branch)
+       #
+       nothing to commit (use -u to show untracked files)
+       EOF
+       git status --untracked-files=no >actual &&
+       test_i18ncmp expected actual
+'
+
+
+test_expect_success 'status in an am session: file does not exist' '
+       git reset --hard am_session &&
+       git checkout -b am_not_exists &&
+       git rm three.txt &&
+       git commit -m "delete three.txt" &&
+       test_when_finished "rm Maildir/* && git am --abort" &&
+       git format-patch -1 -oMaildir &&
+       test_must_fail git am Maildir/*.patch &&
+       cat >expected <<-\EOF &&
+       # On branch am_not_exists
+       # You are in the middle of an am session.
+       #   (fix conflicts and then run "git am --resolved")
+       #   (use "git am --skip" to skip this patch)
+       #   (use "git am --abort" to restore the original branch)
+       #
+       nothing to commit (use -u to show untracked files)
+       EOF
+       git status --untracked-files=no >actual &&
+       test_i18ncmp expected actual
+'
+
+
+test_expect_success 'status in an am session: empty patch' '
+       git reset --hard am_session &&
+       git checkout -b am_empty &&
+       test_when_finished "rm Maildir/* && git am --abort" &&
+       git format-patch -3 -oMaildir &&
+       git rm one.txt two.txt three.txt &&
+       git commit -m "delete all am_empty" &&
+       echo error >Maildir/0002-two_am.patch &&
+       test_must_fail git am Maildir/*.patch &&
+       cat >expected <<-\EOF &&
+       # On branch am_empty
+       # You are in the middle of an am session.
+       # The current patch is empty.
+       #   (use "git am --skip" to skip this patch)
+       #   (use "git am --abort" to restore the original branch)
+       #
+       nothing to commit (use -u to show untracked files)
+       EOF
+       git status --untracked-files=no >actual &&
+       test_i18ncmp expected actual
+'
+
+
+test_expect_success 'status when bisecting' '
+       git reset --hard master &&
+       git checkout -b bisect &&
+       test_commit one_bisect main.txt one &&
+       test_commit two_bisect main.txt two &&
+       test_commit three_bisect main.txt three &&
+       test_when_finished "git bisect reset" &&
+       git bisect start &&
+       git bisect bad &&
+       git bisect good one_bisect &&
+       cat >expected <<-\EOF &&
+       # Not currently on any branch.
+       # You are currently bisecting.
+       #   (use "git bisect reset" to get back to the original branch)
+       #
+       nothing to commit (use -u to show untracked files)
+       EOF
+       git status --untracked-files=no >actual &&
+       test_i18ncmp expected actual
+'
+
+
+test_expect_success 'status when rebase conflicts with statushints disabled' '
+       git reset --hard master &&
+       git checkout -b statushints_disabled &&
+       test_when_finished "git config --local advice.statushints true" &&
+       git config --local advice.statushints false &&
+       test_commit one_statushints main.txt one &&
+       test_commit two_statushints main.txt two &&
+       test_commit three_statushints main.txt three &&
+       test_when_finished "git rebase --abort" &&
+       test_must_fail git rebase HEAD^ --onto HEAD^^ &&
+       cat >expected <<-\EOF &&
+       # Not currently on any branch.
+       # You are currently rebasing.
+       #
+       # Unmerged paths:
+       #       both modified:      main.txt
+       #
+       no changes added to commit
+       EOF
+       git status --untracked-files=no >actual &&
+       test_i18ncmp expected actual
+'
+
+
+test_expect_success 'prepare for cherry-pick conflicts' '
+       git reset --hard master &&
+       git checkout -b cherry_branch &&
+       test_commit one_cherry main.txt one &&
+       test_commit two_cherries main.txt two &&
+       git checkout -b cherry_branch_second &&
+       test_commit second_cherry main.txt second &&
+       git checkout cherry_branch &&
+       test_commit three_cherries main.txt three
+'
+
+
+test_expect_success 'status when cherry-picking before resolving conflicts' '
+       test_when_finished "git cherry-pick --abort" &&
+       test_must_fail git cherry-pick cherry_branch_second &&
+       cat >expected <<-\EOF &&
+       # On branch cherry_branch
+       # You are currently cherry-picking.
+       #   (fix conflicts and run "git commit")
+       #
+       # Unmerged paths:
+       #   (use "git add <file>..." to mark resolution)
+       #
+       #       both modified:      main.txt
+       #
+       no changes added to commit (use "git add" and/or "git commit -a")
+       EOF
+       git status --untracked-files=no >actual &&
+       test_i18ncmp expected actual
+'
+
+
+test_expect_success 'status when cherry-picking after resolving conflicts' '
+       git reset --hard cherry_branch &&
+       test_when_finished "git cherry-pick --abort" &&
+       test_must_fail git cherry-pick cherry_branch_second &&
+       echo end >main.txt &&
+       git add main.txt &&
+       cat >expected <<-\EOF &&
+       # On branch cherry_branch
+       # You are currently cherry-picking.
+       #   (all conflicts fixed: run "git commit")
+       #
+       # Changes to be committed:
+       #
+       #       modified:   main.txt
+       #
+       # Untracked files not listed (use -u option to show untracked files)
+       EOF
+       git status --untracked-files=no >actual &&
+       test_i18ncmp expected actual
+'
+
+
+test_done
index 9e27bbf902e275671cb80310630a8bedcaab353c..5e19598fe72787e17d521980a3edfacb1dfa2024 100755 (executable)
@@ -157,7 +157,7 @@ test_expect_success 'merge -h with invalid index' '
                >.git/index &&
                test_expect_code 129 git merge -h 2>usage
        ) &&
-       grep "[Uu]sage: git merge" broken/usage
+       test_i18ngrep "[Uu]sage: git merge" broken/usage
 '
 
 test_expect_success 'reject non-strategy with a git-merge-foo name' '
index 6fa0c70506b4a4f6b066d6f3d25aa0e499b419b5..bc38737b2a5ebd9b7ba20fcb92ac87c48b9496c8 100755 (executable)
@@ -509,4 +509,17 @@ test_expect_success 'file with no base' '
     git reset --hard master >/dev/null 2>&1
 '
 
+test_expect_success 'custom commands override built-ins' '
+    git checkout -b test14 branch1 &&
+    git config mergetool.defaults.cmd "cat \"\$REMOTE\" >\"\$MERGED\"" &&
+    git config mergetool.defaults.trustExitCode true &&
+    test_must_fail git merge master &&
+    git mergetool --no-prompt --tool defaults -- both &&
+    echo master both added >expected &&
+    test_cmp both expected &&
+    git config --unset mergetool.defaults.cmd &&
+    git config --unset mergetool.defaults.trustExitCode &&
+    git reset --hard master >/dev/null 2>&1
+'
+
 test_done
index 9c3e997b9d6be69467a78f9ff8b1ff746be8e9b6..eb1d3f85b59b2e74231f0285fc4e90d95d0658fa 100755 (executable)
@@ -76,6 +76,17 @@ test_expect_success PERL 'custom commands' '
        test "$diff" = "branch"
 '
 
+# Ensures that a custom difftool.<tool>.cmd overrides built-ins
+test_expect_success PERL 'custom commands override built-ins' '
+       restore_test_defaults &&
+       git config difftool.defaults.cmd "cat \$REMOTE" &&
+
+       diff=$(git difftool --tool defaults --no-prompt branch) &&
+       test "$diff" = "master" &&
+
+       git config --unset difftool.defaults.cmd
+'
+
 # Ensures that git-difftool ignores bogus --tool values
 test_expect_success PERL 'difftool ignores bad --tool values' '
        diff=$(git difftool --no-prompt --tool=bad-tool branch)
index 523d04123d02cabb8703f91e9bec194c7d737f00..f698001c996ea20847c574f04dad9a65684f324f 100755 (executable)
@@ -250,6 +250,84 @@ do
                git -c grep.extendedRegexp=true grep "a+b*c" ab >actual &&
                test_cmp expected actual
        '
+
+       test_expect_success "grep $L with grep.patterntype=basic" '
+               echo "ab:a+bc" >expected &&
+               git -c grep.patterntype=basic grep "a+b*c" ab >actual &&
+               test_cmp expected actual
+       '
+
+       test_expect_success "grep $L with grep.patterntype=extended" '
+               echo "ab:abc" >expected &&
+               git -c grep.patterntype=extended grep "a+b*c" ab >actual &&
+               test_cmp expected actual
+       '
+
+       test_expect_success "grep $L with grep.patterntype=fixed" '
+               echo "ab:a+b*c" >expected &&
+               git -c grep.patterntype=fixed grep "a+b*c" ab >actual &&
+               test_cmp expected actual
+       '
+
+       test_expect_success LIBPCRE "grep $L with grep.patterntype=perl" '
+               echo "ab:a+b*c" >expected &&
+               git -c grep.patterntype=perl grep "a\x{2b}b\x{2a}c" ab >actual &&
+               test_cmp expected actual
+       '
+
+       test_expect_success "grep $L with grep.patternType=default and grep.extendedRegexp=true" '
+               echo "ab:abc" >expected &&
+               git \
+                       -c grep.patternType=default \
+                       -c grep.extendedRegexp=true \
+                       grep "a+b*c" ab >actual &&
+               test_cmp expected actual
+       '
+
+       test_expect_success "grep $L with grep.extendedRegexp=true and grep.patternType=default" '
+               echo "ab:abc" >expected &&
+               git \
+                       -c grep.extendedRegexp=true \
+                       -c grep.patternType=default \
+                       grep "a+b*c" ab >actual &&
+               test_cmp expected actual
+       '
+
+       test_expect_success 'grep $L with grep.patternType=extended and grep.extendedRegexp=false' '
+               echo "ab:abc" >expected &&
+               git \
+                       -c grep.patternType=extended \
+                       -c grep.extendedRegexp=false \
+                       grep "a+b*c" ab >actual &&
+               test_cmp expected actual
+       '
+
+       test_expect_success 'grep $L with grep.patternType=basic and grep.extendedRegexp=true' '
+               echo "ab:a+bc" >expected &&
+               git \
+                       -c grep.patternType=basic \
+                       -c grep.extendedRegexp=true \
+                       grep "a+b*c" ab >actual &&
+               test_cmp expected actual
+       '
+
+       test_expect_success 'grep $L with grep.extendedRegexp=false and grep.patternType=extended' '
+               echo "ab:abc" >expected &&
+               git \
+                       -c grep.extendedRegexp=false \
+                       -c grep.patternType=extended \
+                       grep "a+b*c" ab >actual &&
+               test_cmp expected actual
+       '
+
+       test_expect_success 'grep $L with grep.extendedRegexp=true and grep.patternType=basic' '
+               echo "ab:a+bc" >expected &&
+               git \
+                       -c grep.extendedRegexp=true \
+                       -c grep.patternType=basic \
+                       grep "a+b*c" ab >actual &&
+               test_cmp expected actual
+       '
 done
 
 cat >expected <<EOF
@@ -424,31 +502,41 @@ test_expect_success 'log grep setup' '
 
 test_expect_success 'log grep (1)' '
        git log --author=author --pretty=tformat:%s >actual &&
-       ( echo third ; echo initial ) >expect &&
+       {
+               echo third && echo initial
+       } >expect &&
        test_cmp expect actual
 '
 
 test_expect_success 'log grep (2)' '
        git log --author=" * " -F --pretty=tformat:%s >actual &&
-       ( echo second ) >expect &&
+       {
+               echo second
+       } >expect &&
        test_cmp expect actual
 '
 
 test_expect_success 'log grep (3)' '
        git log --author="^A U" --pretty=tformat:%s >actual &&
-       ( echo third ; echo initial ) >expect &&
+       {
+               echo third && echo initial
+       } >expect &&
        test_cmp expect actual
 '
 
 test_expect_success 'log grep (4)' '
        git log --author="frotz\.com>$" --pretty=tformat:%s >actual &&
-       ( echo second ) >expect &&
+       {
+               echo second
+       } >expect &&
        test_cmp expect actual
 '
 
 test_expect_success 'log grep (5)' '
        git log --author=Thor -F --pretty=tformat:%s >actual &&
-       ( echo third ; echo initial ) >expect &&
+       {
+               echo third && echo initial
+       } >expect &&
        test_cmp expect actual
 '
 
@@ -458,11 +546,49 @@ test_expect_success 'log grep (6)' '
        test_cmp expect actual
 '
 
-test_expect_success 'log --grep --author implicitly uses all-match' '
-       # grep matches initial and second but not third
-       # author matches only initial and third
-       git log --author="A U Thor" --grep=s --grep=l --format=%s >actual &&
-       echo initial >expect &&
+test_expect_success 'log grep (7)' '
+       git log -g --grep-reflog="commit: third" --pretty=tformat:%s >actual &&
+       echo third >expect &&
+       test_cmp expect actual
+'
+
+test_expect_success 'log grep (8)' '
+       git log -g --grep-reflog="commit: third" --grep-reflog="commit: second" --pretty=tformat:%s >actual &&
+       {
+               echo third && echo second
+       } >expect &&
+       test_cmp expect actual
+'
+
+test_expect_success 'log grep (9)' '
+       git log -g --grep-reflog="commit: third" --author="Thor" --pretty=tformat:%s >actual &&
+       echo third >expect &&
+       test_cmp expect actual
+'
+
+test_expect_success 'log grep (9)' '
+       git log -g --grep-reflog="commit: third" --author="non-existant" --pretty=tformat:%s >actual &&
+       : >expect &&
+       test_cmp expect actual
+'
+
+test_expect_success 'log --grep-reflog can only be used under -g' '
+       test_must_fail git log --grep-reflog="commit: third"
+'
+
+test_expect_success 'log with multiple --grep uses union' '
+       git log --grep=i --grep=r --format=%s >actual &&
+       {
+               echo fourth && echo third && echo initial
+       } >expect &&
+       test_cmp expect actual
+'
+
+test_expect_success 'log --all-match with multiple --grep uses intersection' '
+       git log --all-match --grep=i --grep=r --format=%s >actual &&
+       {
+               echo third
+       } >expect &&
        test_cmp expect actual
 '
 
@@ -474,7 +600,47 @@ test_expect_success 'log with multiple --author uses union' '
        test_cmp expect actual
 '
 
-test_expect_success 'log with --grep and multiple --author uses all-match' '
+test_expect_success 'log --all-match with multiple --author still uses union' '
+       git log --all-match --author="Thor" --author="Aster" --format=%s >actual &&
+       {
+           echo third && echo second && echo initial
+       } >expect &&
+       test_cmp expect actual
+'
+
+test_expect_success 'log --grep --author uses intersection' '
+       # grep matches only third and fourth
+       # author matches only initial and third
+       git log --author="A U Thor" --grep=r --format=%s >actual &&
+       {
+               echo third
+       } >expect &&
+       test_cmp expect actual
+'
+
+test_expect_success 'log --grep --grep --author takes union of greps and intersects with author' '
+       # grep matches initial and second but not third
+       # author matches only initial and third
+       git log --author="A U Thor" --grep=s --grep=l --format=%s >actual &&
+       {
+               echo initial
+       } >expect &&
+       test_cmp expect actual
+'
+
+test_expect_success 'log ---all-match -grep --author --author still takes union of authors and intersects with grep' '
+       # grep matches only initial and third
+       # author matches all but second
+       git log --all-match --author="Thor" --author="Night" --grep=i --format=%s >actual &&
+       {
+           echo third && echo initial
+       } >expect &&
+       test_cmp expect actual
+'
+
+test_expect_success 'log --grep --author --author takes union of authors and intersects with grep' '
+       # grep matches only initial and third
+       # author matches all but second
        git log --author="Thor" --author="Night" --grep=i --format=%s >actual &&
        {
            echo third && echo initial
@@ -482,9 +648,25 @@ test_expect_success 'log with --grep and multiple --author uses all-match' '
        test_cmp expect actual
 '
 
-test_expect_success 'log with --grep and multiple --author uses all-match' '
-       git log --author="Thor" --author="Night" --grep=q --format=%s >actual &&
-       >expect &&
+test_expect_success 'log --all-match --grep --grep --author takes intersection' '
+       # grep matches only third
+       # author matches only initial and third
+       git log --all-match --author="A U Thor" --grep=i --grep=r --format=%s >actual &&
+       {
+               echo third
+       } >expect &&
+       test_cmp expect actual
+'
+
+test_expect_success 'log --author does not search in timestamp' '
+       : >expect &&
+       git log --author="$GIT_AUTHOR_DATE" >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'log --committer does not search in timestamp' '
+       : >expect &&
+       git log --committer="$GIT_COMMITTER_DATE" >actual &&
        test_cmp expect actual
 '
 
@@ -761,44 +943,147 @@ test_expect_success 'grep -G invalidpattern properly dies ' '
        test_must_fail git grep -G "a["
 '
 
+test_expect_success 'grep invalidpattern properly dies with grep.patternType=basic' '
+       test_must_fail git -c grep.patterntype=basic grep "a["
+'
+
 test_expect_success 'grep -E invalidpattern properly dies ' '
        test_must_fail git grep -E "a["
 '
 
+test_expect_success 'grep invalidpattern properly dies with grep.patternType=extended' '
+       test_must_fail git -c grep.patterntype=extended grep "a["
+'
+
 test_expect_success LIBPCRE 'grep -P invalidpattern properly dies ' '
        test_must_fail git grep -P "a["
 '
 
+test_expect_success LIBPCRE 'grep invalidpattern properly dies with grep.patternType=perl' '
+       test_must_fail git -c grep.patterntype=perl grep "a["
+'
+
 test_expect_success 'grep -G -E -F pattern' '
        echo "ab:a+b*c" >expected &&
        git grep -G -E -F "a+b*c" ab >actual &&
        test_cmp expected actual
 '
 
+test_expect_success 'grep pattern with grep.patternType=basic, =extended, =fixed' '
+       echo "ab:a+b*c" >expected &&
+       git \
+               -c grep.patterntype=basic \
+               -c grep.patterntype=extended \
+               -c grep.patterntype=fixed \
+               grep "a+b*c" ab >actual &&
+       test_cmp expected actual
+'
+
 test_expect_success 'grep -E -F -G pattern' '
        echo "ab:a+bc" >expected &&
        git grep -E -F -G "a+b*c" ab >actual &&
        test_cmp expected actual
 '
 
+test_expect_success 'grep pattern with grep.patternType=extended, =fixed, =basic' '
+       echo "ab:a+bc" >expected &&
+       git \
+               -c grep.patterntype=extended \
+               -c grep.patterntype=fixed \
+               -c grep.patterntype=basic \
+               grep "a+b*c" ab >actual &&
+       test_cmp expected actual
+'
+
 test_expect_success 'grep -F -G -E pattern' '
        echo "ab:abc" >expected &&
        git grep -F -G -E "a+b*c" ab >actual &&
        test_cmp expected actual
 '
 
+test_expect_success 'grep pattern with grep.patternType=fixed, =basic, =extended' '
+       echo "ab:abc" >expected &&
+       git \
+               -c grep.patterntype=fixed \
+               -c grep.patterntype=basic \
+               -c grep.patterntype=extended \
+               grep "a+b*c" ab >actual &&
+       test_cmp expected actual
+'
+
 test_expect_success 'grep -G -F -P -E pattern' '
        >empty &&
        test_must_fail git grep -G -F -P -E "a\x{2b}b\x{2a}c" ab >actual &&
        test_cmp empty actual
 '
 
+test_expect_success 'grep pattern with grep.patternType=fixed, =basic, =perl, =extended' '
+       >empty &&
+       test_must_fail git \
+               -c grep.patterntype=fixed \
+               -c grep.patterntype=basic \
+               -c grep.patterntype=perl \
+               -c grep.patterntype=extended \
+               grep "a\x{2b}b\x{2a}c" ab >actual &&
+       test_cmp empty actual
+'
+
 test_expect_success LIBPCRE 'grep -G -F -E -P pattern' '
        echo "ab:a+b*c" >expected &&
        git grep -G -F -E -P "a\x{2b}b\x{2a}c" ab >actual &&
        test_cmp expected actual
 '
 
+test_expect_success LIBPCRE 'grep pattern with grep.patternType=fixed, =basic, =extended, =perl' '
+       echo "ab:a+b*c" >expected &&
+       git \
+               -c grep.patterntype=fixed \
+               -c grep.patterntype=basic \
+               -c grep.patterntype=extended \
+               -c grep.patterntype=perl \
+               grep "a\x{2b}b\x{2a}c" ab >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success LIBPCRE 'grep -P pattern with grep.patternType=fixed' '
+       echo "ab:a+b*c" >expected &&
+       git \
+               -c grep.patterntype=fixed \
+               grep -P "a\x{2b}b\x{2a}c" ab >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success 'grep -F pattern with grep.patternType=basic' '
+       echo "ab:a+b*c" >expected &&
+       git \
+               -c grep.patterntype=basic \
+               grep -F "*c" ab >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success 'grep -G pattern with grep.patternType=fixed' '
+       {
+               echo "ab:a+b*c"
+               echo "ab:a+bc"
+       } >expected &&
+       git \
+               -c grep.patterntype=fixed \
+               grep -G "a+b" ab >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success 'grep -E pattern with grep.patternType=fixed' '
+       {
+               echo "ab:a+b*c"
+               echo "ab:a+bc"
+               echo "ab:abc"
+       } >expected &&
+       git \
+               -c grep.patterntype=fixed \
+               grep -E "a+" ab >actual &&
+       test_cmp expected actual
+'
+
 test_config() {
        git config "$1" "$2" &&
        test_when_finished "git config --unset $1"
index ba19ac127e630c01e009fa6eda1fac0086d7184d..9c353ab22276c052de054281dd57808d1826a355 100755 (executable)
@@ -66,7 +66,7 @@ test_expect_success \
        git blame file2
 '
 
-test_expect_success 'blame runs on conflicted file in stages 1,3' '
+test_expect_success 'blame does not crash with conflicted file in stages 1,3' '
        git blame file1
 '
 
diff --git a/t/t9020-remote-svn.sh b/t/t9020-remote-svn.sh
new file mode 100755 (executable)
index 0000000..4f2dfe0
--- /dev/null
@@ -0,0 +1,84 @@
+#!/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
+
+# We override svnrdump by placing a symlink to the svnrdump-emulator in .
+export PATH="$HOME:$PATH"
+ln -sf $GIT_BUILD_DIR/contrib/svn-fe/svnrdump_sim.py "$HOME/svnrdump"
+
+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
+       which git
+       which 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 289fc313fb737ac7895580fd8407cff758b085e7..ee73013eed0b1c6410319aa3d7e4e57ea242a594 100755 (executable)
@@ -27,15 +27,17 @@ test_expect_success 'setup old-looking metadata' '
 head=`git rev-parse --verify refs/heads/git-svn-HEAD^0`
 test_expect_success 'git-svn-HEAD is a real HEAD' "test -n '$head'"
 
+svnrepo_escaped=`echo $svnrepo | sed 's/ /%20/'`
+
 test_expect_success 'initialize old-style (v0) git svn layout' '
        mkdir -p "$GIT_DIR"/git-svn/info "$GIT_DIR"/svn/info &&
        echo "$svnrepo" > "$GIT_DIR"/git-svn/info/url &&
        echo "$svnrepo" > "$GIT_DIR"/svn/info/url &&
        git svn migrate &&
-       ! test -d "$GIT_DIR"/git svn &&
+       ! test -d "$GIT_DIR"/git-svn &&
        git rev-parse --verify refs/${remotes_git_svn}^0 &&
        git rev-parse --verify refs/remotes/svn^0 &&
-       test "$(git config --get svn-remote.svn.url)" = "$svnrepo" &&
+       test "$(git config --get svn-remote.svn.url)" = "$svnrepo_escaped" &&
        test `git config --get svn-remote.svn.fetch` = \
              ":refs/${remotes_git_svn}"
        '
index 63fc982c8cdbd9c19eb06bba58ad5e86da5dd03e..15f93b4c2879d46309431f142b52ea61ece52215 100755 (executable)
@@ -28,10 +28,15 @@ test_expect_success 'setup svnrepo' '
        svn_cmd cp -m "trailing .lock" "$svnrepo/pr ject/trunk" \
                        "$svnrepo/pr ject/branches/trailing_dotlock.lock" &&
        svn_cmd cp -m "reflog" "$svnrepo/pr ject/trunk" \
-                       "$svnrepo/pr ject/branches/not-a%40{0}reflog" &&
+                       "$svnrepo/pr ject/branches/not-a@{0}reflog@" &&
        start_httpd
        '
 
+# SVN 1.7 will truncate "not-a%40{0]" to just "not-a".
+# Look at what SVN wound up naming the branch and use that.
+# Be sure to escape the @ if it shows up.
+non_reflog=`svn_cmd ls "$svnrepo/pr ject/branches" | grep not-a | sed 's/\///' | sed 's/@/%40/'`
+
 test_expect_success 'test clone with funky branch names' '
        git svn clone -s "$svnrepo/pr ject" project &&
        (
@@ -42,7 +47,7 @@ test_expect_success 'test clone with funky branch names' '
                git rev-parse "refs/remotes/%2Eleading_dot" &&
                git rev-parse "refs/remotes/trailing_dot%2E" &&
                git rev-parse "refs/remotes/trailing_dotlock%2Elock" &&
-               git rev-parse "refs/remotes/not-a%40{0}reflog"
+               git rev-parse "refs/remotes/$non_reflog"
        )
        '
 
index a6a56a6cb908b30799b46b1e122c1b59079db43d..b780e0efe3de8939f12e408517510f3601de494d 100755 (executable)
@@ -21,6 +21,15 @@ test_expect_success 'add red branch' "
        test_must_fail git rev-parse refs/remotes/blue
        "
 
+test_expect_success 'add gre branch' "
+       GIT_CONFIG=.git/svn/.metadata git config --unset svn-remote.svn.branches-maxRev &&
+       git config svn-remote.svn.branches 'branches/{red,gre}:refs/remotes/*' &&
+       git svn fetch &&
+       git rev-parse refs/remotes/red &&
+       test_must_fail git rev-parse refs/remotes/green &&
+       test_must_fail git rev-parse refs/remotes/blue
+       "
+
 test_expect_success 'add green branch' "
        GIT_CONFIG=.git/svn/.metadata git config --unset svn-remote.svn.branches-maxRev &&
        git config svn-remote.svn.branches 'branches/{red,green}:refs/remotes/*' &&
diff --git a/t/t9163-git-svn-reset-clears-caches.sh b/t/t9163-git-svn-reset-clears-caches.sh
new file mode 100755 (executable)
index 0000000..cd4c662
--- /dev/null
@@ -0,0 +1,78 @@
+#!/bin/sh
+#
+# Copyright (c) 2012 Peter Baumann
+#
+
+test_description='git svn reset clears memoized caches'
+. ./lib-git-svn.sh
+
+svn_ver="$(svn --version --quiet)"
+case $svn_ver in
+0.* | 1.[0-4].*)
+       skip_all="skipping git-svn test - SVN too old ($svn_ver)"
+       test_done
+       ;;
+esac
+
+# ... a  -  b - m   <- trunk
+#      \       /
+#       ... c       <- branch1
+#
+# SVN Commits not interesting for this test are abbreviated with "..."
+#
+test_expect_success 'initialize source svn repo' '
+       svn_cmd mkdir -m "create trunk" "$svnrepo"/trunk &&
+       svn_cmd mkdir -m "create branches" "$svnrepo/branches" &&
+       svn_cmd co "$svnrepo"/trunk "$SVN_TREE" &&
+       (
+               cd "$SVN_TREE" &&
+               touch foo &&
+               svn_cmd add foo &&
+               svn_cmd commit -m "a" &&
+               svn_cmd cp -m branch "$svnrepo"/trunk "$svnrepo"/branches/branch1 &&
+               svn_cmd switch "$svnrepo"/branches/branch1 &&
+               touch bar &&
+               svn_cmd add bar &&
+               svn_cmd commit -m b &&
+               svn_cmd switch "$svnrepo"/trunk &&
+               touch baz &&
+               svn_cmd add baz &&
+               svn_cmd commit -m c &&
+               svn_cmd up &&
+               svn_cmd merge "$svnrepo"/branches/branch1 &&
+               svn_cmd commit -m "m"
+       ) &&
+       rm -rf "$SVN_TREE"
+'
+
+test_expect_success 'fetch to merge-base (a)' '
+       git svn init -s "$svnrepo" &&
+       git svn fetch --revision BASE:3
+'
+
+# git svn rebase looses the merge commit
+#
+# ... a  -  b - m  <- trunk
+#      \
+#       ... c
+#
+test_expect_success 'rebase looses SVN merge (m)' '
+       git svn rebase &&
+       git svn fetch &&
+       test 1 = $(git cat-file -p master|grep parent|wc -l)
+'
+
+# git svn fetch creates correct history with merge commit
+#
+# ... a  -  b - m  <- trunk
+#      \       /
+#       ... c      <- branch1
+#
+test_expect_success 'reset and fetch gets the SVN merge (m) correctly' '
+       git svn reset -r 3 &&
+       git reset --hard trunk &&
+       git svn fetch &&
+       test 2 = $(git cat-file -p trunk|grep parent|wc -l)
+'
+
+test_done
diff --git a/t/t9164-git-svn-dcommit-concurrent.sh b/t/t9164-git-svn-dcommit-concurrent.sh
new file mode 100755 (executable)
index 0000000..d8464d4
--- /dev/null
@@ -0,0 +1,216 @@
+#!/bin/sh
+#
+# Copyright (c) 2012 Robert Luberda
+#
+
+test_description='concurrent git svn dcommit'
+. ./lib-git-svn.sh
+
+
+
+test_expect_success 'setup svn repository' '
+       svn_cmd checkout "$svnrepo" work.svn &&
+       (
+               cd work.svn &&
+               echo >file && echo > auto_updated_file
+               svn_cmd add file auto_updated_file &&
+               svn_cmd commit -m "initial commit"
+       ) &&
+       svn_cmd checkout "$svnrepo" work-auto-commits.svn
+'
+N=0
+next_N()
+{
+       N=$(( $N + 1 ))
+}
+
+# Setup SVN repository hooks to emulate SVN failures or concurrent commits
+# The function adds
+# either pre-commit  hook, which causes SVN commit given in second argument
+#                    to fail
+# or     post-commit hook, which creates a new commit (a new line added to
+#                    auto_updated_file) after given SVN commit
+# The first argument contains a type of the hook
+# The second argument contains a number (not SVN revision) of commit
+# the hook should be applied for (each time the hook is run, the given
+# number is decreased by one until it gets 0, in which case the hook
+# will execute its real action)
+setup_hook()
+{
+       hook_type="$1"  # "pre-commit" or "post-commit"
+       skip_revs="$2"
+       [ "$hook_type" = "pre-commit" ] ||
+               [ "$hook_type" = "post-commit" ] ||
+               { echo "ERROR: invalid argument ($hook_type)" \
+                       "passed to setup_hook" >&2 ; return 1; }
+       echo "cnt=$skip_revs" > "$hook_type-counter"
+       rm -f "$rawsvnrepo/hooks/"*-commit # drop previous hooks
+       hook="$rawsvnrepo/hooks/$hook_type"
+       cat > "$hook" <<- 'EOF1'
+               #!/bin/sh
+               set -e
+               cd "$1/.."  # "$1" is repository location
+               exec >> svn-hook.log 2>&1
+               hook="$(basename "$0")"
+               echo "*** Executing $hook $@"
+               set -x
+               . ./$hook-counter
+               cnt="$(($cnt - 1))"
+               echo "cnt=$cnt" > ./$hook-counter
+               [ "$cnt" = "0" ] || exit 0
+EOF1
+       if [ "$hook_type" = "pre-commit" ]; then
+               echo "echo 'commit disallowed' >&2; exit 1" >>"$hook"
+       else
+               echo "PATH=\"$PATH\"; export PATH" >>"$hook"
+               echo "svnconf=\"$svnconf\"" >>"$hook"
+               cat >>"$hook" <<- 'EOF2'
+                       cd work-auto-commits.svn
+                       svn up --config-dir "$svnconf"
+                       echo "$$" >> auto_updated_file
+                       svn commit --config-dir "$svnconf" \
+                               -m "auto-committing concurrent change"
+                       exit 0
+EOF2
+       fi
+       chmod 755 "$hook"
+}
+
+check_contents()
+{
+       gitdir="$1"
+       (cd ../work.svn && svn_cmd up) &&
+       test_cmp file ../work.svn/file &&
+       test_cmp auto_updated_file ../work.svn/auto_updated_file
+}
+
+test_expect_success 'check if post-commit hook creates a concurrent commit' '
+       setup_hook post-commit 1 &&
+       (
+               cd work.svn &&
+               cp auto_updated_file au_file_saved &&
+               echo 1 >> file &&
+               svn_cmd commit -m "changing file" &&
+               svn_cmd up &&
+               test_must_fail test_cmp auto_updated_file au_file_saved
+       )
+'
+
+test_expect_success 'check if pre-commit hook fails' '
+       setup_hook pre-commit 2 &&
+       (
+               cd work.svn &&
+               echo 2 >> file &&
+               svn_cmd commit -m "changing file once again" &&
+               echo 3 >> file &&
+               test_must_fail svn_cmd commit -m "this commit should fail" &&
+               svn_cmd revert file
+       )
+'
+
+test_expect_success 'dcommit error handling' '
+       setup_hook pre-commit 2 &&
+       next_N && git svn clone "$svnrepo" work$N.git &&
+       (
+               cd work$N.git &&
+               echo 1 >> file && git commit -am "commit change $N.1" &&
+               echo 2 >> file && git commit -am "commit change $N.2" &&
+               echo 3 >> file && git commit -am "commit change $N.3" &&
+               # should fail to dcommit 2nd and 3rd change
+               # but still should leave the repository in reasonable state
+               test_must_fail git svn dcommit &&
+               git update-index --refresh &&
+               git show HEAD~2   | grep -q git-svn-id &&
+               ! git show HEAD~1 | grep -q git-svn-id &&
+               ! git show HEAD   | grep -q git-svn-id
+       )
+'
+
+test_expect_success 'dcommit concurrent change in non-changed file' '
+       setup_hook post-commit 2 &&
+       next_N && git svn clone "$svnrepo" work$N.git &&
+       (
+               cd work$N.git &&
+               echo 1 >> file && git commit -am "commit change $N.1" &&
+               echo 2 >> file && git commit -am "commit change $N.2" &&
+               echo 3 >> file && git commit -am "commit change $N.3" &&
+               # should rebase and leave the repository in reasonable state
+               git svn dcommit &&
+               git update-index --refresh &&
+               check_contents &&
+               git show HEAD~3 | grep -q git-svn-id &&
+               git show HEAD~2 | grep -q git-svn-id &&
+               git show HEAD~1 | grep -q auto-committing &&
+               git show HEAD   | grep -q git-svn-id
+       )
+'
+
+# An utility function used in the following test
+delete_first_line()
+{
+       file="$1" &&
+       sed 1d < "$file" > "${file}.tmp" &&
+       rm "$file" &&
+       mv "${file}.tmp" "$file"
+}
+
+test_expect_success 'dcommit concurrent non-conflicting change' '
+       setup_hook post-commit 2 &&
+       next_N && git svn clone "$svnrepo" work$N.git &&
+       (
+               cd work$N.git &&
+               cat file >> auto_updated_file &&
+                       git commit -am "commit change $N.1" &&
+               delete_first_line auto_updated_file &&
+                       git commit -am "commit change $N.2" &&
+               delete_first_line auto_updated_file &&
+                       git commit -am "commit change $N.3" &&
+               # should rebase and leave the repository in reasonable state
+               git svn dcommit &&
+               git update-index --refresh &&
+               check_contents &&
+               git show HEAD~3 | grep -q git-svn-id &&
+               git show HEAD~2 | grep -q git-svn-id &&
+               git show HEAD~1 | grep -q auto-committing &&
+               git show HEAD   | grep -q git-svn-id
+       )
+'
+
+test_expect_success 'dcommit --no-rebase concurrent non-conflicting change' '
+       setup_hook post-commit 2 &&
+       next_N && git svn clone "$svnrepo" work$N.git &&
+       (
+               cd work$N.git &&
+               cat file >> auto_updated_file &&
+                       git commit -am "commit change $N.1" &&
+               delete_first_line auto_updated_file &&
+                       git commit -am "commit change $N.2" &&
+               delete_first_line auto_updated_file &&
+                       git commit -am "commit change $N.3" &&
+               # should fail as rebase is needed
+               test_must_fail git svn dcommit --no-rebase &&
+               # but should leave HEAD unchanged
+               git update-index --refresh &&
+               ! git show HEAD~2 | grep -q git-svn-id &&
+               ! git show HEAD~1 | grep -q git-svn-id &&
+               ! git show HEAD   | grep -q git-svn-id
+       )
+'
+
+test_expect_success 'dcommit fails on concurrent conflicting change' '
+       setup_hook post-commit 1 &&
+       next_N && git svn clone "$svnrepo" work$N.git &&
+       (
+               cd work$N.git &&
+               echo a >> file &&
+                       git commit -am "commit change $N.1" &&
+               echo b >> auto_updated_file &&
+                       git commit -am "commit change $N.2" &&
+               echo c >> auto_updated_file &&
+                       git commit -am "commit change $N.3" &&
+               test_must_fail git svn dcommit && # rebase should fail
+               test_must_fail git update-index --refresh
+       )
+'
+
+test_done
diff --git a/t/t9165-git-svn-fetch-merge-branch-of-branch.sh b/t/t9165-git-svn-fetch-merge-branch-of-branch.sh
new file mode 100755 (executable)
index 0000000..13ae7e3
--- /dev/null
@@ -0,0 +1,60 @@
+#!/bin/sh
+#
+# Copyright (c) 2012 Steven Walter
+#
+
+test_description='git svn merge detection'
+. ./lib-git-svn.sh
+
+svn_ver="$(svn --version --quiet)"
+case $svn_ver in
+0.* | 1.[0-4].*)
+       skip_all="skipping git-svn test - SVN too old ($svn_ver)"
+       test_done
+       ;;
+esac
+
+test_expect_success 'initialize source svn repo' '
+       svn_cmd mkdir -m x "$svnrepo"/trunk &&
+       svn_cmd mkdir -m x "$svnrepo"/branches &&
+       svn_cmd co "$svnrepo"/trunk "$SVN_TREE" &&
+       (
+               cd "$SVN_TREE" &&
+               touch foo &&
+               svn_cmd add foo &&
+               svn_cmd commit -m "initial commit" &&
+               svn_cmd cp -m branch "$svnrepo"/trunk "$svnrepo"/branches/branch1 &&
+               svn_cmd switch "$svnrepo"/branches/branch1 &&
+               touch bar &&
+               svn_cmd add bar &&
+               svn_cmd commit -m branch1 &&
+               svn_cmd cp -m branch "$svnrepo"/branches/branch1 "$svnrepo"/branches/branch2 &&
+               svn_cmd switch "$svnrepo"/branches/branch2 &&
+               touch baz &&
+               svn_cmd add baz &&
+               svn_cmd commit -m branch2 &&
+               svn_cmd switch "$svnrepo"/trunk &&
+               touch bar2 &&
+               svn_cmd add bar2 &&
+               svn_cmd commit -m trunk &&
+               svn_cmd switch "$svnrepo"/branches/branch2 &&
+               svn_cmd merge "$svnrepo"/trunk &&
+               svn_cmd commit -m "merge trunk"
+               svn_cmd switch "$svnrepo"/trunk &&
+               svn_cmd merge --reintegrate "$svnrepo"/branches/branch2 &&
+               svn_cmd commit -m "merge branch2"
+       ) &&
+       rm -rf "$SVN_TREE"
+'
+
+test_expect_success 'clone svn repo' '
+       git svn init -s "$svnrepo" &&
+       git svn fetch
+'
+
+test_expect_success 'verify merge commit' 'x=$(git rev-parse HEAD^2) &&
+       y=$(git rev-parse branch2) &&
+       test "x$x" = "x$y"
+'
+
+test_done
diff --git a/t/t9166-git-svn-fetch-merge-branch-of-branch2.sh b/t/t9166-git-svn-fetch-merge-branch-of-branch2.sh
new file mode 100755 (executable)
index 0000000..af0ec0e
--- /dev/null
@@ -0,0 +1,53 @@
+#!/bin/sh
+#
+# Copyright (c) 2012 Steven Walter
+#
+
+test_description='git svn merge detection'
+. ./lib-git-svn.sh
+
+svn_ver="$(svn --version --quiet)"
+case $svn_ver in
+0.* | 1.[0-4].*)
+       skip_all="skipping git-svn test - SVN too old ($svn_ver)"
+       test_done
+       ;;
+esac
+
+test_expect_success 'initialize source svn repo' '
+       svn_cmd mkdir -m x "$svnrepo"/trunk &&
+       svn_cmd mkdir -m x "$svnrepo"/branches &&
+       svn_cmd co "$svnrepo"/trunk "$SVN_TREE" &&
+       (
+               cd "$SVN_TREE" &&
+               touch foo &&
+               svn_cmd add foo &&
+               svn_cmd commit -m "initial commit" &&
+               svn_cmd cp -m branch "$svnrepo"/trunk "$svnrepo"/branches/branch1 &&
+               svn_cmd switch "$svnrepo"/branches/branch1 &&
+               touch bar &&
+               svn_cmd add bar &&
+               svn_cmd commit -m branch1 &&
+               svn_cmd cp -m branch "$svnrepo"/branches/branch1 "$svnrepo"/branches/branch2 &&
+               svn_cmd switch "$svnrepo"/branches/branch2 &&
+               touch baz &&
+               svn_cmd add baz &&
+               svn_cmd commit -m branch2 &&
+               svn_cmd switch "$svnrepo"/trunk &&
+               svn_cmd merge --reintegrate "$svnrepo"/branches/branch2 &&
+               svn_cmd commit -m "merge branch2"
+       ) &&
+       rm -rf "$SVN_TREE"
+'
+
+test_expect_success 'clone svn repo' '
+       git svn init -s "$svnrepo" &&
+       git svn fetch
+'
+
+test_expect_success 'verify merge commit' 'x=$(git rev-parse HEAD^2) &&
+       y=$(git rev-parse branch2) &&
+       test "x$x" = "x$y"
+'
+
+test_done
index b59be9a894b2481ece7dc5ea9038bc6c88d29f15..69934b2e775c8591ca209c9275abc40b921ecab6 100755 (executable)
@@ -19,7 +19,7 @@ then
     test_done
 fi
 
-CVSROOT=$PWD/cvsroot
+CVSROOT=$PWD/tmpcvsroot
 CVSWORK=$PWD/cvswork
 GIT_DIR=$PWD/.git
 export CVSROOT CVSWORK GIT_DIR
index 0f410c45f7005e7de1237e556396db5726a22e50..b7ad716b09facbc068a23c48cdbfe68a87f52d4c 100755 (executable)
@@ -45,7 +45,8 @@ test_expect_success 'git p4 sync uninitialized repo' '
        test_when_finished cleanup_git &&
        (
                cd "$git" &&
-               test_must_fail git p4 sync
+               test_must_fail git p4 sync 2>errs &&
+               test_i18ngrep "Perhaps you never did" errs
        )
 '
 
@@ -126,150 +127,24 @@ test_expect_success 'clone two dirs, @all, conflicting files' '
 '
 
 test_expect_success 'exit when p4 fails to produce marshaled output' '
-       badp4dir="$TRASH_DIRECTORY/badp4dir" &&
-       mkdir "$badp4dir" &&
-       test_when_finished "rm \"$badp4dir/p4\" && rmdir \"$badp4dir\"" &&
-       cat >"$badp4dir"/p4 <<-EOF &&
+       mkdir badp4dir &&
+       test_when_finished "rm badp4dir/p4 && rmdir badp4dir" &&
+       cat >badp4dir/p4 <<-EOF &&
        #!$SHELL_PATH
        exit 1
        EOF
-       chmod 755 "$badp4dir"/p4 &&
-       PATH="$badp4dir:$PATH" git p4 clone --dest="$git" //depot >errs 2>&1 ; retval=$? &&
-       test $retval -eq 1 &&
-       test_must_fail grep -q Traceback errs
-'
-
-test_expect_success 'add p4 files with wildcards in the names' '
-       (
-               cd "$cli" &&
-               echo file-wild-hash >file-wild#hash &&
-               echo file-wild-star >file-wild\*star &&
-               echo file-wild-at >file-wild@at &&
-               echo file-wild-percent >file-wild%percent &&
-               p4 add -f file-wild* &&
-               p4 submit -d "file wildcards"
-       )
-'
-
-test_expect_success 'wildcard files git p4 clone' '
-       git p4 clone --dest="$git" //depot &&
-       test_when_finished cleanup_git &&
-       (
-               cd "$git" &&
-               test -f file-wild#hash &&
-               test -f file-wild\*star &&
-               test -f file-wild@at &&
-               test -f file-wild%percent
-       )
-'
-
-test_expect_success 'wildcard files submit back to p4, add' '
-       test_when_finished cleanup_git &&
-       git p4 clone --dest="$git" //depot &&
-       (
-               cd "$git" &&
-               echo git-wild-hash >git-wild#hash &&
-               echo git-wild-star >git-wild\*star &&
-               echo git-wild-at >git-wild@at &&
-               echo git-wild-percent >git-wild%percent &&
-               git add git-wild* &&
-               git commit -m "add some wildcard filenames" &&
-               git config git-p4.skipSubmitEdit true &&
-               git p4 submit
-       ) &&
-       (
-               cd "$cli" &&
-               test_path_is_file git-wild#hash &&
-               test_path_is_file git-wild\*star &&
-               test_path_is_file git-wild@at &&
-               test_path_is_file git-wild%percent
-       )
-'
-
-test_expect_success 'wildcard files submit back to p4, modify' '
-       test_when_finished cleanup_git &&
-       git p4 clone --dest="$git" //depot &&
-       (
-               cd "$git" &&
-               echo new-line >>git-wild#hash &&
-               echo new-line >>git-wild\*star &&
-               echo new-line >>git-wild@at &&
-               echo new-line >>git-wild%percent &&
-               git add git-wild* &&
-               git commit -m "modify the wildcard files" &&
-               git config git-p4.skipSubmitEdit true &&
-               git p4 submit
-       ) &&
-       (
-               cd "$cli" &&
-               test_line_count = 2 git-wild#hash &&
-               test_line_count = 2 git-wild\*star &&
-               test_line_count = 2 git-wild@at &&
-               test_line_count = 2 git-wild%percent
-       )
-'
-
-test_expect_success 'wildcard files submit back to p4, copy' '
-       test_when_finished cleanup_git &&
-       git p4 clone --dest="$git" //depot &&
+       chmod 755 badp4dir/p4 &&
        (
-               cd "$git" &&
-               cp file2 git-wild-cp#hash &&
-               git add git-wild-cp#hash &&
-               cp git-wild\*star file-wild-3 &&
-               git add file-wild-3 &&
-               git commit -m "wildcard copies" &&
-               git config git-p4.detectCopies true &&
-               git config git-p4.detectCopiesHarder true &&
-               git config git-p4.skipSubmitEdit true &&
-               git p4 submit
+               PATH="$TRASH_DIRECTORY/badp4dir:$PATH" &&
+               export PATH &&
+               test_expect_code 1 git p4 clone --dest="$git" //depot >errs 2>&1
        ) &&
-       (
-               cd "$cli" &&
-               test_path_is_file git-wild-cp#hash &&
-               test_path_is_file file-wild-3
-       )
-'
-
-test_expect_success 'wildcard files submit back to p4, rename' '
-       test_when_finished cleanup_git &&
-       git p4 clone --dest="$git" //depot &&
-       (
-               cd "$git" &&
-               git mv git-wild@at file-wild-4 &&
-               git mv file-wild-3 git-wild-cp%percent &&
-               git commit -m "wildcard renames" &&
-               git config git-p4.detectRenames true &&
-               git config git-p4.skipSubmitEdit true &&
-               git p4 submit
-       ) &&
-       (
-               cd "$cli" &&
-               test_path_is_missing git-wild@at &&
-               test_path_is_file git-wild-cp%percent
-       )
-'
-
-test_expect_success 'wildcard files submit back to p4, delete' '
-       test_when_finished cleanup_git &&
-       git p4 clone --dest="$git" //depot &&
-       (
-               cd "$git" &&
-               git rm git-wild* &&
-               git commit -m "delete the wildcard files" &&
-               git config git-p4.skipSubmitEdit true &&
-               git p4 submit
-       ) &&
-       (
-               cd "$cli" &&
-               test_path_is_missing git-wild#hash &&
-               test_path_is_missing git-wild\*star &&
-               test_path_is_missing git-wild@at &&
-               test_path_is_missing git-wild%percent
-       )
+       cat errs &&
+       ! test_i18ngrep Traceback errs
 '
 
 test_expect_success 'clone bare' '
+       rm -rf "$git" &&
        git p4 clone --dest="$git" --bare //depot &&
        test_when_finished cleanup_git &&
        (
@@ -280,138 +155,6 @@ test_expect_success 'clone bare' '
        )
 '
 
-p4_add_user() {
-       name=$1 fullname=$2 &&
-       p4 user -f -i <<-EOF &&
-       User: $name
-       Email: $name@localhost
-       FullName: $fullname
-       EOF
-       p4 passwd -P secret $name
-}
-
-p4_grant_admin() {
-       name=$1 &&
-       {
-               p4 protect -o &&
-               echo "    admin user $name * //depot/..."
-       } | p4 protect -i
-}
-
-p4_check_commit_author() {
-       file=$1 user=$2 &&
-       p4 changes -m 1 //depot/$file | grep -q $user
-}
-
-make_change_by_user() {
-       file=$1 name=$2 email=$3 &&
-       echo "username: a change by $name" >>"$file" &&
-       git add "$file" &&
-       git commit --author "$name <$email>" -m "a change by $name"
-}
-
-# Test username support, submitting as user 'alice'
-test_expect_success 'preserve users' '
-       p4_add_user alice Alice &&
-       p4_add_user bob Bob &&
-       p4_grant_admin alice &&
-       git p4 clone --dest="$git" //depot &&
-       test_when_finished cleanup_git &&
-       (
-               cd "$git" &&
-               echo "username: a change by alice" >>file1 &&
-               echo "username: a change by bob" >>file2 &&
-               git commit --author "Alice <alice@localhost>" -m "a change by alice" file1 &&
-               git commit --author "Bob <bob@localhost>" -m "a change by bob" file2 &&
-               git config git-p4.skipSubmitEditCheck true &&
-               P4EDITOR=touch P4USER=alice P4PASSWD=secret git p4 commit --preserve-user &&
-               p4_check_commit_author file1 alice &&
-               p4_check_commit_author file2 bob
-       )
-'
-
-# Test username support, submitting as bob, who lacks admin rights. Should
-# not submit change to p4 (git diff should show deltas).
-test_expect_success 'refuse to preserve users without perms' '
-       git p4 clone --dest="$git" //depot &&
-       test_when_finished cleanup_git &&
-       (
-               cd "$git" &&
-               git config git-p4.skipSubmitEditCheck true &&
-               echo "username-noperms: a change by alice" >>file1 &&
-               git commit --author "Alice <alice@localhost>" -m "perms: a change by alice" file1 &&
-               P4EDITOR=touch P4USER=bob P4PASSWD=secret &&
-               export P4EDITOR P4USER P4PASSWD &&
-               test_must_fail git p4 commit --preserve-user &&
-               ! git diff --exit-code HEAD..p4/master
-       )
-'
-
-# What happens with unknown author? Without allowMissingP4Users it should fail.
-test_expect_success 'preserve user where author is unknown to p4' '
-       git p4 clone --dest="$git" //depot &&
-       test_when_finished cleanup_git &&
-       (
-               cd "$git" &&
-               git config git-p4.skipSubmitEditCheck true &&
-               echo "username-bob: a change by bob" >>file1 &&
-               git commit --author "Bob <bob@localhost>" -m "preserve: a change by bob" file1 &&
-               echo "username-unknown: a change by charlie" >>file1 &&
-               git commit --author "Charlie <charlie@localhost>" -m "preserve: a change by charlie" file1 &&
-               P4EDITOR=touch P4USER=alice P4PASSWD=secret &&
-               export P4EDITOR P4USER P4PASSWD &&
-               test_must_fail git p4 commit --preserve-user &&
-               ! git diff --exit-code HEAD..p4/master &&
-
-               echo "$0: repeat with allowMissingP4Users enabled" &&
-               git config git-p4.allowMissingP4Users true &&
-               git config git-p4.preserveUser true &&
-               git p4 commit &&
-               git diff --exit-code HEAD..p4/master &&
-               p4_check_commit_author file1 alice
-       )
-'
-
-# If we're *not* using --preserve-user, git p4 should warn if we're submitting
-# changes that are not all ours.
-# Test: user in p4 and user unknown to p4.
-# Test: warning disabled and user is the same.
-test_expect_success 'not preserving user with mixed authorship' '
-       git p4 clone --dest="$git" //depot &&
-       test_when_finished cleanup_git &&
-       (
-               cd "$git" &&
-               git config git-p4.skipSubmitEditCheck true &&
-               p4_add_user derek Derek &&
-
-               make_change_by_user usernamefile3 Derek derek@localhost &&
-               P4EDITOR=cat P4USER=alice P4PASSWD=secret &&
-               export P4EDITOR P4USER P4PASSWD &&
-               git p4 commit |\
-               grep "git author derek@localhost does not match" &&
-
-               make_change_by_user usernamefile3 Charlie charlie@localhost &&
-               git p4 commit |\
-               grep "git author charlie@localhost does not match" &&
-
-               make_change_by_user usernamefile3 alice alice@localhost &&
-               git p4 commit |\
-               test_must_fail grep "git author.*does not match" &&
-
-               git config git-p4.skipUserNameCheck true &&
-               make_change_by_user usernamefile3 Charlie charlie@localhost &&
-               git p4 commit |\
-               test_must_fail grep "git author.*does not match" &&
-
-               p4_check_commit_author usernamefile3 alice
-       )
-'
-
-marshal_dump() {
-       what=$1
-       "$PYTHON_PATH" -c 'import marshal, sys; d = marshal.load(sys.stdin); print d["'$what'"]'
-}
-
 # Sleep a bit so that the top-most p4 change did not happen "now".  Then
 # import the repo and make sure that the initial import has the same time
 # as the top-most change.
@@ -429,146 +172,6 @@ test_expect_success 'initial import time from top change time' '
        )
 '
 
-# Rename a file and confirm that rename is not detected in P4.
-# Rename the new file again with detectRenames option enabled and confirm that
-# this is detected in P4.
-# Rename the new file again adding an extra line, configure a big threshold in
-# detectRenames and confirm that rename is not detected in P4.
-# Repeat, this time with a smaller threshold and confirm that the rename is
-# detected in P4.
-test_expect_success 'detect renames' '
-       git p4 clone --dest="$git" //depot@all &&
-       test_when_finished cleanup_git &&
-       (
-               cd "$git" &&
-               git config git-p4.skipSubmitEdit true &&
-
-               git mv file1 file4 &&
-               git commit -a -m "Rename file1 to file4" &&
-               git diff-tree -r -M HEAD &&
-               git p4 submit &&
-               p4 filelog //depot/file4 &&
-               p4 filelog //depot/file4 | test_must_fail grep -q "branch from" &&
-
-               git mv file4 file5 &&
-               git commit -a -m "Rename file4 to file5" &&
-               git diff-tree -r -M HEAD &&
-               git config git-p4.detectRenames true &&
-               git p4 submit &&
-               p4 filelog //depot/file5 &&
-               p4 filelog //depot/file5 | grep -q "branch from //depot/file4" &&
-
-               git mv file5 file6 &&
-               echo update >>file6 &&
-               git add file6 &&
-               git commit -a -m "Rename file5 to file6 with changes" &&
-               git diff-tree -r -M HEAD &&
-               level=$(git diff-tree -r -M HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/R0*//") &&
-               test -n "$level" && test "$level" -gt 0 && test "$level" -lt 98 &&
-               git config git-p4.detectRenames $(($level + 2)) &&
-               git p4 submit &&
-               p4 filelog //depot/file6 &&
-               p4 filelog //depot/file6 | test_must_fail grep -q "branch from" &&
-
-               git mv file6 file7 &&
-               echo update >>file7 &&
-               git add file7 &&
-               git commit -a -m "Rename file6 to file7 with changes" &&
-               git diff-tree -r -M HEAD &&
-               level=$(git diff-tree -r -M HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/R0*//") &&
-               test -n "$level" && test "$level" -gt 2 && test "$level" -lt 100 &&
-               git config git-p4.detectRenames $(($level - 2)) &&
-               git p4 submit &&
-               p4 filelog //depot/file7 &&
-               p4 filelog //depot/file7 | grep -q "branch from //depot/file6"
-       )
-'
-
-# Copy a file and confirm that copy is not detected in P4.
-# Copy a file with detectCopies option enabled and confirm that copy is not
-# detected in P4.
-# Modify and copy a file with detectCopies option enabled and confirm that copy
-# is detected in P4.
-# Copy a file with detectCopies and detectCopiesHarder options enabled and
-# confirm that copy is detected in P4.
-# Modify and copy a file, configure a bigger threshold in detectCopies and
-# confirm that copy is not detected in P4.
-# Modify and copy a file, configure a smaller threshold in detectCopies and
-# confirm that copy is detected in P4.
-test_expect_success 'detect copies' '
-       git p4 clone --dest="$git" //depot@all &&
-       test_when_finished cleanup_git &&
-       (
-               cd "$git" &&
-               git config git-p4.skipSubmitEdit true &&
-
-               cp file2 file8 &&
-               git add file8 &&
-               git commit -a -m "Copy file2 to file8" &&
-               git diff-tree -r -C HEAD &&
-               git p4 submit &&
-               p4 filelog //depot/file8 &&
-               p4 filelog //depot/file8 | test_must_fail grep -q "branch from" &&
-
-               cp file2 file9 &&
-               git add file9 &&
-               git commit -a -m "Copy file2 to file9" &&
-               git diff-tree -r -C HEAD &&
-               git config git-p4.detectCopies true &&
-               git p4 submit &&
-               p4 filelog //depot/file9 &&
-               p4 filelog //depot/file9 | test_must_fail grep -q "branch from" &&
-
-               echo "file2" >>file2 &&
-               cp file2 file10 &&
-               git add file2 file10 &&
-               git commit -a -m "Modify and copy file2 to file10" &&
-               git diff-tree -r -C HEAD &&
-               git p4 submit &&
-               p4 filelog //depot/file10 &&
-               p4 filelog //depot/file10 | grep -q "branch from //depot/file" &&
-
-               cp file2 file11 &&
-               git add file11 &&
-               git commit -a -m "Copy file2 to file11" &&
-               git diff-tree -r -C --find-copies-harder HEAD &&
-               src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) &&
-               test "$src" = file10 &&
-               git config git-p4.detectCopiesHarder true &&
-               git p4 submit &&
-               p4 filelog //depot/file11 &&
-               p4 filelog //depot/file11 | grep -q "branch from //depot/file" &&
-
-               cp file2 file12 &&
-               echo "some text" >>file12 &&
-               git add file12 &&
-               git commit -a -m "Copy file2 to file12 with changes" &&
-               git diff-tree -r -C --find-copies-harder HEAD &&
-               level=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/C0*//") &&
-               test -n "$level" && test "$level" -gt 0 && test "$level" -lt 98 &&
-               src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) &&
-               test "$src" = file10 &&
-               git config git-p4.detectCopies $(($level + 2)) &&
-               git p4 submit &&
-               p4 filelog //depot/file12 &&
-               p4 filelog //depot/file12 | test_must_fail grep -q "branch from" &&
-
-               cp file2 file13 &&
-               echo "different text" >>file13 &&
-               git add file13 &&
-               git commit -a -m "Copy file2 to file13 with changes" &&
-               git diff-tree -r -C --find-copies-harder HEAD &&
-               level=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/C0*//") &&
-               test -n "$level" && test "$level" -gt 2 && test "$level" -lt 100 &&
-               src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) &&
-               test "$src" = file10 &&
-               git config git-p4.detectCopies $(($level - 2)) &&
-               git p4 submit &&
-               p4 filelog //depot/file13 &&
-               p4 filelog //depot/file13 | grep -q "branch from //depot/file"
-       )
-'
-
 test_expect_success 'kill p4d' '
        kill_p4d
 '
index 99fe16b72d448e9b5cf686304cb040c221ad1f44..9730821c3032c7d3251e2ce0d260df15f6c24f21 100755 (executable)
@@ -410,6 +410,83 @@ test_expect_failure 'git p4 clone file subset branch' '
                test_path_is_missing file3
        )
 '
+
+# From a report in http://stackoverflow.com/questions/11893688
+# where --use-client-spec caused branch prefixes not to be removed;
+# every file in git appeared into a subdirectory of the branch name.
+test_expect_success 'use-client-spec detect-branches setup' '
+       rm -rf "$cli" &&
+       mkdir "$cli" &&
+       (
+               cd "$cli" &&
+               client_view "//depot/usecs/... //client/..." &&
+               mkdir b1 &&
+               echo b1/b1-file1 >b1/b1-file1 &&
+               p4 add b1/b1-file1 &&
+               p4 submit -d "b1/b1-file1" &&
+
+               p4 integrate //depot/usecs/b1/... //depot/usecs/b2/... &&
+               p4 submit -d "b1 -> b2" &&
+               p4 branch -i <<-EOF &&
+               Branch: b2
+               View: //depot/usecs/b1/... //depot/usecs/b2/...
+               EOF
+
+               echo b2/b2-file2 >b2/b2-file2 &&
+               p4 add b2/b2-file2 &&
+               p4 submit -d "b2/b2-file2"
+       )
+'
+
+test_expect_success 'use-client-spec detect-branches files in top-level' '
+       test_when_finished cleanup_git &&
+       test_create_repo "$git" &&
+       (
+               cd "$git" &&
+               git p4 sync --detect-branches --use-client-spec //depot/usecs@all &&
+               git checkout -b master p4/usecs/b1 &&
+               test_path_is_file b1-file1 &&
+               test_path_is_missing b2-file2 &&
+               test_path_is_missing b1 &&
+               test_path_is_missing b2 &&
+
+               git checkout -b b2 p4/usecs/b2 &&
+               test_path_is_file b1-file1 &&
+               test_path_is_file b2-file2 &&
+               test_path_is_missing b1 &&
+               test_path_is_missing b2
+       )
+'
+
+test_expect_success 'use-client-spec detect-branches skips branches setup' '
+       (
+               cd "$cli" &&
+
+               p4 integrate //depot/usecs/b1/... //depot/usecs/b3/... &&
+               p4 submit -d "b1 -> b3" &&
+               p4 branch -i <<-EOF &&
+               Branch: b3
+               View: //depot/usecs/b1/... //depot/usecs/b3/...
+               EOF
+
+               echo b3/b3-file3 >b3/b3-file3 &&
+               p4 add b3/b3-file3 &&
+               p4 submit -d "b3/b3-file3"
+       )
+'
+
+test_expect_success 'use-client-spec detect-branches skips branches' '
+       client_view "//depot/usecs/... //client/..." \
+                   "-//depot/usecs/b3/... //client/b3/..." &&
+       test_when_finished cleanup_git &&
+       test_create_repo "$git" &&
+       (
+               cd "$git" &&
+               git p4 sync --detect-branches --use-client-spec //depot/usecs@all &&
+               test_must_fail git rev-parse refs/remotes/p4/usecs/b3
+       )
+'
+
 test_expect_success 'kill p4d' '
        kill_p4d
 '
index 353dcfbe09fec2c2a85427e3e5cb378b9a8318d8..ff2cc79701cce5ff570ff3c11d1ad0b60459d9ef 100755 (executable)
@@ -38,7 +38,7 @@ test_expect_success 'no config, unedited, say no' '
                cd "$git" &&
                echo line >>file1 &&
                git commit -a -m "change 3 (not really)" &&
-               printf "bad response\nn\n" | git p4 submit &&
+               printf "bad response\nn\n" | test_expect_code 1 git p4 submit &&
                p4 changes //depot/... >wc &&
                test_line_count = 2 wc
        )
@@ -78,20 +78,19 @@ test_expect_success 'skipSubmitEditCheck' '
 test_expect_success 'no config, edited' '
        git p4 clone --dest="$git" //depot &&
        test_when_finished cleanup_git &&
-       ed="$TRASH_DIRECTORY/ed.sh" &&
-       test_when_finished "rm \"$ed\"" &&
-       cat >"$ed" <<-EOF &&
+       test_when_finished "rm ed.sh" &&
+       cat >ed.sh <<-EOF &&
                #!$SHELL_PATH
                sleep 1
                touch "\$1"
                exit 0
        EOF
-       chmod 755 "$ed" &&
+       chmod 755 ed.sh &&
        (
                cd "$git" &&
                echo line >>file1 &&
                git commit -a -m "change 5" &&
-               P4EDITOR="" EDITOR="\"$ed\"" git p4 submit &&
+               P4EDITOR="" EDITOR="\"$TRASH_DIRECTORY/ed.sh\"" git p4 submit &&
                p4 changes //depot/... >wc &&
                test_line_count = 5 wc
        )
index 2892367830c90353698ef0554b84c1e66d36a0a2..fa40cc8bb59a4e785681013e1dc676709d808410 100755 (executable)
@@ -39,10 +39,9 @@ test_expect_success 'clone --branch' '
 '
 
 test_expect_success 'clone --changesfile' '
-       cf="$TRASH_DIRECTORY/cf" &&
-       test_when_finished "rm \"$cf\"" &&
-       printf "1\n3\n" >"$cf" &&
-       git p4 clone --changesfile="$cf" --dest="$git" //depot &&
+       test_when_finished "rm cf" &&
+       printf "1\n3\n" >cf &&
+       git p4 clone --changesfile="$TRASH_DIRECTORY/cf" --dest="$git" //depot &&
        test_when_finished cleanup_git &&
        (
                cd "$git" &&
@@ -55,10 +54,9 @@ test_expect_success 'clone --changesfile' '
 '
 
 test_expect_success 'clone --changesfile, @all' '
-       cf="$TRASH_DIRECTORY/cf" &&
-       test_when_finished "rm \"$cf\"" &&
-       printf "1\n3\n" >"$cf" &&
-       test_must_fail git p4 clone --changesfile="$cf" --dest="$git" //depot@all
+       test_when_finished "rm cf" &&
+       printf "1\n3\n" >cf &&
+       test_must_fail git p4 clone --changesfile="$TRASH_DIRECTORY/cf" --dest="$git" //depot@all
 '
 
 # imports both master and p4/master in refs/heads
@@ -128,7 +126,7 @@ test_expect_success 'clone --use-client-spec' '
                exec >/dev/null &&
                test_must_fail git p4 clone --dest="$git" --use-client-spec
        ) &&
-       cli2="$TRASH_DIRECTORY/cli2" &&
+       cli2=$(test-path-utils real_path "$TRASH_DIRECTORY/cli2") &&
        mkdir -p "$cli2" &&
        test_when_finished "rmdir \"$cli2\"" &&
        (
@@ -151,7 +149,6 @@ test_expect_success 'clone --use-client-spec' '
        cleanup_git &&
 
        # same thing again, this time with variable instead of option
-       mkdir "$git" &&
        (
                cd "$git" &&
                git init &&
index f23b4c3620592704cac35839a010ce55de139da7..0ae048f29f548eac6cfa37fbabcd9b7f80440515 100755 (executable)
@@ -54,6 +54,47 @@ test_expect_success 'submit --origin' '
        )
 '
 
+test_expect_success 'submit --dry-run' '
+       test_when_finished cleanup_git &&
+       git p4 clone --dest="$git" //depot &&
+       (
+               cd "$git" &&
+               test_commit "dry-run1" &&
+               test_commit "dry-run2" &&
+               git p4 submit --dry-run >out &&
+               test_i18ngrep "Would apply" out
+       ) &&
+       (
+               cd "$cli" &&
+               test_path_is_missing "dry-run1.t" &&
+               test_path_is_missing "dry-run2.t"
+       )
+'
+
+test_expect_success 'submit --dry-run --export-labels' '
+       test_when_finished cleanup_git &&
+       git p4 clone --dest="$git" //depot &&
+       (
+               cd "$git" &&
+               echo dry-run1 >dry-run1 &&
+               git add dry-run1 &&
+               git commit -m "dry-run1" dry-run1 &&
+               git config git-p4.skipSubmitEdit true &&
+               git p4 submit &&
+               echo dry-run2 >dry-run2 &&
+               git add dry-run2 &&
+               git commit -m "dry-run2" dry-run2 &&
+               git tag -m "dry-run-tag1" dry-run-tag1 HEAD^ &&
+               git p4 submit --dry-run --export-labels >out &&
+               test_i18ngrep "Would create p4 label" out
+       ) &&
+       (
+               cd "$cli" &&
+               test_path_is_file "dry-run1" &&
+               test_path_is_missing "dry-run2"
+       )
+'
+
 test_expect_success 'submit with allowSubmit' '
        test_when_finished cleanup_git &&
        git p4 clone --dest="$git" //depot &&
@@ -182,6 +223,185 @@ test_expect_success 'submit rename' '
        )
 '
 
+#
+# Converting git commit message to p4 change description, including
+# parsing out the optional Jobs: line.
+#
+test_expect_success 'simple one-line description' '
+       test_when_finished cleanup_git &&
+       git p4 clone --dest="$git" //depot &&
+       (
+               cd "$git" &&
+               echo desc2 >desc2 &&
+               git add desc2 &&
+               cat >msg <<-EOF &&
+               One-line description line for desc2.
+               EOF
+               git commit -F - <msg &&
+               git config git-p4.skipSubmitEdit true &&
+               git p4 submit &&
+               change=$(p4 -G changes -m 1 //depot/... | \
+                        marshal_dump change) &&
+               # marshal_dump always adds a newline
+               p4 -G describe $change | marshal_dump desc | sed \$d >pmsg &&
+               test_cmp msg pmsg
+       )
+'
+
+test_expect_success 'description with odd formatting' '
+       test_when_finished cleanup_git &&
+       git p4 clone --dest="$git" //depot &&
+       (
+               cd "$git" &&
+               echo desc3 >desc3 &&
+               git add desc3 &&
+               (
+                       printf "subject line\n\n\tExtra tab\nline.\n\n" &&
+                       printf "Description:\n\tBogus description marker\n\n" &&
+                       # git commit eats trailing newlines; only use one
+                       printf "Files:\n\tBogus descs marker\n"
+               ) >msg &&
+               git commit -F - <msg &&
+               git config git-p4.skipSubmitEdit true &&
+               git p4 submit &&
+               change=$(p4 -G changes -m 1 //depot/... | \
+                        marshal_dump change) &&
+               # marshal_dump always adds a newline
+               p4 -G describe $change | marshal_dump desc | sed \$d >pmsg &&
+               test_cmp msg pmsg
+       )
+'
+
+make_job() {
+       name="$1" &&
+       tab="$(printf \\t)" &&
+       p4 job -o | \
+       sed -e "/^Job:/s/.*/Job: $name/" \
+           -e "/^Description/{ n; s/.*/$tab job text/; }" | \
+       p4 job -i
+}
+
+test_expect_success 'description with Jobs section at end' '
+       test_when_finished cleanup_git &&
+       git p4 clone --dest="$git" //depot &&
+       (
+               cd "$git" &&
+               echo desc4 >desc4 &&
+               git add desc4 &&
+               echo 6060842 >jobname &&
+               (
+                       printf "subject line\n\n\tExtra tab\nline.\n\n" &&
+                       printf "Files:\n\tBogus files marker\n" &&
+                       printf "Junk: 3164175\n" &&
+                       printf "Jobs: $(cat jobname)\n"
+               ) >msg &&
+               git commit -F - <msg &&
+               git config git-p4.skipSubmitEdit true &&
+               # build a job
+               make_job $(cat jobname) &&
+               git p4 submit &&
+               change=$(p4 -G changes -m 1 //depot/... | \
+                        marshal_dump change) &&
+               # marshal_dump always adds a newline
+               p4 -G describe $change | marshal_dump desc | sed \$d >pmsg &&
+               # make sure Jobs line and all following is gone
+               sed "/^Jobs:/,\$d" msg >jmsg &&
+               test_cmp jmsg pmsg &&
+               # make sure p4 knows about job
+               p4 -G describe $change | marshal_dump job0 >job0 &&
+               test_cmp jobname job0
+       )
+'
+
+test_expect_success 'description with Jobs and values on separate lines' '
+       test_when_finished cleanup_git &&
+       git p4 clone --dest="$git" //depot &&
+       (
+               cd "$git" &&
+               echo desc5 >desc5 &&
+               git add desc5 &&
+               echo PROJ-6060842 >jobname1 &&
+               echo PROJ-6060847 >jobname2 &&
+               (
+                       printf "subject line\n\n\tExtra tab\nline.\n\n" &&
+                       printf "Files:\n\tBogus files marker\n" &&
+                       printf "Junk: 3164175\n" &&
+                       printf "Jobs:\n" &&
+                       printf "\t$(cat jobname1)\n" &&
+                       printf "\t$(cat jobname2)\n"
+               ) >msg &&
+               git commit -F - <msg &&
+               git config git-p4.skipSubmitEdit true &&
+               # build two jobs
+               make_job $(cat jobname1) &&
+               make_job $(cat jobname2) &&
+               git p4 submit &&
+               change=$(p4 -G changes -m 1 //depot/... | \
+                        marshal_dump change) &&
+               # marshal_dump always adds a newline
+               p4 -G describe $change | marshal_dump desc | sed \$d >pmsg &&
+               # make sure Jobs line and all following is gone
+               sed "/^Jobs:/,\$d" msg >jmsg &&
+               test_cmp jmsg pmsg &&
+               # make sure p4 knows about the two jobs
+               p4 -G describe $change >change &&
+               (
+                       marshal_dump job0 <change &&
+                       marshal_dump job1 <change
+               ) | sort >jobs &&
+               cat jobname1 jobname2 | sort >expected &&
+               test_cmp expected jobs
+       )
+'
+
+test_expect_success 'description with Jobs section and bogus following text' '
+       test_when_finished cleanup_git &&
+       git p4 clone --dest="$git" //depot &&
+       (
+               cd "$git" &&
+               echo desc6 >desc6 &&
+               git add desc6 &&
+               echo 6060843 >jobname &&
+               (
+                       printf "subject line\n\n\tExtra tab\nline.\n\n" &&
+                       printf "Files:\n\tBogus files marker\n" &&
+                       printf "Junk: 3164175\n" &&
+                       printf "Jobs: $(cat jobname)\n" &&
+                       printf "MoreJunk: 3711\n"
+               ) >msg &&
+               git commit -F - <msg &&
+               git config git-p4.skipSubmitEdit true &&
+               # build a job
+               make_job $(cat jobname) &&
+               test_must_fail git p4 submit 2>err &&
+               test_i18ngrep "Unknown field name" err
+       ) &&
+       (
+               cd "$cli" &&
+               p4 revert desc6 &&
+               rm desc6
+       )
+'
+
+test_expect_success 'submit --prepare-p4-only' '
+       test_when_finished cleanup_git &&
+       git p4 clone --dest="$git" //depot &&
+       (
+               cd "$git" &&
+               echo prep-only-add >prep-only-add &&
+               git add prep-only-add &&
+               git commit -m "prep only add" &&
+               git p4 submit --prepare-p4-only >out &&
+               test_i18ngrep "prepared for submission" out &&
+               test_i18ngrep "must be deleted" out
+       ) &&
+       (
+               cd "$cli" &&
+               test_path_is_file prep-only-add &&
+               p4 fstat -T action prep-only-add | grep -w add
+       )
+'
+
 test_expect_success 'kill p4d' '
        kill_p4d
 '
index 2f8014a60ef07d84430b9a696d46cd63c4822524..dc92e60cd6f09fa5e2610d491cf1c07d43c45dfd 100755 (executable)
@@ -21,7 +21,7 @@ test_expect_success 'init depot' '
 # environment variable is set
 test_expect_success 'P4CONFIG and absolute dir clone' '
        printf "P4PORT=$P4PORT\nP4CLIENT=$P4CLIENT\n" >p4config &&
-       test_when_finished "rm \"$TRASH_DIRECTORY/p4config\"" &&
+       test_when_finished "rm p4config" &&
        test_when_finished cleanup_git &&
        (
                P4CONFIG=p4config && export P4CONFIG &&
@@ -33,7 +33,7 @@ test_expect_success 'P4CONFIG and absolute dir clone' '
 # same thing, but with relative directory name, note missing $ on --dest
 test_expect_success 'P4CONFIG and relative dir clone' '
        printf "P4PORT=$P4PORT\nP4CLIENT=$P4CLIENT\n" >p4config &&
-       test_when_finished "rm \"$TRASH_DIRECTORY/p4config\"" &&
+       test_when_finished "rm p4config" &&
        test_when_finished cleanup_git &&
        (
                P4CONFIG=p4config && export P4CONFIG &&
index 7d993ef80acdf1775d70713d2b9abfb984c47c1e..281be29174b8b4fea854d72c663eaa2d46b00259 100755 (executable)
@@ -8,23 +8,6 @@ test_expect_success 'start p4d' '
        start_p4d
 '
 
-#
-# Construct a client with this list of View lines
-#
-client_view() {
-       (
-               cat <<-EOF &&
-               Client: client
-               Description: client
-               Root: $cli
-               View:
-               EOF
-               for arg ; do
-                       printf "\t$arg\n"
-               done
-       ) | p4 client -i
-}
-
 #
 # Verify these files exist, exactly.  Caller creates
 # a list of files in file "files".
index b00ad09d23d8e859d3b52c73579e84ad4620b36c..fe30ad881f67c9f1fdcb2ee40922880126ec13cc 100755 (executable)
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-test_description='git-p4 rcs keywords'
+test_description='git p4 rcs keywords'
 
 . ./lib-git-p4.sh
 
@@ -147,7 +147,7 @@ test_expect_success 'scrub ko files differently' '
        )
 '
 
-# hack; git-p4 submit should do it on its own
+# hack; git p4 submit should do it on its own
 test_expect_success 'cleanup after failure' '
        (
                cd "$cli" &&
@@ -160,9 +160,6 @@ test_expect_success 'cleanup after failure' '
 # the cli file so that submit will get a conflict.  Make sure that
 # scrubbing doesn't make a mess of things.
 #
-# Assumes that git-p4 exits leaving the p4 file open, with the
-# conflict-generating patch unapplied.
-#
 # This might happen only if the git repo is behind the p4 repo at
 # submit time, and there is a conflict.
 #
@@ -181,19 +178,16 @@ test_expect_success 'do not scrub plain text' '
                        sed -i "s/^line5/line5 p4 edit/" file_text &&
                        p4 submit -d "file5 p4 edit"
                ) &&
-               ! git p4 submit &&
+               echo s | test_expect_code 1 git p4 submit &&
                (
-                       # exepct something like:
-                       #    file_text - file(s) not opened on this client
-                       # but not copious diff output
+                       # make sure the file is not left open
                        cd "$cli" &&
-                       p4 diff file_text >wc &&
-                       test_line_count = 1 wc
+                       ! p4 fstat -T action file_text
                )
        )
 '
 
-# hack; git-p4 submit should do it on its own
+# hack; git p4 submit should do it on its own
 test_expect_success 'cleanup after failure 2' '
        (
                cd "$cli" &&
@@ -244,7 +238,7 @@ test_expect_success 'cope with rcs keyword expansion damage' '
                cd "$git" &&
                git config git-p4.skipSubmitEdit true &&
                git config git-p4.attemptRCSCleanup true &&
-               (cd ../cli && p4_append_to_file kwfile1.c) &&
+               (cd "$cli" && p4_append_to_file kwfile1.c) &&
                old_lines=$(wc -l <kwfile1.c) &&
                "$PERL_PATH" -n -i -e "print unless m/Revision:/" kwfile1.c &&
                new_lines=$(wc -l <kwfile1.c) &&
@@ -343,44 +337,6 @@ test_expect_failure 'Add keywords in git which do not match the default p4 value
        )
 '
 
-# Check that the existing merge conflict handling still works.
-# Modify kwfile1.c in git, and delete in p4. We should be able
-# to skip the git commit.
-#
-test_expect_success 'merge conflict handling still works' '
-       test_when_finished cleanup_git &&
-       (
-               cd "$cli" &&
-               echo "Hello:\$Id\$" >merge2.c &&
-               echo "World" >>merge2.c &&
-               p4 add -t ktext merge2.c &&
-               p4 submit -d "add merge test file"
-       ) &&
-       git p4 clone --dest="$git" //depot &&
-       (
-               cd "$git" &&
-               sed -e "/Hello/d" merge2.c >merge2.c.tmp &&
-               mv merge2.c.tmp merge2.c &&
-               git add merge2.c &&
-               git commit -m "Modifying merge2.c"
-       ) &&
-       (
-               cd "$cli" &&
-               p4 delete merge2.c &&
-               p4 submit -d "remove merge test file"
-       ) &&
-       (
-               cd "$git" &&
-               test -f merge2.c &&
-               git config git-p4.skipSubmitEdit true &&
-               git config git-p4.attemptRCSCleanup true &&
-               !(echo "s" | git p4 submit) &&
-               git rebase --skip &&
-               ! test -f merge2.c
-       )
-'
-
-
 test_expect_success 'kill p4d' '
        kill_p4d
 '
diff --git a/t/t9812-git-p4-wildcards.sh b/t/t9812-git-p4-wildcards.sh
new file mode 100755 (executable)
index 0000000..143d413
--- /dev/null
@@ -0,0 +1,147 @@
+#!/bin/sh
+
+test_description='git p4 wildcards'
+
+. ./lib-git-p4.sh
+
+test_expect_success 'start p4d' '
+       start_p4d
+'
+
+test_expect_success 'add p4 files with wildcards in the names' '
+       (
+               cd "$cli" &&
+               printf "file2\nhas\nsome\nrandom\ntext\n" >file2 &&
+               p4 add file2 &&
+               echo file-wild-hash >file-wild#hash &&
+               echo file-wild-star >file-wild\*star &&
+               echo file-wild-at >file-wild@at &&
+               echo file-wild-percent >file-wild%percent &&
+               p4 add -f file-wild* &&
+               p4 submit -d "file wildcards"
+       )
+'
+
+test_expect_success 'wildcard files git p4 clone' '
+       git p4 clone --dest="$git" //depot &&
+       test_when_finished cleanup_git &&
+       (
+               cd "$git" &&
+               test -f file-wild#hash &&
+               test -f file-wild\*star &&
+               test -f file-wild@at &&
+               test -f file-wild%percent
+       )
+'
+
+test_expect_success 'wildcard files submit back to p4, add' '
+       test_when_finished cleanup_git &&
+       git p4 clone --dest="$git" //depot &&
+       (
+               cd "$git" &&
+               echo git-wild-hash >git-wild#hash &&
+               echo git-wild-star >git-wild\*star &&
+               echo git-wild-at >git-wild@at &&
+               echo git-wild-percent >git-wild%percent &&
+               git add git-wild* &&
+               git commit -m "add some wildcard filenames" &&
+               git config git-p4.skipSubmitEdit true &&
+               git p4 submit
+       ) &&
+       (
+               cd "$cli" &&
+               test_path_is_file git-wild#hash &&
+               test_path_is_file git-wild\*star &&
+               test_path_is_file git-wild@at &&
+               test_path_is_file git-wild%percent
+       )
+'
+
+test_expect_success 'wildcard files submit back to p4, modify' '
+       test_when_finished cleanup_git &&
+       git p4 clone --dest="$git" //depot &&
+       (
+               cd "$git" &&
+               echo new-line >>git-wild#hash &&
+               echo new-line >>git-wild\*star &&
+               echo new-line >>git-wild@at &&
+               echo new-line >>git-wild%percent &&
+               git add git-wild* &&
+               git commit -m "modify the wildcard files" &&
+               git config git-p4.skipSubmitEdit true &&
+               git p4 submit
+       ) &&
+       (
+               cd "$cli" &&
+               test_line_count = 2 git-wild#hash &&
+               test_line_count = 2 git-wild\*star &&
+               test_line_count = 2 git-wild@at &&
+               test_line_count = 2 git-wild%percent
+       )
+'
+
+test_expect_success 'wildcard files submit back to p4, copy' '
+       test_when_finished cleanup_git &&
+       git p4 clone --dest="$git" //depot &&
+       (
+               cd "$git" &&
+               cp file2 git-wild-cp#hash &&
+               git add git-wild-cp#hash &&
+               cp git-wild\*star file-wild-3 &&
+               git add file-wild-3 &&
+               git commit -m "wildcard copies" &&
+               git config git-p4.detectCopies true &&
+               git config git-p4.detectCopiesHarder true &&
+               git config git-p4.skipSubmitEdit true &&
+               git p4 submit
+       ) &&
+       (
+               cd "$cli" &&
+               test_path_is_file git-wild-cp#hash &&
+               test_path_is_file file-wild-3
+       )
+'
+
+test_expect_success 'wildcard files submit back to p4, rename' '
+       test_when_finished cleanup_git &&
+       git p4 clone --dest="$git" //depot &&
+       (
+               cd "$git" &&
+               git mv git-wild@at file-wild-4 &&
+               git mv file-wild-3 git-wild-cp%percent &&
+               git commit -m "wildcard renames" &&
+               git config git-p4.detectRenames true &&
+               git config git-p4.skipSubmitEdit true &&
+               git p4 submit
+       ) &&
+       (
+               cd "$cli" &&
+               test_path_is_missing git-wild@at &&
+               test_path_is_file git-wild-cp%percent
+       )
+'
+
+test_expect_success 'wildcard files submit back to p4, delete' '
+       test_when_finished cleanup_git &&
+       git p4 clone --dest="$git" //depot &&
+       (
+               cd "$git" &&
+               git rm git-wild* &&
+               git commit -m "delete the wildcard files" &&
+               git config git-p4.skipSubmitEdit true &&
+               git p4 submit
+       ) &&
+       (
+               cd "$cli" &&
+               test_path_is_missing git-wild#hash &&
+               test_path_is_missing git-wild\*star &&
+               test_path_is_missing git-wild@at &&
+               test_path_is_missing git-wild%percent
+       )
+'
+
+test_expect_success 'kill p4d' '
+       kill_p4d
+'
+
+test_done
diff --git a/t/t9813-git-p4-preserve-users.sh b/t/t9813-git-p4-preserve-users.sh
new file mode 100755 (executable)
index 0000000..f2e85e5
--- /dev/null
@@ -0,0 +1,153 @@
+#!/bin/sh
+
+test_description='git p4 preserve users'
+
+. ./lib-git-p4.sh
+
+test_expect_success 'start p4d' '
+       start_p4d
+'
+
+test_expect_success 'create files' '
+       (
+               cd "$cli" &&
+               p4 client -o | sed "/LineEnd/s/:.*/:unix/" | p4 client -i &&
+               echo file1 >file1 &&
+               echo file2 >file2 &&
+               p4 add file1 file2 &&
+               p4 submit -d "add files"
+       )
+'
+
+p4_add_user() {
+       name=$1 fullname=$2 &&
+       p4 user -f -i <<-EOF &&
+       User: $name
+       Email: $name@localhost
+       FullName: $fullname
+       EOF
+       p4 passwd -P secret $name
+}
+
+p4_grant_admin() {
+       name=$1 &&
+       {
+               p4 protect -o &&
+               echo "    admin user $name * //depot/..."
+       } | p4 protect -i
+}
+
+p4_check_commit_author() {
+       file=$1 user=$2 &&
+       p4 changes -m 1 //depot/$file | grep -q $user
+}
+
+make_change_by_user() {
+       file=$1 name=$2 email=$3 &&
+       echo "username: a change by $name" >>"$file" &&
+       git add "$file" &&
+       git commit --author "$name <$email>" -m "a change by $name"
+}
+
+# Test username support, submitting as user 'alice'
+test_expect_success 'preserve users' '
+       p4_add_user alice Alice &&
+       p4_add_user bob Bob &&
+       p4_grant_admin alice &&
+       git p4 clone --dest="$git" //depot &&
+       test_when_finished cleanup_git &&
+       (
+               cd "$git" &&
+               echo "username: a change by alice" >>file1 &&
+               echo "username: a change by bob" >>file2 &&
+               git commit --author "Alice <alice@localhost>" -m "a change by alice" file1 &&
+               git commit --author "Bob <bob@localhost>" -m "a change by bob" file2 &&
+               git config git-p4.skipSubmitEditCheck true &&
+               P4EDITOR=touch P4USER=alice P4PASSWD=secret git p4 commit --preserve-user &&
+               p4_check_commit_author file1 alice &&
+               p4_check_commit_author file2 bob
+       )
+'
+
+# Test username support, submitting as bob, who lacks admin rights. Should
+# not submit change to p4 (git diff should show deltas).
+test_expect_success 'refuse to preserve users without perms' '
+       git p4 clone --dest="$git" //depot &&
+       test_when_finished cleanup_git &&
+       (
+               cd "$git" &&
+               git config git-p4.skipSubmitEditCheck true &&
+               echo "username-noperms: a change by alice" >>file1 &&
+               git commit --author "Alice <alice@localhost>" -m "perms: a change by alice" file1 &&
+               P4EDITOR=touch P4USER=bob P4PASSWD=secret &&
+               export P4EDITOR P4USER P4PASSWD &&
+               test_must_fail git p4 commit --preserve-user &&
+               ! git diff --exit-code HEAD..p4/master
+       )
+'
+
+# What happens with unknown author? Without allowMissingP4Users it should fail.
+test_expect_success 'preserve user where author is unknown to p4' '
+       git p4 clone --dest="$git" //depot &&
+       test_when_finished cleanup_git &&
+       (
+               cd "$git" &&
+               git config git-p4.skipSubmitEditCheck true &&
+               echo "username-bob: a change by bob" >>file1 &&
+               git commit --author "Bob <bob@localhost>" -m "preserve: a change by bob" file1 &&
+               echo "username-unknown: a change by charlie" >>file1 &&
+               git commit --author "Charlie <charlie@localhost>" -m "preserve: a change by charlie" file1 &&
+               P4EDITOR=touch P4USER=alice P4PASSWD=secret &&
+               export P4EDITOR P4USER P4PASSWD &&
+               test_must_fail git p4 commit --preserve-user &&
+               ! git diff --exit-code HEAD..p4/master &&
+
+               echo "$0: repeat with allowMissingP4Users enabled" &&
+               git config git-p4.allowMissingP4Users true &&
+               git config git-p4.preserveUser true &&
+               git p4 commit &&
+               git diff --exit-code HEAD..p4/master &&
+               p4_check_commit_author file1 alice
+       )
+'
+
+# If we're *not* using --preserve-user, git-p4 should warn if we're submitting
+# changes that are not all ours.
+# Test: user in p4 and user unknown to p4.
+# Test: warning disabled and user is the same.
+test_expect_success 'not preserving user with mixed authorship' '
+       git p4 clone --dest="$git" //depot &&
+       test_when_finished cleanup_git &&
+       (
+               cd "$git" &&
+               git config git-p4.skipSubmitEditCheck true &&
+               p4_add_user derek Derek &&
+
+               make_change_by_user usernamefile3 Derek derek@localhost &&
+               P4EDITOR=cat P4USER=alice P4PASSWD=secret &&
+               export P4EDITOR P4USER P4PASSWD &&
+               git p4 commit |\
+               grep "git author derek@localhost does not match" &&
+
+               make_change_by_user usernamefile3 Charlie charlie@localhost &&
+               git p4 commit |\
+               grep "git author charlie@localhost does not match" &&
+
+               make_change_by_user usernamefile3 alice alice@localhost &&
+               git p4 commit |\
+               test_must_fail grep "git author.*does not match" &&
+
+               git config git-p4.skipUserNameCheck true &&
+               make_change_by_user usernamefile3 Charlie charlie@localhost &&
+               git p4 commit |\
+               test_must_fail grep "git author.*does not match" &&
+
+               p4_check_commit_author usernamefile3 alice
+       )
+'
+
+test_expect_success 'kill p4d' '
+       kill_p4d
+'
+
+test_done
diff --git a/t/t9814-git-p4-rename.sh b/t/t9814-git-p4-rename.sh
new file mode 100755 (executable)
index 0000000..3bf1224
--- /dev/null
@@ -0,0 +1,206 @@
+#!/bin/sh
+
+test_description='git p4 rename'
+
+. ./lib-git-p4.sh
+
+test_expect_success 'start p4d' '
+       start_p4d
+'
+
+# We rely on this behavior to detect for p4 move availability.
+test_expect_success 'p4 help unknown returns 1' '
+       (
+               cd "$cli" &&
+               (
+                       p4 help client >errs 2>&1
+                       echo $? >retval
+               )
+               echo 0 >expected &&
+               test_cmp expected retval &&
+               rm retval &&
+               (
+                       p4 help nosuchcommand >errs 2>&1
+                       echo $? >retval
+               )
+               echo 1 >expected &&
+               test_cmp expected retval &&
+               rm retval
+       )
+'
+
+test_expect_success 'create files' '
+       (
+               cd "$cli" &&
+               p4 client -o | sed "/LineEnd/s/:.*/:unix/" | p4 client -i &&
+               cat >file1 <<-EOF &&
+               A large block of text
+               in file1 that will generate
+               enough context so that rename
+               and copy detection will find
+               something interesting to do.
+               EOF
+               cat >file2 <<-EOF &&
+               /*
+                * This blob looks a bit
+                * different.
+                */
+               int main(int argc, char **argv)
+               {
+                       char text[200];
+
+                       strcpy(text, "copy/rename this");
+                       printf("text is %s\n", text);
+                       return 0;
+               }
+               EOF
+               p4 add file1 file2 &&
+               p4 submit -d "add files"
+       )
+'
+
+# Rename a file and confirm that rename is not detected in P4.
+# Rename the new file again with detectRenames option enabled and confirm that
+# this is detected in P4.
+# Rename the new file again adding an extra line, configure a big threshold in
+# detectRenames and confirm that rename is not detected in P4.
+# Repeat, this time with a smaller threshold and confirm that the rename is
+# detected in P4.
+test_expect_success 'detect renames' '
+       git p4 clone --dest="$git" //depot@all &&
+       test_when_finished cleanup_git &&
+       (
+               cd "$git" &&
+               git config git-p4.skipSubmitEdit true &&
+
+               git mv file1 file4 &&
+               git commit -a -m "Rename file1 to file4" &&
+               git diff-tree -r -M HEAD &&
+               git p4 submit &&
+               p4 filelog //depot/file4 >filelog &&
+               ! grep " from //depot" filelog &&
+
+               git mv file4 file5 &&
+               git commit -a -m "Rename file4 to file5" &&
+               git diff-tree -r -M HEAD &&
+               git config git-p4.detectRenames true &&
+               git p4 submit &&
+               p4 filelog //depot/file5 >filelog &&
+               grep " from //depot/file4" filelog &&
+
+               git mv file5 file6 &&
+               echo update >>file6 &&
+               git add file6 &&
+               git commit -a -m "Rename file5 to file6 with changes" &&
+               git diff-tree -r -M HEAD &&
+               level=$(git diff-tree -r -M HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/R0*//") &&
+               test -n "$level" && test "$level" -gt 0 && test "$level" -lt 98 &&
+               git config git-p4.detectRenames $(($level + 2)) &&
+               git p4 submit &&
+               p4 filelog //depot/file6 >filelog &&
+               ! grep " from //depot" filelog &&
+
+               git mv file6 file7 &&
+               echo update >>file7 &&
+               git add file7 &&
+               git commit -a -m "Rename file6 to file7 with changes" &&
+               git diff-tree -r -M HEAD &&
+               level=$(git diff-tree -r -M HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/R0*//") &&
+               test -n "$level" && test "$level" -gt 2 && test "$level" -lt 100 &&
+               git config git-p4.detectRenames $(($level - 2)) &&
+               git p4 submit &&
+               p4 filelog //depot/file7 >filelog &&
+               grep " from //depot/file6" filelog
+       )
+'
+
+# Copy a file and confirm that copy is not detected in P4.
+# Copy a file with detectCopies option enabled and confirm that copy is not
+# detected in P4.
+# Modify and copy a file with detectCopies option enabled and confirm that copy
+# is detected in P4.
+# Copy a file with detectCopies and detectCopiesHarder options enabled and
+# confirm that copy is detected in P4.
+# Modify and copy a file, configure a bigger threshold in detectCopies and
+# confirm that copy is not detected in P4.
+# Modify and copy a file, configure a smaller threshold in detectCopies and
+# confirm that copy is detected in P4.
+test_expect_success 'detect copies' '
+       git p4 clone --dest="$git" //depot@all &&
+       test_when_finished cleanup_git &&
+       (
+               cd "$git" &&
+               git config git-p4.skipSubmitEdit true &&
+
+               cp file2 file8 &&
+               git add file8 &&
+               git commit -a -m "Copy file2 to file8" &&
+               git diff-tree -r -C HEAD &&
+               git p4 submit &&
+               p4 filelog //depot/file8 &&
+               p4 filelog //depot/file8 | test_must_fail grep -q "branch from" &&
+
+               cp file2 file9 &&
+               git add file9 &&
+               git commit -a -m "Copy file2 to file9" &&
+               git diff-tree -r -C HEAD &&
+               git config git-p4.detectCopies true &&
+               git p4 submit &&
+               p4 filelog //depot/file9 &&
+               p4 filelog //depot/file9 | test_must_fail grep -q "branch from" &&
+
+               echo "file2" >>file2 &&
+               cp file2 file10 &&
+               git add file2 file10 &&
+               git commit -a -m "Modify and copy file2 to file10" &&
+               git diff-tree -r -C HEAD &&
+               git p4 submit &&
+               p4 filelog //depot/file10 &&
+               p4 filelog //depot/file10 | grep -q "branch from //depot/file" &&
+
+               cp file2 file11 &&
+               git add file11 &&
+               git commit -a -m "Copy file2 to file11" &&
+               git diff-tree -r -C --find-copies-harder HEAD &&
+               src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) &&
+               test "$src" = file10 &&
+               git config git-p4.detectCopiesHarder true &&
+               git p4 submit &&
+               p4 filelog //depot/file11 &&
+               p4 filelog //depot/file11 | grep -q "branch from //depot/file" &&
+
+               cp file2 file12 &&
+               echo "some text" >>file12 &&
+               git add file12 &&
+               git commit -a -m "Copy file2 to file12 with changes" &&
+               git diff-tree -r -C --find-copies-harder HEAD &&
+               level=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/C0*//") &&
+               test -n "$level" && test "$level" -gt 0 && test "$level" -lt 98 &&
+               src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) &&
+               test "$src" = file10 -o "$src" = file11 &&
+               git config git-p4.detectCopies $(($level + 2)) &&
+               git p4 submit &&
+               p4 filelog //depot/file12 &&
+               p4 filelog //depot/file12 | test_must_fail grep -q "branch from" &&
+
+               cp file2 file13 &&
+               echo "different text" >>file13 &&
+               git add file13 &&
+               git commit -a -m "Copy file2 to file13 with changes" &&
+               git diff-tree -r -C --find-copies-harder HEAD &&
+               level=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/C0*//") &&
+               test -n "$level" && test "$level" -gt 2 && test "$level" -lt 100 &&
+               src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) &&
+               test "$src" = file10 -o "$src" = file11 -o "$src" = file12 &&
+               git config git-p4.detectCopies $(($level - 2)) &&
+               git p4 submit &&
+               p4 filelog //depot/file13 &&
+               p4 filelog //depot/file13 | grep -q "branch from //depot/file"
+       )
+'
+
+test_expect_success 'kill p4d' '
+       kill_p4d
+'
+
+test_done
diff --git a/t/t9815-git-p4-submit-fail.sh b/t/t9815-git-p4-submit-fail.sh
new file mode 100755 (executable)
index 0000000..d2b7b3d
--- /dev/null
@@ -0,0 +1,429 @@
+#!/bin/sh
+
+test_description='git p4 submit failure handling'
+
+. ./lib-git-p4.sh
+
+test_expect_success 'start p4d' '
+       start_p4d
+'
+
+test_expect_success 'init depot' '
+       (
+               cd "$cli" &&
+               p4 client -o | sed "/LineEnd/s/:.*/:unix/" | p4 client -i &&
+               echo line1 >file1 &&
+               p4 add file1 &&
+               p4 submit -d "line1 in file1"
+       )
+'
+
+test_expect_success 'conflict on one commit' '
+       test_when_finished cleanup_git &&
+       git p4 clone --dest="$git" //depot &&
+       (
+               cd "$cli" &&
+               p4 open file1 &&
+               echo line2 >>file1 &&
+               p4 submit -d "line2 in file1"
+       ) &&
+       (
+               # now this commit should cause a conflict
+               cd "$git" &&
+               git config git-p4.skipSubmitEdit true &&
+               echo line3 >>file1 &&
+               git add file1 &&
+               git commit -m "line3 in file1 will conflict" &&
+               test_expect_code 1 git p4 submit >out &&
+               test_i18ngrep "No commits applied" out
+       )
+'
+
+test_expect_success 'conflict on second of two commits' '
+       test_when_finished cleanup_git &&
+       git p4 clone --dest="$git" //depot &&
+       (
+               cd "$cli" &&
+               p4 open file1 &&
+               echo line3 >>file1 &&
+               p4 submit -d "line3 in file1"
+       ) &&
+       (
+               cd "$git" &&
+               git config git-p4.skipSubmitEdit true &&
+               # this commit is okay
+               test_commit "first_commit_okay" &&
+               # now this submit should cause a conflict
+               echo line4 >>file1 &&
+               git add file1 &&
+               git commit -m "line4 in file1 will conflict" &&
+               test_expect_code 1 git p4 submit >out &&
+               test_i18ngrep "Applied only the commits" out
+       )
+'
+
+test_expect_success 'conflict on first of two commits, skip' '
+       test_when_finished cleanup_git &&
+       git p4 clone --dest="$git" //depot &&
+       (
+               cd "$cli" &&
+               p4 open file1 &&
+               echo line4 >>file1 &&
+               p4 submit -d "line4 in file1"
+       ) &&
+       (
+               cd "$git" &&
+               git config git-p4.skipSubmitEdit true &&
+               # this submit should cause a conflict
+               echo line5 >>file1 &&
+               git add file1 &&
+               git commit -m "line5 in file1 will conflict" &&
+               # but this commit is okay
+               test_commit "okay_commit_after_skip" &&
+               echo s | test_expect_code 1 git p4 submit >out &&
+               test_i18ngrep "Applied only the commits" out
+       )
+'
+
+test_expect_success 'conflict on first of two commits, quit' '
+       test_when_finished cleanup_git &&
+       git p4 clone --dest="$git" //depot &&
+       (
+               cd "$cli" &&
+               p4 open file1 &&
+               echo line7 >>file1 &&
+               p4 submit -d "line7 in file1"
+       ) &&
+       (
+               cd "$git" &&
+               git config git-p4.skipSubmitEdit true &&
+               # this submit should cause a conflict
+               echo line8 >>file1 &&
+               git add file1 &&
+               git commit -m "line8 in file1 will conflict" &&
+               # but this commit is okay
+               test_commit "okay_commit_after_quit" &&
+               echo q | test_expect_code 1 git p4 submit >out &&
+               test_i18ngrep "No commits applied" out
+       )
+'
+
+test_expect_success 'conflict cli and config options' '
+       test_when_finished cleanup_git &&
+       git p4 clone --dest="$git" //depot &&
+       (
+               cd "$git" &&
+               git p4 submit --conflict=ask &&
+               git p4 submit --conflict=skip &&
+               git p4 submit --conflict=quit &&
+               test_expect_code 2 git p4 submit --conflict=foo &&
+               test_expect_code 2 git p4 submit --conflict &&
+               git config git-p4.conflict foo &&
+               test_expect_code 1 git p4 submit &&
+               git config --unset git-p4.conflict &&
+               git p4 submit
+       )
+'
+
+test_expect_success 'conflict on first of two commits, --conflict=skip' '
+       test_when_finished cleanup_git &&
+       git p4 clone --dest="$git" //depot &&
+       (
+               cd "$cli" &&
+               p4 open file1 &&
+               echo line9 >>file1 &&
+               p4 submit -d "line9 in file1"
+       ) &&
+       (
+               cd "$git" &&
+               git config git-p4.skipSubmitEdit true &&
+               # this submit should cause a conflict
+               echo line10 >>file1 &&
+               git add file1 &&
+               git commit -m "line10 in file1 will conflict" &&
+               # but this commit is okay
+               test_commit "okay_commit_after_auto_skip" &&
+               test_expect_code 1 git p4 submit --conflict=skip >out &&
+               test_i18ngrep "Applied only the commits" out
+       )
+'
+
+test_expect_success 'conflict on first of two commits, --conflict=quit' '
+       test_when_finished cleanup_git &&
+       git p4 clone --dest="$git" //depot &&
+       (
+               cd "$cli" &&
+               p4 open file1 &&
+               echo line11 >>file1 &&
+               p4 submit -d "line11 in file1"
+       ) &&
+       (
+               cd "$git" &&
+               git config git-p4.skipSubmitEdit true &&
+               # this submit should cause a conflict
+               echo line12 >>file1 &&
+               git add file1 &&
+               git commit -m "line12 in file1 will conflict" &&
+               # but this commit is okay
+               test_commit "okay_commit_after_auto_quit" &&
+               test_expect_code 1 git p4 submit --conflict=quit >out &&
+               test_i18ngrep "No commits applied" out
+       )
+'
+
+#
+# Cleanup after submit fail, all cases.  Some modifications happen
+# before trying to apply the patch.  Make sure these are unwound
+# properly.  Put each one in a diff along with something that will
+# obviously conflict.  Make sure it is back to normal after.
+#
+
+test_expect_success 'cleanup edit p4 populate' '
+       (
+               cd "$cli" &&
+               echo text file >text &&
+               p4 add text &&
+               echo text+x file >text+x &&
+               chmod 755 text+x &&
+               p4 add text+x &&
+               p4 submit -d "populate p4"
+       )
+'
+
+setup_conflict() {
+       # clone before modifying file1 to force it to conflict
+       test_when_finished cleanup_git &&
+       git p4 clone --dest="$git" //depot &&
+       # ticks outside subshells
+       test_tick &&
+       (
+               cd "$cli" &&
+               p4 open file1 &&
+               echo $test_tick >>file1 &&
+               p4 submit -d "$test_tick in file1"
+       ) &&
+       test_tick &&
+       (
+               cd "$git" &&
+               git config git-p4.skipSubmitEdit true &&
+               # easy conflict
+               echo $test_tick >>file1 &&
+               git add file1
+               # caller will add more and submit
+       )
+}
+
+test_expect_success 'cleanup edit after submit fail' '
+       setup_conflict &&
+       (
+               cd "$git" &&
+               echo another line >>text &&
+               git add text &&
+               git commit -m "conflict" &&
+               test_expect_code 1 git p4 submit
+       ) &&
+       (
+               cd "$cli" &&
+               # make sure it is not open
+               ! p4 fstat -T action text
+       )
+'
+
+test_expect_success 'cleanup add after submit fail' '
+       setup_conflict &&
+       (
+               cd "$git" &&
+               echo new file >textnew &&
+               git add textnew &&
+               git commit -m "conflict" &&
+               test_expect_code 1 git p4 submit
+       ) &&
+       (
+               cd "$cli" &&
+               # make sure it is not there
+               # and that p4 thinks it is not added
+               #   P4 returns 0 both for "not there but added" and
+               #   "not there", so grep.
+               test_path_is_missing textnew &&
+               p4 fstat -T action textnew 2>&1 | grep "no such file"
+       )
+'
+
+test_expect_success 'cleanup delete after submit fail' '
+       setup_conflict &&
+       (
+               cd "$git" &&
+               git rm text+x &&
+               git commit -m "conflict" &&
+               test_expect_code 1 git p4 submit
+       ) &&
+       (
+               cd "$cli" &&
+               # make sure it is there
+               test_path_is_file text+x &&
+               ! p4 fstat -T action text+x
+       )
+'
+
+test_expect_success 'cleanup copy after submit fail' '
+       setup_conflict &&
+       (
+               cd "$git" &&
+               cp text text2 &&
+               git add text2 &&
+               git commit -m "conflict" &&
+               git config git-p4.detectCopies true &&
+               git config git-p4.detectCopiesHarder true &&
+               # make sure setup is okay
+               git diff-tree -r -C --find-copies-harder HEAD | grep text2 | grep C100 &&
+               test_expect_code 1 git p4 submit
+       ) &&
+       (
+               cd "$cli" &&
+               test_path_is_missing text2 &&
+               p4 fstat -T action text2 2>&1 | grep "no such file"
+       )
+'
+
+test_expect_success 'cleanup rename after submit fail' '
+       setup_conflict &&
+       (
+               cd "$git" &&
+               git mv text text2 &&
+               git commit -m "conflict" &&
+               git config git-p4.detectRenames true &&
+               # make sure setup is okay
+               git diff-tree -r -M HEAD | grep text2 | grep R100 &&
+               test_expect_code 1 git p4 submit
+       ) &&
+       (
+               cd "$cli" &&
+               test_path_is_missing text2 &&
+               p4 fstat -T action text2 2>&1 | grep "no such file"
+       )
+'
+
+#
+# Cleanup after deciding not to submit during editTemplate.  This
+# involves unwinding more work, because files have been added, deleted
+# and chmod-ed now.  Same approach as above.
+#
+
+test_expect_success 'cleanup edit after submit cancel' '
+       test_when_finished cleanup_git &&
+       git p4 clone --dest="$git" //depot &&
+       (
+               cd "$git" &&
+               echo line >>text &&
+               git add text &&
+               git commit -m text &&
+               echo n | test_expect_code 1 git p4 submit &&
+               git reset --hard HEAD^
+       ) &&
+       (
+               cd "$cli" &&
+               ! p4 fstat -T action text &&
+               test_cmp "$git"/text text
+       )
+'
+
+test_expect_success 'cleanup add after submit cancel' '
+       test_when_finished cleanup_git &&
+       git p4 clone --dest="$git" //depot &&
+       (
+               cd "$git" &&
+               echo line >textnew &&
+               git add textnew &&
+               git commit -m textnew &&
+               echo n | test_expect_code 1 git p4 submit
+       ) &&
+       (
+               cd "$cli" &&
+               test_path_is_missing textnew &&
+               p4 fstat -T action textnew 2>&1 | grep "no such file"
+       )
+'
+
+test_expect_success 'cleanup delete after submit cancel' '
+       test_when_finished cleanup_git &&
+       git p4 clone --dest="$git" //depot &&
+       (
+               cd "$git" &&
+               git rm text &&
+               git commit -m "rm text" &&
+               echo n | test_expect_code 1 git p4 submit
+       ) &&
+       (
+               cd "$cli" &&
+               test_path_is_file text &&
+               ! p4 fstat -T action text
+       )
+'
+
+test_expect_success 'cleanup copy after submit cancel' '
+       test_when_finished cleanup_git &&
+       git p4 clone --dest="$git" //depot &&
+       (
+               cd "$git" &&
+               cp text text2 &&
+               git add text2 &&
+               git commit -m text2 &&
+               git config git-p4.detectCopies true &&
+               git config git-p4.detectCopiesHarder true &&
+               git diff-tree -r -C --find-copies-harder HEAD | grep text2 | grep C100 &&
+               echo n | test_expect_code 1 git p4 submit
+       ) &&
+       (
+               cd "$cli" &&
+               test_path_is_missing text2 &&
+               p4 fstat -T action text2 2>&1 | grep "no such file"
+       )
+'
+
+test_expect_success 'cleanup rename after submit cancel' '
+       test_when_finished cleanup_git &&
+       git p4 clone --dest="$git" //depot &&
+       (
+               cd "$git" &&
+               git mv text text2 &&
+               git commit -m text2 &&
+               git config git-p4.detectRenames true &&
+               git diff-tree -r -M HEAD | grep text2 | grep R100 &&
+               echo n | test_expect_code 1 git p4 submit
+       ) &&
+       (
+               cd "$cli" &&
+               test_path_is_missing text2 &&
+               p4 fstat -T action text2 2>&1 | grep "no such file"
+               test_path_is_file text &&
+               ! p4 fstat -T action text
+       )
+'
+
+test_expect_success 'cleanup chmod after submit cancel' '
+       test_when_finished cleanup_git &&
+       git p4 clone --dest="$git" //depot &&
+       (
+               cd "$git" &&
+               chmod u+x text &&
+               chmod u-x text+x &&
+               git add text text+x &&
+               git commit -m "chmod texts" &&
+               echo n | test_expect_code 1 git p4 submit
+       ) &&
+       (
+               cd "$cli" &&
+               test_path_is_file text &&
+               ! p4 fstat -T action text &&
+               stat --format=%A text | egrep ^-r-- &&
+               test_path_is_file text+x &&
+               ! p4 fstat -T action text+x &&
+               stat --format=%A text+x | egrep ^-r-x
+       )
+'
+
+test_expect_success 'kill p4d' '
+       kill_p4d
+'
+
+test_done
index 256e6a0b3f3d001482cf0a21605f6a860d935d58..cbd0fb66f93fae6bb1d9fa341aad3e48c723c0e1 100755 (executable)
@@ -3,21 +3,9 @@
 # Copyright (c) 2012 Felipe Contreras
 #
 
-if test -n "$BASH" && test -z "$POSIXLY_CORRECT"; then
-       # we are in full-on bash mode
-       true
-elif type bash >/dev/null 2>&1; then
-       # execute in full-on bash mode
-       unset POSIXLY_CORRECT
-       exec bash "$0" "$@"
-else
-       echo '1..0 #SKIP skipping bash completion tests; bash not available'
-       exit 0
-fi
-
 test_description='test bash completion'
 
-. ./test-lib.sh
+. ./lib-bash.sh
 
 complete ()
 {
@@ -73,6 +61,15 @@ test_completion ()
        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 ()
+{
+       tr _ " " >expected &&
+       test_completion "$1"
+}
+
 newline=$'\n'
 
 test_expect_success '__gitcomp - trailing space - options' '
@@ -240,4 +237,55 @@ test_expect_success 'general options plus command' '
        test_completion "git --no-replace-objects check" "checkout "
 '
 
+test_expect_success 'setup for ref completion' '
+       echo content >file1 &&
+       echo more >file2 &&
+       git add . &&
+       git commit -m one &&
+       git branch mybranch &&
+       git tag mytag
+'
+
+test_expect_success 'checkout completes ref names' '
+       test_completion_long "git checkout m" <<-\EOF
+       master_
+       mybranch_
+       mytag_
+       EOF
+'
+
+test_expect_success 'show completes all refs' '
+       test_completion_long "git show m" <<-\EOF
+       master_
+       mybranch_
+       mytag_
+       EOF
+'
+
+test_expect_success '<ref>: completes paths' '
+       test_completion_long "git show mytag:f" <<-\EOF
+       file1_
+       file2_
+       EOF
+'
+
+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_
+       EOF
+'
+
+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_
+       EOF
+'
+
 test_done
diff --git a/t/t9903-bash-prompt.sh b/t/t9903-bash-prompt.sh
new file mode 100755 (executable)
index 0000000..f17c1f8
--- /dev/null
@@ -0,0 +1,456 @@
+#!/bin/sh
+#
+# Copyright (c) 2012 SZEDER Gábor
+#
+
+test_description='test git-specific bash prompt functions'
+
+. ./lib-bash.sh
+
+. "$GIT_BUILD_DIR/contrib/completion/git-prompt.sh"
+
+actual="$TRASH_DIRECTORY/actual"
+
+test_expect_success 'setup for prompt tests' '
+       mkdir -p subdir/subsubdir &&
+       git init otherrepo &&
+       echo 1 > file &&
+       git add file &&
+       test_tick &&
+       git commit -m initial &&
+       git tag -a -m msg1 t1 &&
+       git checkout -b b1 &&
+       echo 2 > file &&
+       git commit -m "second b1" file &&
+       echo 3 > file &&
+       git commit -m "third b1" file &&
+       git tag -a -m msg2 t2 &&
+       git checkout -b b2 master &&
+       echo 0 > file &&
+       git commit -m "second b2" file &&
+       git checkout master
+'
+
+test_expect_success 'gitdir - from command line (through $__git_dir)' '
+       echo "$TRASH_DIRECTORY/otherrepo/.git" > expected &&
+       (
+               __git_dir="$TRASH_DIRECTORY/otherrepo/.git" &&
+               __gitdir > "$actual"
+       ) &&
+       test_cmp expected "$actual"
+'
+
+test_expect_success 'gitdir - repo as argument' '
+       echo "otherrepo/.git" > expected &&
+       __gitdir "otherrepo" > "$actual" &&
+       test_cmp expected "$actual"
+'
+
+test_expect_success 'gitdir - remote as argument' '
+       echo "remote" > expected &&
+       __gitdir "remote" > "$actual" &&
+       test_cmp expected "$actual"
+'
+
+test_expect_success 'gitdir - .git directory in cwd' '
+       echo ".git" > expected &&
+       __gitdir > "$actual" &&
+       test_cmp expected "$actual"
+'
+
+test_expect_success 'gitdir - .git directory in parent' '
+       echo "$TRASH_DIRECTORY/.git" > expected &&
+       (
+               cd subdir/subsubdir &&
+               __gitdir > "$actual"
+       ) &&
+       test_cmp expected "$actual"
+'
+
+test_expect_success 'gitdir - cwd is a .git directory' '
+       echo "." > expected &&
+       (
+               cd .git &&
+               __gitdir > "$actual"
+       ) &&
+       test_cmp expected "$actual"
+'
+
+test_expect_success 'gitdir - parent is a .git directory' '
+       echo "$TRASH_DIRECTORY/.git" > expected &&
+       (
+               cd .git/refs/heads &&
+               __gitdir > "$actual"
+       ) &&
+       test_cmp expected "$actual"
+'
+
+test_expect_success 'gitdir - $GIT_DIR set while .git directory in cwd' '
+       echo "$TRASH_DIRECTORY/otherrepo/.git" > expected &&
+       (
+               GIT_DIR="$TRASH_DIRECTORY/otherrepo/.git" &&
+               export GIT_DIR &&
+               __gitdir > "$actual"
+       ) &&
+       test_cmp expected "$actual"
+'
+
+test_expect_success 'gitdir - $GIT_DIR set while .git directory in parent' '
+       echo "$TRASH_DIRECTORY/otherrepo/.git" > expected &&
+       (
+               GIT_DIR="$TRASH_DIRECTORY/otherrepo/.git" &&
+               export GIT_DIR &&
+               cd subdir &&
+               __gitdir > "$actual"
+       ) &&
+       test_cmp expected "$actual"
+'
+
+test_expect_success 'gitdir - non-existing $GIT_DIR' '
+       (
+               GIT_DIR="$TRASH_DIRECTORY/non-existing" &&
+               export GIT_DIR &&
+               test_must_fail __gitdir
+       )
+'
+
+test_expect_success 'gitdir - gitfile in cwd' '
+       echo "$TRASH_DIRECTORY/otherrepo/.git" > expected &&
+       echo "gitdir: $TRASH_DIRECTORY/otherrepo/.git" > subdir/.git &&
+       test_when_finished "rm -f subdir/.git" &&
+       (
+               cd subdir &&
+               __gitdir > "$actual"
+       ) &&
+       test_cmp expected "$actual"
+'
+
+test_expect_success 'gitdir - gitfile in parent' '
+       echo "$TRASH_DIRECTORY/otherrepo/.git" > expected &&
+       echo "gitdir: $TRASH_DIRECTORY/otherrepo/.git" > subdir/.git &&
+       test_when_finished "rm -f subdir/.git" &&
+       (
+               cd subdir/subsubdir &&
+               __gitdir > "$actual"
+       ) &&
+       test_cmp expected "$actual"
+'
+
+test_expect_success SYMLINKS 'gitdir - resulting path avoids symlinks' '
+       echo "$TRASH_DIRECTORY/otherrepo/.git" > expected &&
+       mkdir otherrepo/dir &&
+       test_when_finished "rm -rf otherrepo/dir" &&
+       ln -s otherrepo/dir link &&
+       test_when_finished "rm -f link" &&
+       (
+               cd link &&
+               __gitdir > "$actual"
+       ) &&
+       test_cmp expected "$actual"
+'
+
+test_expect_success 'gitdir - not a git repository' '
+       (
+               cd subdir/subsubdir &&
+               GIT_CEILING_DIRECTORIES="$TRASH_DIRECTORY" &&
+               export GIT_CEILING_DIRECTORIES &&
+               test_must_fail __gitdir
+       )
+'
+
+test_expect_success 'prompt - branch name' '
+       printf " (master)" > expected &&
+       __git_ps1 > "$actual" &&
+       test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - detached head' '
+       printf " ((%s...))" $(git log -1 --format="%h" b1^) > expected &&
+       git checkout b1^ &&
+       test_when_finished "git checkout master" &&
+       __git_ps1 > "$actual" &&
+       test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - describe detached head - contains' '
+       printf " ((t2~1))" > expected &&
+       git checkout b1^ &&
+       test_when_finished "git checkout master" &&
+       (
+               GIT_PS1_DESCRIBE_STYLE=contains &&
+               __git_ps1 > "$actual"
+       ) &&
+       test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - describe detached head - branch' '
+       printf " ((b1~1))" > expected &&
+       git checkout b1^ &&
+       test_when_finished "git checkout master" &&
+       (
+               GIT_PS1_DESCRIBE_STYLE=branch &&
+               __git_ps1 > "$actual"
+       ) &&
+       test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - describe detached head - describe' '
+       printf " ((t1-1-g%s))" $(git log -1 --format="%h" b1^) > expected &&
+       git checkout b1^ &&
+       test_when_finished "git checkout master" &&
+       (
+               GIT_PS1_DESCRIBE_STYLE=describe &&
+               __git_ps1 > "$actual"
+       ) &&
+       test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - describe detached head - default' '
+       printf " ((t2))" > expected &&
+       git checkout --detach b1 &&
+       test_when_finished "git checkout master" &&
+       __git_ps1 > "$actual" &&
+       test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - inside .git directory' '
+       printf " (GIT_DIR!)" > expected &&
+       (
+               cd .git &&
+               __git_ps1 > "$actual"
+       ) &&
+       test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - deep inside .git directory' '
+       printf " (GIT_DIR!)" > expected &&
+       (
+               cd .git/refs/heads &&
+               __git_ps1 > "$actual"
+       ) &&
+       test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - inside bare repository' '
+       printf " (BARE:master)" > expected &&
+       git init --bare bare.git &&
+       test_when_finished "rm -rf bare.git" &&
+       (
+               cd bare.git &&
+               __git_ps1 > "$actual"
+       ) &&
+       test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - interactive rebase' '
+       printf " (b1|REBASE-i)" > expected
+       echo "#!$SHELL_PATH" >fake_editor.sh &&
+       cat >>fake_editor.sh <<\EOF &&
+echo "edit $(git log -1 --format="%h")" > "$1"
+EOF
+       test_when_finished "rm -f fake_editor.sh" &&
+       chmod a+x fake_editor.sh &&
+       test_set_editor "$TRASH_DIRECTORY/fake_editor.sh" &&
+       git checkout b1 &&
+       test_when_finished "git checkout master" &&
+       git rebase -i HEAD^ &&
+       test_when_finished "git rebase --abort"
+       __git_ps1 > "$actual" &&
+       test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - rebase merge' '
+       printf " (b2|REBASE-m)" > expected &&
+       git checkout b2 &&
+       test_when_finished "git checkout master" &&
+       test_must_fail git rebase --merge b1 b2 &&
+       test_when_finished "git rebase --abort" &&
+       __git_ps1 > "$actual" &&
+       test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - rebase' '
+       printf " ((t2)|REBASE)" > expected &&
+       git checkout b2 &&
+       test_when_finished "git checkout master" &&
+       test_must_fail git rebase b1 b2 &&
+       test_when_finished "git rebase --abort" &&
+       __git_ps1 > "$actual" &&
+       test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - merge' '
+       printf " (b1|MERGING)" > expected &&
+       git checkout b1 &&
+       test_when_finished "git checkout master" &&
+       test_must_fail git merge b2 &&
+       test_when_finished "git reset --hard" &&
+       __git_ps1 > "$actual" &&
+       test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - cherry-pick' '
+       printf " (master|CHERRY-PICKING)" > expected &&
+       test_must_fail git cherry-pick b1 &&
+       test_when_finished "git reset --hard" &&
+       __git_ps1 > "$actual" &&
+       test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - bisect' '
+       printf " (master|BISECTING)" > expected &&
+       git bisect start &&
+       test_when_finished "git bisect reset" &&
+       __git_ps1 > "$actual" &&
+       test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - dirty status indicator - clean' '
+       printf " (master)" > expected &&
+       (
+               GIT_PS1_SHOWDIRTYSTATE=y &&
+               __git_ps1 > "$actual"
+       ) &&
+       test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - dirty status indicator - dirty worktree' '
+       printf " (master *)" > expected &&
+       echo "dirty" > file &&
+       test_when_finished "git reset --hard" &&
+       (
+               GIT_PS1_SHOWDIRTYSTATE=y &&
+               __git_ps1 > "$actual"
+       ) &&
+       test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - dirty status indicator - dirty index' '
+       printf " (master +)" > expected &&
+       echo "dirty" > file &&
+       test_when_finished "git reset --hard" &&
+       git add -u &&
+       (
+               GIT_PS1_SHOWDIRTYSTATE=y &&
+               __git_ps1 > "$actual"
+       ) &&
+       test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - dirty status indicator - dirty index and worktree' '
+       printf " (master *+)" > expected &&
+       echo "dirty index" > file &&
+       test_when_finished "git reset --hard" &&
+       git add -u &&
+       echo "dirty worktree" > file &&
+       (
+               GIT_PS1_SHOWDIRTYSTATE=y &&
+               __git_ps1 > "$actual"
+       ) &&
+       test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - dirty status indicator - before root commit' '
+       printf " (master #)" > expected &&
+       (
+               GIT_PS1_SHOWDIRTYSTATE=y &&
+               cd otherrepo &&
+               __git_ps1 > "$actual"
+       ) &&
+       test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - dirty status indicator - disabled by config' '
+       printf " (master)" > expected &&
+       echo "dirty" > file &&
+       test_when_finished "git reset --hard" &&
+       test_config bash.showDirtyState false &&
+       (
+               GIT_PS1_SHOWDIRTYSTATE=y &&
+               __git_ps1 > "$actual"
+       ) &&
+       test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - dirty status indicator - not shown inside .git directory' '
+       printf " (GIT_DIR!)" > expected &&
+       echo "dirty" > file &&
+       test_when_finished "git reset --hard" &&
+       (
+               GIT_PS1_SHOWDIRTYSTATE=y &&
+               cd .git &&
+               __git_ps1 > "$actual"
+       ) &&
+       test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - stash status indicator - no stash' '
+       printf " (master)" > expected &&
+       (
+               GIT_PS1_SHOWSTASHSTATE=y &&
+               __git_ps1 > "$actual"
+       ) &&
+       test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - stash status indicator - stash' '
+       printf " (master $)" > expected &&
+       echo 2 >file &&
+       git stash &&
+       test_when_finished "git stash drop" &&
+       (
+               GIT_PS1_SHOWSTASHSTATE=y &&
+               __git_ps1 > "$actual"
+       ) &&
+       test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - stash status indicator - not shown inside .git directory' '
+       printf " (GIT_DIR!)" > expected &&
+       echo 2 >file &&
+       git stash &&
+       test_when_finished "git stash drop" &&
+       (
+               GIT_PS1_SHOWSTASHSTATE=y &&
+               cd .git &&
+               __git_ps1 > "$actual"
+       ) &&
+       test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - untracked files status indicator - no untracked files' '
+       printf " (master)" > expected &&
+       (
+               GIT_PS1_SHOWUNTRACKEDFILES=y &&
+               cd otherrepo &&
+               __git_ps1 > "$actual"
+       ) &&
+       test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - untracked files status indicator - untracked files' '
+       printf " (master %%)" > expected &&
+       (
+               GIT_PS1_SHOWUNTRACKEDFILES=y &&
+               __git_ps1 > "$actual"
+       ) &&
+       test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - untracked files status indicator - not shown inside .git directory' '
+       printf " (GIT_DIR!)" > expected &&
+       (
+               GIT_PS1_SHOWUNTRACKEDFILES=y &&
+               cd .git &&
+               __git_ps1 > "$actual"
+       ) &&
+       test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - format string starting with dash' '
+       printf -- "-master" > expected &&
+       __git_ps1 "-%s" > "$actual" &&
+       test_cmp expected "$actual"
+'
+
+test_done
index 9096398b184df722492cd6072d618edb78eb5206..8889ba5104cd3f7c783a179d45816d3a82685ef0 100644 (file)
@@ -144,11 +144,22 @@ test_pause () {
 
 test_commit () {
        notick= &&
-       if test "z$1" = "z--notick"
-       then
-               notick=yes
+       signoff= &&
+       while test $# != 0
+       do
+               case "$1" in
+               --notick)
+                       notick=yes
+                       ;;
+               --signoff)
+                       signoff="$1"
+                       ;;
+               *)
+                       break
+                       ;;
+               esac
                shift
-       fi &&
+       done &&
        file=${2:-"$1.t"} &&
        echo "${3-$1}" > "$file" &&
        git add "$file" &&
@@ -156,7 +167,7 @@ test_commit () {
        then
                test_tick
        fi &&
-       git commit -m "$1" &&
+       git commit $signoff -m "$1" &&
        git tag "$1"
 }
 
@@ -221,9 +232,35 @@ write_script () {
 # capital letters by convention).
 
 test_set_prereq () {
-       satisfied="$satisfied$1 "
+       satisfied_prereq="$satisfied_prereq$1 "
+}
+satisfied_prereq=" "
+lazily_testable_prereq= lazily_tested_prereq=
+
+# Usage: test_lazy_prereq PREREQ 'script'
+test_lazy_prereq () {
+       lazily_testable_prereq="$lazily_testable_prereq$1 "
+       eval test_prereq_lazily_$1=\$2
+}
+
+test_run_lazy_prereq_ () {
+       script='
+mkdir -p "$TRASH_DIRECTORY/prereq-test-dir" &&
+(
+       cd "$TRASH_DIRECTORY/prereq-test-dir" &&'"$2"'
+)'
+       say >&3 "checking prerequisite: $1"
+       say >&3 "$script"
+       test_eval_ "$script"
+       eval_ret=$?
+       rm -rf "$TRASH_DIRECTORY/prereq-test-dir"
+       if test "$eval_ret" = 0; then
+               say >&3 "prerequisite $1 ok"
+       else
+               say >&3 "prerequisite $1 not satisfied"
+       fi
+       return $eval_ret
 }
-satisfied=" "
 
 test_have_prereq () {
        # prerequisites can be concatenated with ','
@@ -238,8 +275,24 @@ test_have_prereq () {
 
        for prerequisite
        do
+               case " $lazily_tested_prereq " in
+               *" $prerequisite "*)
+                       ;;
+               *)
+                       case " $lazily_testable_prereq " in
+                       *" $prerequisite "*)
+                               eval "script=\$test_prereq_lazily_$prerequisite" &&
+                               if test_run_lazy_prereq_ "$prerequisite" "$script"
+                               then
+                                       test_set_prereq $prerequisite
+                               fi
+                               lazily_tested_prereq="$lazily_tested_prereq$prerequisite "
+                       esac
+                       ;;
+               esac
+
                total_prereq=$(($total_prereq + 1))
-               case $satisfied in
+               case "$satisfied_prereq" in
                *" $prerequisite "*)
                        ok_prereq=$(($ok_prereq + 1))
                        ;;
index acda33d177197c4288e8b7a33385f11c63c44698..489bc80fc1b1ba4066a1fd5ad6d2024d67160ba7 100644 (file)
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see http://www.gnu.org/licenses/ .
 
+# Keep the original TERM for say_color
+ORIGINAL_TERM=$TERM
+
+# Test the binaries we have just built.  The tests are kept in
+# t/ subdirectory and are run in 'trash directory' subdirectory.
+if test -z "$TEST_DIRECTORY"
+then
+       # We allow tests to override this, in case they want to run tests
+       # outside of t/, e.g. for running tests on the test library
+       # itself.
+       TEST_DIRECTORY=$(pwd)
+fi
+if test -z "$TEST_OUTPUT_DIRECTORY"
+then
+       # Similarly, override this to store the test-results subdir
+       # elsewhere
+       TEST_OUTPUT_DIRECTORY=$TEST_DIRECTORY
+fi
+GIT_BUILD_DIR="$TEST_DIRECTORY"/..
+
+################################################################
+# It appears that people try to run tests without building...
+"$GIT_BUILD_DIR/git" >/dev/null
+if test $? != 1
+then
+       echo >&2 'error: you do not seem to have built git yet.'
+       exit 1
+fi
+
+. "$GIT_BUILD_DIR"/GIT-BUILD-OPTIONS
+export PERL_PATH SHELL_PATH
+
 # if --tee was passed, write the output not only to the terminal, but
 # additionally to the file test-results/$BASENAME.out, too.
 case "$GIT_TEST_TEE_STARTED, $* " in
@@ -24,16 +56,13 @@ done,*)
 *' --tee '*|*' --va'*)
        mkdir -p test-results
        BASE=test-results/$(basename "$0" .sh)
-       (GIT_TEST_TEE_STARTED=done ${SHELL-sh} "$0" "$@" 2>&1;
+       (GIT_TEST_TEE_STARTED=done ${SHELL_PATH} "$0" "$@" 2>&1;
         echo $? > $BASE.exit) | tee $BASE.out
        test "$(cat $BASE.exit)" = 0
        exit
        ;;
 esac
 
-# Keep the original TERM for say_color
-ORIGINAL_TERM=$TERM
-
 # For repeatability, reset the environment to known value.
 LANG=C
 LC_ALL=C
@@ -46,7 +75,7 @@ EDITOR=:
 # /usr/xpg4/bin/sh and /bin/ksh to bail out.  So keep the unsets
 # deriving from the command substitution clustered with the other
 # ones.
-unset VISUAL EMAIL LANGUAGE COLUMNS $(perl -e '
+unset VISUAL EMAIL LANGUAGE COLUMNS $("$PERL_PATH" -e '
        my @env = keys %ENV;
        my $ok = join("|", qw(
                TRACE
@@ -61,6 +90,7 @@ unset VISUAL EMAIL LANGUAGE COLUMNS $(perl -e '
        my @vars = grep(/^GIT_/ && !/^GIT_($ok)/o, @env);
        print join("\n", @vars);
 ')
+unset XDG_CONFIG_HOME
 GIT_AUTHOR_EMAIL=author@example.com
 GIT_AUTHOR_NAME='A U Thor'
 GIT_COMMITTER_EMAIL=committer@example.com
@@ -72,6 +102,27 @@ export GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME
 export GIT_COMMITTER_EMAIL GIT_COMMITTER_NAME
 export EDITOR
 
+# Add libc MALLOC and MALLOC_PERTURB test
+# only if we are not executing the test with valgrind
+if expr " $GIT_TEST_OPTS " : ".* --valgrind " >/dev/null ||
+   test -n "$TEST_NO_MALLOC_CHECK"
+then
+       setup_malloc_check () {
+               : nothing
+       }
+       teardown_malloc_check () {
+               : nothing
+       }
+else
+       setup_malloc_check () {
+               MALLOC_CHECK_=3 MALLOC_PERTURB_=165
+               export MALLOC_CHECK_ MALLOC_PERTURB_
+       }
+       teardown_malloc_check () {
+               unset MALLOC_CHECK_ MALLOC_PERTURB_
+       }
+fi
+
 # Protect ourselves from common misconfiguration to export
 # CDPATH into the environment
 unset CDPATH
@@ -79,12 +130,12 @@ unset CDPATH
 unset GREP_OPTIONS
 
 case $(echo $GIT_TRACE |tr "[A-Z]" "[a-z]") in
-       1|2|true)
-               echo "* warning: Some tests will not work if GIT_TRACE" \
-                       "is set as to trace on STDERR ! *"
-               echo "* warning: Please set GIT_TRACE to something" \
-                       "other than 1, 2 or true ! *"
-               ;;
+1|2|true)
+       echo "* warning: Some tests will not work if GIT_TRACE" \
+               "is set as to trace on STDERR ! *"
+       echo "* warning: Please set GIT_TRACE to something" \
+               "other than 1, 2 or true ! *"
+       ;;
 esac
 
 # Convenience
@@ -151,17 +202,23 @@ do
        esac
 done
 
-if test -n "$color"; then
+if test -n "$color"
+then
        say_color () {
                (
                TERM=$ORIGINAL_TERM
                export TERM
                case "$1" in
-                       error) tput bold; tput setaf 1;; # bold red
-                       skip)  tput bold; tput setaf 2;; # bold green
-                       pass)  tput setaf 2;;            # green
-                       info)  tput setaf 3;;            # brown
-                       *) test -n "$quiet" && return;;
+               error)
+                       tput bold; tput setaf 1;; # bold red
+               skip)
+                       tput bold; tput setaf 2;; # bold green
+               pass)
+                       tput setaf 2;;            # green
+               info)
+                       tput setaf 3;;            # brown
+               *)
+                       test -n "$quiet" && return;;
                esac
                shift
                printf "%s" "$*"
@@ -173,7 +230,7 @@ else
        say_color() {
                test -z "$1" && test -n "$quiet" && return
                shift
-               echo "$*"
+               printf "%s\n" "$*"
        }
 fi
 
@@ -229,7 +286,7 @@ trap 'die' EXIT
 
 # The user-facing functions are loaded from a separate file so that
 # test_perf subshells can have them too
-. "${TEST_DIRECTORY:-.}"/test-lib-functions.sh
+. "$TEST_DIRECTORY/test-lib-functions.sh"
 
 # You are not expected to call test_ok_ and test_failure_ directly, use
 # the text_expect_* functions instead.
@@ -275,9 +332,12 @@ test_run_ () {
 
        if test -z "$immediate" || test $eval_ret = 0 || test -n "$expecting_failure"
        then
+               setup_malloc_check
                test_eval_ "$test_cleanup"
+               teardown_malloc_check
        fi
-       if test "$verbose" = "t" && test -n "$HARNESS_ACTIVE"; then
+       if test "$verbose" = "t" && test -n "$HARNESS_ACTIVE"
+       then
                echo ""
        fi
        return "$eval_ret"
@@ -325,7 +385,8 @@ test_at_end_hook_ () {
 test_done () {
        GIT_EXIT_OK=t
 
-       if test -z "$HARNESS_ACTIVE"; then
+       if test -z "$HARNESS_ACTIVE"
+       then
                test_results_dir="$TEST_OUTPUT_DIRECTORY/test-results"
                mkdir -p "$test_results_dir"
                test_results_path="$test_results_dir/${0%.sh}-$$.counts"
@@ -354,10 +415,18 @@ test_done () {
        case "$test_failure" in
        0)
                # Maybe print SKIP message
+               if test -n "$skip_all" && test $test_count -gt 0
+               then
+                       error "Can't use skip_all after running some tests"
+               fi
                [ -z "$skip_all" ] || skip_all=" # SKIP $skip_all"
 
-               if test $test_external_has_tap -eq 0; then
-                       say_color pass "# passed all $msg"
+               if test $test_external_has_tap -eq 0
+               then
+                       if test $test_count -gt 0
+                       then
+                               say_color pass "# passed all $msg"
+                       fi
                        say "1..$test_count$skip_all"
                fi
 
@@ -370,7 +439,8 @@ test_done () {
                exit 0 ;;
 
        *)
-               if test $test_external_has_tap -eq 0; then
+               if test $test_external_has_tap -eq 0
+               then
                        say_color error "# failed $test_failure among $msg"
                        say "1..$test_count"
                fi
@@ -380,23 +450,6 @@ test_done () {
        esac
 }
 
-# Test the binaries we have just built.  The tests are kept in
-# t/ subdirectory and are run in 'trash directory' subdirectory.
-if test -z "$TEST_DIRECTORY"
-then
-       # We allow tests to override this, in case they want to run tests
-       # outside of t/, e.g. for running tests on the test library
-       # itself.
-       TEST_DIRECTORY=$(pwd)
-fi
-if test -z "$TEST_OUTPUT_DIRECTORY"
-then
-       # Similarly, override this to store the test-results subdir
-       # elsewhere
-       TEST_OUTPUT_DIRECTORY=$TEST_DIRECTORY
-fi
-GIT_BUILD_DIR="$TEST_DIRECTORY"/..
-
 if test -n "$valgrind"
 then
        make_symlink () {
@@ -467,22 +520,26 @@ then
        PATH=$GIT_VALGRIND/bin:$PATH
        GIT_EXEC_PATH=$GIT_VALGRIND/bin
        export GIT_VALGRIND
-elif test -n "$GIT_TEST_INSTALLED" ; then
+elif test -n "$GIT_TEST_INSTALLED"
+then
        GIT_EXEC_PATH=$($GIT_TEST_INSTALLED/git --exec-path)  ||
        error "Cannot run git from $GIT_TEST_INSTALLED."
        PATH=$GIT_TEST_INSTALLED:$GIT_BUILD_DIR:$PATH
        GIT_EXEC_PATH=${GIT_TEST_EXEC_PATH:-$GIT_EXEC_PATH}
 else # normal case, use ../bin-wrappers only unless $with_dashes:
        git_bin_dir="$GIT_BUILD_DIR/bin-wrappers"
-       if ! test -x "$git_bin_dir/git" ; then
-               if test -z "$with_dashes" ; then
+       if ! test -x "$git_bin_dir/git"
+       then
+               if test -z "$with_dashes"
+               then
                        say "$git_bin_dir/git is not executable; using GIT_EXEC_PATH"
                fi
                with_dashes=t
        fi
        PATH="$git_bin_dir:$PATH"
        GIT_EXEC_PATH=$GIT_BUILD_DIR
-       if test -n "$with_dashes" ; then
+       if test -n "$with_dashes"
+       then
                PATH="$GIT_BUILD_DIR:$PATH"
        fi
 fi
@@ -492,10 +549,6 @@ GIT_CONFIG_NOSYSTEM=1
 GIT_ATTR_NOSYSTEM=1
 export PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR GIT_CONFIG_NOSYSTEM GIT_ATTR_NOSYSTEM
 
-. "$GIT_BUILD_DIR"/GIT-BUILD-OPTIONS
-
-export PERL_PATH
-
 if test -z "$GIT_TEST_CMP"
 then
        if test -n "$GIT_TEST_CMP_USE_COPIED_CONTEXT"
@@ -521,7 +574,8 @@ then
        }
 fi
 
-if ! test -x "$GIT_BUILD_DIR"/test-chmtime; then
+if ! test -x "$GIT_BUILD_DIR"/test-chmtime
+then
        echo >&2 'You need to build test-chmtime:'
        echo >&2 'Run "make test-chmtime" in the source (toplevel) directory'
        exit 1
@@ -544,7 +598,8 @@ rm -fr "$test" || {
 HOME="$TRASH_DIRECTORY"
 export HOME
 
-if test -z "$TEST_NO_CREATE_REPO"; then
+if test -z "$TEST_NO_CREATE_REPO"
+then
        test_create_repo "$test"
 else
        mkdir -p "$test"
@@ -659,9 +714,29 @@ test_i18ngrep () {
        fi
 }
 
-# test whether the filesystem supports symbolic links
-ln -s x y 2>/dev/null && test -h y 2>/dev/null && test_set_prereq SYMLINKS
-rm -f y
+test_lazy_prereq SYMLINKS '
+       # test whether the filesystem supports symbolic links
+       ln -s x y && test -h y
+'
+
+test_lazy_prereq CASE_INSENSITIVE_FS '
+       echo good >CamelCase &&
+       echo bad >camelcase &&
+       test "$(cat CamelCase)" != good
+'
+
+test_lazy_prereq UTF8_NFD_TO_NFC '
+       # check whether FS converts nfd unicode to nfc
+       auml=$(printf "\303\244")
+       aumlcdiar=$(printf "\141\314\210")
+       >"$auml" &&
+       case "$(echo *)" in
+       "$aumlcdiar")
+               true ;;
+       *)
+               false ;;
+       esac
+'
 
 # When the tests are run as root, permission tests will report that
 # things are writable when they shouldn't be.
diff --git a/test-credential.c b/test-credential.c
deleted file mode 100644 (file)
index dee200e..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-#include "cache.h"
-#include "credential.h"
-#include "string-list.h"
-
-static const char usage_msg[] =
-"test-credential <fill|approve|reject> [helper...]";
-
-int main(int argc, const char **argv)
-{
-       const char *op;
-       struct credential c = CREDENTIAL_INIT;
-       int i;
-
-       op = argv[1];
-       if (!op)
-               usage(usage_msg);
-       for (i = 2; i < argc; i++)
-               string_list_append(&c.helpers, argv[i]);
-
-       if (credential_read(&c, stdin) < 0)
-               die("unable to read credential from stdin");
-
-       if (!strcmp(op, "fill")) {
-               credential_fill(&c);
-               if (c.username)
-                       printf("username=%s\n", c.username);
-               if (c.password)
-                       printf("password=%s\n", c.password);
-       }
-       else if (!strcmp(op, "approve"))
-               credential_approve(&c);
-       else if (!strcmp(op, "reject"))
-               credential_reject(&c);
-       else
-               usage(usage_msg);
-
-       return 0;
-}
index 7ec9b13c9b2ceb84fb6dd0dd229e9f6cb8c1a635..ef1d7bae1441e07b6cb74e83a23d07b4720a8ebf 100644 (file)
@@ -87,6 +87,5 @@ int main(int argc, char *argv[])
                die("input error");
        if (ferror(stdout))
                die("output error");
-       buffer_reset(&stdin_buf);
        return 0;
 }
diff --git a/test-string-list.c b/test-string-list.c
new file mode 100644 (file)
index 0000000..4693295
--- /dev/null
@@ -0,0 +1,123 @@
+#include "cache.h"
+#include "string-list.h"
+
+/*
+ * Parse an argument into a string list.  arg should either be a
+ * ':'-separated list of strings, or "-" to indicate an empty string
+ * list (as opposed to "", which indicates a string list containing a
+ * single empty string).  list->strdup_strings must be set.
+ */
+static void parse_string_list(struct string_list *list, const char *arg)
+{
+       if (!strcmp(arg, "-"))
+               return;
+
+       (void)string_list_split(list, arg, ':', -1);
+}
+
+static void write_list(const struct string_list *list)
+{
+       int i;
+       for (i = 0; i < list->nr; i++)
+               printf("[%d]: \"%s\"\n", i, list->items[i].string);
+}
+
+static void write_list_compact(const struct string_list *list)
+{
+       int i;
+       if (!list->nr)
+               printf("-\n");
+       else {
+               printf("%s", list->items[0].string);
+               for (i = 1; i < list->nr; i++)
+                       printf(":%s", list->items[i].string);
+               printf("\n");
+       }
+}
+
+static int prefix_cb(struct string_list_item *item, void *cb_data)
+{
+       const char *prefix = (const char *)cb_data;
+       return !prefixcmp(item->string, prefix);
+}
+
+int main(int argc, char **argv)
+{
+       if (argc == 5 && !strcmp(argv[1], "split")) {
+               struct string_list list = STRING_LIST_INIT_DUP;
+               int i;
+               const char *s = argv[2];
+               int delim = *argv[3];
+               int maxsplit = atoi(argv[4]);
+
+               i = string_list_split(&list, s, delim, maxsplit);
+               printf("%d\n", i);
+               write_list(&list);
+               string_list_clear(&list, 0);
+               return 0;
+       }
+
+       if (argc == 5 && !strcmp(argv[1], "split_in_place")) {
+               struct string_list list = STRING_LIST_INIT_NODUP;
+               int i;
+               char *s = xstrdup(argv[2]);
+               int delim = *argv[3];
+               int maxsplit = atoi(argv[4]);
+
+               i = string_list_split_in_place(&list, s, delim, maxsplit);
+               printf("%d\n", i);
+               write_list(&list);
+               string_list_clear(&list, 0);
+               free(s);
+               return 0;
+       }
+
+       if (argc == 4 && !strcmp(argv[1], "filter")) {
+               /*
+                * Retain only the items that have the specified prefix.
+                * Arguments: list|- prefix
+                */
+               struct string_list list = STRING_LIST_INIT_DUP;
+               const char *prefix = argv[3];
+
+               parse_string_list(&list, argv[2]);
+               filter_string_list(&list, 0, prefix_cb, (void *)prefix);
+               write_list_compact(&list);
+               string_list_clear(&list, 0);
+               return 0;
+       }
+
+       if (argc == 3 && !strcmp(argv[1], "remove_duplicates")) {
+               struct string_list list = STRING_LIST_INIT_DUP;
+
+               parse_string_list(&list, argv[2]);
+               string_list_remove_duplicates(&list, 0);
+               write_list_compact(&list);
+               string_list_clear(&list, 0);
+               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 332a5f711df8f3e3fea3305eb5ecb10de5581033..0f2d9a4a3d8ea732c7c61e3818bd0bbe417c76b0 100644 (file)
@@ -31,9 +31,7 @@ static int apply_delta(int argc, char *argv[])
                die_errno("cannot close preimage");
        if (buffer_deinit(&delta))
                die_errno("cannot close delta");
-       buffer_reset(&preimage);
        strbuf_release(&preimage_view.buf);
-       buffer_reset(&delta);
        return 0;
 }
 
@@ -42,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;
diff --git a/trace.c b/trace.c
index d95341693fa9b27caed38ffe1308838bedb49f83..5ec0e3bd16b5cfc59254c6e10d4555ef3029aa36 100644 (file)
--- a/trace.c
+++ b/trace.c
@@ -62,7 +62,7 @@ static int get_trace_fd(const char *key, int *need_close)
 static const char err_msg[] = "Could not trace into fd given by "
        "GIT_TRACE environment variable";
 
-void trace_vprintf(const char *key, const char *fmt, va_list ap)
+static void trace_vprintf(const char *key, const char *fmt, va_list ap)
 {
        struct strbuf buf = STRBUF_INIT;
 
index 61c928f6cd85aa9cf60942208423e615c9b99352..4713b6930248d961824c9f867b10340e6278132f 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,12 +450,33 @@ 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
+        * the "refspec" capability writes to the refs named after the
+        * right hand side of the first refspec matching each ref we
+        * were fetching.
+        *
+        * (If no "refspec" capability was specified, for historical
+        * reasons we default to *:*.)
+        *
+        * Store the result in to_fetch[i].old_sha1.  Callers such
+        * as "git fetch" can use the value to write feedback to the
+        * terminal, populate FETCH_HEAD, and determine what new value
+        * should be written to peer_ref if the update is a
+        * fast-forward or this is a forced update.
+        */
        for (i = 0; i < nr_heads; i++) {
                char *private;
                posn = to_fetch[i];
index 1811b500d92b1120a01d0ac09f86c0218f3d163b..9932f402dfee2605dbb498b120813aebaa3961f8 100644 (file)
@@ -518,8 +518,7 @@ static int fetch_refs_via_pack(struct transport *transport,
                               int nr_heads, struct ref **to_fetch)
 {
        struct git_transport_data *data = transport->data;
-       char **heads = xmalloc(nr_heads * sizeof(*heads));
-       char **origh = xmalloc(nr_heads * sizeof(*origh));
+       struct string_list sought = STRING_LIST_INIT_DUP;
        const struct ref *refs;
        char *dest = xstrdup(transport->url);
        struct fetch_pack_args args;
@@ -538,7 +537,7 @@ static int fetch_refs_via_pack(struct transport *transport,
        args.depth = data->options.depth;
 
        for (i = 0; i < nr_heads; i++)
-               origh[i] = heads[i] = xstrdup(to_fetch[i]->name);
+               string_list_append(&sought, to_fetch[i]->name);
 
        if (!data->got_remote_heads) {
                connect_setup(transport, 0, 0);
@@ -548,7 +547,7 @@ static int fetch_refs_via_pack(struct transport *transport,
 
        refs = fetch_pack(&args, data->fd, data->conn,
                          refs_tmp ? refs_tmp : transport->remote_refs,
-                         dest, nr_heads, heads, &transport->pack_lockfile);
+                         dest, &sought, &transport->pack_lockfile);
        close(data->fd[0]);
        close(data->fd[1]);
        if (finish_connect(data->conn))
@@ -558,10 +557,7 @@ static int fetch_refs_via_pack(struct transport *transport,
 
        free_refs(refs_tmp);
 
-       for (i = 0; i < nr_heads; i++)
-               free(origh[i]);
-       free(origh);
-       free(heads);
+       string_list_clear(&sought, 0);
        free(dest);
        return (refs ? 0 : -1);
 }
index b866c126e695810131cdab537b8b994c0c32e14e..3b21c4abe6d8890f99fe0169792605c98644fafd 100644 (file)
@@ -106,6 +106,7 @@ struct transport {
 #define TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND 256
 
 #define TRANSPORT_SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3)
+#define TRANSPORT_SUMMARY(x) (int)(TRANSPORT_SUMMARY_WIDTH + strlen(x) - gettext_width(x)), (x)
 
 /* Returns a transport suitable for the url */
 struct transport *transport_get(struct remote *, const char *);
diff --git a/tree.c b/tree.c
index 676e9f710ca8d5a568e0c6ea2fa88132da81b48c..62fed632d8a1ade389dd645b5887155c21ae25ba 100644 (file)
--- a/tree.c
+++ b/tree.c
@@ -22,7 +22,8 @@ static int read_one_entry_opt(const unsigned char *sha1, const char *base, int b
        ce = xcalloc(1, size);
 
        ce->ce_mode = create_ce_mode(mode);
-       ce->ce_flags = create_ce_flags(baselen + len, stage);
+       ce->ce_flags = create_ce_flags(stage);
+       ce->ce_namelen = baselen + len;
        memcpy(ce->name, base, baselen);
        memcpy(ce->name + baselen, pathname, len+1);
        hashcpy(ce->sha1, sha1);
@@ -133,8 +134,8 @@ static int cmp_cache_name_compare(const void *a_, const void *b_)
 
        ce1 = *((const struct cache_entry **)a_);
        ce2 = *((const struct cache_entry **)b_);
-       return cache_name_compare(ce1->name, ce1->ce_flags,
-                                 ce2->name, ce2->ce_flags);
+       return cache_name_stage_compare(ce1->name, ce1->ce_namelen, ce_stage(ce1),
+                                 ce2->name, ce2->ce_namelen, ce_stage(ce2));
 }
 
 int read_tree(struct tree *tree, int stage, struct pathspec *match)
index 33a581924e11167dc546bdf97c8d49460b43674e..6d9636623a2cbb5d5a38eb58d625ef0164d953c0 100644 (file)
@@ -539,7 +539,8 @@ static struct cache_entry *create_ce_entry(const struct traverse_info *info, con
        struct cache_entry *ce = xcalloc(1, cache_entry_size(len));
 
        ce->ce_mode = create_ce_mode(n->mode);
-       ce->ce_flags = create_ce_flags(len, stage);
+       ce->ce_flags = create_ce_flags(stage);
+       ce->ce_namelen = len;
        hashcpy(ce->sha1, n->sha1);
        make_traverse_path(ce->name, info, n);
 
@@ -1296,7 +1297,7 @@ static int verify_clean_subdirectory(struct cache_entry *ce,
         * First let's make sure we do not have a local modification
         * in that directory.
         */
-       namelen = strlen(ce->name);
+       namelen = ce_namelen(ce);
        for (i = locate_in_src_index(ce, o);
             i < o->src_index->cache_nr;
             i++) {
index bb08e2eb0dc52f68807a83b671fa61a2c2224f41..6142421ea1172f7fe6b57486a4f41b81d92bab85 100644 (file)
@@ -11,6 +11,7 @@
 #include "list-objects.h"
 #include "run-command.h"
 #include "sigchain.h"
+#include "version.h"
 
 static const char upload_pack_usage[] = "git upload-pack [--strict] [--timeout=<n>] <dir>";
 
@@ -726,17 +727,14 @@ 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\n", sha1_to_hex(sha1), refname_nons,
+               packet_write(1, "%s %s%c%s%s agent=%s\n",
+                            sha1_to_hex(sha1), refname_nons,
                             0, capabilities,
-                            stateless_rpc ? " no-done" : "");
+                            stateless_rpc ? " no-done" : "",
+                            git_user_agent_sanitized());
        else
                packet_write(1, "%s %s\n", sha1_to_hex(sha1), refname_nons);
        capabilities = NULL;
@@ -744,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;
 }
 
index 1e7184f7f00bc75872369761116141c087fa1c1c..ed958ef6b8b912436ad0145fe650adea083412e3 100644 (file)
@@ -14,6 +14,15 @@ static int drivers_alloc;
        { name, NULL, -1, { pattern, REG_EXTENDED | REG_ICASE }, \
          word_regex "|[^[:space:]]|[\xc0-\xff][\x80-\xbf]+" }
 static struct userdiff_driver builtin_drivers[] = {
+IPATTERN("ada",
+        "!^(.*[ \t])?(is new|renames|is separate)([ \t].*)?$\n"
+        "!^[ \t]*with[ \t].*$\n"
+        "^[ \t]*((procedure|function)[ \t]+.*)$\n"
+        "^[ \t]*((package|protected|task)[ \t]+.*)$",
+        /* -- */
+        "[a-zA-Z][a-zA-Z0-9_]*"
+        "|[0-9][-+0-9#_.eE]"
+        "|=>|\\.\\.|\\*\\*|:=|/=|>=|<=|<<|>>|<>"),
 IPATTERN("fortran",
         "!^([C*]|[ \t]*!)\n"
         "!^[ \t]*MODULE[ \t]+PROCEDURE[ \t]\n"
diff --git a/utf8.c b/utf8.c
index 523a78a651c50129ab759fa319f8bfce55b2bee7..28791a7c3174924967182d54c8b4a7f9600c87bf 100644 (file)
--- a/utf8.c
+++ b/utf8.c
@@ -433,19 +433,12 @@ int is_encoding_utf8(const char *name)
 #else
        typedef char * iconv_ibp;
 #endif
-char *reencode_string(const char *in, const char *out_encoding, const char *in_encoding)
+char *reencode_string_iconv(const char *in, size_t insz, iconv_t conv)
 {
-       iconv_t conv;
-       size_t insz, outsz, outalloc;
+       size_t outsz, outalloc;
        char *out, *outpos;
        iconv_ibp cp;
 
-       if (!in_encoding)
-               return NULL;
-       conv = iconv_open(out_encoding, in_encoding);
-       if (conv == (iconv_t) -1)
-               return NULL;
-       insz = strlen(in);
        outsz = insz;
        outalloc = outsz + 1; /* for terminating NUL */
        out = xmalloc(outalloc);
@@ -459,7 +452,6 @@ char *reencode_string(const char *in, const char *out_encoding, const char *in_e
                        size_t sofar;
                        if (errno != E2BIG) {
                                free(out);
-                               iconv_close(conv);
                                return NULL;
                        }
                        /* insz has remaining number of bytes.
@@ -478,6 +470,20 @@ char *reencode_string(const char *in, const char *out_encoding, const char *in_e
                        break;
                }
        }
+       return out;
+}
+
+char *reencode_string(const char *in, const char *out_encoding, const char *in_encoding)
+{
+       iconv_t conv;
+       char *out;
+
+       if (!in_encoding)
+               return NULL;
+       conv = iconv_open(out_encoding, in_encoding);
+       if (conv == (iconv_t) -1)
+               return NULL;
+       out = reencode_string_iconv(in, strlen(in), conv);
        iconv_close(conv);
        return out;
 }
diff --git a/utf8.h b/utf8.h
index 81f2c82fabcf63e3bb02c15beb4a0409afd9ab7b..3c0ae7624e027a802c38c4afb9fe5b0a590e093d 100644 (file)
--- a/utf8.h
+++ b/utf8.h
@@ -14,6 +14,7 @@ int strbuf_add_wrapped_bytes(struct strbuf *buf, const char *data, int len,
                             int indent, int indent2, int width);
 
 #ifndef NO_ICONV
+char *reencode_string_iconv(const char *in, size_t insz, iconv_t conv);
 char *reencode_string(const char *in, const char *out_encoding, const char *in_encoding);
 #else
 #define reencode_string(a,b,c) NULL
index b823b8519c6dc76aa534e056c44eea7210e716f5..f2b23c81de11a63c2c1c2ac925be9081ad5bea5c 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"
@@ -42,11 +41,6 @@ void fast_export_deinit(void)
                die_errno("error closing fast-import feedback stream");
 }
 
-void fast_export_reset(void)
-{
-       buffer_reset(&report_buffer);
-}
-
 void fast_export_delete(const char *path)
 {
        putchar('D');
@@ -73,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)
@@ -89,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",
@@ -163,7 +179,7 @@ static int parse_cat_response_line(const char *header, off_t *len)
 
        if (ends_with(header, headerlen, " missing"))
                return error("cat-blob reports missing blob: %s", header);
-       type = memmem(header, headerlen, " blob ", strlen(" blob "));
+       type = strstr(header, " blob ");
        if (!type)
                return error("cat-blob header has wrong object type: %s", header);
        n = strtoumax(type + strlen(" blob "), (char **) &end, 10);
@@ -227,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);
@@ -259,7 +282,7 @@ static int parse_ls_response(const char *response, uint32_t *mode,
        }
 
        /* Mode. */
-       if (response_end - response < strlen("100644") ||
+       if (response_end - response < (signed) strlen("100644") ||
            response[strlen("100644")] != ' ')
                die("invalid ls response: missing mode: %s", response);
        *mode = 0;
@@ -272,7 +295,7 @@ static int parse_ls_response(const char *response, uint32_t *mode,
        }
 
        /* ' blob ' or ' tree ' */
-       if (response_end - response < strlen(" blob ") ||
+       if (response_end - response < (signed) strlen(" blob ") ||
            (response[1] != 'b' && response[1] != 't'))
                die("unexpected ls response: not a tree or blob: %s", response);
        response += strlen(" blob ");
index aa629f54ff5b49075eb6dafd1d480077fa8c16f2..c8b5adb811c7ba5652b94a6cf6f9ea54d6d9335f 100644 (file)
@@ -6,15 +6,18 @@ struct line_buffer;
 
 void fast_export_init(int fd);
 void fast_export_deinit(void);
-void fast_export_reset(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 01fcb842f1dcc27517109f0d317a239d3493dc4a..57cc1cec033f638e6d408370039b46b653289e84 100644 (file)
@@ -124,7 +124,3 @@ off_t buffer_skip_bytes(struct line_buffer *buf, off_t nbytes)
        }
        return done;
 }
-
-void buffer_reset(struct line_buffer *buf)
-{
-}
index 8901f214bafce3917025721137a85d827cd1c1a6..ee23b4f490258548a7c50fa7c9a50213b70f5359 100644 (file)
@@ -14,7 +14,6 @@ struct line_buffer {
 int buffer_init(struct line_buffer *buf, const char *filename);
 int buffer_fdinit(struct line_buffer *buf, int fd);
 int buffer_deinit(struct line_buffer *buf);
-void buffer_reset(struct line_buffer *buf);
 
 int buffer_tmpfile_init(struct line_buffer *buf);
 FILE *buffer_tmpfile_rewind(struct line_buffer *buf);  /* prepare to write. */
index ec2707c9c421424a8b34f456aa7472c4c0f45559..f11d490995ee7e3367c1d18e1058f2e322cfa177 100644 (file)
@@ -54,7 +54,7 @@ int move_window(struct sliding_view *view, off_t off, size_t width)
                return -1;
        if (off < view->off || off + width < view->off + view->width)
                return error("invalid delta: window slides left");
-       if (view->max_off >= 0 && view->max_off < off + width)
+       if (view->max_off >= 0 && view->max_off < off + (off_t) width)
                return error("delta preimage ends early");
 
        file_offset = view->off + view->buf.len;
index 1647c1a780c5a6153455fdc73b6e422b474dab8e..74c97c4543d1fa707961aab1453edfb69b2679d2 100644 (file)
@@ -77,8 +77,9 @@ static int error_short_read(struct line_buffer *input)
 static int read_chunk(struct line_buffer *delta, off_t *delta_len,
                      struct strbuf *buf, size_t len)
 {
+       assert(*delta_len >= 0);
        strbuf_reset(buf);
-       if (len > *delta_len ||
+       if (len > (uintmax_t) *delta_len ||
            buffer_read_binary(delta, buf, len) != len)
                return error_short_read(delta);
        *delta_len -= buf->len;
@@ -258,6 +259,7 @@ static int apply_window_in_core(struct window *ctx)
 static int apply_one_window(struct line_buffer *delta, off_t *delta_len,
                            struct sliding_view *preimage, FILE *out)
 {
+       int rv = -1;
        struct window ctx = WINDOW_INIT(preimage);
        size_t out_len;
        size_t instructions_len;
@@ -275,27 +277,26 @@ static int apply_one_window(struct line_buffer *delta, off_t *delta_len,
        if (apply_window_in_core(&ctx))
                goto error_out;
        if (ctx.out.len != out_len) {
-               error("invalid delta: incorrect postimage length");
+               rv = error("invalid delta: incorrect postimage length");
                goto error_out;
        }
        if (write_strbuf(&ctx.out, out))
                goto error_out;
-       window_release(&ctx);
-       return 0;
+       rv = 0;
 error_out:
        window_release(&ctx);
-       return -1;
+       return rv;
 }
 
 int svndiff0_apply(struct line_buffer *delta, off_t delta_len,
                        struct sliding_view *preimage, FILE *postimage)
 {
-       assert(delta && preimage && postimage);
+       assert(delta && preimage && postimage && delta_len >= 0);
 
        if (read_magic(delta, &delta_len))
                return -1;
        while (delta_len) {     /* For each window: */
-               off_t pre_off = pre_off; /* stupid GCC... */
+               off_t pre_off = -1;
                size_t pre_len;
 
                if (read_offset(delta, &pre_off, &delta_len) ||
index 0899790a3331d82b72ba3e58fd7ff6ff83b38466..31d1d83d451e0e78f19067799d14e555a62e2cc8 100644 (file)
 #define NODE_CTX 2     /* node metadata */
 #define INTERNODE_CTX 3        /* between nodes */
 
-#define LENGTH_UNKNOWN (~0)
 #define DATE_RFC2822_LEN 31
 
 static struct line_buffer input = LINE_BUFFER_INIT;
 
 static struct {
-       uint32_t action, propLength, srcRev, type;
-       off_t text_length;
+       uint32_t action, srcRev, type;
+       off_t prop_length, text_length;
        struct strbuf src, dst;
        uint32_t text_delta, prop_delta;
 } node_ctx;
@@ -49,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 {
@@ -61,7 +60,7 @@ static void reset_node_ctx(char *fname)
 {
        node_ctx.type = 0;
        node_ctx.action = NODEACT_UNKNOWN;
-       node_ctx.propLength = LENGTH_UNKNOWN;
+       node_ctx.prop_length = -1;
        node_ctx.text_length = -1;
        strbuf_reset(&node_ctx.src);
        node_ctx.srcRev = 0;
@@ -78,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)
@@ -209,7 +209,7 @@ static void read_props(void)
 static void handle_node(void)
 {
        const uint32_t type = node_ctx.type;
-       const int have_props = node_ctx.propLength != LENGTH_UNKNOWN;
+       const int have_props = node_ctx.prop_length != -1;
        const int have_text = node_ctx.text_length != -1;
        /*
         * Old text for this node:
@@ -273,7 +273,7 @@ static void handle_node(void)
        if (have_props) {
                if (!node_ctx.prop_delta)
                        node_ctx.type = type;
-               if (node_ctx.propLength)
+               if (node_ctx.prop_length)
                        read_props();
        }
 
@@ -300,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;
@@ -354,26 +361,29 @@ 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 (prefixcmp(t, "Node-"))
+                       if (constcmp(t, "Node-"))
                                continue;
                        if (!constcmp(t + strlen("Node-"), "path")) {
                                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"))
@@ -384,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")) {
@@ -402,29 +413,35 @@ 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-content-length")) {
+                       if (constcmp(t, "Text") && constcmp(t, "Prop"))
+                               continue;
+                       if (constcmp(t + 4, "-content-length"))
+                               continue;
+                       {
                                char *end;
-                               uintmax_t textlen;
+                               uintmax_t len;
 
-                               textlen = strtoumax(val, &end, 10);
+                               len = strtoumax(val, &end, 10);
                                if (!isdigit(*val) || *end)
                                        die("invalid dump: non-numeric length %s", val);
-                               if (textlen > maximum_signed_value_of_type(off_t))
+                               if (len > maximum_signed_value_of_type(off_t))
                                        die("unrepresentable length in dump: %s", val);
-                               node_ctx.text_length = (off_t) textlen;
+
+                               if (*t == 'T')
+                                       node_ctx.text_length = (off_t) len;
+                               else
+                                       node_ctx.prop_length = (off_t) len;
                                break;
                        }
-                       if (constcmp(t, "Prop-content-length"))
-                               continue;
-                       node_ctx.propLength = atoi(val);
-                       break;
                case sizeof("Text-delta"):
                        if (!constcmp(t, "Text-delta")) {
                                node_ctx.text_delta = !strcmp(val, "true");
@@ -460,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;
 }
 
@@ -489,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))
@@ -499,8 +533,6 @@ void svndump_deinit(void)
 
 void svndump_reset(void)
 {
-       fast_export_reset();
-       buffer_reset(&input);
        strbuf_release(&dump_ctx.uuid);
        strbuf_release(&dump_ctx.url);
        strbuf_release(&rev_ctx.log);
index df9ceb0e8d473b65fc22ac142d3856dc4f9980e0..b8eb12954e816e0e1490f6ef7eefe64901c38ae1 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.c b/version.c
new file mode 100644 (file)
index 0000000..6106a80
--- /dev/null
+++ b/version.c
@@ -0,0 +1,38 @@
+#include "git-compat-util.h"
+#include "version.h"
+#include "strbuf.h"
+
+const char git_version_string[] = GIT_VERSION;
+
+const char *git_user_agent(void)
+{
+       static const char *agent = NULL;
+
+       if (!agent) {
+               agent = getenv("GIT_USER_AGENT");
+               if (!agent)
+                       agent = GIT_USER_AGENT;
+       }
+
+       return agent;
+}
+
+const char *git_user_agent_sanitized(void)
+{
+       static const char *agent = NULL;
+
+       if (!agent) {
+               struct strbuf buf = STRBUF_INIT;
+               int i;
+
+               strbuf_addstr(&buf, git_user_agent());
+               strbuf_trim(&buf);
+               for (i = 0; i < buf.len; i++) {
+                       if (buf.buf[i] <= 32 || buf.buf[i] >= 127)
+                               buf.buf[i] = '.';
+               }
+               agent = buf.buf;
+       }
+
+       return agent;
+}
diff --git a/version.h b/version.h
new file mode 100644 (file)
index 0000000..6911a4f
--- /dev/null
+++ b/version.h
@@ -0,0 +1,9 @@
+#ifndef VERSION_H
+#define VERSION_H
+
+extern const char git_version_string[];
+
+const char *git_user_agent(void);
+const char *git_user_agent_sanitized(void);
+
+#endif /* VERSION_H */
index b5e33e49c77bdf1d19292971b63ff5221b013f33..68739aaa3b9e9e1a1bbbd43c75c9b5c244fb6c3e 100644 (file)
--- a/wrapper.c
+++ b/wrapper.c
@@ -403,6 +403,19 @@ int remove_or_warn(unsigned int mode, const char *file)
        return S_ISGITLINK(mode) ? rmdir_or_warn(file) : unlink_or_warn(file);
 }
 
+void warn_on_inaccessible(const char *path)
+{
+       warning(_("unable to access '%s': %s"), path, strerror(errno));
+}
+
+int access_or_warn(const char *path, int mode)
+{
+       int ret = access(path, mode);
+       if (ret && errno != ENOENT)
+               warn_on_inaccessible(path);
+       return ret;
+}
+
 struct passwd *xgetpwuid_self(void)
 {
        struct passwd *pw;
index d45b536021e15c5a674f7969be39f238194bef99..960f448cffd9ffd4e53763dfed3669bc374b8620 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 dd6d8c41068e6664cff1c07100e482e7ca9f0959..2a9658bad4c5035893e9363b51985f285dd3b34c 100644 (file)
@@ -12,6 +12,7 @@
 #include "refs.h"
 #include "submodule.h"
 #include "column.h"
+#include "strbuf.h"
 
 static char default_wt_status_colors[][COLOR_MAXLEN] = {
        GIT_COLOR_NORMAL, /* WT_STATUS_HEADER */
@@ -99,8 +100,8 @@ void status_printf(struct wt_status *s, const char *color,
        va_end(ap);
 }
 
-void status_printf_more(struct wt_status *s, const char *color,
-                       const char *fmt, ...)
+static void status_printf_more(struct wt_status *s, const char *color,
+                              const char *fmt, ...)
 {
        va_list ap;
 
@@ -130,9 +131,34 @@ void wt_status_prepare(struct wt_status *s)
 
 static void wt_status_print_unmerged_header(struct wt_status *s)
 {
+       int i;
+       int del_mod_conflict = 0;
+       int both_deleted = 0;
+       int not_deleted = 0;
        const char *c = color(WT_STATUS_HEADER, s);
 
        status_printf_ln(s, c, _("Unmerged paths:"));
+
+       for (i = 0; i < s->change.nr; i++) {
+               struct string_list_item *it = &(s->change.items[i]);
+               struct wt_status_change_data *d = it->util;
+
+               switch (d->stagemask) {
+               case 0:
+                       break;
+               case 1:
+                       both_deleted = 1;
+                       break;
+               case 3:
+               case 5:
+                       del_mod_conflict = 1;
+                       break;
+               default:
+                       not_deleted = 1;
+                       break;
+               }
+       }
+
        if (!advice_status_hints)
                return;
        if (s->whence != FROM_COMMIT)
@@ -141,7 +167,17 @@ static void wt_status_print_unmerged_header(struct wt_status *s)
                status_printf_ln(s, c, _("  (use \"git reset %s <file>...\" to unstage)"), s->reference);
        else
                status_printf_ln(s, c, _("  (use \"git rm --cached <file>...\" to unstage)"));
-       status_printf_ln(s, c, _("  (use \"git add/rm <file>...\" as appropriate to mark resolution)"));
+
+       if (!both_deleted) {
+               if (!del_mod_conflict)
+                       status_printf_ln(s, c, _("  (use \"git add <file>...\" to mark resolution)"));
+               else
+                       status_printf_ln(s, c, _("  (use \"git add/rm <file>...\" as appropriate to mark resolution)"));
+       } else if (!del_mod_conflict && !not_deleted) {
+               status_printf_ln(s, c, _("  (use \"git rm <file>...\" to mark resolution)"));
+       } else {
+               status_printf_ln(s, c, _("  (use \"git add/rm <file>...\" as appropriate to mark resolution)"));
+       }
        status_printf_ln(s, c, "");
 }
 
@@ -185,7 +221,7 @@ static void wt_status_print_other_header(struct wt_status *s,
                                         const char *how)
 {
        const char *c = color(WT_STATUS_HEADER, s);
-       status_printf_ln(s, c, _("%s files:"), what);
+       status_printf_ln(s, c, "%s:", what);
        if (!advice_status_hints)
                return;
        status_printf_ln(s, c, _("  (use \"git %s <file>...\" to include in what will be committed)"), how);
@@ -728,6 +764,211 @@ static void wt_status_print_tracking(struct wt_status *s)
        color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "#");
 }
 
+static int has_unmerged(struct wt_status *s)
+{
+       int i;
+
+       for (i = 0; i < s->change.nr; i++) {
+               struct wt_status_change_data *d;
+               d = s->change.items[i].util;
+               if (d->stagemask)
+                       return 1;
+       }
+       return 0;
+}
+
+static void show_merge_in_progress(struct wt_status *s,
+                               struct wt_status_state *state,
+                               const char *color)
+{
+       if (has_unmerged(s)) {
+               status_printf_ln(s, color, _("You have unmerged paths."));
+               if (advice_status_hints)
+                       status_printf_ln(s, color,
+                               _("  (fix conflicts and run \"git commit\")"));
+       } else {
+               status_printf_ln(s, color,
+                       _("All conflicts fixed but you are still merging."));
+               if (advice_status_hints)
+                       status_printf_ln(s, color,
+                               _("  (use \"git commit\" to conclude merge)"));
+       }
+       wt_status_print_trailer(s);
+}
+
+static void show_am_in_progress(struct wt_status *s,
+                               struct wt_status_state *state,
+                               const char *color)
+{
+       status_printf_ln(s, color,
+               _("You are in the middle of an am session."));
+       if (state->am_empty_patch)
+               status_printf_ln(s, color,
+                       _("The current patch is empty."));
+       if (advice_status_hints) {
+               if (!state->am_empty_patch)
+                       status_printf_ln(s, color,
+                               _("  (fix conflicts and then run \"git am --resolved\")"));
+               status_printf_ln(s, color,
+                       _("  (use \"git am --skip\" to skip this patch)"));
+               status_printf_ln(s, color,
+                       _("  (use \"git am --abort\" to restore the original branch)"));
+       }
+       wt_status_print_trailer(s);
+}
+
+static char *read_line_from_git_path(const char *filename)
+{
+       struct strbuf buf = STRBUF_INIT;
+       FILE *fp = fopen(git_path("%s", filename), "r");
+       if (!fp) {
+               strbuf_release(&buf);
+               return NULL;
+       }
+       strbuf_getline(&buf, fp, '\n');
+       if (!fclose(fp)) {
+               return strbuf_detach(&buf, NULL);
+       } else {
+               strbuf_release(&buf);
+               return NULL;
+       }
+}
+
+static int split_commit_in_progress(struct wt_status *s)
+{
+       int split_in_progress = 0;
+       char *head = read_line_from_git_path("HEAD");
+       char *orig_head = read_line_from_git_path("ORIG_HEAD");
+       char *rebase_amend = read_line_from_git_path("rebase-merge/amend");
+       char *rebase_orig_head = read_line_from_git_path("rebase-merge/orig-head");
+
+       if (!head || !orig_head || !rebase_amend || !rebase_orig_head ||
+           !s->branch || strcmp(s->branch, "HEAD"))
+               return split_in_progress;
+
+       if (!strcmp(rebase_amend, rebase_orig_head)) {
+               if (strcmp(head, rebase_amend))
+                       split_in_progress = 1;
+       } else if (strcmp(orig_head, rebase_orig_head)) {
+               split_in_progress = 1;
+       }
+
+       if (!s->amend && !s->nowarn && !s->workdir_dirty)
+               split_in_progress = 0;
+
+       free(head);
+       free(orig_head);
+       free(rebase_amend);
+       free(rebase_orig_head);
+       return split_in_progress;
+}
+
+static void show_rebase_in_progress(struct wt_status *s,
+                               struct wt_status_state *state,
+                               const char *color)
+{
+       struct stat st;
+
+       if (has_unmerged(s)) {
+               status_printf_ln(s, color, _("You are currently rebasing."));
+               if (advice_status_hints) {
+                       status_printf_ln(s, color,
+                               _("  (fix conflicts and then run \"git rebase --continue\")"));
+                       status_printf_ln(s, color,
+                               _("  (use \"git rebase --skip\" to skip this patch)"));
+                       status_printf_ln(s, color,
+                               _("  (use \"git rebase --abort\" to check out the original branch)"));
+               }
+       } else if (state->rebase_in_progress || !stat(git_path("MERGE_MSG"), &st)) {
+               status_printf_ln(s, color, _("You are currently rebasing."));
+               if (advice_status_hints)
+                       status_printf_ln(s, color,
+                               _("  (all conflicts fixed: run \"git rebase --continue\")"));
+       } else if (split_commit_in_progress(s)) {
+               status_printf_ln(s, color, _("You are currently splitting a commit during a rebase."));
+               if (advice_status_hints)
+                       status_printf_ln(s, color,
+                               _("  (Once your working directory is clean, run \"git rebase --continue\")"));
+       } else {
+               status_printf_ln(s, color, _("You are currently editing a commit during a rebase."));
+               if (advice_status_hints && !s->amend) {
+                       status_printf_ln(s, color,
+                               _("  (use \"git commit --amend\" to amend the current commit)"));
+                       status_printf_ln(s, color,
+                               _("  (use \"git rebase --continue\" once you are satisfied with your changes)"));
+               }
+       }
+       wt_status_print_trailer(s);
+}
+
+static void show_cherry_pick_in_progress(struct wt_status *s,
+                                       struct wt_status_state *state,
+                                       const char *color)
+{
+       status_printf_ln(s, color, _("You are currently cherry-picking."));
+       if (advice_status_hints) {
+               if (has_unmerged(s))
+                       status_printf_ln(s, color,
+                               _("  (fix conflicts and run \"git commit\")"));
+               else
+                       status_printf_ln(s, color,
+                               _("  (all conflicts fixed: run \"git commit\")"));
+       }
+       wt_status_print_trailer(s);
+}
+
+static void show_bisect_in_progress(struct wt_status *s,
+                               struct wt_status_state *state,
+                               const char *color)
+{
+       status_printf_ln(s, color, _("You are currently bisecting."));
+       if (advice_status_hints)
+               status_printf_ln(s, color,
+                       _("  (use \"git bisect reset\" to get back to the original branch)"));
+       wt_status_print_trailer(s);
+}
+
+static void wt_status_print_state(struct wt_status *s)
+{
+       const char *state_color = color(WT_STATUS_HEADER, s);
+       struct wt_status_state state;
+       struct stat st;
+
+       memset(&state, 0, sizeof(state));
+
+       if (!stat(git_path("MERGE_HEAD"), &st)) {
+               state.merge_in_progress = 1;
+       } else if (!stat(git_path("rebase-apply"), &st)) {
+               if (!stat(git_path("rebase-apply/applying"), &st)) {
+                       state.am_in_progress = 1;
+                       if (!stat(git_path("rebase-apply/patch"), &st) && !st.st_size)
+                               state.am_empty_patch = 1;
+               } else {
+                       state.rebase_in_progress = 1;
+               }
+       } else if (!stat(git_path("rebase-merge"), &st)) {
+               if (!stat(git_path("rebase-merge/interactive"), &st))
+                       state.rebase_interactive_in_progress = 1;
+               else
+                       state.rebase_in_progress = 1;
+       } else if (!stat(git_path("CHERRY_PICK_HEAD"), &st)) {
+               state.cherry_pick_in_progress = 1;
+       }
+       if (!stat(git_path("BISECT_LOG"), &st))
+               state.bisect_in_progress = 1;
+
+       if (state.merge_in_progress)
+               show_merge_in_progress(s, &state, state_color);
+       else if (state.am_in_progress)
+               show_am_in_progress(s, &state, state_color);
+       else if (state.rebase_in_progress || state.rebase_interactive_in_progress)
+               show_rebase_in_progress(s, &state, state_color);
+       else if (state.cherry_pick_in_progress)
+               show_cherry_pick_in_progress(s, &state, state_color);
+       if (state.bisect_in_progress)
+               show_bisect_in_progress(s, &state, state_color);
+}
+
 void wt_status_print(struct wt_status *s)
 {
        const char *branch_color = color(WT_STATUS_ONBRANCH, s);
@@ -750,6 +991,7 @@ void wt_status_print(struct wt_status *s)
                        wt_status_print_tracking(s);
        }
 
+       wt_status_print_state(s);
        if (s->is_initial) {
                status_printf_ln(s, color(WT_STATUS_HEADER, s), "");
                status_printf_ln(s, color(WT_STATUS_HEADER, s), _("Initial commit"));
@@ -766,9 +1008,9 @@ void wt_status_print(struct wt_status *s)
                wt_status_print_submodule_summary(s, 1);  /* unstaged */
        }
        if (s->show_untracked_files) {
-               wt_status_print_other(s, &s->untracked, _("Untracked"), "add");
+               wt_status_print_other(s, &s->untracked, _("Untracked files"), "add");
                if (s->show_ignored_files)
-                       wt_status_print_other(s, &s->ignored, _("Ignored"), "add -f");
+                       wt_status_print_other(s, &s->ignored, _("Ignored files"), "add -f");
        } else if (s->commitable)
                status_printf_ln(s, GIT_COLOR_NORMAL, _("Untracked files not listed%s"),
                        advice_status_hints
@@ -781,23 +1023,31 @@ void wt_status_print(struct wt_status *s)
                        status_printf_ln(s, GIT_COLOR_NORMAL, _("No changes"));
                else if (s->nowarn)
                        ; /* nothing */
-               else if (s->workdir_dirty)
-                       printf(_("no changes added to commit%s\n"),
-                               advice_status_hints
-                               ? _(" (use \"git add\" and/or \"git commit -a\")") : "");
-               else if (s->untracked.nr)
-                       printf(_("nothing added to commit but untracked files present%s\n"),
-                               advice_status_hints
-                               ? _(" (use \"git add\" to track)") : "");
-               else if (s->is_initial)
-                       printf(_("nothing to commit%s\n"), advice_status_hints
-                               ? _(" (create/copy files and use \"git add\" to track)") : "");
-               else if (!s->show_untracked_files)
-                       printf(_("nothing to commit%s\n"), advice_status_hints
-                               ? _(" (use -u to show untracked files)") : "");
-               else
-                       printf(_("nothing to commit%s\n"), advice_status_hints
-                               ? _(" (working directory clean)") : "");
+               else if (s->workdir_dirty) {
+                       if (advice_status_hints)
+                               printf(_("no changes added to commit "
+                                        "(use \"git add\" and/or \"git commit -a\")\n"));
+                       else
+                               printf(_("no changes added to commit\n"));
+               } else if (s->untracked.nr) {
+                       if (advice_status_hints)
+                               printf(_("nothing added to commit but untracked files "
+                                        "present (use \"git add\" to track)\n"));
+                       else
+                               printf(_("nothing added to commit but untracked files present\n"));
+               } else if (s->is_initial) {
+                       if (advice_status_hints)
+                               printf(_("nothing to commit (create/copy files "
+                                        "and use \"git add\" to track)\n"));
+                       else
+                               printf(_("nothing to commit\n"));
+               } else if (!s->show_untracked_files) {
+                       if (advice_status_hints)
+                               printf(_("nothing to commit (use -u to show untracked files)\n"));
+                       else
+                               printf(_("nothing to commit\n"));
+               } else
+                       printf(_("nothing to commit, working directory clean\n"));
        }
 }
 
index 14aa9f7e13342f1210ead3aca658a6ed60961649..236b41fd345ca3dd95ce450ac3fb3fca2b725e47 100644 (file)
@@ -71,6 +71,16 @@ struct wt_status {
        struct string_list ignored;
 };
 
+struct wt_status_state {
+       int merge_in_progress;
+       int am_in_progress;
+       int am_empty_patch;
+       int rebase_in_progress;
+       int rebase_interactive_in_progress;
+       int cherry_pick_in_progress;
+       int bisect_in_progress;
+};
+
 void wt_status_prepare(struct wt_status *s);
 void wt_status_print(struct wt_status *s);
 void wt_status_collect(struct wt_status *s);
@@ -82,7 +92,5 @@ void status_printf_ln(struct wt_status *s, const char *color, const char *fmt, .
        ;
 void status_printf(struct wt_status *s, const char *color, const char *fmt, ...)
        ;
-void status_printf_more(struct wt_status *s, const char *color, const char *fmt, ...)
-       __attribute__((format(printf, 3, 4)));
 
 #endif /* STATUS_H */