summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--.mailmap8
-rw-r--r--Documentation/Makefile2
-rw-r--r--Documentation/RelNotes/1.7.10.1.txt78
-rw-r--r--Documentation/RelNotes/1.7.10.2.txt85
-rw-r--r--Documentation/RelNotes/1.7.10.3.txt43
-rw-r--r--Documentation/RelNotes/1.7.10.txt219
-rw-r--r--Documentation/config.txt73
-rw-r--r--Documentation/diff-config.txt4
-rw-r--r--Documentation/diff-generate-patch.txt2
-rw-r--r--Documentation/diff-options.txt31
-rw-r--r--Documentation/everyday.txt4
-rw-r--r--Documentation/git-am.txt3
-rw-r--r--Documentation/git-archive.txt2
-rw-r--r--Documentation/git-blame.txt2
-rw-r--r--Documentation/git-branch.txt19
-rw-r--r--Documentation/git-bundle.txt8
-rw-r--r--Documentation/git-check-ref-format.txt12
-rw-r--r--Documentation/git-checkout.txt8
-rw-r--r--Documentation/git-cherry-pick.txt4
-rw-r--r--Documentation/git-clone.txt16
-rw-r--r--Documentation/git-commit.txt17
-rw-r--r--Documentation/git-config.txt23
-rw-r--r--Documentation/git-cvsserver.txt2
-rw-r--r--Documentation/git-difftool.txt5
-rw-r--r--Documentation/git-fast-export.txt2
-rw-r--r--Documentation/git-fast-import.txt6
-rw-r--r--Documentation/git-fetch-pack.txt10
-rw-r--r--Documentation/git-filter-branch.txt34
-rw-r--r--Documentation/git-format-patch.txt4
-rw-r--r--Documentation/git-fsck.txt7
-rw-r--r--Documentation/git-gc.txt2
-rw-r--r--Documentation/git-grep.txt4
-rw-r--r--Documentation/git-log.txt2
-rw-r--r--Documentation/git-merge.txt2
-rw-r--r--Documentation/git-notes.txt2
-rw-r--r--Documentation/git-p4.txt12
-rw-r--r--Documentation/git-pack-refs.txt2
-rw-r--r--Documentation/git-pull.txt2
-rw-r--r--Documentation/git-push.txt22
-rw-r--r--Documentation/git-rebase.txt10
-rw-r--r--Documentation/git-reflog.txt6
-rw-r--r--Documentation/git-remote-helpers.txt8
-rw-r--r--Documentation/git-remote.txt6
-rw-r--r--Documentation/git-repack.txt2
-rw-r--r--Documentation/git-rerere.txt6
-rw-r--r--Documentation/git-reset.txt2
-rw-r--r--Documentation/git-rev-parse.txt7
-rw-r--r--Documentation/git-revert.txt4
-rw-r--r--Documentation/git-rm.txt3
-rw-r--r--Documentation/git-send-email.txt4
-rw-r--r--Documentation/git-sh-i18n--envsubst.txt2
-rw-r--r--Documentation/git-shortlog.txt2
-rw-r--r--Documentation/git-show-ref.txt2
-rw-r--r--Documentation/git-show.txt4
-rw-r--r--Documentation/git-stash.txt18
-rw-r--r--Documentation/git-status.txt6
-rw-r--r--Documentation/git-submodule.txt15
-rw-r--r--Documentation/git-symbolic-ref.txt7
-rw-r--r--Documentation/git-tag.txt6
-rw-r--r--Documentation/git-tar-tree.txt2
-rw-r--r--Documentation/git-whatchanged.txt2
-rw-r--r--Documentation/git.txt7
-rw-r--r--Documentation/gitattributes.txt41
-rw-r--r--Documentation/gitcli.txt12
-rw-r--r--Documentation/gitcore-tutorial.txt28
-rw-r--r--Documentation/gitcredentials.txt4
-rw-r--r--Documentation/gitdiffcore.txt10
-rw-r--r--Documentation/githooks.txt8
-rw-r--r--Documentation/gitmodules.txt9
-rw-r--r--Documentation/gitweb.conf.txt12
-rw-r--r--Documentation/gitworkflows.txt4
-rw-r--r--Documentation/howto/using-merge-subtree.txt2
-rw-r--r--Documentation/merge-options.txt17
-rw-r--r--Documentation/pretty-formats.txt6
-rw-r--r--Documentation/pull-fetch-param.txt2
-rw-r--r--Documentation/rev-list-options.txt6
-rw-r--r--Documentation/technical/api-argv-array.txt5
-rw-r--r--Documentation/technical/api-config.txt140
-rw-r--r--Documentation/technical/api-parse-options.txt37
-rw-r--r--Documentation/technical/pack-protocol.txt4
-rw-r--r--Documentation/technical/protocol-common.txt2
-rw-r--r--Documentation/user-manual.txt23
-rwxr-xr-xGIT-VERSION-GEN4
-rw-r--r--Makefile89
l---------RelNotes2
-rw-r--r--advice.c20
-rw-r--r--advice.h4
-rw-r--r--argv-array.c14
-rw-r--r--argv-array.h3
-rw-r--r--attr.h2
-rw-r--r--builtin/blame.c27
-rw-r--r--builtin/cat-file.c8
-rw-r--r--builtin/checkout.c35
-rw-r--r--builtin/clone.c349
-rw-r--r--builtin/commit.c223
-rw-r--r--builtin/config.c96
-rw-r--r--builtin/diff.c6
-rw-r--r--builtin/fast-export.c4
-rw-r--r--builtin/fetch-pack.c65
-rw-r--r--builtin/fetch.c25
-rw-r--r--builtin/fmt-merge-msg.c136
-rw-r--r--builtin/fsck.c7
-rw-r--r--builtin/gc.c89
-rw-r--r--builtin/grep.c12
-rw-r--r--builtin/index-pack.c164
-rw-r--r--builtin/log.c4
-rw-r--r--builtin/mailinfo.c11
-rw-r--r--builtin/merge.c155
-rw-r--r--builtin/pack-objects.c351
-rw-r--r--builtin/prune-packed.c4
-rw-r--r--builtin/prune.c2
-rw-r--r--builtin/push.c88
-rw-r--r--builtin/remote.c2
-rw-r--r--builtin/rev-list.c1
-rw-r--r--builtin/rev-parse.c2
-rw-r--r--builtin/revert.c959
-rw-r--r--builtin/send-pack.c13
-rw-r--r--builtin/symbolic-ref.c11
-rw-r--r--builtin/tag.c50
-rw-r--r--builtin/verify-tag.c10
-rw-r--r--cache-tree.c27
-rw-r--r--cache-tree.h4
-rw-r--r--cache.h49
-rw-r--r--combine-diff.c2
-rw-r--r--commit.c13
-rw-r--r--commit.h1
-rw-r--r--compat/mingw.c6
-rw-r--r--compat/mingw.h4
-rw-r--r--config.c157
-rw-r--r--configure.ac17
-rwxr-xr-xcontrib/completion/git-completion.bash38
-rw-r--r--contrib/credential/osxkeychain/Makefile7
-rw-r--r--contrib/diff-highlight/README109
-rwxr-xr-xcontrib/diff-highlight/diff-highlight109
-rw-r--r--contrib/diffall/README31
-rwxr-xr-xcontrib/diffall/git-diffall257
-rwxr-xr-xcontrib/fast-import/git-p4256
-rwxr-xr-xcontrib/rerere-train.sh2
-rw-r--r--contrib/svn-fe/svn-fe.txt10
-rw-r--r--convert.c28
-rw-r--r--ctype.c36
-rw-r--r--daemon.c6
-rw-r--r--diff-no-index.c44
-rw-r--r--diff.c262
-rw-r--r--diff.h7
-rw-r--r--diffcore-pickaxe.c9
-rw-r--r--diffcore-rename.c6
-rw-r--r--dir.c35
-rw-r--r--dir.h1
-rw-r--r--environment.c2
-rw-r--r--exec_cmd.c2
-rw-r--r--fast-import.c110
-rw-r--r--fetch-pack.h1
-rwxr-xr-xgit-add--interactive.perl25
-rwxr-xr-xgit-am.sh24
-rw-r--r--git-compat-util.h3
-rw-r--r--git-parse-remote.sh43
-rwxr-xr-xgit-pull.sh10
-rw-r--r--git-rebase--interactive.sh4
-rwxr-xr-xgit-rebase.sh2
-rwxr-xr-xgit-relink.perl2
-rw-r--r--git-remote-testgit.py7
-rwxr-xr-xgit-repack.sh10
-rw-r--r--git-sh-i18n.sh106
-rwxr-xr-xgit-stash.sh4
-rwxr-xr-xgit-submodule.sh59
-rwxr-xr-xgit-svn.perl70
-rw-r--r--git.spec.in1
-rwxr-xr-xgitk-git/gitk415
-rwxr-xr-xgitweb/gitweb.perl269
-rw-r--r--gitweb/static/gitweb.css7
-rw-r--r--gitweb/static/js/lib/cookies.js2
-rw-r--r--graph.c3
-rw-r--r--grep.c13
-rw-r--r--http-backend.c22
-rw-r--r--http.c27
-rw-r--r--http.h2
-rw-r--r--ident.c68
-rw-r--r--log-tree.c19
-rw-r--r--merge-recursive.c9
-rw-r--r--mergetools/deltawalker21
-rw-r--r--notes-merge.c63
-rw-r--r--object.c9
-rw-r--r--pack-refs.c3
-rw-r--r--pager.c12
-rw-r--r--parse-options.c35
-rw-r--r--parse-options.h4
-rw-r--r--perl/Git.pm2
-rw-r--r--perl/Git/I18N.pm11
-rw-r--r--perl/Makefile7
-rw-r--r--po/.gitignore1
-rw-r--r--po/README109
-rw-r--r--po/TEAMS38
-rw-r--r--po/da.po3503
-rw-r--r--po/de.po3809
-rw-r--r--po/git.pot3534
-rw-r--r--po/nl.po3493
-rw-r--r--po/pt_PT.po3595
-rw-r--r--po/sv.po3907
-rw-r--r--po/zh_CN.po3732
-rw-r--r--pretty.c67
-rw-r--r--read-cache.c10
-rw-r--r--reflog-walk.c22
-rw-r--r--reflog-walk.h4
-rw-r--r--refs.c54
-rw-r--r--refs.h10
-rw-r--r--remote-curl.c19
-rw-r--r--remote.c107
-rw-r--r--remote.h3
-rw-r--r--revision.c70
-rw-r--r--revision.h1
-rw-r--r--run-command.c66
-rw-r--r--sequencer.c922
-rw-r--r--sequencer.h37
-rw-r--r--setup.c22
-rw-r--r--sha1_file.c3
-rw-r--r--submodule.c3
-rw-r--r--submodule.h2
-rw-r--r--symlinks.c28
-rw-r--r--t/Makefile43
-rw-r--r--t/README13
-rw-r--r--t/gitweb-lib.sh2
-rw-r--r--t/lib-git-daemon.sh69
-rw-r--r--t/lib-httpd.sh2
-rw-r--r--t/lib-httpd/apache.conf7
-rw-r--r--t/perf/.gitignore2
-rw-r--r--t/perf/Makefile15
-rw-r--r--t/perf/README146
-rwxr-xr-xt/perf/aggregate.perl166
-rwxr-xr-xt/perf/min_time.perl21
-rwxr-xr-xt/perf/p0000-perf-lib-sanity.sh55
-rwxr-xr-xt/perf/p0001-rev-list.sh17
-rwxr-xr-xt/perf/p4000-diff-algorithms.sh29
-rwxr-xr-xt/perf/p7810-grep.sh23
-rw-r--r--t/perf/perf-lib.sh202
-rwxr-xr-xt/perf/run82
-rwxr-xr-xt/t0000-basic.sh563
-rwxr-xr-xt/t0021-conversion.sh37
-rwxr-xr-xt/t0040-parse-options.sh70
-rwxr-xr-xt/t0061-run-command.sh13
-rwxr-xr-xt/t0080-vcs-svn.sh117
-rwxr-xr-xt/t0204-gettext-reencode-sanity.sh37
-rwxr-xr-xt/t0300-credentials.sh8
-rwxr-xr-xt/t1300-repo-config.sh35
-rwxr-xr-xt/t1305-config-include.sh142
-rwxr-xr-xt/t1410-reflog.sh26
-rwxr-xr-xt/t1411-reflog-show.sh61
-rwxr-xr-xt/t1450-fsck.sh6
-rwxr-xr-xt/t1501-worktree.sh2
-rwxr-xr-xt/t2004-checkout-cache-temp.sh20
-rwxr-xr-xt/t2015-checkout-unborn.sh11
-rwxr-xr-xt/t2020-checkout-detach.sh21
-rwxr-xr-xt/t2030-unresolve-info.sh2
-rwxr-xr-xt/t3310-notes-merge-manual-resolve.sh27
-rwxr-xr-xt/t3400-rebase.sh6
-rwxr-xr-xt/t3404-rebase-interactive.sh31
-rwxr-xr-xt/t3415-rebase-autosquash.sh16
-rwxr-xr-xt/t3507-cherry-pick-conflict.sh14
-rwxr-xr-xt/t3701-add-interactive.sh26
-rwxr-xr-xt/t3900-i18n-commit.sh2
-rwxr-xr-xt/t4015-diff-whitespace.sh14
-rwxr-xr-xt/t4034-diff-words.sh36
-rwxr-xr-xt/t4035-diff-quiet.sh26
-rwxr-xr-xt/t4041-diff-submodule-option.sh34
-rwxr-xr-xt/t4052-stat-output.sh336
-rwxr-xr-xt/t4053-diff-no-index.sh19
-rwxr-xr-xt/t4150-am.sh14
-rwxr-xr-xt/t4202-log.sh290
-rwxr-xr-xt/t4205-log-pretty-formats.sh28
-rwxr-xr-xt/t4209-log-pickaxe.sh119
-rwxr-xr-xt/t5100-mailinfo.sh2
-rwxr-xr-xt/t5300-pack-object.sh4
-rwxr-xr-xt/t5302-pack-index.sh4
-rwxr-xr-xt/t5500-fetch-pack.sh146
-rwxr-xr-xt/t5510-fetch.sh30
-rwxr-xr-xt/t5516-fetch-push.sh16
-rwxr-xr-xt/t5528-push-default.sh54
-rwxr-xr-xt/t5541-http-push.sh50
-rwxr-xr-xt/t5550-http-fetch.sh15
-rwxr-xr-xt/t5551-http-fetch.sh31
-rwxr-xr-xt/t5570-git-daemon.sh148
-rwxr-xr-xt/t5601-clone.sh40
-rwxr-xr-xt/t5700-clone-reference.sh38
-rwxr-xr-xt/t5706-clone-branch.sh8
-rwxr-xr-xt/t5710-info-alternate.sh2
-rwxr-xr-xt/t5800-remote-helpers.sh13
-rwxr-xr-xt/t6006-rev-list-format.sh13
-rwxr-xr-xt/t6022-merge-rename.sh16
-rwxr-xr-xt/t6028-merge-up-to-date.sh17
-rwxr-xr-xt/t6030-bisect-porcelain.sh2
-rwxr-xr-xt/t6032-merge-large-rename.sh2
-rwxr-xr-xt/t6042-merge-rename-corner-cases.sh2
-rwxr-xr-xt/t7004-tag.sh39
-rwxr-xr-xt/t7201-co.sh4
-rwxr-xr-xt/t7300-clean.sh27
-rwxr-xr-xt/t7400-submodule-basic.sh24
-rwxr-xr-xt/t7406-submodule-update.sh17
-rwxr-xr-xt/t7408-submodule-reference.sh8
-rwxr-xr-xt/t7501-commit.sh14
-rwxr-xr-xt/t7502-commit.sh2
-rwxr-xr-xt/t7503-pre-commit-hook.sh18
-rwxr-xr-xt/t7508-status.sh16
-rwxr-xr-xt/t7602-merge-octopus-many.sh10
-rwxr-xr-xt/t7603-merge-reduce-heads.sh50
-rwxr-xr-xt/t7701-repack-unpack-unreachable.sh14
-rwxr-xr-xt/t7810-grep.sh23
-rwxr-xr-xt/t9010-svn-fe.sh365
-rwxr-xr-xt/t9011-svn-da.sh248
-rwxr-xr-xt/t9100-git-svn-basic.sh45
-rwxr-xr-xt/t9300-fast-import.sh377
-rwxr-xr-xt/t9350-fast-export.sh4
-rwxr-xr-xt/t9400-git-cvsserver-server.sh8
-rwxr-xr-xt/t9801-git-p4-branch.sh94
-rwxr-xr-xt/t9803-git-p4-shell-metachars.sh48
-rwxr-xr-xt/t9804-git-p4-label.sh115
-rwxr-xr-xt/t9806-git-p4-options.sh4
-rwxr-xr-xt/t9809-git-p4-client-view.sh395
-rwxr-xr-xt/t9810-git-p4-rcs.sh388
-rw-r--r--t/test-lib-functions.sh565
-rw-r--r--t/test-lib.sh567
-rw-r--r--tag.c12
-rw-r--r--tag.h1
-rw-r--r--test-dump-cache-tree.c2
-rw-r--r--test-obj-pool.c116
-rw-r--r--test-parse-options.c12
-rw-r--r--test-string-pool.c31
-rw-r--r--test-subprocess.c6
-rw-r--r--test-svn-fe.c50
-rw-r--r--test-treap.c70
-rw-r--r--transport.c17
-rw-r--r--transport.h3
-rw-r--r--unpack-trees.c29
-rw-r--r--upload-pack.c11
-rw-r--r--userdiff.c19
-rw-r--r--vcs-svn/LICENSE3
-rw-r--r--vcs-svn/fast_export.c256
-rw-r--r--vcs-svn/fast_export.h26
-rw-r--r--vcs-svn/line_buffer.c6
-rw-r--r--vcs-svn/line_buffer.h2
-rw-r--r--vcs-svn/obj_pool.h61
-rw-r--r--vcs-svn/repo_tree.c330
-rw-r--r--vcs-svn/repo_tree.h12
-rw-r--r--vcs-svn/sliding_window.c79
-rw-r--r--vcs-svn/sliding_window.h18
-rw-r--r--vcs-svn/string_pool.c102
-rw-r--r--vcs-svn/string_pool.h11
-rw-r--r--vcs-svn/string_pool.txt43
-rw-r--r--vcs-svn/svndiff.c308
-rw-r--r--vcs-svn/svndiff.h10
-rw-r--r--vcs-svn/svndump.c134
-rw-r--r--vcs-svn/trp.h237
-rw-r--r--vcs-svn/trp.txt109
-rw-r--r--wt-status.c35
-rw-r--r--wt-status.h6
-rw-r--r--xdiff/xdiff.h10
-rw-r--r--xdiff/xdiffi.c4
-rw-r--r--xdiff/xemit.c12
-rw-r--r--xdiff/xhistogram.c2
-rw-r--r--xdiff/xpatience.c2
-rw-r--r--xdiff/xprepare.c21
361 files changed, 38602 insertions, 5409 deletions
diff --git a/.gitignore b/.gitignore
index 3b7680ea1e..87fcc5f6ff 100644
--- a/.gitignore
+++ b/.gitignore
@@ -181,16 +181,13 @@
/test-line-buffer
/test-match-trees
/test-mktemp
-/test-obj-pool
/test-parse-options
/test-path-utils
/test-run-command
/test-sha1
/test-sigchain
-/test-string-pool
/test-subprocess
/test-svn-fe
-/test-treap
/common-cmds.h
*.tar.gz
*.dsc
diff --git a/.mailmap b/.mailmap
index 19c8726232..6303782106 100644
--- a/.mailmap
+++ b/.mailmap
@@ -29,7 +29,13 @@ Joachim Berdal Haga <cjhaga@fys.uio.no>
Jon Loeliger <jdl@freescale.com>
Jon Seymour <jon@blackcubes.dyndns.org>
Jonathan Nieder <jrnieder@uchicago.edu>
-Junio C Hamano <junio@twinsun.com>
+Junio C Hamano <gitster@pobox.com> <gitster@pobox.com>
+Junio C Hamano <gitster@pobox.com> <junio@pobox.com>
+Junio C Hamano <gitster@pobox.com> <junio@twinsun.com>
+Junio C Hamano <gitster@pobox.com> <junkio@twinsun.com>
+Junio C Hamano <gitster@pobox.com> <junio@hera.kernel.org>
+Junio C Hamano <gitster@pobox.com> <junio@kernel.org>
+Junio C Hamano <gitster@pobox.com> <junkio@cox.net>
Karl Hasselström <kha@treskal.com>
Kent Engstrom <kent@lysator.liu.se>
Lars Doelle <lars.doelle@on-line ! de>
diff --git a/Documentation/Makefile b/Documentation/Makefile
index d40e211f22..9ad6a6a300 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -82,7 +82,7 @@ endif
#
ifndef ASCIIDOC7
-ASCIIDOC_EXTRA += -a asciidoc7compatible -a no-inline-literal
+ASCIIDOC_EXTRA += -a asciidoc7compatible
endif
ifdef DOCBOOK_XSL_172
ASCIIDOC_EXTRA += -a git-asciidoc-no-roff
diff --git a/Documentation/RelNotes/1.7.10.1.txt b/Documentation/RelNotes/1.7.10.1.txt
new file mode 100644
index 0000000000..806a965a1b
--- /dev/null
+++ b/Documentation/RelNotes/1.7.10.1.txt
@@ -0,0 +1,78 @@
+Git v1.7.10.1 Release Notes
+===========================
+
+Additions since v1.7.10
+-----------------------
+
+Localization message files for Danish and German have been added.
+
+
+Fixes since v1.7.10
+-------------------
+
+ * "git add -p" is not designed to deal with unmerged paths but did
+ not exclude them and tried to apply funny patches only to fail.
+
+ * "git blame" started missing quite a few changes from the origin
+ since we stopped using the diff minimalization by default in v1.7.2
+ era.
+
+ * When PATH contains an unreadable directory, alias expansion code
+ did not kick in, and failed with an error that said "git-subcmd"
+ was not found.
+
+ * "git clean -d -f" (not "-d -f -f") is supposed to protect nested
+ working trees of independent git repositories that exist in the
+ current project working tree from getting removed, but the
+ protection applied only to such working trees that are at the
+ top-level of the current project by mistake.
+
+ * "git commit --author=$name" did not tell the name that was being
+ recorded in the resulting commit to hooks, even though it does do
+ so when the end user overrode the authorship via the
+ "GIT_AUTHOR_NAME" environment variable.
+
+ * When "git commit --template F" errors out because the user did not
+ touch the message, it claimed that it aborts due to "empty
+ message", which was utterly wrong.
+
+ * The regexp configured with diff.wordregex was incorrectly reused
+ across files.
+
+ * An age-old corner case bug in combine diff (only triggered with -U0
+ and the hunk at the beginning of the file needs to be shown) has
+ been fixed.
+
+ * Rename detection logic used to match two empty files as renames
+ during merge-recursive, leading to unnatural mismerges.
+
+ * The parser in "fast-import" did not diagnose ":9" style references
+ that is not followed by required SP/LF as an error.
+
+ * When "git fetch" encounters repositories with too many references,
+ the command line of "fetch-pack" that is run by a helper
+ e.g. remote-curl, may fail to hold all of them. Now such an
+ internal invocation can feed the references through the standard
+ input of "fetch-pack".
+
+ * "git fetch" that recurses into submodules on demand did not check
+ if it needs to go into submodules when non branches (most notably,
+ tags) are fetched.
+
+ * "log -p --graph" used with "--stat" had a few formatting error.
+
+ * Running "notes merge --commit" failed to perform correctly when run
+ from any directory inside $GIT_DIR/. When "notes merge" stops with
+ conflicts, $GIT_DIR/NOTES_MERGE_WORKTREE is the place a user edits
+ to resolve it.
+
+ * The 'push to upstream' implementation was broken in some corner
+ cases. "git push $there" without refspec, when the current branch
+ is set to push to a remote different from $there, used to push to
+ $there using the upstream information to a remote unreleated to
+ $there.
+
+ * Giving "--continue" to a conflicted "rebase -i" session skipped a
+ commit that only results in changes to submodules.
+
+Also contains minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.10.2.txt b/Documentation/RelNotes/1.7.10.2.txt
new file mode 100644
index 0000000000..7a7e9d6fd1
--- /dev/null
+++ b/Documentation/RelNotes/1.7.10.2.txt
@@ -0,0 +1,85 @@
+Git v1.7.10.2 Release Notes
+===========================
+
+Fixes since v1.7.10.1
+---------------------
+
+ * The test scaffolding for git-daemon was flaky.
+
+ * The test scaffolding for fast-import was flaky.
+
+ * The filesystem boundary was not correctly reported when .git directory
+ discovery stopped at a mount point.
+
+ * HTTP transport that requires authentication did not work correctly when
+ multiple connections are used simultaneously.
+
+ * Minor memory leak during unpack_trees (hence "merge" and "checkout"
+ to check out another branch) has been plugged.
+
+ * In the older days, the header "Conflicts:" in "cherry-pick" and "merge"
+ was separated by a blank line from the list of paths that follow for
+ readability, but when "merge" was rewritten in C, we lost it by
+ mistake. Remove the newline from "cherry-pick" to make them match
+ again.
+
+ * The command line parser choked "git cherry-pick $name" when $name can
+ be both revision name and a pathname, even though $name can never be a
+ path in the context of the command.
+
+ * The "include.path" facility in the configuration mechanism added in
+ 1.7.10 forgot to interpret "~/path" and "~user/path" as it should.
+
+ * "git config --rename-section" to rename an existing section into a
+ bogus one did not check the new name.
+
+ * The "diff --no-index" codepath used limited-length buffers, risking
+ pathnames getting truncated. Update it to use the strbuf API.
+
+ * The report from "git fetch" said "new branch" even for a non branch
+ ref.
+
+ * The http-backend (the server side of the smart http transfer) used
+ to overwrite GIT_COMMITTER_NAME and GIT_COMMITTER_EMAIL with the
+ value obtained from REMOTE_USER unconditionally, making it
+ impossible for the server side site-specific customization to use
+ different identity sources to affect the names logged. It now uses
+ REMOTE_USER only as a fallback value.
+
+ * "log --graph" was not very friendly with "--stat" option and its
+ output had line breaks at wrong places.
+
+ * Octopus merge strategy did not reduce heads that are recorded in the
+ final commit correctly.
+
+ * "git push" over smart-http lost progress output a few releases ago;
+ this release resurrects it.
+
+ * The error and advice messages given by "git push" when it fails due
+ to non-ff were not very helpful to new users; it has been broken
+ into three cases, and each is given a separate advice message.
+
+ * The insn sheet given by "rebase -i" did not make it clear that the
+ insn lines can be re-ordered to affect the order of the commits in
+ the resulting history.
+
+ * "git repack" used to write out unreachable objects as loose objects
+ when repacking, even if such loose objects will immediately pruned
+ due to its age.
+
+ * A contrib script "rerere-train" did not work out of the box unless
+ user futzed with her $PATH.
+
+ * "git rev-parse --show-prefix" used to emit nothing when run at the
+ top-level of the working tree, but now it gives a blank line.
+
+ * The i18n of error message "git stash save" was not properly done.
+
+ * "git submodule" used a sed script that some platforms mishandled.
+
+ * When using a Perl script on a system where "perl" found on user's
+ $PATH could be ancient or otherwise broken, we allow builders to
+ specify the path to a good copy of Perl with $PERL_PATH. The
+ gitweb test forgot to use that Perl when running its test.
+
+Also contains minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.10.3.txt b/Documentation/RelNotes/1.7.10.3.txt
new file mode 100644
index 0000000000..703fbf1d60
--- /dev/null
+++ b/Documentation/RelNotes/1.7.10.3.txt
@@ -0,0 +1,43 @@
+Git v1.7.10.3 Release Notes
+===========================
+
+Fixes since v1.7.10.2
+---------------------
+
+ * The message file for German translation has been updated a bit.
+
+ * Running "git checkout" on an unborn branch used to corrupt HEAD.
+
+ * When checking out another commit from an already detached state, we
+ used to report all commits that are not reachable from any of the
+ refs as lossage, but some of them might be reachable from the new
+ HEAD, and there is no need to warn about them.
+
+ * Some time ago, "git clone" lost the progress output for its
+ "checkout" phase; when run without any "--quiet" option, it should
+ give progress to the lengthy operation.
+
+ * The directory path used in "git diff --no-index", when it recurses
+ down, was broken with a recent update after v1.7.10.1 release.
+
+ * "log -z --pretty=tformat:..." did not terminate each record with
+ NUL. The fix is not entirely correct when the output also asks for
+ --patch and/or --stat, though.
+
+ * The DWIM behaviour for "log --pretty=format:%gd -g" was somewhat
+ broken and gave undue precedence to configured log.date, causing
+ "git stash list" to show "stash@{time stamp string}".
+
+ * "git status --porcelain" ignored "--branch" option by mistake. The
+ output for "git status --branch -z" was also incorrect and did not
+ terminate the record for the current branch name with NUL as asked.
+
+ * When a submodule repository uses alternate object store mechanism,
+ some commands that were started from the superproject did not
+ notice it and failed with "No such object" errors. The subcommands
+ of "git submodule" command that recursed into the submodule in a
+ separate process were OK; only the ones that cheated and peeked
+ directly into the submodule's repository from the primary process
+ were affected.
+
+Also contains minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.10.txt b/Documentation/RelNotes/1.7.10.txt
new file mode 100644
index 0000000000..58100bf04e
--- /dev/null
+++ b/Documentation/RelNotes/1.7.10.txt
@@ -0,0 +1,219 @@
+Git v1.7.10 Release Notes
+=========================
+
+Compatibility Notes
+-------------------
+
+ * From this release on, the "git merge" command in an interactive
+ session will start an editor when it automatically resolves the
+ merge for the user to explain the resulting commit, just like the
+ "git commit" command does when it wasn't given a commit message.
+
+ If you have a script that runs "git merge" and keeps its standard
+ input and output attached to the user's terminal, and if you do not
+ want the user to explain the resulting merge commits, you can
+ export GIT_MERGE_AUTOEDIT environment variable set to "no", like
+ this:
+
+ #!/bin/sh
+ GIT_MERGE_AUTOEDIT=no
+ export GIT_MERGE_AUTOEDIT
+
+ to disable this behavior (if you want your users to explain their
+ merge commits, you do not have to do anything). Alternatively, you
+ can give the "--no-edit" option to individual invocations of the
+ "git merge" command if you know everybody who uses your script has
+ Git v1.7.8 or newer.
+
+ * The "--binary/-b" options to "git am" have been a no-op for quite a
+ while and were deprecated in mid 2008 (v1.6.0). When you give these
+ options to "git am", it will now warn and ask you not to use them.
+
+ * When you do not tell which branches and tags to push to the "git
+ push" command in any way, the command used "matching refs" rule to
+ update remote branches and tags with branches and tags with the
+ same name you locally have. In future versions of Git, this will
+ change to push out only your current branch according to either the
+ "upstream" or the "current" rule. Although "upstream" may be more
+ powerful once the user understands Git better, the semantics
+ "current" gives is simpler and easier to understand for beginners
+ and may be a safer and better default option. We haven't decided
+ yet which one to switch to.
+
+
+Updates since v1.7.9
+--------------------
+
+UI, Workflows & Features
+
+ * various "gitk" updates.
+ - show the path to the top level directory in the window title
+ - update preference edit dialog
+ - display file list correctly when directories are given on command line
+ - make "git-describe" output in the log message into a clickable link
+ - avoid matching the UNIX timestamp part when searching all fields
+ - give preference to symbolic font names like sans & monospace
+ - allow comparing two commits using a mark
+ - "gitk" honors log.showroot configuration.
+
+ * Teams for localizing the messages from the Porcelain layer of
+ commands are starting to form, thanks to Jiang Xin who volunteered
+ to be the localization coordinator. Translated messages for
+ simplified Chinese, Swedish and Portuguese are available.
+
+ * The configuration mechanism learned an "include" facility; an
+ assignment to the include.path pseudo-variable causes the named
+ file to be included in-place when Git looks up configuration
+ variables.
+
+ * A content filter (clean/smudge) used to be just a way to make the
+ recorded contents "more useful", and allowed to fail; a filter can
+ now optionally be marked as "required".
+
+ * Options whose names begin with "--no-" (e.g. the "--no-verify"
+ option of the "git commit" command) can be negated by omitting
+ "no-" from its name, e.g. "git commit --verify".
+
+ * "git am" learned to pass "-b" option to underlying "git mailinfo", so
+ that a bracketed string other than "PATCH" at the beginning can be kept.
+
+ * "git clone" learned "--single-branch" option to limit cloning to a
+ single branch (surprise!); tags that do not point into the history
+ of the branch are not fetched.
+
+ * "git clone" learned to detach the HEAD in the resulting repository
+ when the user specifies a tag with "--branch" (e.g., "--branch=v1.0").
+ Clone also learned to print the usual "detached HEAD" advice in such
+ a case, similar to "git checkout v1.0".
+
+ * When showing a patch while ignoring whitespace changes, the context
+ lines are taken from the postimage, in order to make it easier to
+ view the output.
+
+ * "git diff --stat" learned to adjust the width of the output on
+ wider terminals, and give more columns to pathnames as needed.
+
+ * "diff-highlight" filter (in contrib/) was updated to produce more
+ aesthetically pleasing output.
+
+ * "fsck" learned "--no-dangling" option to omit dangling object
+ information.
+
+ * "git log -G" and "git log -S" learned to pay attention to the "-i"
+ option. With "-i", "log -G" ignores the case when finding patch
+ hunks that introduce or remove a string that matches the given
+ pattern. Similarly with "-i", "log -S" ignores the case when
+ finding the commit the given block of text appears or disappears
+ from the file.
+
+ * "git merge" in an interactive session learned to spawn the editor
+ by default to let the user edit the auto-generated merge message,
+ to encourage people to explain their merges better. Legacy scripts
+ can export GIT_MERGE_AUTOEDIT=no to retain the historical behavior.
+ Both "git merge" and "git pull" can be given --no-edit from the
+ command line to accept the auto-generated merge message.
+
+ * The advice message given when the user didn't give enough clue on
+ what to merge to "git pull" and "git merge" has been updated to
+ be more concise and easier to understand.
+
+ * "git push" learned the "--prune" option, similar to "git fetch".
+
+ * The whole directory that houses a top-level superproject managed by
+ "git submodule" can be moved to another place.
+
+ * "git symbolic-ref" learned the "--short" option to abbreviate the
+ refname it shows unambiguously.
+
+ * "git tag --list" can be given "--points-at <object>" to limit its
+ output to those that point at the given object.
+
+ * "gitweb" allows intermediate entries in the directory hierarchy
+ that leads to a project to be clicked, which in turn shows the
+ list of projects inside that directory.
+
+ * "gitweb" learned to read various pieces of information for the
+ repositories lazily, instead of reading everything that could be
+ needed (including the ones that are not necessary for a specific
+ task).
+
+ * Project search in "gitweb" shows the substring that matched in the
+ project name and description highlighted.
+
+ * HTTP transport learned to authenticate with a proxy if needed.
+
+ * A new script "diffall" is added to contrib/; it drives an
+ external tool to perform a directory diff of two Git revisions
+ in one go, unlike "difftool" that compares one file at a time.
+
+Foreign Interface
+
+ * Improved handling of views, labels and branches in "git-p4" (in contrib).
+
+ * "git-p4" (in contrib) suffered from unnecessary merge conflicts when
+ p4 expanded the embedded $RCS$-like keywords; it can be now told to
+ unexpand them.
+
+ * Some "git-svn" updates.
+
+ * "vcs-svn"/"svn-fe" learned to read dumps with svn-deltas and
+ support incremental imports.
+
+ * "git difftool/mergetool" learned to drive DeltaWalker.
+
+Performance
+
+ * Unnecessary calls to parse_object() "git upload-pack" makes in
+ response to "git fetch", have been eliminated, to help performance
+ in repositories with excessive number of refs.
+
+Internal Implementation (please report possible regressions)
+
+ * Recursive call chains in "git index-pack" to deal with long delta
+ chains have been flattened, to reduce the stack footprint.
+
+ * Use of add_extra_ref() API is now gone, to make it possible to
+ cleanly restructure the overall refs API.
+
+ * The command line parser of "git pack-objects" now uses parse-options
+ API.
+
+ * The test suite supports the new "test_pause" helper function.
+
+ * Parallel to the test suite, there is a beginning of performance
+ benchmarking framework.
+
+ * t/Makefile is adjusted to prevent newer versions of GNU make from
+ running tests in seemingly random order.
+
+ * The code to check if a path points at a file beyond a symbolic link
+ has been restructured to be thread-safe.
+
+ * When pruning directories that has become empty during "git prune"
+ and "git prune-packed", call closedir() that iterates over a
+ directory before rmdir() it.
+
+Also contains minor documentation updates and code clean-ups.
+
+
+Fixes since v1.7.9
+------------------
+
+Unless otherwise noted, all the fixes since v1.7.9 in the maintenance
+releases are contained in this release (see release notes to them for
+details).
+
+ * Build with NO_PERL_MAKEMAKER was broken and Git::I18N did not work
+ with versions of Perl older than 5.8.3.
+ (merge 5eb660e ab/perl-i18n later to maint).
+
+ * "git tag -s" honored "gpg.program" configuration variable since
+ 1.7.9, but "git tag -v" and "git verify-tag" didn't.
+ (merge a2c2506 az/verify-tag-use-gpg-config later to maint).
+
+ * "configure" script learned to take "--with-sane-tool-path" from the
+ command line to record SANE_TOOL_PATH (used to avoid broken platform
+ tools in /usr/bin) in config.mak.autogen. This may be useful for
+ people on Solaris who have saner tools outside /usr/xpg[46]/bin.
+
+ * zsh port of bash completion script needed another workaround.
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 0e1168c066..e533df655d 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -86,6 +86,19 @@ customary UNIX fashion.
Some variables may require a special value format.
+Includes
+~~~~~~~~
+
+You can include one config file from another by setting the special
+`include.path` variable to the name of the file to be included. The
+included file is expanded immediately, as if its contents had been
+found at the location of the include directive. If the value of the
+`include.path` variable is a relative path, the path is considered to be
+relative to the configuration file in which the include directive was
+found. The value of `include.path` is subject to tilde expansion: `{tilde}/`
+is expanded to the value of `$HOME`, and `{tilde}user/` to the specified
+user's home directory. See below for examples.
+
Example
~~~~~~~
@@ -108,6 +121,11 @@ Example
gitProxy="ssh" for "kernel.org"
gitProxy=default-proxy ; for the rest
+ [include]
+ path = /path/to/foo.inc ; include by absolute path
+ path = foo ; expand "foo" relative to the current file
+ path = ~/foo ; expand "foo" in your $HOME directory
+
Variables
~~~~~~~~~
@@ -123,8 +141,23 @@ advice.*::
+
--
pushNonFastForward::
- Advice shown when linkgit:git-push[1] refuses
- non-fast-forward refs.
+ Set this variable to 'false' if you want to disable
+ 'pushNonFFCurrent', 'pushNonFFDefault', and
+ 'pushNonFFMatching' simultaneously.
+ pushNonFFCurrent::
+ Advice shown when linkgit:git-push[1] fails due to a
+ non-fast-forward update to the current branch.
+ pushNonFFDefault::
+ Advice to set 'push.default' to 'upstream' or 'current'
+ when you ran linkgit:git-push[1] and pushed 'matching
+ refs' by default (i.e. you did not provide an explicit
+ refspec, and no 'push.default' configuration was set)
+ and it resulted in a non-fast-forward error.
+ pushNonFFMatching::
+ Advice shown when you ran linkgit:git-push[1] and pushed
+ 'matching refs' explicitly (i.e. you used ':', or
+ 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
@@ -448,8 +481,8 @@ Common unit suffixes of 'k', 'm', or 'g' are supported.
core.excludesfile::
In addition to '.gitignore' (per-directory) and
'.git/info/exclude', git looks into this file for patterns
- of files which are not meant to be tracked. "{tilde}/" is expanded
- to the value of `$HOME` and "{tilde}user/" to the specified user's
+ 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].
core.askpass::
@@ -830,7 +863,7 @@ commit.status::
commit.template::
Specify a file to use as the template for new commit messages.
- "{tilde}/" is expanded to the value of `$HOME` and "{tilde}user/" to the
+ "`~/`" is expanded to the value of `$HOME` and "`~user/`" to the
specified user's home directory.
credential.helper::
@@ -955,7 +988,7 @@ format.thread::
a boolean value, or `shallow` or `deep`. `shallow` threading
makes every mail a reply to the head of the series,
where the head is chosen from the cover letter, the
- `\--in-reply-to`, and the first patch mail, in this order.
+ `--in-reply-to`, and the first patch mail, in this order.
`deep` threading makes every mail a reply to the previous one.
A true boolean value is the same as `shallow`, and a false
value disables threading.
@@ -1386,7 +1419,7 @@ instaweb.port::
interactive.singlekey::
In interactive commands, allow the user to provide one-letter
input with a single key (i.e., without hitting enter).
- Currently this is used by the `\--patch` mode of
+ Currently this is used by the `--patch` mode of
linkgit:git-add[1], linkgit:git-checkout[1], linkgit:git-commit[1],
linkgit:git-reset[1], and linkgit:git-stash[1]. Note that this
setting is silently ignored if portable keystroke input
@@ -1394,13 +1427,13 @@ interactive.singlekey::
log.abbrevCommit::
If true, makes linkgit:git-log[1], linkgit:git-show[1], and
- linkgit:git-whatchanged[1] assume `\--abbrev-commit`. You may
- override this option with `\--no-abbrev-commit`.
+ linkgit:git-whatchanged[1] assume `--abbrev-commit`. You may
+ override this option with `--no-abbrev-commit`.
log.date::
Set the default date-time mode for the 'log' command.
Setting a value for log.date is similar to using 'git log''s
- `\--date` option. Possible values are `relative`, `local`,
+ `--date` option. Possible values are `relative`, `local`,
`default`, `iso`, `rfc`, and `short`; see linkgit:git-log[1]
for details.
@@ -1590,18 +1623,18 @@ pack.indexVersion::
and this config option ignored whenever the corresponding pack is
larger than 2 GB.
+
-If you have an old git that does not understand the version 2 `{asterisk}.idx` file,
+If you have an old git that does not understand the version 2 `*.idx` file,
cloning or fetching over a non native protocol (e.g. "http" and "rsync")
-that will copy both `{asterisk}.pack` file and corresponding `{asterisk}.idx` file from the
+that will copy both `*.pack` file and corresponding `*.idx` file from the
other side may give you a repository that cannot be accessed with your
-older version of git. If the `{asterisk}.pack` file is smaller than 2 GB, however,
+older version of git. If the `*.pack` file is smaller than 2 GB, however,
you can use linkgit:git-index-pack[1] on the *.pack file to regenerate
-the `{asterisk}.idx` file.
+the `*.idx` file.
pack.packSizeLimit::
The maximum size of a pack. This setting only affects
packing to a file when repacking, i.e. the git:// protocol
- is unaffected. It can be overridden by the `\--max-pack-size`
+ is unaffected. It can be overridden by the `--max-pack-size`
option of linkgit:git-repack[1]. The minimum size allowed is
limited to 1 MiB. The default is unlimited.
Common unit suffixes of 'k', 'm', or 'g' are
@@ -1611,8 +1644,8 @@ pager.<cmd>::
If the value is boolean, turns on or off pagination of the
output of a particular git subcommand when writing to a tty.
Otherwise, turns on pagination for the subcommand using the
- pager specified by the value of `pager.<cmd>`. If `\--paginate`
- or `\--no-pager` is specified on the command line, it takes
+ pager specified by the value of `pager.<cmd>`. If `--paginate`
+ or `--no-pager` is specified on the command line, it takes
precedence over this option. To disable pagination for all
commands, set `core.pager` or `GIT_PAGER` to `cat`.
@@ -1620,9 +1653,9 @@ pretty.<name>::
Alias for a --pretty= format string, as specified in
linkgit:git-log[1]. Any aliases defined here can be used just
as the built-in pretty formats could. For example,
- running `git config pretty.changelog "format:{asterisk} %H %s"`
+ running `git config pretty.changelog "format:* %H %s"`
would cause the invocation `git log --pretty=changelog`
- to be equivalent to running `git log "--pretty=format:{asterisk} %H %s"`.
+ to be equivalent to running `git log "--pretty=format:* %H %s"`.
Note that an alias with the same name as a built-in format
will be silently ignored.
@@ -1735,7 +1768,7 @@ remote.<name>.push::
remote.<name>.mirror::
If true, pushing to this remote will automatically behave
- as if the `\--mirror` option was given on the command line.
+ as if the `--mirror` option was given on the command line.
remote.<name>.skipDefaultUpdate::
If true, this remote will be skipped by default when updating
diff --git a/Documentation/diff-config.txt b/Documentation/diff-config.txt
index 1aed79e7dc..6aa1be0478 100644
--- a/Documentation/diff-config.txt
+++ b/Documentation/diff-config.txt
@@ -52,6 +52,10 @@ directories with less than 10% of the total amount of changed files,
and accumulating child directory counts in the parent directories:
`files,10,cumulative`.
+diff.statGraphWidth::
+ Limit the width of the graph part in --stat output. If set, applies
+ to all commands generating --stat outuput except format-patch.
+
diff.external::
If this config variable is set, diff generation is not
performed using the internal diff machinery, but using the
diff --git a/Documentation/diff-generate-patch.txt b/Documentation/diff-generate-patch.txt
index c57460c03d..55f499a160 100644
--- a/Documentation/diff-generate-patch.txt
+++ b/Documentation/diff-generate-patch.txt
@@ -175,7 +175,7 @@ In the above example output, the function signature was changed
from both files (hence two `-` removals from both file1 and
file2, plus `++` to mean one line that was added does not appear
in either file1 nor file2). Also eight other lines are the same
-from file1 but do not appear in file2 (hence prefixed with `{plus}`).
+from file1 but do not appear in file2 (hence prefixed with `+`).
When shown by `git diff-tree -c`, it compares the parents of a
merge commit with the merge result (i.e. file1..fileN are the
diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
index ba7cd13483..6cfedd85dc 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -56,19 +56,25 @@ endif::git-format-patch[]
Generate a diff using the "histogram diff" algorithm.
--stat[=<width>[,<name-width>[,<count>]]]::
- Generate a diffstat. You can override the default
- output width for 80-column terminal by `--stat=<width>`.
- The width of the filename part can be controlled by
- giving another width to it separated by a comma.
+ Generate a diffstat. By default, as much space as necessary
+ will be used for the filename part, and the rest for the graph
+ part. Maximum width defaults to terminal width, or 80 columns
+ if not connected to a terminal, and can be overriden by
+ `<width>`. The width of the filename part can be limited by
+ giving another width `<name-width>` after a comma. The width
+ of the graph part can be limited by using
+ `--stat-graph-width=<width>` (affects all commands generating
+ a stat graph) or by setting `diff.statGraphWidth=<width>`
+ (does not affect `git format-patch`).
By giving a third parameter `<count>`, you can limit the
- output to the first `<count>` lines, followed by
- `...` if there are more.
+ output to the first `<count>` lines, followed by `...` if
+ there are more.
+
These parameters can also be set individually with `--stat-width=<width>`,
`--stat-name-width=<name-width>` and `--stat-count=<count>`.
--numstat::
- Similar to `\--stat`, but shows number of added and
+ Similar to `--stat`, but shows number of added and
deleted lines in decimal notation and pathname without
abbreviation, to make it more machine friendly. For
binary files, outputs two `-` instead of saying
@@ -159,11 +165,12 @@ any of those replacements occurred.
of the `--diff-filter` option on what the status letters mean.
--submodule[=<format>]::
- Chose the output format for submodule differences. <format> can be one of
- 'short' and 'log'. 'short' just shows pairs of commit names, this format
- is used when this option is not given. 'log' is the default value for this
- option and lists the commits in that commit range like the 'summary'
- option of linkgit:git-submodule[1] does.
+ Specify how differences in submodules are shown. When `--submodule`
+ or `--submodule=log` is given, the 'log' format is used. This format lists
+ the commits in the range like linkgit:git-submodule[1] `summary` does.
+ Omitting the `--submodule` option or specifying `--submodule=short`,
+ uses the 'short' format. This format just shows the names of the commits
+ at the beginning and end of the range.
--color[=<when>]::
Show colored diff.
diff --git a/Documentation/everyday.txt b/Documentation/everyday.txt
index ae413e52a5..048337b40f 100644
--- a/Documentation/everyday.txt
+++ b/Documentation/everyday.txt
@@ -98,8 +98,8 @@ you originally wrote.
<9> switch to the master branch.
<10> merge a topic branch into your master branch.
<11> review commit logs; other forms to limit output can be
-combined and include `\--max-count=10` (show 10 commits),
-`\--until=2005-12-10`, etc.
+combined and include `--max-count=10` (show 10 commits),
+`--until=2005-12-10`, etc.
<12> view only the changes that touch what's in `curses/`
directory, since `v2.43` tag.
diff --git a/Documentation/git-am.txt b/Documentation/git-am.txt
index 887466d777..ee6cca2e13 100644
--- a/Documentation/git-am.txt
+++ b/Documentation/git-am.txt
@@ -40,6 +40,9 @@ OPTIONS
--keep::
Pass `-k` flag to 'git mailinfo' (see linkgit:git-mailinfo[1]).
+--keep-non-patch::
+ Pass `-b` flag to 'git mailinfo' (see linkgit:git-mailinfo[1]).
+
--keep-cr::
--no-keep-cr::
With `--keep-cr`, call 'git mailsplit' (see linkgit:git-mailsplit[1])
diff --git a/Documentation/git-archive.txt b/Documentation/git-archive.txt
index ac7006e640..59d73e532f 100644
--- a/Documentation/git-archive.txt
+++ b/Documentation/git-archive.txt
@@ -160,7 +160,7 @@ EXAMPLES
Same as above, but the format is inferred from the output file.
-`git archive --format=tar --prefix=git-1.4.0/ v1.4.0{caret}\{tree\} | gzip >git-1.4.0.tar.gz`::
+`git archive --format=tar --prefix=git-1.4.0/ v1.4.0^{tree} | gzip >git-1.4.0.tar.gz`::
Create a compressed tarball for v1.4.0 release, but without a
global extended pax header.
diff --git a/Documentation/git-blame.txt b/Documentation/git-blame.txt
index 9516914236..7ee923629e 100644
--- a/Documentation/git-blame.txt
+++ b/Documentation/git-blame.txt
@@ -160,7 +160,7 @@ introduced the file with:
git log --diff-filter=A --pretty=short -- foo
and then annotate the change between the commit and its
-parents, using `commit{caret}!` notation:
+parents, using `commit^!` notation:
git blame -C -C -f $commit^! -- foo
diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index 0427e80a35..6410c3d345 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -24,8 +24,8 @@ be highlighted with an asterisk. Option `-r` causes the remote-tracking
branches to be listed, and option `-a` shows both. This list mode is also
activated by the `--list` option (see below).
<pattern> restricts the output to matching branches, the pattern is a shell
-wildcard (i.e., matched using fnmatch(3))
-Multiple patterns may be given; if any of them matches, the tag is shown.
+wildcard (i.e., matched using fnmatch(3)).
+Multiple patterns may be given; if any of them matches, the branch is shown.
With `--contains`, shows only the branches that contain the named commit
(in other words, the branches whose tip commits are descendants of the
@@ -49,7 +49,7 @@ the remote-tracking branch. This behavior may be changed via the global
overridden by using the `--track` and `--no-track` options, and
changed later using `git branch --set-upstream`.
-With a '-m' or '-M' option, <oldbranch> will be renamed to <newbranch>.
+With a `-m` or `-M` option, <oldbranch> will be renamed to <newbranch>.
If <oldbranch> had a corresponding reflog, it is renamed to match
<newbranch>, and a reflog entry is created to remember the branch
renaming. If <newbranch> exists, -M must be used to force the rename
@@ -59,7 +59,7 @@ With a `-d` or `-D` option, `<branchname>` will be deleted. You may
specify more than one branch for deletion. If the branch currently
has a reflog then the reflog will also be deleted.
-Use -r together with -d to delete remote-tracking branches. Note, that it
+Use `-r` together with `-d` to delete remote-tracking branches. Note, that it
only makes sense to delete remote-tracking branches if they no longer exist
in the remote repository or if 'git fetch' was configured not to fetch
them again. See also the 'prune' subcommand of linkgit:git-remote[1] for a
@@ -154,17 +154,18 @@ start-point is either a local or remote-tracking branch.
branch.autosetupmerge configuration variable is true.
--set-upstream::
- If specified branch does not exist yet or if '--force' has been
- given, acts exactly like '--track'. Otherwise sets up configuration
- like '--track' would when creating the branch, except that where
+ If specified branch does not exist yet or if `--force` has been
+ given, acts exactly like `--track`. Otherwise sets up configuration
+ like `--track` would when creating the branch, except that where
branch points to is not changed.
--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`).
---contains <commit>::
- Only list branches which contain the specified commit.
+--contains [<commit>]::
+ Only list branches which contain the specified commit (HEAD
+ if not specified).
--merged [<commit>]::
Only list branches whose tips are reachable from the
diff --git a/Documentation/git-bundle.txt b/Documentation/git-bundle.txt
index 92b01ec25d..16a6b0aceb 100644
--- a/Documentation/git-bundle.txt
+++ b/Documentation/git-bundle.txt
@@ -61,7 +61,7 @@ unbundle <file>::
A list of arguments, acceptable to 'git rev-parse' and
'git rev-list' (and containing a named ref, see SPECIFYING REFERENCES
below), that specifies the specific objects and references
- to transport. For example, `master{tilde}10..master` causes the
+ to transport. For example, `master~10..master` causes the
current master reference to be packaged along with all objects
added since its 10th ancestor commit. There is no explicit
limit to the number of references and objects that may be
@@ -80,12 +80,12 @@ SPECIFYING REFERENCES
'git bundle' will only package references that are shown by
'git show-ref': this includes heads, tags, and remote heads. References
-such as `master{tilde}1` cannot be packaged, but are perfectly suitable for
+such as `master~1` cannot be packaged, but are perfectly suitable for
defining the basis. More than one reference may be packaged, and more
than one basis can be specified. The objects packaged are those not
contained in the union of the given bases. Each basis can be
-specified explicitly (e.g. `^master{tilde}10`), or implicitly (e.g.
-`master{tilde}10..master`, `--since=10.days.ago master`).
+specified explicitly (e.g. `^master~10`), or implicitly (e.g.
+`master~10..master`, `--since=10.days.ago master`).
It is very important that the basis used be held by the destination.
It is okay to err on the side of caution, causing the bundle file
diff --git a/Documentation/git-check-ref-format.txt b/Documentation/git-check-ref-format.txt
index 103e7b128d..98009d1bd5 100644
--- a/Documentation/git-check-ref-format.txt
+++ b/Documentation/git-check-ref-format.txt
@@ -40,9 +40,9 @@ git imposes the following rules on how references are named:
. They cannot have ASCII control characters (i.e. bytes whose
values are lower than \040, or \177 `DEL`), space, tilde `~`,
- caret `{caret}`, or colon `:` anywhere.
+ caret `^`, or colon `:` anywhere.
-. They cannot have question-mark `?`, asterisk `{asterisk}`, or open
+. They cannot have question-mark `?`, asterisk `*`, or open
bracket `[` anywhere. See the `--refspec-pattern` option below for
an exception to this rule.
@@ -62,10 +62,10 @@ unquoted (by mistake), and also avoids ambiguities in certain
reference name expressions (see linkgit:gitrevisions[7]):
. A double-dot `..` is often used as in `ref1..ref2`, and in some
- contexts this notation means `{caret}ref1 ref2` (i.e. not in
+ contexts this notation means `^ref1 ref2` (i.e. not in
`ref1` and in `ref2`).
-. A tilde `~` and caret `{caret}` are used to introduce the postfix
+. A tilde `~` and caret `^` are used to introduce the postfix
'nth parent' and 'peel onion' operation.
. A colon `:` is used as in `srcref:dstref` to mean "use srcref\'s
@@ -92,9 +92,9 @@ OPTIONS
--refspec-pattern::
Interpret <refname> as a reference name pattern for a refspec
(as used with remote repositories). If this option is
- enabled, <refname> is allowed to contain a single `{asterisk}`
+ enabled, <refname> is allowed to contain a single `*`
in place of a one full pathname component (e.g.,
- `foo/{asterisk}/bar` but not `foo/bar{asterisk}`).
+ `foo/*/bar` but not `foo/bar*`).
--normalize::
Normalize 'refname' by removing any leading slash (`/`)
diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index c0a96e6c1e..63a251612a 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -184,7 +184,7 @@ the conflicted merge in the specified paths.
+
This means that you can use `git checkout -p` to selectively discard
edits from your current working tree. See the ``Interactive Mode''
-section of linkgit:git-add[1] to learn how to operate the `\--patch` mode.
+section of linkgit:git-add[1] to learn how to operate the `--patch` mode.
<branch>::
Branch to checkout; if it refers to a branch (i.e., a name that,
@@ -193,11 +193,11 @@ section of linkgit:git-add[1] to learn how to operate the `\--patch` mode.
commit, your HEAD becomes "detached" and you are no longer on
any branch (see below for details).
+
-As a special case, the `"@\{-N\}"` syntax for the N-th last branch
+As a special case, the `"@{-N}"` syntax for the N-th last branch
checks out the branch (instead of detaching). You may also specify
-`-` which is synonymous with `"@\{-1\}"`.
+`-` which is synonymous with `"@{-1}"`.
+
-As a further special case, you may use `"A\...B"` as a shortcut for the
+As a further special case, you may use `"A...B"` as a shortcut for the
merge base of `A` and `B` if there is exactly one merge base. You can
leave out at most one of `A` and `B`, in which case it defaults to `HEAD`.
diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index fed5097e00..06a0bfde8d 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -130,7 +130,7 @@ EXAMPLES
Apply the changes introduced by all commits that are ancestors
of master but not of HEAD to produce new commits.
-`git cherry-pick master{tilde}4 master{tilde}2`::
+`git cherry-pick master~4 master~2`::
Apply the changes introduced by the fifth and third last
commits pointed to by master and create 2 new commits with
@@ -151,7 +151,7 @@ EXAMPLES
are in next but not HEAD to the current branch, creating a new
commit for each new change.
-`git rev-list --reverse master \-- README | git cherry-pick -n --stdin`::
+`git rev-list --reverse master -- README | git cherry-pick -n --stdin`::
Apply the changes introduced by all commits on the master
branch that touched README to the working tree and index,
diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt
index 4b8b26b75e..6e22522c4f 100644
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.txt
@@ -13,7 +13,8 @@ SYNOPSIS
[-l] [-s] [--no-hardlinks] [-q] [-n] [--bare] [--mirror]
[-o <name>] [-b <name>] [-u <upload-pack>] [--reference <repository>]
[--separate-git-dir <git dir>]
- [--depth <depth>] [--recursive|--recurse-submodules] [--] <repository>
+ [--depth <depth>] [--[no-]single-branch]
+ [--recursive|--recurse-submodules] [--] <repository>
[<directory>]
DESCRIPTION
@@ -146,8 +147,9 @@ 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. In a non-bare repository, this is the branch that will
- be checked out.
+ 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.
--upload-pack <upload-pack>::
-u <upload-pack>::
@@ -179,6 +181,14 @@ objects from the source repository into a pack in the cloned repository.
with a long history, and would want to send in fixes
as patches.
+--single-branch::
+ Clone only the history leading to the tip of a single branch,
+ either specified by the `--branch` option or the primary
+ branch remote's `HEAD` points at. When creating a shallow
+ 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.
+
--recursive::
--recurse-submodules::
After the clone is created, initialize all submodules within,
diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt
index 5cc84a1391..2d695f619c 100644
--- a/Documentation/git-commit.txt
+++ b/Documentation/git-commit.txt
@@ -42,7 +42,7 @@ The content to be added can be specified in several ways:
5. by using the --interactive or --patch switches with the 'commit' command
to decide one by one which files or hunks should be part of the commit,
- before finalizing the operation. See the ``Interactive Mode`` section of
+ before finalizing the operation. See the ``Interactive Mode'' section of
linkgit:git-add[1] to learn how to operate these modes.
The `--dry-run` option can be used to obtain a
@@ -132,11 +132,14 @@ OPTIONS
-t <file>::
--template=<file>::
- Use the contents of the given file as the initial version
- of the commit message. The editor is invoked and you can
- make subsequent changes. If a message is specified using
- the `-m` or `-F` options, this option has no effect. This
- overrides the `commit.template` configuration variable.
+ When editing the commit message, start the editor with the
+ contents in the given file. The `commit.template` configuration
+ variable is often used to give this option implicitly to the
+ command. This mechanism can be used by projects that want to
+ guide participants with some hints on what to write in the message
+ in what order. If the user exits the editor without editing the
+ message, the commit is aborted. This has no effect when a message
+ is given by other means, e.g. with the `-m` or `-F` options.
-s::
--signoff::
@@ -284,7 +287,7 @@ When recording your own work, the contents of modified files in
your working tree are temporarily stored to a staging area
called the "index" with 'git add'. A file can be
reverted back, only in the index but not in the working tree,
-to that of the last commit with `git reset HEAD \-- <file>`,
+to that of the last commit with `git reset HEAD -- <file>`,
which effectively reverts 'git add' and prevents the changes to
this file from participating in the next commit. After building
the state to be committed incrementally with these commands,
diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt
index 7617d9eb24..d9463cb387 100644
--- a/Documentation/git-config.txt
+++ b/Documentation/git-config.txt
@@ -44,11 +44,15 @@ a "true" or "false" string for bool), or '--path', which does some
path expansion (see '--path' below). If no type specifier is passed, no
checks or transformations are performed on the value.
-The file-option can be one of '--system', '--global' or '--file'
-which specify where the values will be read from or written to.
-The default is to assume the config file of the current repository,
-.git/config unless defined otherwise with GIT_DIR and GIT_CONFIG
-(see <<FILES>>).
+When reading, the values are read from the system, global and
+repository local configuration files by default, and options
+'--system', '--global', '--local' and '--file <filename>' can be
+used to tell the command to read from only that location (see <<FILES>>).
+
+When writing, the new value is written to the repository local
+configuration file by default, and options '--system', '--global',
+'--file <filename>' can be used to tell the command to write to
+that location (you can say '--local' but that is the default).
This command will fail (with exit code ret) if:
@@ -181,6 +185,11 @@ See also <<FILES>>.
Opens an editor to modify the specified config file; either
'--system', '--global', or repository (default).
+--includes::
+--no-includes::
+ Respect `include.*` directives in config files when looking up
+ values. Defaults to on.
+
[[FILES]]
FILES
-----
@@ -189,9 +198,7 @@ If not set explicitly with '--file', there are three files where
'git config' will search for configuration options:
$GIT_DIR/config::
- Repository specific configuration file. (The filename is
- of course relative to the repository root, not the working
- directory.)
+ Repository specific configuration file.
~/.gitconfig::
User-specific configuration file. Also called "global"
diff --git a/Documentation/git-cvsserver.txt b/Documentation/git-cvsserver.txt
index 827bc988ed..88d814af0e 100644
--- a/Documentation/git-cvsserver.txt
+++ b/Documentation/git-cvsserver.txt
@@ -252,7 +252,7 @@ Configuring database backend
'git-cvsserver' uses the Perl DBI module. Please also read
its documentation if changing these variables, especially
-about `DBI\->connect()`.
+about `DBI->connect()`.
gitcvs.dbname::
Database name. The exact meaning depends on the
diff --git a/Documentation/git-difftool.txt b/Documentation/git-difftool.txt
index 19d473c070..fe38f667f9 100644
--- a/Documentation/git-difftool.txt
+++ b/Documentation/git-difftool.txt
@@ -32,8 +32,9 @@ OPTIONS
--tool=<tool>::
Use the diff tool specified by <tool>.
Valid diff tools are:
- araxis, bc3, diffuse, emerge, ecmerge, gvimdiff, kdiff3,
- kompare, meld, opendiff, p4merge, tkdiff, vimdiff and xxdiff.
+ araxis, bc3, deltawalker, diffuse, emerge, ecmerge, gvimdiff,
+ kdiff3, kompare, meld, opendiff, p4merge, tkdiff, vimdiff and
+ xxdiff.
+
If a diff tool is not specified, 'git difftool'
will use the configuration variable `diff.tool`. If the
diff --git a/Documentation/git-fast-export.txt b/Documentation/git-fast-export.txt
index f37eada63a..d6487e1ce0 100644
--- a/Documentation/git-fast-export.txt
+++ b/Documentation/git-fast-export.txt
@@ -104,7 +104,7 @@ marks the same across runs.
[<git-rev-list-args>...]::
A list of arguments, acceptable to 'git rev-parse' and
'git rev-list', that specifies the specific objects and references
- to export. For example, `master{tilde}10..master` causes the
+ to export. For example, `master~10..master` causes the
current master reference to be exported along with all objects
added since its 10th ancestor commit.
diff --git a/Documentation/git-fast-import.txt b/Documentation/git-fast-import.txt
index ec6ef31197..45101ca957 100644
--- a/Documentation/git-fast-import.txt
+++ b/Documentation/git-fast-import.txt
@@ -478,9 +478,9 @@ current branch value should be written as:
----
from refs/heads/branch^0
----
-The `{caret}0` suffix is necessary as fast-import does not permit a branch to
+The `^0` suffix is necessary as fast-import does not permit a branch to
start from itself, and the branch is created in memory before the
-`from` command is even read from the input. Adding `{caret}0` will force
+`from` command is even read from the input. Adding `^0` will force
fast-import to resolve the commit through Git's revision parsing library,
rather than its internal branch table, thereby loading in the
existing value of the branch.
@@ -975,7 +975,7 @@ Reading from a named tree::
See `filemodify` above for a detailed description of `<path>`.
-Output uses the same format as `git ls-tree <tree> {litdd} <path>`:
+Output uses the same format as `git ls-tree <tree> -- <path>`:
====
<mode> SP ('blob' | 'tree' | 'commit') SP <dataref> HT <path> LF
diff --git a/Documentation/git-fetch-pack.txt b/Documentation/git-fetch-pack.txt
index ed1bdaacd1..474fa307a0 100644
--- a/Documentation/git-fetch-pack.txt
+++ b/Documentation/git-fetch-pack.txt
@@ -32,6 +32,16 @@ OPTIONS
--all::
Fetch all remote refs.
+--stdin::
+ Take the list of refs from stdin, one per line. If there
+ are refs specified on the command line in addition to this
+ option, then the refs from stdin are processed after those
+ on the command line.
++
+If '--stateless-rpc' is specified together with this option then
+the list of refs must be in packet format (pkt-line). Each ref must
+be in a separate packet, and the list must end with a flush packet.
+
-q::
--quiet::
Pass '-q' flag to 'git unpack-objects'; this makes the
diff --git a/Documentation/git-filter-branch.txt b/Documentation/git-filter-branch.txt
index 0f2f117383..81f58234a7 100644
--- a/Documentation/git-filter-branch.txt
+++ b/Documentation/git-filter-branch.txt
@@ -96,8 +96,8 @@ OPTIONS
--index-filter <command>::
This is the filter for rewriting the index. It is similar to the
tree filter but does not check out the tree, which makes it much
- faster. Frequently used with `git rm \--cached
- \--ignore-unmatch ...`, see EXAMPLES below. For hairy
+ faster. Frequently used with `git rm --cached
+ --ignore-unmatch ...`, see EXAMPLES below. For hairy
cases, see linkgit:git-update-index[1].
--parent-filter <command>::
@@ -222,11 +222,11 @@ However, if the file is absent from the tree of some commit,
a simple `rm filename` will fail for that tree and commit.
Thus you may instead want to use `rm -f filename` as the script.
-Using `\--index-filter` with 'git rm' yields a significantly faster
+Using `--index-filter` with 'git rm' yields a significantly faster
version. Like with using `rm filename`, `git rm --cached filename`
will fail if the file is absent from the tree of a commit. If you
want to "completely forget" a file, it does not matter when it entered
-history, so we also add `\--ignore-unmatch`:
+history, so we also add `--ignore-unmatch`:
--------------------------------------------------------------------------
git filter-branch --index-filter 'git rm --cached --ignore-unmatch filename' HEAD
@@ -242,8 +242,8 @@ git filter-branch --subdirectory-filter foodir -- --all
-------------------------------------------------------
Thus you can, e.g., turn a library subdirectory into a repository of
-its own. Note the `\--` that separates 'filter-branch' options from
-revision options, and the `\--all` to rewrite all branches and tags.
+its own. Note the `--` that separates 'filter-branch' options from
+revision options, and the `--all` to rewrite all branches and tags.
To set a commit (which typically is at the tip of another
history) to be the parent of the current initial commit, in
@@ -371,23 +371,23 @@ Checklist for Shrinking a Repository
------------------------------------
git-filter-branch is often used to get rid of a subset of files,
-usually with some combination of `\--index-filter` and
-`\--subdirectory-filter`. People expect the resulting repository to
+usually with some combination of `--index-filter` and
+`--subdirectory-filter`. People expect the resulting repository to
be smaller than the original, but you need a few more steps to
actually make it smaller, because git tries hard not to lose your
objects until you tell it to. First make sure that:
* You really removed all variants of a filename, if a blob was moved
- over its lifetime. `git log \--name-only \--follow \--all \--
- filename` can help you find renames.
+ over its lifetime. `git log --name-only --follow --all -- filename`
+ can help you find renames.
-* You really filtered all refs: use `\--tag-name-filter cat \--
- \--all` when calling git-filter-branch.
+* You really filtered all refs: use `--tag-name-filter cat -- --all`
+ when calling git-filter-branch.
Then there are two ways to get a smaller repository. A safer way is
to clone, that keeps your original intact.
-* Clone it with `git clone +++file:///path/to/repo+++`. The clone
+* Clone it with `git clone file:///path/to/repo`. The clone
will not have the removed objects. See linkgit:git-clone[1]. (Note
that cloning with a plain path just hardlinks everything!)
@@ -397,14 +397,14 @@ approach, so *make a backup* or go back to cloning it. You have been
warned.
* Remove the original refs backed up by git-filter-branch: say `git
- for-each-ref \--format="%(refname)" refs/original/ | xargs -n 1 git
+ for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git
update-ref -d`.
-* Expire all reflogs with `git reflog expire \--expire=now \--all`.
+* Expire all reflogs with `git reflog expire --expire=now --all`.
-* Garbage collect all unreferenced objects with `git gc \--prune=now`
+* Garbage collect all unreferenced objects with `git gc --prune=now`
(or if your git-gc is not new enough to support arguments to
- `\--prune`, use `git repack -ad; git prune` instead).
+ `--prune`, use `git repack -ad; git prune` instead).
GIT
---
diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt
index 6ea9be775c..04c7346e3e 100644
--- a/Documentation/git-format-patch.txt
+++ b/Documentation/git-format-patch.txt
@@ -45,7 +45,7 @@ There are two ways to specify which commits to operate on.
The first rule takes precedence in the case of a single <commit>. To
apply the second rule, i.e., format everything since the beginning of
history up until <commit>, use the '\--root' option: `git format-patch
-\--root <commit>`. If you want to format only <commit> itself, you
+--root <commit>`. If you want to format only <commit> itself, you
can do this with `git format-patch -1 <commit>`.
By default, each output file is numbered sequentially from 1, and uses the
@@ -134,7 +134,7 @@ include::diff-options.txt[]
The optional <style> argument can be either `shallow` or `deep`.
'shallow' threading makes every mail a reply to the head of the
series, where the head is chosen from the cover letter, the
-`\--in-reply-to`, and the first patch mail, in this order. 'deep'
+`--in-reply-to`, and the first patch mail, in this order. 'deep'
threading makes every mail a reply to the previous one.
+
The default is `--no-thread`, unless the 'format.thread' configuration
diff --git a/Documentation/git-fsck.txt b/Documentation/git-fsck.txt
index 6c47395ad2..bbb25da2dd 100644
--- a/Documentation/git-fsck.txt
+++ b/Documentation/git-fsck.txt
@@ -11,7 +11,7 @@ SYNOPSIS
[verse]
'git fsck' [--tags] [--root] [--unreachable] [--cache] [--no-reflogs]
[--[no-]full] [--strict] [--verbose] [--lost-found]
- [--[no-]progress] [<object>*]
+ [--[no-]dangling] [--[no-]progress] [<object>*]
DESCRIPTION
-----------
@@ -30,6 +30,11 @@ index file, all SHA1 references in .git/refs/*, and all reflogs (unless
Print out objects that exist but that aren't reachable from any
of the reference nodes.
+--dangling::
+--no-dangling::
+ Print objects that exist but that are never 'directly' used (default).
+ `--no-dangling` can be used to omit this information from the output.
+
--root::
Report root nodes.
diff --git a/Documentation/git-gc.txt b/Documentation/git-gc.txt
index 815afcb922..b370b025b8 100644
--- a/Documentation/git-gc.txt
+++ b/Documentation/git-gc.txt
@@ -84,7 +84,7 @@ The optional configuration variable 'gc.reflogExpireUnreachable'
can be set to indicate how long historical reflog entries which
are not part of the current branch should remain available in
this repository. These types of entries are generally created as
-a result of using `git commit \--amend` or `git rebase` and are the
+a result of using `git commit --amend` or `git rebase` and are the
commits prior to the amend or rebase occurring. Since these changes
are not part of the current project most users will want to expire
them sooner. This option defaults to '30 days'.
diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt
index 343eadd407..4785f1c5c6 100644
--- a/Documentation/git-grep.txt
+++ b/Documentation/git-grep.txt
@@ -247,11 +247,11 @@ OPTIONS
Examples
--------
-`git grep {apostrophe}time_t{apostrophe} \-- {apostrophe}*.[ch]{apostrophe}`::
+`git grep 'time_t' -- '*.[ch]'`::
Looks for `time_t` in all tracked .c and .h files in the working
directory and its subdirectories.
-`git grep -e {apostrophe}#define{apostrophe} --and \( -e MAX_PATH -e PATH_MAX \)`::
+`git grep -e '#define' --and \( -e MAX_PATH -e PATH_MAX \)`::
Looks for a line that has `#define` and either `MAX_PATH` or
`PATH_MAX`.
diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt
index 249fc878ec..1f906208f9 100644
--- a/Documentation/git-log.txt
+++ b/Documentation/git-log.txt
@@ -100,7 +100,7 @@ Examples
Show all commits since version 'v2.6.12' that changed any file
in the include/scsi or drivers/scsi subdirectories
-`git log --since="2 weeks ago" \-- gitk`::
+`git log --since="2 weeks ago" -- gitk`::
Show the changes during the last two weeks to the file 'gitk'.
The "--" is necessary to avoid confusion with the *branch* named
diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt
index e2e6aba17e..3ceefb8a1f 100644
--- a/Documentation/git-merge.txt
+++ b/Documentation/git-merge.txt
@@ -9,7 +9,7 @@ git-merge - Join two or more development histories together
SYNOPSIS
--------
[verse]
-'git merge' [-n] [--stat] [--no-commit] [--squash]
+'git merge' [-n] [--stat] [--no-commit] [--squash] [--[no-]edit]
[-s <strategy>] [-X <strategy-option>]
[--[no-]rerere-autoupdate] [-m <msg>] [<commit>...]
'git merge' <msg> HEAD <commit>...
diff --git a/Documentation/git-notes.txt b/Documentation/git-notes.txt
index e8319eac69..b95aafae2d 100644
--- a/Documentation/git-notes.txt
+++ b/Documentation/git-notes.txt
@@ -70,7 +70,7 @@ copy::
second object). This subcommand is equivalent to:
`git notes add [-f] -C $(git notes list <from-object>) <to-object>`
+
-In `\--stdin` mode, take lines in the format
+In `--stdin` mode, take lines in the format
+
----------
<from-object> SP <to-object> [ SP <rest> ] LF
diff --git a/Documentation/git-p4.txt b/Documentation/git-p4.txt
index ed827902fc..cf3a9fd27e 100644
--- a/Documentation/git-p4.txt
+++ b/Documentation/git-p4.txt
@@ -183,6 +183,7 @@ subsequent 'sync' operations.
+
This example imports a new remote "p4/proj2" into an existing
git repository:
++
----
$ git init
$ git p4 sync --branch=refs/remotes/p4/proj2 //depot/proj2
@@ -318,6 +319,11 @@ around whitespace. Of the possible wildcards, git-p4 only handles
'...', and only when it is at the end of the path. Git-p4 will complain
if it encounters an unhandled wildcard.
+Bugs in the implementation of overlap mappings exist. If multiple depot
+paths map through overlays to the same location in the repository,
+git-p4 can choose the wrong one. This is hard to solve without
+dedicating a client spec just for git-p4.
+
The name of the client can be given to git-p4 in multiple ways. The
variable 'git-p4.client' takes precedence if it exists. Otherwise,
normal p4 mechanisms of determining the client are used: environment
@@ -429,6 +435,7 @@ git-p4.branchList::
enabled. Each entry should be a pair of branch names separated
by a colon (:). This example declares that both branchA and
branchB were created from main:
++
-------------
git config git-p4.branchList main:branchA
git config --add git-p4.branchList main:branchB
@@ -482,6 +489,11 @@ git-p4.skipUserNameCheck::
user map, 'git p4' exits. This option can be used to force
submission regardless.
+git-p4.attemptRCSCleanup::
+ If enabled, 'git p4 submit' will attempt to cleanup RCS keywords
+ ($Header$, etc). These would otherwise cause merge conflicts and prevent
+ the submit going ahead. This option should be considered experimental at
+ present.
IMPLEMENTATION DETAILS
----------------------
diff --git a/Documentation/git-pack-refs.txt b/Documentation/git-pack-refs.txt
index a3c6677bfa..10afd4edfe 100644
--- a/Documentation/git-pack-refs.txt
+++ b/Documentation/git-pack-refs.txt
@@ -32,7 +32,7 @@ Subsequent updates to branches always create new files under
A recommended practice to deal with a repository with too many
refs is to pack its refs with `--all --prune` once, and
-occasionally run `git pack-refs \--prune`. Tags are by
+occasionally run `git pack-refs --prune`. Tags are by
definition stationary and are not expected to change. Branch
heads will be packed with the initial `pack-refs --all`, but
only the currently active branch heads will become unpacked,
diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt
index 0f18ec891a..defb544ed0 100644
--- a/Documentation/git-pull.txt
+++ b/Documentation/git-pull.txt
@@ -110,7 +110,7 @@ include::merge-options.txt[]
+
See `pull.rebase`, `branch.<name>.rebase` and `branch.autosetuprebase` in
linkgit:git-config[1] if you want to make `git pull` always use
-`{litdd}rebase` instead of merging.
+`--rebase` instead of merging.
+
[NOTE]
This is a potentially _dangerous_ mode of operation.
diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt
index aede48877f..620f8b421f 100644
--- a/Documentation/git-push.txt
+++ b/Documentation/git-push.txt
@@ -10,7 +10,7 @@ SYNOPSIS
--------
[verse]
'git push' [--all | --mirror | --tags] [-n | --dry-run] [--receive-pack=<git-receive-pack>]
- [--repo=<repository>] [-f | --force] [-v | --verbose] [-u | --set-upstream]
+ [--repo=<repository>] [-f | --force] [--prune] [-v | --verbose] [-u | --set-upstream]
[<repository> [<refspec>...]]
DESCRIPTION
@@ -34,7 +34,7 @@ OPTIONS[[OPTIONS]]
<refspec>...::
The format of a <refspec> parameter is an optional plus
- `{plus}`, followed by the source ref <src>, followed
+ `+`, 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.
@@ -50,7 +50,7 @@ updated.
+
The object referenced by <src> is used to update the <dst> reference
on the remote side, but by default this is only allowed if the
-update can fast-forward <dst>. By having the optional leading `{plus}`,
+update can fast-forward <dst>. By having the optional leading `+`,
you can tell git to update the <dst> ref even when the update is not a
fast-forward. This does *not* attempt to merge <src> into <dst>. See
EXAMPLES below for details.
@@ -60,7 +60,7 @@ EXAMPLES below for details.
Pushing an empty <src> allows you to delete the <dst> ref from
the remote repository.
+
-The special refspec `:` (or `{plus}:` to allow non-fast-forward updates)
+The special refspec `:` (or `+:` to allow non-fast-forward updates)
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
@@ -71,6 +71,14 @@ nor in any Push line of the corresponding remotes file---see below).
Instead of naming each ref to push, specifies that all
refs under `refs/heads/` be pushed.
+--prune::
+ Remove remote branches that don't have a local counterpart. For example
+ a remote branch `tmp` will be removed if a local branch with the same
+ name doesn't exist any more. This also respects refspecs, e.g.
+ `git push --prune remote refs/heads/*:refs/tmp/*` would
+ make sure that remote `refs/tmp/foo` will be removed if `refs/heads/foo`
+ doesn't exist.
+
--mirror::
Instead of naming each ref to push, specifies that all
refs under `refs/` (which includes but is not
@@ -196,7 +204,7 @@ option is used.
flag::
A single character indicating the status of the ref:
(space);; for a successfully pushed fast-forward;
-`{plus}`;; for a successful forced update;
+`+`;; for a successful forced update;
`-`;; for a successfully deleted ref;
`*`;; for a successfully pushed new ref;
`!`;; for a ref that was rejected or failed to push; and
@@ -206,7 +214,7 @@ summary::
For a successfully pushed ref, the summary shows the old and new
values of the ref in a form suitable for using as an argument to
`git log` (this is `<old>..<new>` in most cases, and
- `<old>\...<new>` for forced non-fast-forward updates).
+ `<old>...<new>` for forced non-fast-forward updates).
+
For a failed update, more details are given:
+
@@ -388,7 +396,7 @@ the ones in the examples below) can be configured as the default for
Find a ref that matches `experimental` in the `origin` repository
(e.g. `refs/heads/experimental`), and delete it.
-`git push origin {plus}dev:master`::
+`git push origin +dev:master`::
Update the origin repository's master branch with the dev branch,
allowing non-fast-forward updates. *This can leave unreferenced
commits dangling in the origin repository.* Consider the
diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index 520aaa94fb..b0e13e5bf4 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -267,7 +267,7 @@ which makes little sense.
-X <strategy-option>::
--strategy-option=<strategy-option>::
Pass the <strategy-option> through to the merge strategy.
- This implies `\--merge` and, if no strategy has been
+ This implies `--merge` and, if no strategy has been
specified, `-s recursive`. Note the reversal of 'ours' and
'theirs' as noted in above for the `-m` option.
@@ -611,8 +611,8 @@ Easy case: The changes are literally the same.::
Hard case: The changes are not the same.::
This happens if the 'subsystem' rebase had conflicts, or used
- `\--interactive` to omit, edit, squash, or fixup commits; or
- if the upstream used one of `commit \--amend`, `reset`, or
+ `--interactive` to omit, edit, squash, or fixup commits; or
+ if the upstream used one of `commit --amend`, `reset`, or
`filter-branch`.
@@ -648,7 +648,7 @@ correspond to the ones before the rebase.
NOTE: While an "easy case recovery" sometimes appears to be successful
even in the hard case, it may have unintended consequences. For
example, a commit that was removed via `git rebase
- \--interactive` will be **resurrected**!
+ --interactive` will be **resurrected**!
The idea is to manually tell 'git rebase' "where the old 'subsystem'
ended and your 'topic' began", that is, what the old merge-base
@@ -656,7 +656,7 @@ between them was. You will have to find a way to name the last commit
of the old 'subsystem', for example:
* With the 'subsystem' reflog: after 'git fetch', the old tip of
- 'subsystem' is at `subsystem@\{1}`. Subsequent fetches will
+ 'subsystem' is at `subsystem@{1}`. Subsequent fetches will
increase the number. (See linkgit:git-reflog[1].)
* Relative to the tip of 'topic': knowing that your 'topic' has three
diff --git a/Documentation/git-reflog.txt b/Documentation/git-reflog.txt
index 976dc14937..7fe2d2247b 100644
--- a/Documentation/git-reflog.txt
+++ b/Documentation/git-reflog.txt
@@ -39,13 +39,13 @@ as well). It is an alias for `git log -g --abbrev-commit --pretty=oneline`;
see linkgit:git-log[1].
The reflog is useful in various git commands, to specify the old value
-of a reference. For example, `HEAD@\{2\}` means "where HEAD used to be
-two moves ago", `master@\{one.week.ago\}` means "where master used to
+of a reference. For example, `HEAD@{2}` means "where HEAD used to be
+two moves ago", `master@{one.week.ago}` means "where master used to
point to one week ago", and so on. See linkgit:gitrevisions[7] for
more details.
To delete single entries from the reflog, use the subcommand "delete"
-and specify the _exact_ entry (e.g. "`git reflog delete master@\{2\}`").
+and specify the _exact_ entry (e.g. "`git reflog delete master@{2}`").
OPTIONS
diff --git a/Documentation/git-remote-helpers.txt b/Documentation/git-remote-helpers.txt
index 674797cd83..f5836e46d0 100644
--- a/Documentation/git-remote-helpers.txt
+++ b/Documentation/git-remote-helpers.txt
@@ -87,7 +87,7 @@ to the `capabilities` command (see COMMANDS, below).
capability use this.
+
A helper advertising the capability
-`refspec refs/heads/{asterisk}:refs/svn/origin/branches/{asterisk}`
+`refspec refs/heads/*:refs/svn/origin/branches/*`
is saying that, when it is asked to `import refs/heads/topic`, the
stream it outputs will update the `refs/svn/origin/branches/topic`
ref.
@@ -96,7 +96,7 @@ This capability can be advertised multiple times. The first
applicable refspec takes precedence. The left-hand of refspecs
advertised with this capability must cover all refs reported by
the list command. If no 'refspec' capability is advertised,
-there is an implied `refspec {asterisk}:{asterisk}`.
+there is an implied `refspec *:*`.
Capabilities for Pushing
~~~~~~~~~~~~~~~~~~~~~~~~
@@ -148,7 +148,7 @@ Other frontends may have some other order of preference.
This modifies the 'import' capability.
+
A helper advertising
-`refspec refs/heads/{asterisk}:refs/svn/origin/branches/{asterisk}`
+`refspec refs/heads/*:refs/svn/origin/branches/*`
in its capabilities is saying that, when it handles
`import refs/heads/topic`, the stream it outputs will update the
`refs/svn/origin/branches/topic` ref.
@@ -157,7 +157,7 @@ This capability can be advertised multiple times. The first
applicable refspec takes precedence. The left-hand of refspecs
advertised with this capability must cover all refs reported by
the list command. If no 'refspec' capability is advertised,
-there is an implied `refspec {asterisk}:{asterisk}`.
+there is an implied `refspec *:*`.
INVOCATION
----------
diff --git a/Documentation/git-remote.txt b/Documentation/git-remote.txt
index d376d19ef7..a308f4c79f 100644
--- a/Documentation/git-remote.txt
+++ b/Documentation/git-remote.txt
@@ -67,14 +67,14 @@ multiple branches without grabbing all branches.
With `-m <master>` option, a symbolic-ref `refs/remotes/<name>/HEAD` is set
up to point at remote's `<master>` branch. See also the set-head command.
+
-When a fetch mirror is created with `\--mirror=fetch`, the refs will not
+When a fetch mirror is created with `--mirror=fetch`, the refs will not
be stored in the 'refs/remotes/' namespace, but rather everything in
'refs/' on the remote will be directly mirrored into 'refs/' in the
local repository. This option only makes sense in bare repositories,
because a fetch would overwrite any local commits.
+
-When a push mirror is created with `\--mirror=push`, then `git push`
-will always behave as if `\--mirror` was passed.
+When a push mirror is created with `--mirror=push`, then `git push`
+will always behave as if `--mirror` was passed.
'rename'::
diff --git a/Documentation/git-repack.txt b/Documentation/git-repack.txt
index 40af321153..4c1aff65e6 100644
--- a/Documentation/git-repack.txt
+++ b/Documentation/git-repack.txt
@@ -34,7 +34,7 @@ OPTIONS
Especially useful when packing a repository that is used
for private development. Use
with '-d'. This will clean up the objects that `git prune`
- leaves behind, but `git fsck --full` shows as
+ leaves behind, but `git fsck --full --dangling` shows as
dangling.
+
Note that users fetching over dumb protocols will have to fetch the
diff --git a/Documentation/git-rerere.txt b/Documentation/git-rerere.txt
index b43b7c8c0e..a62227f84e 100644
--- a/Documentation/git-rerere.txt
+++ b/Documentation/git-rerere.txt
@@ -101,15 +101,15 @@ One way to do it is to pull master into the topic branch:
The commits marked with `*` touch the same area in the same
file; you need to resolve the conflicts when creating the commit
-marked with `{plus}`. Then you can test the result to make sure your
+marked with `+`. Then you can test the result to make sure your
work-in-progress still works with what is in the latest master.
After this test merge, there are two ways to continue your work
on the topic. The easiest is to build on top of the test merge
-commit `{plus}`, and when your work in the topic branch is finally
+commit `+`, and when your work in the topic branch is finally
ready, pull the topic branch into master, and/or ask the
upstream to pull from you. By that time, however, the master or
-the upstream might have been advanced since the test merge `{plus}`,
+the upstream might have been advanced since the test merge `+`,
in which case the final commit graph would look like this:
------------
diff --git a/Documentation/git-reset.txt b/Documentation/git-reset.txt
index b674866e6d..117e3743a6 100644
--- a/Documentation/git-reset.txt
+++ b/Documentation/git-reset.txt
@@ -41,7 +41,7 @@ working tree in one go.
+
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.
+section of linkgit:git-add[1] to learn how to operate the `--patch` mode.
'git reset' --<mode> [<commit>]::
This form resets the current branch head to <commit> and
diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt
index 8023dc086d..f63b81aad6 100644
--- a/Documentation/git-rev-parse.txt
+++ b/Documentation/git-rev-parse.txt
@@ -113,15 +113,14 @@ OPTIONS
+
If a `pattern` is given, only refs matching the given shell glob are
shown. If the pattern does not contain a globbing character (`?`,
-`{asterisk}`, or `[`), it is turned into a prefix match by
-appending `/{asterisk}`.
+`*`, or `[`), it is turned into a prefix match by appending `/*`.
--glob=pattern::
Show all refs matching the shell glob pattern `pattern`. If
the pattern does not start with `refs/`, this is automatically
prepended. If the pattern does not contain a globbing
- character (`?`, `{asterisk}`, or `[`), it is turned into a prefix
- match by appending `/{asterisk}`.
+ character (`?`, `*`, or `[`), it is turned into a prefix
+ match by appending `/*`.
--show-toplevel::
Show the absolute path of the top-level directory.
diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt
index b699a3458e..70152e8b1e 100644
--- a/Documentation/git-revert.txt
+++ b/Documentation/git-revert.txt
@@ -27,7 +27,7 @@ throw away all uncommitted changes in your working directory, you
should see linkgit:git-reset[1], particularly the '--hard' option. If
you want to extract specific files as they were in another commit, you
should see linkgit:git-checkout[1], specifically the `git checkout
-<commit> \-- <filename>` syntax. Take care with these alternatives as
+<commit> -- <filename>` syntax. Take care with these alternatives as
both will discard uncommitted changes in your working directory.
OPTIONS
@@ -105,7 +105,7 @@ EXAMPLES
Revert the changes specified by the fourth last commit in HEAD
and create a new commit with the reverted changes.
-`git revert -n master{tilde}5..master{tilde}2`::
+`git revert -n master~5..master~2`::
Revert the changes done by commits from the fifth last commit
in master (included) to the third last commit in master
diff --git a/Documentation/git-rm.txt b/Documentation/git-rm.txt
index 665ad4ddab..5d31860eb1 100644
--- a/Documentation/git-rm.txt
+++ b/Documentation/git-rm.txt
@@ -79,8 +79,7 @@ a file that you have not told git about does not remove that file.
File globbing matches across directory boundaries. Thus, given
two directories `d` and `d2`, there is a difference between
-using `git rm {apostrophe}d{asterisk}{apostrophe}` and
-`git rm {apostrophe}d/{asterisk}{apostrophe}`, as the former will
+using `git rm 'd*'` and `git rm 'd/*'`, as the former will
also remove all of directory `d2`.
REMOVING FILES THAT HAVE DISAPPEARED FROM THE FILESYSTEM
diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt
index 327233c85b..324117072d 100644
--- a/Documentation/git-send-email.txt
+++ b/Documentation/git-send-email.txt
@@ -198,6 +198,10 @@ must be used for each option.
if a username is not specified (with '--smtp-user' or 'sendemail.smtpuser'),
then authentication is not attempted.
+--smtp-debug=0|1::
+ Enable (1) or disable (0) debug output. If enabled, SMTP
+ commands and replies will be printed. Useful to debug TLS
+ connection and authentication problems.
Automating
~~~~~~~~~~
diff --git a/Documentation/git-sh-i18n--envsubst.txt b/Documentation/git-sh-i18n--envsubst.txt
index 5c3ec327bb..2ffaf9392e 100644
--- a/Documentation/git-sh-i18n--envsubst.txt
+++ b/Documentation/git-sh-i18n--envsubst.txt
@@ -25,7 +25,7 @@ plumbing scripts and/or are writing new ones.
'git sh-i18n{litdd}envsubst' is Git's stripped-down copy of the GNU
`envsubst(1)` program that comes with the GNU gettext package. It's
used internally by linkgit:git-sh-i18n[1] to interpolate the variables
-passed to the the `eval_gettext` function.
+passed to the `eval_gettext` function.
No promises are made about the interface, or that this
program won't disappear without warning in the next version
diff --git a/Documentation/git-shortlog.txt b/Documentation/git-shortlog.txt
index ff3755b4c7..01d8417316 100644
--- a/Documentation/git-shortlog.txt
+++ b/Documentation/git-shortlog.txt
@@ -47,7 +47,7 @@ OPTIONS
--format[=<format>]::
Instead of the commit subject, use some other information to
describe each commit. '<format>' can be any string accepted
- by the `--format` option of 'git log', such as '{asterisk} [%h] %s'.
+ by the `--format` option of 'git log', such as '* [%h] %s'.
(See the "PRETTY FORMATS" section of linkgit:git-log[1].)
Each pretty-printed commit will be rewrapped before it is shown.
diff --git a/Documentation/git-show-ref.txt b/Documentation/git-show-ref.txt
index fcee0008a9..5dbcd47fec 100644
--- a/Documentation/git-show-ref.txt
+++ b/Documentation/git-show-ref.txt
@@ -73,7 +73,7 @@ OPTIONS
--exclude-existing[=<pattern>]::
Make 'git show-ref' act as a filter that reads refs from stdin of the
- form "`{caret}(?:<anything>\s)?<refname>(?:{backslash}{caret}{})?$`"
+ form "`^(?:<anything>\s)?<refname>(?:\^{})?$`"
and performs the following actions on each:
(1) strip "{caret}{}" at the end of line if any;
(2) ignore if pattern is provided and does not head-match refname;
diff --git a/Documentation/git-show.txt b/Documentation/git-show.txt
index 1e38819e67..ae4edcccfb 100644
--- a/Documentation/git-show.txt
+++ b/Documentation/git-show.txt
@@ -52,10 +52,10 @@ EXAMPLES
Shows the tag `v1.0.0`, along with the object the tags
points at.
-`git show v1.0.0^\{tree\}`::
+`git show v1.0.0^{tree}`::
Shows the tree pointed to by the tag `v1.0.0`.
-`git show -s --format=%s v1.0.0^\{commit\}`::
+`git show -s --format=%s v1.0.0^{commit}`::
Shows the subject of the commit pointed to by the
tag `v1.0.0`.
diff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt
index 43af38aa4b..0aa4e20eae 100644
--- a/Documentation/git-stash.txt
+++ b/Documentation/git-stash.txt
@@ -36,8 +36,8 @@ you create one.
The latest stash you created is stored in `refs/stash`; older
stashes are found in the reflog of this reference and can be named using
-the usual reflog syntax (e.g. `stash@\{0}` is the most recently
-created stash, `stash@\{1}` is the one before it, `stash@\{2.hours.ago}`
+the usual reflog syntax (e.g. `stash@{0}` is the most recently
+created stash, `stash@{1}` is the one before it, `stash@{2.hours.ago}`
is also possible).
OPTIONS
@@ -66,7 +66,7 @@ constructed such that its index state is the same as the index state
of your repository, and its worktree contains only the changes you
selected interactively. The selected changes are then rolled back
from your worktree. See the ``Interactive Mode'' section of
-linkgit:git-add[1] to learn how to operate the `\--patch` mode.
+linkgit:git-add[1] to learn how to operate the `--patch` mode.
+
The `--patch` option implies `--keep-index`. You can use
`--no-keep-index` to override this.
@@ -74,7 +74,7 @@ The `--patch` option implies `--keep-index`. You can use
list [<options>]::
List the stashes that you currently have. Each 'stash' is listed
- with its name (e.g. `stash@\{0}` is the latest stash, `stash@\{1}` is
+ with its name (e.g. `stash@{0}` is the latest stash, `stash@{1}` is
the one before, etc.), the name of the branch that was current when the
stash was made, and a short description of the commit the stash was
based on.
@@ -93,7 +93,7 @@ show [<stash>]::
stashed state and its original parent. When no `<stash>` is given,
shows the latest one. By default, the command shows the diffstat, but
it will accept any format known to 'git diff' (e.g., `git stash show
- -p stash@\{1}` to view the second most recent stash in patch form).
+ -p stash@{1}` to view the second most recent stash in patch form).
pop [--index] [-q|--quiet] [<stash>]::
@@ -111,8 +111,8 @@ tree's changes, but also the index's ones. However, this can fail, when you
have conflicts (which are stored in the index, where you therefore can no
longer apply the changes as they were originally).
+
-When no `<stash>` is given, `stash@\{0}` is assumed, otherwise `<stash>` must
-be a reference of the form `stash@\{<revision>}`.
+When no `<stash>` is given, `stash@{0}` is assumed, otherwise `<stash>` must
+be a reference of the form `stash@{<revision>}`.
apply [--index] [-q|--quiet] [<stash>]::
@@ -143,9 +143,9 @@ clear::
drop [-q|--quiet] [<stash>]::
Remove a single stashed state from the stash list. When no `<stash>`
- is given, it removes the latest one. i.e. `stash@\{0}`, otherwise
+ is given, it removes the latest one. i.e. `stash@{0}`, otherwise
`<stash>` must a valid stash log reference of the form
- `stash@\{<revision>}`.
+ `stash@{<revision>}`.
create::
diff --git a/Documentation/git-status.txt b/Documentation/git-status.txt
index 3d51717bbe..277e1e2ca3 100644
--- a/Documentation/git-status.txt
+++ b/Documentation/git-status.txt
@@ -98,12 +98,12 @@ In the short-format, the status of each path is shown as
XY PATH1 -> PATH2
-where `PATH1` is the path in the `HEAD`, and the ` \-> PATH2` part is
+where `PATH1` is the path in the `HEAD`, and the " `-> PATH2`" part is
shown only when `PATH1` corresponds to a different path in the
index/worktree (i.e. the file is renamed). The 'XY' is a two-letter
status code.
-The fields (including the `\->`) are separated from each other by a
+The fields (including the `->`) are separated from each other by a
single space. If a filename contains whitespace or other nonprintable
characters, that field will be quoted in the manner of a C string
literal: surrounded by ASCII double quote (34) characters, and with
@@ -177,7 +177,7 @@ order is reversed (e.g 'from \-> to' becomes 'to from'). Second, a NUL
and the terminating newline (but a space still separates the status
field from the first filename). Third, filenames containing special
characters are not specially formatted; no quoting or
-backslash-escaping is performed. Fourth, there is no branch line.
+backslash-escaping is performed.
CONFIGURATION
-------------
diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
index b72964947a..9e488c0aad 100644
--- a/Documentation/git-submodule.txt
+++ b/Documentation/git-submodule.txt
@@ -43,9 +43,9 @@ if you choose to go that route.
Submodules are composed from a so-called `gitlink` tree entry
in the main repository that refers to a particular commit object
within the inner repository that is completely separate.
-A record in the `.gitmodules` file at the root of the source
-tree assigns a logical name to the submodule and describes
-the default URL the submodule shall be cloned from.
+A record in the `.gitmodules` (see linkgit:gitmodules[5]) file at the
+root of the source tree assigns a logical name to the submodule and
+describes the default URL the submodule shall be cloned from.
The logical name can be used for overriding this URL within your
local repository configuration (see 'submodule init').
@@ -140,7 +140,8 @@ update::
checkout the commit specified in the index of the containing repository.
This will make the submodules HEAD be detached unless `--rebase` or
`--merge` is specified or the key `submodule.$name.update` is set to
- `rebase`, `merge` or `none`.
+ `rebase`, `merge` or `none`. `none` can be overriden by specifying
+ `--checkout`.
+
If the submodule is not yet initialized, and you just want to use the
setting as stored in .gitmodules, you can automatically initialize the
@@ -148,10 +149,6 @@ submodule with the `--init` option.
+
If `--recursive` is specified, this command will recurse into the
registered submodules, and update any nested submodules within.
-+
-If the configuration key `submodule.$name.update` is set to `none` the
-submodule with name `$name` will not be updated by default. This can be
-overriden by adding `--checkout` to the command.
summary::
Show commit summary between the given commit (defaults to HEAD) and
@@ -190,7 +187,7 @@ commit for each submodule.
sync::
Synchronizes submodules' remote URL configuration setting
to the value specified in .gitmodules. It will only affect those
- submodules which already have an url entry in .git/config (that is the
+ submodules which already have a URL entry in .git/config (that is the
case when they are initialized or freshly added). This is useful when
submodule URLs change upstream and you need to update your local
repositories accordingly.
diff --git a/Documentation/git-symbolic-ref.txt b/Documentation/git-symbolic-ref.txt
index a45d4c4f29..981d3a8fc1 100644
--- a/Documentation/git-symbolic-ref.txt
+++ b/Documentation/git-symbolic-ref.txt
@@ -8,7 +8,8 @@ git-symbolic-ref - Read and modify symbolic refs
SYNOPSIS
--------
[verse]
-'git symbolic-ref' [-q] [-m <reason>] <name> [<ref>]
+'git symbolic-ref' [-m <reason>] <name> <ref>
+'git symbolic-ref' [-q] [--short] <name>
DESCRIPTION
-----------
@@ -33,6 +34,10 @@ OPTIONS
symbolic ref but a detached HEAD; instead exit with
non-zero status silently.
+--short::
+ When showing the value of <name> as a symbolic ref, try to shorten the
+ value, e.g. from `refs/heads/master` to `master`.
+
-m::
Update the reflog for <name> with <reason>. This is valid only
when creating or updating a symbolic ref.
diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt
index 53ff5f6cf7..8d32b9a814 100644
--- a/Documentation/git-tag.txt
+++ b/Documentation/git-tag.txt
@@ -12,7 +12,8 @@ SYNOPSIS
'git tag' [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>]
<tagname> [<commit> | <object>]
'git tag' -d <tagname>...
-'git tag' [-n[<num>]] -l [--contains <commit>] [<pattern>...]
+'git tag' [-n[<num>]] -l [--contains <commit>] [--points-at <object>]
+ [<pattern>...]
'git tag' -v <tagname>...
DESCRIPTION
@@ -86,6 +87,9 @@ OPTIONS
--contains <commit>::
Only list tags which contain the specified commit.
+--points-at <object>::
+ Only list tags of the given object.
+
-m <msg>::
--message=<msg>::
Use the given tag message (instead of prompting).
diff --git a/Documentation/git-tar-tree.txt b/Documentation/git-tar-tree.txt
index 346e7a2079..f7362dc2d1 100644
--- a/Documentation/git-tar-tree.txt
+++ b/Documentation/git-tar-tree.txt
@@ -63,7 +63,7 @@ EXAMPLES
Create a tarball for v1.4.0 release.
-`git tar-tree v1.4.0{caret}\{tree\} git-1.4.0 | gzip >git-1.4.0.tar.gz`::
+`git tar-tree v1.4.0^{tree} git-1.4.0 | gzip >git-1.4.0.tar.gz`::
Create a tarball for v1.4.0 release, but without a
global extended pax header.
diff --git a/Documentation/git-whatchanged.txt b/Documentation/git-whatchanged.txt
index 76c7f7eec5..6c8f510c3f 100644
--- a/Documentation/git-whatchanged.txt
+++ b/Documentation/git-whatchanged.txt
@@ -58,7 +58,7 @@ Examples
Show as patches the commits since version 'v2.6.12' that changed
any file in the include/scsi or drivers/scsi subdirectories
-`git whatchanged --since="2 weeks ago" \-- gitk`::
+`git whatchanged --since="2 weeks ago" -- gitk`::
Show the changes during the last two weeks to the file 'gitk'.
The "--" is necessary to avoid confusion with the *branch* named
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 8f3167587d..c543213126 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -44,6 +44,13 @@ unreleased) version of git, that is available from 'master'
branch of the `git.git` repository.
Documentation for older releases are available here:
+* link:v1.7.10.2/git.html[documentation for release 1.7.10.2]
+
+* release notes for
+ link:RelNotes/1.7.10.2.txt[1.7.10.2],
+ link:RelNotes/1.7.10.1.txt[1.7.10.1],
+ link:RelNotes/1.7.10.txt[1.7.10].
+
* link:v1.7.9.7/git.html[documentation for release 1.7.9.7]
* release notes for
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index a85b187e04..80120ea14f 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -294,16 +294,27 @@ output is used to update the worktree file. Similarly, the
`clean` command is used to convert the contents of worktree file
upon checkin.
-A missing filter driver definition in the config is not an error
-but makes the filter a no-op passthru.
-
-The content filtering is done to massage the content into a
-shape that is more convenient for the platform, filesystem, and
-the user to use. The key phrase here is "more convenient" and not
-"turning something unusable into usable". In other words, the
-intent is that if someone unsets the filter driver definition,
-or does not have the appropriate filter program, the project
-should still be usable.
+One use of the content filtering is to massage the content into a shape
+that is more convenient for the platform, filesystem, and the user to use.
+For this mode of operation, the key phrase here is "more convenient" and
+not "turning something unusable into usable". In other words, the intent
+is that if someone unsets the filter driver definition, or does not have
+the appropriate filter program, the project should still be usable.
+
+Another use of the content filtering is to store the content that cannot
+be directly used in the repository (e.g. a UUID that refers to the true
+content stored outside git, or an encrypted content) and turn it into a
+usable form upon checkout (e.g. download the external content, or decrypt
+the encrypted content).
+
+These two filters behave differently, and by default, a filter is taken as
+the former, massaging the contents into more convenient shape. A missing
+filter driver definition in the config, or a filter driver that exits with
+a non-zero status, is not an error but makes the filter a no-op passthru.
+
+You can declare that a filter turns a content that by itself is unusable
+into a usable content by setting the filter.<driver>.required configuration
+variable to `true`.
For example, in .gitattributes, you would assign the `filter`
attribute for paths.
@@ -335,6 +346,16 @@ input that is already correctly indented. In this case, the lack of a
smudge filter means that the clean filter _must_ accept its own output
without modifying it.
+If a filter _must_ succeed in order to make the stored contents usable,
+you can declare that the filter is `required`, in the configuration:
+
+------------------------
+[filter "crypt"]
+ clean = openssl enc ...
+ smudge = openssl enc -d ...
+ required
+------------------------
+
Sequence "%f" on the filter command line is replaced with the name of
the file the filter is working on. A filter might use this in keyword
substitution. For example:
diff --git a/Documentation/gitcli.txt b/Documentation/gitcli.txt
index f734f97b8e..ea17f7a53b 100644
--- a/Documentation/gitcli.txt
+++ b/Documentation/gitcli.txt
@@ -25,22 +25,22 @@ arguments. Here are the rules:
are paths.
* When an argument can be misunderstood as either a revision or a path,
- they can be disambiguated by placing `\--` between them.
- E.g. `git diff \-- HEAD` is, "I have a file called HEAD in my work
+ they can be disambiguated by placing `--` between them.
+ E.g. `git diff -- HEAD` is, "I have a file called HEAD in my work
tree. Please show changes between the version I staged in the index
and what I have in the work tree for that file". not "show difference
between the HEAD commit and the work tree as a whole". You can say
- `git diff HEAD \--` to ask for the latter.
+ `git diff HEAD --` to ask for the latter.
- * Without disambiguating `\--`, git makes a reasonable guess, but errors
+ * Without disambiguating `--`, git makes a reasonable guess, but errors
out and asking you to disambiguate when ambiguous. E.g. if you have a
file called HEAD in your work tree, `git diff HEAD` is ambiguous, and
- you have to say either `git diff HEAD \--` or `git diff \-- HEAD` to
+ you have to say either `git diff HEAD --` or `git diff -- HEAD` to
disambiguate.
When writing a script that is expected to handle random user-input, it is
a good practice to make it explicit which arguments are which by placing
-disambiguating `\--` at appropriate places.
+disambiguating `--` at appropriate places.
Here are the rules regarding the "flags" that you should follow when you are
scripting git:
diff --git a/Documentation/gitcore-tutorial.txt b/Documentation/gitcore-tutorial.txt
index fb0d5692a4..f5074a8976 100644
--- a/Documentation/gitcore-tutorial.txt
+++ b/Documentation/gitcore-tutorial.txt
@@ -151,8 +151,8 @@ to your working tree, you use the 'git update-index' program. That
program normally just takes a list of filenames you want to update, but
to avoid trivial mistakes, it refuses to add new entries to the index
(or remove existing ones) unless you explicitly tell it that you're
-adding a new entry with the `\--add` flag (or removing an entry with the
-`\--remove`) flag.
+adding a new entry with the `--add` flag (or removing an entry with the
+`--remove`) flag.
So to populate the index with the two files you just created, you can do
@@ -399,10 +399,10 @@ $ git diff HEAD
which ends up doing the above for you.
In other words, 'git diff-index' normally compares a tree against the
-working tree, but when given the `\--cached` flag, it is told to
+working tree, but when given the `--cached` flag, it is told to
instead compare against just the index cache contents, and ignore the
current working tree state entirely. Since we just wrote the index
-file to HEAD, doing `git diff-index \--cached -p HEAD` should thus return
+file to HEAD, doing `git diff-index --cached -p HEAD` should thus return
an empty set of differences, and that's exactly what it does.
[NOTE]
@@ -411,7 +411,7 @@ an empty set of differences, and that's exactly what it does.
comparisons, and saying that it compares a tree against the working
tree is thus not strictly accurate. In particular, the list of
files to compare (the "meta-data") *always* comes from the index file,
-regardless of whether the `\--cached` flag is used or not. The `\--cached`
+regardless of whether the `--cached` flag is used or not. The `--cached`
flag really only determines whether the file *contents* to be compared
come from the working tree or not.
@@ -433,7 +433,7 @@ update the index cache:
$ git update-index hello
------------------------------------------------
-(note how we didn't need the `\--add` flag this time, since git knew
+(note how we didn't need the `--add` flag this time, since git knew
about the file already).
Note what happens to the different 'git diff-{asterisk}' versions here.
@@ -560,7 +560,7 @@ short history.
When using the above two commands, the initial commit will be shown.
If this is a problem because it is huge, you can hide it by setting
the log.showroot configuration variable to false. Having this, you
-can still show it for each command just adding the `\--root` option,
+can still show it for each command just adding the `--root` option,
which is a flag for 'git diff-tree' accepted by both commands.
With that, you should now be having some inkling of what git does, and
@@ -881,7 +881,7 @@ helps you view what's going on:
$ gitk --all
----------------
-will show you graphically both of your branches (that's what the `\--all`
+will show you graphically both of your branches (that's what the `--all`
means: normally it will just show you your current `HEAD`) and their
histories. You can also see exactly how they came to be from a common
source.
@@ -935,7 +935,7 @@ which will very loudly warn you that you're now committing a merge
(which is correct, so never mind), and you can write a small merge
message about your adventures in 'git merge'-land.
-After you're done, start up `gitk \--all` to see graphically what the
+After you're done, start up `gitk --all` to see graphically what the
history looks like. Notice that `mybranch` still exists, and you can
switch to it, and continue to work with it if you want to. The
`mybranch` branch will not contain the merge, but next time you merge it
@@ -958,11 +958,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 `{asterisk}` character), and the first column for
+(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.
-All of them have non blank characters in the first column (`{asterisk}`
+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
work" commit has the plus `+` character in the second column,
@@ -1013,7 +1013,7 @@ not actually do a merge. Instead, it just updated the top of
the tree of your branch to that of the `master` branch. This is
often called 'fast-forward' merge.
-You can run `gitk \--all` again to see how the commit ancestry
+You can run `gitk --all` again to see how the commit ancestry
looks like, or run 'show-branch', which tells you this.
------------------------------------------------
@@ -1257,7 +1257,7 @@ this 'collapsing' tends to trivially merge most of the paths
fairly quickly, leaving only a handful of real changes in non-zero
stages.
-To look at only non-zero stages, use `\--unmerged` flag:
+To look at only non-zero stages, use `--unmerged` flag:
------------
$ git ls-files --unmerged
@@ -1420,7 +1420,7 @@ packed, and stores the packed file in `.git/objects/pack`
directory.
[NOTE]
-You will see two files, `pack-{asterisk}.pack` and `pack-{asterisk}.idx`,
+You will see two files, `pack-*.pack` and `pack-*.idx`,
in `.git/objects/pack` directory. They are closely related to
each other, and if you ever copy them by hand to a different
repository for whatever reason, you should make sure you copy
diff --git a/Documentation/gitcredentials.txt b/Documentation/gitcredentials.txt
index 066f825f2e..7dfffc0046 100644
--- a/Documentation/gitcredentials.txt
+++ b/Documentation/gitcredentials.txt
@@ -143,8 +143,8 @@ CONFIGURATION OPTIONS
---------------------
Options for a credential context can be configured either in
-`credential.\*` (which applies to all credentials), or
-`credential.<url>.\*`, where <url> matches the context as described
+`credential.*` (which applies to all credentials), or
+`credential.<url>.*`, where <url> matches the context as described
above.
The following options are available in either location:
diff --git a/Documentation/gitdiffcore.txt b/Documentation/gitdiffcore.txt
index 370624c171..daf1782a31 100644
--- a/Documentation/gitdiffcore.txt
+++ b/Documentation/gitdiffcore.txt
@@ -168,11 +168,11 @@ a similarity score different from the default of 50% by giving a
number after the "-M" or "-C" option (e.g. "-M8" to tell it to use
8/10 = 80%).
-Note. When the "-C" option is used with `\--find-copies-harder`
+Note. When the "-C" option is used with `--find-copies-harder`
option, 'git diff-{asterisk}' commands feed unmodified filepairs to
diffcore mechanism as well as modified ones. This lets the copy
detector consider unmodified files as copy source candidates at
-the expense of making it slower. Without `\--find-copies-harder`,
+the expense of making it slower. Without `--find-copies-harder`,
'git diff-{asterisk}' commands can detect copies only if the file that was
copied happened to have been modified in the same changeset.
@@ -224,7 +224,7 @@ diffcore-pickaxe: For Detecting Addition/Deletion of Specified String
This transformation is used to find filepairs that represent
changes that touch a specified string, and is controlled by the
--S option and the `\--pickaxe-all` option to the 'git diff-{asterisk}'
+-S option and the `--pickaxe-all` option to the 'git diff-*'
commands.
When diffcore-pickaxe is in use, it checks if there are
@@ -233,9 +233,9 @@ different number of specified string. Such a filepair represents
"the string appeared in this changeset". It also checks for the
opposite case that loses the specified string.
-When `\--pickaxe-all` is not in effect, diffcore-pickaxe leaves
+When `--pickaxe-all` is not in effect, diffcore-pickaxe leaves
only such filepairs that touch the specified string in its
-output. When `\--pickaxe-all` is used, diffcore-pickaxe leaves all
+output. When `--pickaxe-all` is used, diffcore-pickaxe leaves all
filepairs intact if there is such a filepair, or makes the
output empty otherwise. The latter behaviour is designed to
make reviewing of the changes in the context of the whole
diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt
index 28edefa202..b9003fed24 100644
--- a/Documentation/githooks.txt
+++ b/Documentation/githooks.txt
@@ -73,7 +73,7 @@ pre-commit
~~~~~~~~~~
This hook is invoked by 'git commit', and can be bypassed
-with `\--no-verify` option. It takes no parameter, and is
+with `--no-verify` option. It takes no parameter, and is
invoked before obtaining the proposed commit log message and
making a commit. Exiting with non-zero status from this script
causes the 'git commit' to abort.
@@ -99,12 +99,12 @@ given); `template` (if a `-t` option was given or the
configuration option `commit.template` is set); `merge` (if the
commit is a merge or a `.git/MERGE_MSG` file exists); `squash`
(if a `.git/SQUASH_MSG` file exists); or `commit`, followed by
-a commit SHA1 (if a `-c`, `-C` or `\--amend` option was given).
+a commit SHA1 (if a `-c`, `-C` or `--amend` option was given).
If the exit status is non-zero, 'git commit' will abort.
The purpose of the hook is to edit the message file in place, and
-it is not suppressed by the `\--no-verify` option. A non-zero exit
+it is not suppressed by the `--no-verify` option. A non-zero exit
means a failure of the hook and aborts the commit. It should not
be used as replacement for pre-commit hook.
@@ -115,7 +115,7 @@ commit-msg
~~~~~~~~~~
This hook is invoked by 'git commit', and can be bypassed
-with `\--no-verify` option. It takes a single parameter, the
+with `--no-verify` option. It takes a single parameter, the
name of the file that holds the proposed commit log message.
Exiting with non-zero status causes the 'git commit' to
abort.
diff --git a/Documentation/gitmodules.txt b/Documentation/gitmodules.txt
index 4040941e55..4effd78902 100644
--- a/Documentation/gitmodules.txt
+++ b/Documentation/gitmodules.txt
@@ -28,7 +28,7 @@ submodule.<name>.path::
be unique within the .gitmodules file.
submodule.<name>.url::
- Defines an url from where the submodule repository can be cloned.
+ Defines a URL from which the submodule repository can be cloned.
This may be either an absolute URL ready to be passed to
linkgit:git-clone[1] or (if it begins with ./ or ../) a location
relative to the superproject's origin repository.
@@ -41,8 +41,11 @@ submodule.<name>.update::
the commit specified in the superproject. If 'merge', the commit
specified in the superproject will be merged into the current branch
in the submodule.
+ If 'none', the submodule with name `$name` will not be updated
+ by default.
+
This config option is overridden if 'git submodule update' is given
- the '--merge' or '--rebase' options.
+ the '--merge', '--rebase' or '--checkout' options.
submodule.<name>.fetchRecurseSubmodules::
This option can be used to control recursive fetching of this
@@ -84,7 +87,7 @@ Consider the following .gitmodules file:
This defines two submodules, `libfoo` and `libbar`. These are expected to
be checked out in the paths 'include/foo' and 'include/bar', and for both
-submodules an url is specified which can be used for cloning the submodules.
+submodules a URL is specified which can be used for cloning the submodules.
SEE ALSO
--------
diff --git a/Documentation/gitweb.conf.txt b/Documentation/gitweb.conf.txt
index 7aba497b74..1cea8cb65e 100644
--- a/Documentation/gitweb.conf.txt
+++ b/Documentation/gitweb.conf.txt
@@ -749,14 +749,14 @@ Project specific override is not supported.
forks::
If this feature is enabled, gitweb considers projects in
subdirectories of project root (basename) to be forks of existing
- projects. For each project `$projname.git`, projects in the
- `$projname/` directory and its subdirectories will not be
- shown in the main projects list. Instead, a \'+' mark is shown
- next to `$projname`, which links to a "forks" view that lists all
- the forks (all projects in `$projname/` subdirectory). Additionally
+ projects. For each project +$projname.git+, projects in the
+ +$projname/+ directory and its subdirectories will not be
+ shown in the main projects list. Instead, a \'\+' mark is shown
+ next to +$projname+, which links to a "forks" view that lists all
+ the forks (all projects in +$projname/+ subdirectory). Additionally
a "forks" view for a project is linked from project summary page.
+
-If the project list is taken from a file (`$projects_list` points to a
+If the project list is taken from a file (+$projects_list+ points to a
file), forks are only recognized if they are listed after the main project
in that file.
+
diff --git a/Documentation/gitworkflows.txt b/Documentation/gitworkflows.txt
index 5e4f362ff8..8b8c6ae5d3 100644
--- a/Documentation/gitworkflows.txt
+++ b/Documentation/gitworkflows.txt
@@ -39,8 +39,8 @@ To achieve this, try to split your work into small steps from the very
beginning. It is always easier to squash a few commits together than
to split one big commit into several. Don't be afraid of making too
small or imperfect steps along the way. You can always go back later
-and edit the commits with `git rebase \--interactive` before you
-publish them. You can use `git stash save \--keep-index` to run the
+and edit the commits with `git rebase --interactive` before you
+publish them. You can use `git stash save --keep-index` to run the
test suite independent of other uncommitted changes; see the EXAMPLES
section of linkgit:git-stash[1].
diff --git a/Documentation/howto/using-merge-subtree.txt b/Documentation/howto/using-merge-subtree.txt
index 2933056120..1ae8d1214e 100644
--- a/Documentation/howto/using-merge-subtree.txt
+++ b/Documentation/howto/using-merge-subtree.txt
@@ -25,7 +25,7 @@ What you want is the 'subtree' merge strategy, which helps you in such a
situation.
In this example, let's say you have the repository at `/path/to/B` (but
-it can be an URL as well, if you want). You want to merge the 'master'
+it can be a URL as well, if you want). You want to merge the 'master'
branch of that repository to the `dir-B` subdirectory in your current
branch.
diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt
index 5afc99f650..0bcbe0ac3c 100644
--- a/Documentation/merge-options.txt
+++ b/Documentation/merge-options.txt
@@ -9,18 +9,19 @@ inspect and further tweak the merge result before committing.
--edit::
--no-edit::
- Invoke editor before committing successful merge to further
- edit the default merge message. The `--no-edit` option can be
+ Invoke an editor before committing successful mechanical merge to
+ further edit the auto-generated merge message, so that the user
+ can explain and justify the merge. The `--no-edit` option can be
used to accept the auto-generated message (this is generally
- discouraged) when merging an annotated tag, in which case
- `git merge` automatically spawns the editor so that the result
- of the GPG verification of the tag can be seen.
+ discouraged). The `--edit` option is still useful if you are
+ giving a draft message with the `-m` option from the command line
+ and want to edit it in the editor.
+
Older scripts may depend on the historical behaviour of not allowing the
user to edit the merge log message. They will see an editor opened when
-they run `git merge` to merge an annotated tag. To make it easier to adjust
-such scripts to the updated behaviour, the environment variable
-`GIT_MERGE_AUTOEDIT` can be set to `no` at the beginning of them.
+they run `git merge`. To make it easier to adjust such scripts to the
+updated behaviour, the environment variable `GIT_MERGE_AUTOEDIT` can be
+set to `no` at the beginning of them.
--ff::
When the merge resolves as a fast-forward, only update the branch
diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
index 880b6f2e6f..e3d8a83b23 100644
--- a/Documentation/pretty-formats.txt
+++ b/Documentation/pretty-formats.txt
@@ -130,8 +130,8 @@ The placeholders are:
- '%b': body
- '%B': raw body (unwrapped subject and body)
- '%N': commit notes
-- '%gD': reflog selector, e.g., `refs/stash@\{1\}`
-- '%gd': shortened reflog selector, e.g., `stash@\{1\}`
+- '%gD': reflog selector, e.g., `refs/stash@{1}`
+- '%gd': shortened reflog selector, e.g., `stash@{1}`
- '%gn': reflog identity name
- '%gN': reflog identity name (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1])
- '%ge': reflog identity email
@@ -155,7 +155,7 @@ insert an empty string unless we are traversing reflog entries (e.g., by
`git log -g`). The `%d` placeholder will use the "short" decoration
format if `--decorate` was not already provided on the command line.
-If you add a `{plus}` (plus sign) after '%' of a placeholder, a line-feed
+If you add a `+` (plus sign) after '%' of a placeholder, a line-feed
is inserted immediately before the expansion if and only if the
placeholder expands to a non-empty string.
diff --git a/Documentation/pull-fetch-param.txt b/Documentation/pull-fetch-param.txt
index 5dd6e5a0c7..94a9d32f1d 100644
--- a/Documentation/pull-fetch-param.txt
+++ b/Documentation/pull-fetch-param.txt
@@ -13,7 +13,7 @@ endif::git-pull[]
<refspec>::
The format of a <refspec> parameter is an optional plus
- `{plus}`, followed by the source ref <src>, followed
+ `+`, followed by the source ref <src>, followed
by a colon `:`, followed by the destination ref <dst>.
+
The remote ref that matches <src>
diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt
index 6a4b6355ba..1ae3c899ef 100644
--- a/Documentation/rev-list-options.txt
+++ b/Documentation/rev-list-options.txt
@@ -198,7 +198,7 @@ excluded from the output.
+
For example, `--cherry-pick --right-only A...B` omits those
commits from `B` which are in `A` or are patch-equivalent to a commit in
-`A`. In other words, this lists the `{plus}` commits from `git cherry A B`.
+`A`. In other words, this lists the `+` commits from `git cherry A B`.
More precisely, `--cherry-pick --right-only --no-merges` gives the exact
list.
@@ -455,7 +455,7 @@ The effect of this is best shown by way of comparing to
`---------'
-----------------------------------------------------------------------
+
-Note the major differences in `N` and `P` over '\--full-history':
+Note the major differences in `N` and `P` over '--full-history':
+
--
* `N`'s parent list had `I` removed, because it is an ancestor of the
@@ -494,7 +494,7 @@ of course).
When we want to find out what commits in `M` are contaminated with the
bug introduced by `D` and need fixing, however, we might want to view
only the subset of 'D..M' that are actually descendants of `D`, i.e.
-excluding `C` and `K`. This is exactly what the '\--ancestry-path'
+excluding `C` and `K`. This is exactly what the '--ancestry-path'
option does. Applied to the 'D..M' range, it results in:
+
-----------------------------------------------------------------------
diff --git a/Documentation/technical/api-argv-array.txt b/Documentation/technical/api-argv-array.txt
index 49b3d52952..1b7d8f140c 100644
--- a/Documentation/technical/api-argv-array.txt
+++ b/Documentation/technical/api-argv-array.txt
@@ -37,6 +37,11 @@ Functions
`argv_array_push`::
Push a copy of a string onto the end of the array.
+`argv_array_pushl`::
+ Push a list of strings onto the end of the array. The arguments
+ should be a list of `const char *` strings, terminated by a NULL
+ argument.
+
`argv_array_pushf`::
Format a string and push it onto the end of the array. This is a
convenience wrapper combining `strbuf_addf` and `argv_array_push`.
diff --git a/Documentation/technical/api-config.txt b/Documentation/technical/api-config.txt
new file mode 100644
index 0000000000..edf8dfb99b
--- /dev/null
+++ b/Documentation/technical/api-config.txt
@@ -0,0 +1,140 @@
+config API
+==========
+
+The config API gives callers a way to access git configuration files
+(and files which have the same syntax). See linkgit:git-config[1] for a
+discussion of the config file syntax.
+
+General Usage
+-------------
+
+Config files are parsed linearly, and each variable found is passed to a
+caller-provided callback function. The callback function is responsible
+for any actions to be taken on the config option, and is free to ignore
+some options. It is not uncommon for the configuration to be parsed
+several times during the run of a git program, with different callbacks
+picking out different variables useful to themselves.
+
+A config callback function takes three parameters:
+
+- the name of the parsed variable. This is in canonical "flat" form: the
+ section, subsection, and variable segments will be separated by dots,
+ and the section and variable segments will be all lowercase. E.g.,
+ `core.ignorecase`, `diff.SomeType.textconv`.
+
+- the value of the found variable, as a string. If the variable had no
+ value specified, the value will be NULL (typically this means it
+ should be interpreted as boolean true).
+
+- a void pointer passed in by the caller of the config API; this can
+ contain callback-specific data
+
+A config callback should return 0 for success, or -1 if the variable
+could not be parsed properly.
+
+Basic Config Querying
+---------------------
+
+Most programs will simply want to look up variables in all config files
+that git knows about, using the normal precedence rules. To do this,
+call `git_config` with a callback function and void data pointer.
+
+`git_config` will read all config sources in order of increasing
+priority. Thus a callback should typically overwrite previously-seen
+entries with new ones (e.g., if both the user-wide `~/.gitconfig` and
+repo-specific `.git/config` contain `color.ui`, the config machinery
+will first feed the user-wide one to the callback, and then the
+repo-specific one; by overwriting, the higher-priority repo-specific
+value is left at the end).
+
+The `git_config_with_options` function lets the caller examine config
+while adjusting some of the default behavior of `git_config`. It should
+almost never be used by "regular" git code that is looking up
+configuration variables. It is intended for advanced callers like
+`git-config`, which are intentionally tweaking the normal config-lookup
+process. It takes two extra parameters:
+
+`filename`::
+If this parameter is non-NULL, it specifies the name of a file to
+parse for configuration, rather than looking in the usual files. Regular
+`git_config` defaults to `NULL`.
+
+`respect_includes`::
+Specify whether include directives should be followed in parsed files.
+Regular `git_config` defaults to `1`.
+
+There is a special version of `git_config` called `git_config_early`.
+This version takes an additional parameter to specify the repository
+config, instead of having it looked up via `git_path`. This is useful
+early in a git program before the repository has been found. Unless
+you're working with early setup code, you probably don't want to use
+this.
+
+Reading Specific Files
+----------------------
+
+To read a specific file in git-config format, use
+`git_config_from_file`. This takes the same callback and data parameters
+as `git_config`.
+
+Value Parsing Helpers
+---------------------
+
+To aid in parsing string values, the config API provides callbacks with
+a number of helper functions, including:
+
+`git_config_int`::
+Parse the string to an integer, including unit factors. Dies on error;
+otherwise, returns the parsed result.
+
+`git_config_ulong`::
+Identical to `git_config_int`, but for unsigned longs.
+
+`git_config_bool`::
+Parse a string into a boolean value, respecting keywords like "true" and
+"false". Integer values are converted into true/false values (when they
+are non-zero or zero, respectively). Other values cause a die(). If
+parsing is successful, the return value is the result.
+
+`git_config_bool_or_int`::
+Same as `git_config_bool`, except that integers are returned as-is, and
+an `is_bool` flag is unset.
+
+`git_config_maybe_bool`::
+Same as `git_config_bool`, except that it returns -1 on error rather
+than dying.
+
+`git_config_string`::
+Allocates and copies the value string into the `dest` parameter; if no
+string is given, prints an error message and returns -1.
+
+`git_config_pathname`::
+Similar to `git_config_string`, but expands `~` or `~user` into the
+user's home directory when found at the beginning of the path.
+
+Include Directives
+------------------
+
+By default, the config parser does not respect include directives.
+However, a caller can use the special `git_config_include` wrapper
+callback to support them. To do so, you simply wrap your "real" callback
+function and data pointer in a `struct config_include_data`, and pass
+the wrapper to the regular config-reading functions. For example:
+
+-------------------------------------------
+int read_file_with_include(const char *file, config_fn_t fn, void *data)
+{
+ struct config_include_data inc = CONFIG_INCLUDE_INIT;
+ inc.fn = fn;
+ inc.data = data;
+ return git_config_from_file(git_config_include, file, &inc);
+}
+-------------------------------------------
+
+`git_config` respects includes automatically. The lower-level
+`git_config_from_file` does not.
+
+Writing Config Files
+--------------------
+
+TODO
diff --git a/Documentation/technical/api-parse-options.txt b/Documentation/technical/api-parse-options.txt
index 4b92514f60..3062389404 100644
--- a/Documentation/technical/api-parse-options.txt
+++ b/Documentation/technical/api-parse-options.txt
@@ -21,7 +21,7 @@ that allow to change the behavior of a command.
* There are basically two forms of options:
'Short options' consist of one dash (`-`) and one alphanumeric
character.
- 'Long options' begin with two dashes (`\--`) and some
+ 'Long options' begin with two dashes (`--`) and some
alphanumeric characters.
* Options are case-sensitive.
@@ -31,7 +31,7 @@ The parse-options API allows:
* 'sticked' and 'separate form' of options with arguments.
`-oArg` is sticked, `-o Arg` is separate form.
- `\--option=Arg` is sticked, `\--option Arg` is separate form.
+ `--option=Arg` is sticked, `--option Arg` is separate form.
* Long options may be 'abbreviated', as long as the abbreviation
is unambiguous.
@@ -39,11 +39,12 @@ The parse-options API allows:
* Short options may be bundled, e.g. `-a -b` can be specified as `-ab`.
* Boolean long options can be 'negated' (or 'unset') by prepending
- `no-`, e.g. `\--no-abbrev` instead of `\--abbrev`.
+ `no-`, e.g. `--no-abbrev` instead of `--abbrev`. Conversely,
+ options that begin with `no-` can be 'negated' by removing it.
-* Options and non-option arguments can clearly be separated using the `\--`
- option, e.g. `-a -b \--option \-- \--this-is-a-file` indicates that
- `\--this-is-a-file` must not be processed as an option.
+* Options and non-option arguments can clearly be separated using the `--`
+ option, e.g. `-a -b --option -- --this-is-a-file` indicates that
+ `--this-is-a-file` must not be processed as an option.
Steps to parse options
----------------------
@@ -75,7 +76,7 @@ before the full parser, which in turn shows the full help message.
Flags are the bitwise-or of:
`PARSE_OPT_KEEP_DASHDASH`::
- Keep the `\--` that usually separates options from
+ Keep the `--` that usually separates options from
non-option arguments.
`PARSE_OPT_STOP_AT_NON_OPTION`::
@@ -113,22 +114,22 @@ say `static struct option builtin_add_options[]`.
There are some macros to easily define options:
`OPT__ABBREV(&int_var)`::
- Add `\--abbrev[=<n>]`.
+ Add `--abbrev[=<n>]`.
`OPT__COLOR(&int_var, description)`::
- Add `\--color[=<when>]` and `--no-color`.
+ Add `--color[=<when>]` and `--no-color`.
`OPT__DRY_RUN(&int_var, description)`::
- Add `-n, \--dry-run`.
+ Add `-n, --dry-run`.
`OPT__FORCE(&int_var, description)`::
- Add `-f, \--force`.
+ Add `-f, --force`.
`OPT__QUIET(&int_var, description)`::
- Add `-q, \--quiet`.
+ Add `-q, --quiet`.
`OPT__VERBOSE(&int_var, description)`::
- Add `-v, \--verbose`.
+ Add `-v, --verbose`.
`OPT_GROUP(description)`::
Start an option group. `description` is a short string that
@@ -215,10 +216,10 @@ The last element of the array must be `OPT_END()`.
If not stated otherwise, interpret the arguments as follows:
* `short` is a character for the short option
- (e.g. `{apostrophe}e{apostrophe}` for `-e`, use `0` to omit),
+ (e.g. `'e'` for `-e`, use `0` to omit),
* `long` is a string for the long option
- (e.g. `"example"` for `\--example`, use `NULL` to omit),
+ (e.g. `"example"` for `--example`, use `NULL` to omit),
* `int_var` is an integer variable,
@@ -242,10 +243,10 @@ The function must be defined in this form:
The callback mechanism is as follows:
* Inside `func`, the only interesting member of the structure
- given by `opt` is the void pointer `opt\->value`.
- `\*opt\->value` will be the value that is saved into `var`, if you
+ given by `opt` is the void pointer `opt->value`.
+ `*opt->value` will be the value that is saved into `var`, if you
use `OPT_CALLBACK()`.
- For example, do `*(unsigned long *)opt\->value = 42;` to get 42
+ For example, do `*(unsigned long *)opt->value = 42;` to get 42
into an `unsigned long` variable.
* Return value `0` indicates success and non-zero return
diff --git a/Documentation/technical/pack-protocol.txt b/Documentation/technical/pack-protocol.txt
index 546980c0a4..49cdc571cd 100644
--- a/Documentation/technical/pack-protocol.txt
+++ b/Documentation/technical/pack-protocol.txt
@@ -351,7 +351,7 @@ Then the server will start sending its packfile data.
A simple clone may look like this (with no 'have' lines):
----
- C: 0054want 74730d410fcb6603ace96f1dc55ea6196122532d\0multi_ack \
+ C: 0054want 74730d410fcb6603ace96f1dc55ea6196122532d multi_ack \
side-band-64k ofs-delta\n
C: 0032want 7d1665144a3a975c05f1f43902ddaf084e784dbe\n
C: 0032want 5a3f6be755bbb7deae50065988cbfa1ffa9ab68a\n
@@ -367,7 +367,7 @@ A simple clone may look like this (with no 'have' lines):
An incremental update (fetch) response might look like this:
----
- C: 0054want 74730d410fcb6603ace96f1dc55ea6196122532d\0multi_ack \
+ C: 0054want 74730d410fcb6603ace96f1dc55ea6196122532d multi_ack \
side-band-64k ofs-delta\n
C: 0032want 7d1665144a3a975c05f1f43902ddaf084e784dbe\n
C: 0032want 5a3f6be755bbb7deae50065988cbfa1ffa9ab68a\n
diff --git a/Documentation/technical/protocol-common.txt b/Documentation/technical/protocol-common.txt
index d30a1b9510..fb7ff084f8 100644
--- a/Documentation/technical/protocol-common.txt
+++ b/Documentation/technical/protocol-common.txt
@@ -36,7 +36,7 @@ More specifically, they:
. They cannot have ASCII control characters (i.e. bytes whose
values are lower than \040, or \177 `DEL`), space, tilde `~`,
- caret `{caret}`, colon `:`, question-mark `?`, asterisk `*`,
+ caret `^`, colon `:`, question-mark `?`, asterisk `*`,
or open bracket `[` anywhere.
. They cannot end with a slash `/` nor a dot `.`.
diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt
index f13a846131..1b942074b6 100644
--- a/Documentation/user-manual.txt
+++ b/Documentation/user-manual.txt
@@ -1582,7 +1582,7 @@ Checking the repository for corruption
The linkgit:git-fsck[1] command runs a number of self-consistency checks
on the repository, and reports on any problems. This may take some
-time. The most common warning by far is about "dangling" objects:
+time.
-------------------------------------------------
$ git fsck
@@ -1597,9 +1597,11 @@ dangling tree b24c2473f1fd3d91352a624795be026d64c8841f
...
-------------------------------------------------
-Dangling objects are not a problem. At worst they may take up a little
-extra disk space. They can sometimes provide a last-resort method for
-recovering lost work--see <<dangling-objects>> for details.
+You will see informational messages on dangling objects. They are objects
+that still exist in the repository but are no longer referenced by any of
+your branches, and can (and will) be removed after a while with "gc".
+You can run `git fsck --no-dangling` to supress these messages, and still
+view real errors.
[[recovering-lost-changes]]
Recovering lost changes
@@ -1609,7 +1611,7 @@ Recovering lost changes
Reflogs
^^^^^^^
-Say you modify a branch with `linkgit:git-reset[1] --hard`, and then
+Say you modify a branch with +linkgit:git-reset[1] \--hard+, and then
realize that the branch was the only reference you had to that point in
history.
@@ -3295,15 +3297,12 @@ it is with linkgit:git-fsck[1]; this may be time-consuming.
Assume the output looks like this:
------------------------------------------------
-$ git fsck --full
+$ git fsck --full --no-dangling
broken link from tree 2d9263c6d23595e7cb2a21e5ebbb53655278dff8
to blob 4b9458b3786228369c63936db65827de3cc06200
missing blob 4b9458b3786228369c63936db65827de3cc06200
------------------------------------------------
-(Typically there will be some "dangling object" messages too, but they
-aren't interesting.)
-
Now you know that blob 4b9458b3 is missing, and that the tree 2d9263c6
points to it. If you could find just one copy of that missing blob
object, possibly in some other repository, you could move it into
@@ -4208,7 +4207,7 @@ commits one by one with the function `get_revision()`.
If you are interested in more details of the revision walking process,
just have a look at the first implementation of `cmd_log()`; call
-`git show v1.3.0{tilde}155^2{tilde}4` and scroll down to that function (note that you
+`git show v1.3.0~155^2~4` and scroll down to that function (note that you
no longer need to call `setup_pager()` directly).
Nowadays, `git log` is a builtin, which means that it is _contained_ in the
@@ -4271,9 +4270,9 @@ Two things are interesting here:
negative numbers in case of different errors--and 0 on success.
- the variable `sha1` in the function signature of `get_sha1()` is `unsigned
- char {asterisk}`, but is actually expected to be a pointer to `unsigned
+ char *`, but is actually expected to be a pointer to `unsigned
char[20]`. This variable will contain the 160-bit SHA-1 of the given
- commit. Note that whenever a SHA-1 is passed as `unsigned char {asterisk}`, it
+ commit. Note that whenever a SHA-1 is passed as `unsigned char *`, it
is the binary representation, as opposed to the ASCII representation in
hex characters, which is passed as `char *`.
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index 5b54635301..86458311a1 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v1.7.9.7
+DEF_VER=v1.7.10.3
LF='
'
@@ -12,7 +12,7 @@ if test -f version
then
VN=$(cat version) || VN="$DEF_VER"
elif test -d .git -o -f .git &&
- VN=$(git describe --match "v[0-9]*" --abbrev=4 HEAD 2>/dev/null) &&
+ VN=$(git describe --match "v[0-9]*" --abbrev=7 HEAD 2>/dev/null) &&
case "$VN" in
*$LF*) (exit 1) ;;
v[0-9]*)
diff --git a/Makefile b/Makefile
index e4f8e0ef08..be1957a5e9 100644
--- a/Makefile
+++ b/Makefile
@@ -47,6 +47,9 @@ all::
# A translated Git requires GNU libintl or another gettext implementation,
# plus libintl-perl at runtime.
#
+# Define USE_GETTEXT_SCHEME and set it to 'fallthrough', if you don't trust
+# the installed gettext translation of the shell scripts output.
+#
# Define HAVE_LIBCHARSET_H if you haven't set NO_GETTEXT and you can't
# trust the langinfo.h's nl_langinfo(CODESET) function to return the
# current character set. GNU and Solaris have a nl_langinfo(CODESET),
@@ -378,6 +381,11 @@ BUILTIN_OBJS =
BUILT_INS =
COMPAT_CFLAGS =
COMPAT_OBJS =
+XDIFF_H =
+XDIFF_OBJS =
+VCSSVN_H =
+VCSSVN_OBJS =
+VCSSVN_TEST_OBJS =
EXTRA_CPPFLAGS =
LIB_H =
LIB_OBJS =
@@ -473,16 +481,13 @@ TEST_PROGRAMS_NEED_X += test-index-version
TEST_PROGRAMS_NEED_X += test-line-buffer
TEST_PROGRAMS_NEED_X += test-match-trees
TEST_PROGRAMS_NEED_X += test-mktemp
-TEST_PROGRAMS_NEED_X += test-obj-pool
TEST_PROGRAMS_NEED_X += test-parse-options
TEST_PROGRAMS_NEED_X += test-path-utils
TEST_PROGRAMS_NEED_X += test-run-command
TEST_PROGRAMS_NEED_X += test-sha1
TEST_PROGRAMS_NEED_X += test-sigchain
-TEST_PROGRAMS_NEED_X += test-string-pool
TEST_PROGRAMS_NEED_X += test-subprocess
TEST_PROGRAMS_NEED_X += test-svn-fe
-TEST_PROGRAMS_NEED_X += test-treap
TEST_PROGRAMS = $(patsubst %,%$X,$(TEST_PROGRAMS_NEED_X))
@@ -1529,6 +1534,7 @@ ifdef GETTEXT_POISON
endif
ifdef NO_GETTEXT
BASIC_CFLAGS += -DNO_GETTEXT
+ USE_GETTEXT_SCHEME ?= fallthrough
endif
ifdef NO_STRCASESTR
COMPAT_CFLAGS += -DNO_STRCASESTR
@@ -1926,6 +1932,7 @@ sed -e '1s|#!.*/sh|#!$(SHELL_PATH_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) \
$@.sh >$@+
endef
@@ -2027,12 +2034,24 @@ GIT_OBJS := $(LIB_OBJS) $(BUILTIN_OBJS) $(PROGRAM_OBJS) $(TEST_OBJS) \
ifndef NO_CURL
GIT_OBJS += http.o http-walker.o remote-curl.o
endif
-XDIFF_OBJS = xdiff/xdiffi.o xdiff/xprepare.o xdiff/xutils.o xdiff/xemit.o \
- xdiff/xmerge.o xdiff/xpatience.o xdiff/xhistogram.o
-VCSSVN_OBJS = vcs-svn/string_pool.o vcs-svn/line_buffer.o \
- vcs-svn/repo_tree.o vcs-svn/fast_export.o vcs-svn/svndump.o
-VCSSVN_TEST_OBJS = test-obj-pool.o test-string-pool.o \
- test-line-buffer.o test-treap.o
+
+XDIFF_OBJS += xdiff/xdiffi.o
+XDIFF_OBJS += xdiff/xprepare.o
+XDIFF_OBJS += xdiff/xutils.o
+XDIFF_OBJS += xdiff/xemit.o
+XDIFF_OBJS += xdiff/xmerge.o
+XDIFF_OBJS += xdiff/xpatience.o
+XDIFF_OBJS += xdiff/xhistogram.o
+
+VCSSVN_OBJS += vcs-svn/line_buffer.o
+VCSSVN_OBJS += vcs-svn/sliding_window.o
+VCSSVN_OBJS += vcs-svn/repo_tree.o
+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)
dep_files := $(foreach f,$(OBJECTS),$(dir $f).depend/$(notdir $f).d)
@@ -2151,16 +2170,25 @@ connect.o transport.o url.o http-backend.o: url.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/xinclude.h xdiff/xmacros.h xdiff/xdiff.h xdiff/xtypes.h \
- xdiff/xutils.h xdiff/xprepare.h xdiff/xdiffi.h xdiff/xemit.h
+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
+
+xdiff-interface.o $(XDIFF_OBJS): $(XDIFF_H)
-$(VCSSVN_OBJS) $(VCSSVN_TEST_OBJS): $(LIB_H) \
- vcs-svn/obj_pool.h vcs-svn/trp.h vcs-svn/string_pool.h \
- vcs-svn/line_buffer.h vcs-svn/repo_tree.h vcs-svn/fast_export.h \
- vcs-svn/svndump.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
-test-svn-fe.o: vcs-svn/svndump.h
+$(VCSSVN_OBJS) $(VCSSVN_TEST_OBJS): $(LIB_H) $(VCSSVN_H)
endif
exec_cmd.sp exec_cmd.s exec_cmd.o: EXTRA_CPPFLAGS = \
@@ -2303,7 +2331,7 @@ cscope:
### Detect prefix changes
TRACK_CFLAGS = $(CC):$(subst ','\'',$(ALL_CFLAGS)):\
$(bindir_SQ):$(gitexecdir_SQ):$(template_dir_SQ):$(prefix_SQ):\
- $(localedir_SQ)
+ $(localedir_SQ):$(USE_GETTEXT_SCHEME)
GIT-CFLAGS: FORCE
@FLAGS='$(TRACK_CFLAGS)'; \
@@ -2334,6 +2362,10 @@ GIT-BUILD-OPTIONS: FORCE
@echo USE_LIBPCRE=\''$(subst ','\'',$(subst ','\'',$(USE_LIBPCRE)))'\' >>$@
@echo NO_PERL=\''$(subst ','\'',$(subst ','\'',$(NO_PERL)))'\' >>$@
@echo NO_PYTHON=\''$(subst ','\'',$(subst ','\'',$(NO_PYTHON)))'\' >>$@
+ @echo NO_UNIX_SOCKETS=\''$(subst ','\'',$(subst ','\'',$(NO_UNIX_SOCKETS)))'\' >>$@
+ifdef GIT_TEST_OPTS
+ @echo GIT_TEST_OPTS=\''$(subst ','\'',$(subst ','\'',$(GIT_TEST_OPTS)))'\' >>$@
+endif
ifdef GIT_TEST_CMP
@echo GIT_TEST_CMP=\''$(subst ','\'',$(subst ','\'',$(GIT_TEST_CMP)))'\' >>$@
endif
@@ -2342,7 +2374,18 @@ ifdef GIT_TEST_CMP_USE_COPIED_CONTEXT
endif
@echo NO_GETTEXT=\''$(subst ','\'',$(subst ','\'',$(NO_GETTEXT)))'\' >>$@
@echo GETTEXT_POISON=\''$(subst ','\'',$(subst ','\'',$(GETTEXT_POISON)))'\' >>$@
- @echo NO_UNIX_SOCKETS=\''$(subst ','\'',$(subst ','\'',$(NO_UNIX_SOCKETS)))'\' >>$@
+ifdef GIT_PERF_REPEAT_COUNT
+ @echo GIT_PERF_REPEAT_COUNT=\''$(subst ','\'',$(subst ','\'',$(GIT_PERF_REPEAT_COUNT)))'\' >>$@
+endif
+ifdef GIT_PERF_REPO
+ @echo GIT_PERF_REPO=\''$(subst ','\'',$(subst ','\'',$(GIT_PERF_REPO)))'\' >>$@
+endif
+ifdef GIT_PERF_LARGE_REPO
+ @echo GIT_PERF_LARGE_REPO=\''$(subst ','\'',$(subst ','\'',$(GIT_PERF_LARGE_REPO)))'\' >>$@
+endif
+ifdef GIT_PERF_MAKE_OPTS
+ @echo GIT_PERF_MAKE_OPTS=\''$(subst ','\'',$(subst ','\'',$(GIT_PERF_MAKE_OPTS)))'\' >>$@
+endif
### Detect Tck/Tk interpreter path changes
ifndef NO_TCLTK
@@ -2378,6 +2421,11 @@ export NO_SVN_TESTS
test: all
$(MAKE) -C t/ all
+perf: all
+ $(MAKE) -C t/perf/ all
+
+.PHONY: test perf
+
test-ctype$X: ctype.o
test-date$X: date.o ctype.o
@@ -2388,8 +2436,6 @@ test-line-buffer$X: vcs-svn/lib.a
test-parse-options$X: parse-options.o parse-options-cb.o
-test-string-pool$X: vcs-svn/lib.a
-
test-svn-fe$X: vcs-svn/lib.a
.PRECIOUS: $(TEST_OBJS)
@@ -2589,7 +2635,6 @@ dist-doc:
distclean: clean
$(RM) configure
- $(RM) po/git.pot
profile-clean:
$(RM) $(addsuffix *.gcda,$(addprefix $(PROFILE_DIR)/, $(object_dirs)))
diff --git a/RelNotes b/RelNotes
index 3f4ce9f4f1..75661f8efa 120000
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/1.7.9.6.txt \ No newline at end of file
+Documentation/RelNotes/1.7.10.3.txt \ No newline at end of file
diff --git a/advice.c b/advice.c
index 65a07859f2..a492eea24f 100644
--- a/advice.c
+++ b/advice.c
@@ -1,6 +1,9 @@
#include "cache.h"
int advice_push_nonfastforward = 1;
+int advice_push_non_ff_current = 1;
+int advice_push_non_ff_default = 1;
+int advice_push_non_ff_matching = 1;
int advice_status_hints = 1;
int advice_commit_before_merge = 1;
int advice_resolve_conflict = 1;
@@ -12,6 +15,9 @@ static struct {
int *preference;
} advice_config[] = {
{ "pushnonfastforward", &advice_push_nonfastforward },
+ { "pushnonffcurrent", &advice_push_non_ff_current },
+ { "pushnonffdefault", &advice_push_non_ff_default },
+ { "pushnonffmatching", &advice_push_non_ff_matching },
{ "statushints", &advice_status_hints },
{ "commitbeforemerge", &advice_commit_before_merge },
{ "resolveconflict", &advice_resolve_conflict },
@@ -73,3 +79,17 @@ void NORETURN die_resolve_conflict(const char *me)
error_resolve_conflict(me);
die("Exiting because of an unresolved conflict.");
}
+
+void detach_advice(const char *new_name)
+{
+ const char fmt[] =
+ "Note: checking out '%s'.\n\n"
+ "You are in 'detached HEAD' state. You can look around, make experimental\n"
+ "changes and commit them, and you can discard any commits you make in this\n"
+ "state without impacting any branches by performing another checkout.\n\n"
+ "If you want to create a new branch to retain commits you create, you may\n"
+ "do so (now or later) by using -b with the checkout command again. Example:\n\n"
+ " git checkout -b new_branch_name\n\n";
+
+ fprintf(stderr, fmt, new_name);
+}
diff --git a/advice.h b/advice.h
index e5d0af782b..f3cdbbf29e 100644
--- a/advice.h
+++ b/advice.h
@@ -4,6 +4,9 @@
#include "git-compat-util.h"
extern int advice_push_nonfastforward;
+extern int advice_push_non_ff_current;
+extern int advice_push_non_ff_default;
+extern int advice_push_non_ff_matching;
extern int advice_status_hints;
extern int advice_commit_before_merge;
extern int advice_resolve_conflict;
@@ -14,5 +17,6 @@ int git_default_advice_config(const char *var, const char *value);
void advise(const char *advice, ...);
int error_resolve_conflict(const char *me);
extern void NORETURN die_resolve_conflict(const char *me);
+void detach_advice(const char *new_name);
#endif /* ADVICE_H */
diff --git a/argv-array.c b/argv-array.c
index a4e04201e6..0b5f8898a1 100644
--- a/argv-array.c
+++ b/argv-array.c
@@ -2,8 +2,7 @@
#include "argv-array.h"
#include "strbuf.h"
-static const char *empty_argv_storage = NULL;
-const char **empty_argv = &empty_argv_storage;
+const char *empty_argv[] = { NULL };
void argv_array_init(struct argv_array *array)
{
@@ -39,6 +38,17 @@ void argv_array_pushf(struct argv_array *array, const char *fmt, ...)
argv_array_push_nodup(array, strbuf_detach(&v, NULL));
}
+void argv_array_pushl(struct argv_array *array, ...)
+{
+ va_list ap;
+ const char *arg;
+
+ va_start(ap, array);
+ while((arg = va_arg(ap, const char *)))
+ argv_array_push(array, arg);
+ va_end(ap);
+}
+
void argv_array_clear(struct argv_array *array)
{
if (array->argv != empty_argv) {
diff --git a/argv-array.h b/argv-array.h
index 74dd2b1bc0..b93a69c36c 100644
--- a/argv-array.h
+++ b/argv-array.h
@@ -1,7 +1,7 @@
#ifndef ARGV_ARRAY_H
#define ARGV_ARRAY_H
-extern const char **empty_argv;
+extern const char *empty_argv[];
struct argv_array {
const char **argv;
@@ -15,6 +15,7 @@ void argv_array_init(struct argv_array *);
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_clear(struct argv_array *);
#endif /* ARGV_ARRAY_H */
diff --git a/attr.h b/attr.h
index eb8ca0d7c0..8b08d33af8 100644
--- a/attr.h
+++ b/attr.h
@@ -40,7 +40,7 @@ int git_check_attr(const char *path, int, struct git_attr_check *);
/*
* Retrieve all attributes that apply to the specified path. *num
- * will be set the the number of attributes on the path; **check will
+ * will be set to the number of attributes on the path; **check will
* be set to point at a newly-allocated array of git_attr_check
* objects describing the attributes and their values. *check must be
* free()ed by the caller.
diff --git a/builtin/blame.c b/builtin/blame.c
index 5a67c202f0..324d476abf 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -1829,18 +1829,6 @@ static int read_ancestry(const char *graft_file)
}
/*
- * How many columns do we need to show line numbers in decimal?
- */
-static int lineno_width(int lines)
-{
- int i, width;
-
- for (width = 1, i = 10; i <= lines; width++)
- i *= 10;
- return width;
-}
-
-/*
* How many columns do we need to show line numbers, authors,
* and filenames?
*/
@@ -1880,9 +1868,9 @@ static void find_alignment(struct scoreboard *sb, int *option)
if (largest_score < ent_score(sb, e))
largest_score = ent_score(sb, e);
}
- max_orig_digits = lineno_width(longest_src_lines);
- max_digits = lineno_width(longest_dst_lines);
- max_score_digits = lineno_width(largest_score);
+ max_orig_digits = decimal_width(longest_src_lines);
+ max_digits = decimal_width(longest_dst_lines);
+ max_score_digits = decimal_width(largest_score);
}
/*
@@ -2050,14 +2038,8 @@ static int git_blame_config(const char *var, const char *value, void *cb)
return 0;
}
- switch (userdiff_config(var, value)) {
- case 0:
- break;
- case -1:
+ if (userdiff_config(var, value) < 0)
return -1;
- default:
- return 0;
- }
return git_default_config(var, value, cb);
}
@@ -2320,6 +2302,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
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 },
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 07bd984084..8ed501f220 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -226,14 +226,8 @@ static const char * const cat_file_usage[] = {
static int git_cat_file_config(const char *var, const char *value, void *cb)
{
- switch (userdiff_config(var, value)) {
- case 0:
- break;
- case -1:
+ if (userdiff_config(var, value) < 0)
return -1;
- default:
- return 0;
- }
return git_default_config(var, value, cb);
}
diff --git a/builtin/checkout.c b/builtin/checkout.c
index a76aa2a6fd..f9f7f40afb 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -343,7 +343,7 @@ static int reset_tree(struct tree *tree, struct checkout_opts *o, int worktree)
opts.reset = 1;
opts.merge = 1;
opts.fn = oneway_merge;
- opts.verbose_update = !o->quiet;
+ opts.verbose_update = !o->quiet && isatty(2);
opts.src_index = &the_index;
opts.dst_index = &the_index;
parse_tree(tree);
@@ -420,7 +420,7 @@ static int merge_working_tree(struct checkout_opts *opts,
topts.update = 1;
topts.merge = 1;
topts.gently = opts->merge && old->commit;
- topts.verbose_update = !opts->quiet;
+ topts.verbose_update = !opts->quiet && isatty(2);
topts.fn = twoway_merge;
if (opts->overwrite_ignore) {
topts.dir = xcalloc(1, sizeof(*topts.dir));
@@ -514,20 +514,6 @@ static void report_tracking(struct branch_info *new)
strbuf_release(&sb);
}
-static void detach_advice(const char *old_path, const char *new_name)
-{
- const char fmt[] =
- "Note: checking out '%s'.\n\n"
- "You are in 'detached HEAD' state. You can look around, make experimental\n"
- "changes and commit them, and you can discard any commits you make in this\n"
- "state without impacting any branches by performing another checkout.\n\n"
- "If you want to create a new branch to retain commits you create, you may\n"
- "do so (now or later) by using -b with the checkout command again. Example:\n\n"
- " git checkout -b new_branch_name\n\n";
-
- fprintf(stderr, fmt, new_name);
-}
-
static void update_refs_for_switch(struct checkout_opts *opts,
struct branch_info *old,
struct branch_info *new)
@@ -575,7 +561,7 @@ static void update_refs_for_switch(struct checkout_opts *opts,
REF_NODEREF, DIE_ON_ERR);
if (!opts->quiet) {
if (old->path && advice_detached_head)
- detach_advice(old->path, new->name);
+ detach_advice(new->name);
describe_detached_head(_("HEAD is now at"), new->commit);
}
} else if (new->path) { /* Switch branches. */
@@ -685,10 +671,10 @@ static void suggest_reattach(struct commit *commit, struct rev_info *revs)
* HEAD. If it is not reachable from any ref, this is the last chance
* for the user to do so without resorting to reflog.
*/
-static void orphaned_commit_warning(struct commit *commit)
+static void orphaned_commit_warning(struct commit *old, struct commit *new)
{
struct rev_info revs;
- struct object *object = &commit->object;
+ struct object *object = &old->object;
struct object_array refs;
init_revisions(&revs, NULL);
@@ -698,16 +684,17 @@ static void orphaned_commit_warning(struct commit *commit)
add_pending_object(&revs, object, sha1_to_hex(object->sha1));
for_each_ref(add_pending_uninteresting_ref, &revs);
+ add_pending_sha1(&revs, "HEAD", new->object.sha1, UNINTERESTING);
refs = revs.pending;
revs.leak_pending = 1;
if (prepare_revision_walk(&revs))
die(_("internal error in revision walk"));
- if (!(commit->object.flags & UNINTERESTING))
- suggest_reattach(commit, &revs);
+ if (!(old->object.flags & UNINTERESTING))
+ suggest_reattach(old, &revs);
else
- describe_detached_head(_("Previous HEAD position was"), commit);
+ describe_detached_head(_("Previous HEAD position was"), old);
clear_commit_marks_for_object_array(&refs, ALL_REV_FLAGS);
free(refs.objects);
@@ -744,7 +731,7 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
}
if (!opts->quiet && !old.path && old.commit && new->commit != old.commit)
- orphaned_commit_warning(old.commit);
+ orphaned_commit_warning(old.commit, new->commit);
update_refs_for_switch(opts, &old, new);
@@ -1104,7 +1091,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
if (opts.writeout_stage)
die(_("--ours/--theirs is incompatible with switching branches."));
- if (!new.commit) {
+ if (!new.commit && opts.new_branch) {
unsigned char rev[20];
int flag;
diff --git a/builtin/clone.c b/builtin/clone.c
index 0fb5956b48..a4d8d25ee3 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -37,7 +37,7 @@ static const char * const builtin_clone_usage[] = {
NULL
};
-static int option_no_checkout, option_bare, option_mirror;
+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 char *option_template, *option_depth;
static char *option_origin = NULL;
@@ -92,6 +92,8 @@ static struct option builtin_clone_options[] = {
"path to git-upload-pack on the remote"),
OPT_STRING(0, "depth", &option_depth, "depth",
"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",
@@ -230,9 +232,6 @@ static int add_one_reference(struct string_list_item *item, void *cb_data)
{
char *ref_git;
struct strbuf alternate = STRBUF_INIT;
- struct remote *remote;
- struct transport *transport;
- const struct ref *extra;
/* Beware: real_path() and mkpath() return static buffer */
ref_git = xstrdup(real_path(item->string));
@@ -247,14 +246,6 @@ static int add_one_reference(struct string_list_item *item, void *cb_data)
strbuf_addf(&alternate, "%s/objects", ref_git);
add_to_alternates_file(alternate.buf);
strbuf_release(&alternate);
-
- remote = remote_get(ref_git);
- transport = transport_get(remote, ref_git);
- for (extra = transport_get_remote_refs(transport); extra;
- extra = extra->next)
- add_extra_ref(extra->name, extra->old_sha1, 0);
-
- transport_disconnect(transport);
free(ref_git);
return 0;
}
@@ -361,13 +352,8 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
closedir(dir);
}
-static const struct ref *clone_local(const char *src_repo,
- const char *dest_repo)
+static void clone_local(const char *src_repo, const char *dest_repo)
{
- const struct ref *ret;
- struct remote *remote;
- struct transport *transport;
-
if (option_shared) {
struct strbuf alt = STRBUF_INIT;
strbuf_addf(&alt, "%s/objects", src_repo);
@@ -383,13 +369,8 @@ static const struct ref *clone_local(const char *src_repo,
strbuf_release(&dest);
}
- remote = remote_get(src_repo);
- transport = transport_get(remote, src_repo);
- ret = transport_get_remote_refs(transport);
- transport_disconnect(transport);
if (0 <= option_verbosity)
printf(_("done.\n"));
- return ret;
}
static const char *junk_work_tree;
@@ -420,6 +401,26 @@ static void remove_junk_on_signal(int signo)
raise(signo);
}
+static struct ref *find_remote_branch(const struct ref *refs, const char *branch)
+{
+ struct ref *ref;
+ struct strbuf head = STRBUF_INIT;
+ strbuf_addstr(&head, "refs/heads/");
+ strbuf_addstr(&head, branch);
+ ref = find_ref_by_name(refs, head.buf);
+ strbuf_release(&head);
+
+ if (ref)
+ return ref;
+
+ strbuf_addstr(&head, "refs/tags/");
+ strbuf_addstr(&head, branch);
+ ref = find_ref_by_name(refs, head.buf);
+ strbuf_release(&head);
+
+ return ref;
+}
+
static struct ref *wanted_peer_refs(const struct ref *refs,
struct refspec *refspec)
{
@@ -427,8 +428,27 @@ static struct ref *wanted_peer_refs(const struct ref *refs,
struct ref *local_refs = head;
struct ref **tail = head ? &head->next : &local_refs;
- get_fetch_map(refs, refspec, &tail, 0);
- if (!option_mirror)
+ if (option_single_branch) {
+ struct ref *remote_head = NULL;
+
+ if (!option_branch)
+ remote_head = guess_remote_head(head, refs, 0);
+ else
+ remote_head = find_remote_branch(refs, option_branch);
+
+ if (!remote_head && option_branch)
+ warning(_("Could not find remote branch %s to clone."),
+ option_branch);
+ else {
+ get_fetch_map(remote_head, refspec, &tail, 0);
+
+ /* if --branch=tag, pull the requested tag explicitly */
+ get_fetch_map(remote_head, tag_refspec, &tail, 0);
+ }
+ } else
+ get_fetch_map(refs, refspec, &tail, 0);
+
+ if (!option_mirror && !option_single_branch)
get_fetch_map(refs, tag_refspec, &tail, 0);
return local_refs;
@@ -441,11 +461,134 @@ static void write_remote_refs(const struct ref *local_refs)
for (r = local_refs; r; r = r->next) {
if (!r->peer_ref)
continue;
- add_extra_ref(r->peer_ref->name, r->old_sha1, 0);
+ add_packed_ref(r->peer_ref->name, r->old_sha1);
}
pack_refs(PACK_REFS_ALL);
- clear_extra_refs();
+}
+
+static void write_followtags(const struct ref *refs, const char *msg)
+{
+ const struct ref *ref;
+ for (ref = refs; ref; ref = ref->next) {
+ if (prefixcmp(ref->name, "refs/tags/"))
+ continue;
+ if (!suffixcmp(ref->name, "^{}"))
+ continue;
+ if (!has_sha1_file(ref->old_sha1))
+ continue;
+ update_ref(msg, ref->name, ref->old_sha1,
+ NULL, 0, DIE_ON_ERR);
+ }
+}
+
+static void update_remote_refs(const struct ref *refs,
+ const struct ref *mapped_refs,
+ const struct ref *remote_head_points_at,
+ const char *branch_top,
+ const char *msg)
+{
+ if (refs) {
+ write_remote_refs(mapped_refs);
+ if (option_single_branch)
+ write_followtags(refs, msg);
+ }
+
+ if (remote_head_points_at && !option_bare) {
+ struct strbuf head_ref = STRBUF_INIT;
+ strbuf_addstr(&head_ref, branch_top);
+ strbuf_addstr(&head_ref, "HEAD");
+ create_symref(head_ref.buf,
+ remote_head_points_at->peer_ref->name,
+ msg);
+ }
+}
+
+static void update_head(const struct ref *our, const struct ref *remote,
+ const char *msg)
+{
+ if (our && !prefixcmp(our->name, "refs/heads/")) {
+ /* Local default branch link */
+ create_symref("HEAD", our->name, NULL);
+ if (!option_bare) {
+ const char *head = skip_prefix(our->name, "refs/heads/");
+ update_ref(msg, "HEAD", our->old_sha1, NULL, 0, DIE_ON_ERR);
+ install_branch_config(0, head, option_origin, our->name);
+ }
+ } else if (our) {
+ struct commit *c = lookup_commit_reference(our->old_sha1);
+ /* --branch specifies a non-branch (i.e. tags), detach HEAD */
+ update_ref(msg, "HEAD", c->object.sha1,
+ NULL, REF_NODEREF, DIE_ON_ERR);
+ } else if (remote) {
+ /*
+ * We know remote HEAD points to a non-branch, or
+ * HEAD points to a branch but we don't know which one.
+ * Detach HEAD in all these cases.
+ */
+ update_ref(msg, "HEAD", remote->old_sha1,
+ NULL, REF_NODEREF, DIE_ON_ERR);
+ }
+}
+
+static int checkout(void)
+{
+ unsigned char sha1[20];
+ char *head;
+ struct lock_file *lock_file;
+ struct unpack_trees_options opts;
+ struct tree *tree;
+ struct tree_desc t;
+ int err = 0, fd;
+
+ if (option_no_checkout)
+ return 0;
+
+ head = resolve_refdup("HEAD", sha1, 1, NULL);
+ if (!head) {
+ warning(_("remote HEAD refers to nonexistent ref, "
+ "unable to checkout.\n"));
+ return 0;
+ }
+ if (!strcmp(head, "HEAD")) {
+ if (advice_detached_head)
+ detach_advice(sha1_to_hex(sha1));
+ } else {
+ if (prefixcmp(head, "refs/heads/"))
+ die(_("HEAD not found below refs/heads!"));
+ }
+ free(head);
+
+ /* We need to be in the new work tree for the checkout */
+ setup_work_tree();
+
+ lock_file = xcalloc(1, sizeof(struct lock_file));
+ fd = hold_locked_index(lock_file, 1);
+
+ memset(&opts, 0, sizeof opts);
+ opts.update = 1;
+ opts.merge = 1;
+ opts.fn = oneway_merge;
+ opts.verbose_update = (option_verbosity >= 0);
+ opts.src_index = &the_index;
+ opts.dst_index = &the_index;
+
+ tree = parse_tree_indirect(sha1);
+ parse_tree(tree);
+ init_tree_desc(&t, tree->buffer, tree->size);
+ unpack_trees(1, &t, &opts);
+
+ if (write_cache(fd, active_cache, active_nr) ||
+ commit_locked_index(lock_file))
+ die(_("unable to write new index file"));
+
+ err |= run_hook(NULL, "post-checkout", sha1_to_hex(null_sha1),
+ sha1_to_hex(sha1), "1", NULL);
+
+ if (!err && option_recursive)
+ err = run_command_v_opt(argv_submodule, RUN_GIT_CMD);
+
+ return err;
}
static int write_one_config(const char *key, const char *value, void *data)
@@ -475,11 +618,13 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
const struct ref *remote_head_points_at;
const struct ref *our_head_points_at;
struct ref *mapped_refs;
+ const struct ref *ref;
struct strbuf key = STRBUF_INIT, value = STRBUF_INIT;
struct strbuf branch_top = STRBUF_INIT, reflog_msg = STRBUF_INIT;
struct transport *transport = NULL;
- char *src_ref_prefix = "refs/heads/";
- int err = 0;
+ const char *src_ref_prefix = "refs/heads/";
+ struct remote *remote;
+ int err = 0, complete_refs_before_fetch = 1;
struct refspec *refspec;
const char *fetch_pattern;
@@ -498,6 +643,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
usage_msg_opt(_("You must specify a repository to clone."),
builtin_clone_usage, builtin_clone_options);
+ if (option_single_branch == -1)
+ option_single_branch = option_depth ? 1 : 0;
+
if (option_mirror)
option_bare = 1;
@@ -630,13 +778,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
strbuf_reset(&value);
- if (is_local) {
- refs = clone_local(path, git_dir);
- mapped_refs = wanted_peer_refs(refs, refspec);
- } else {
- struct remote *remote = remote_get(option_origin);
- transport = transport_get(remote, remote->url[0]);
+ remote = remote_get(option_origin);
+ transport = transport_get(remote, remote->url[0]);
+ if (!is_local) {
if (!transport->get_refs_list || !transport->fetch)
die(_("Don't know how to clone %s"), transport->url);
@@ -645,49 +790,57 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (option_depth)
transport_set_option(transport, TRANS_OPT_DEPTH,
option_depth);
+ if (option_single_branch)
+ transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, "1");
transport_set_verbosity(transport, option_verbosity, option_progress);
if (option_upload_pack)
transport_set_option(transport, TRANS_OPT_UPLOADPACK,
option_upload_pack);
-
- refs = transport_get_remote_refs(transport);
- if (refs) {
- mapped_refs = wanted_peer_refs(refs, refspec);
- transport_fetch_refs(transport, mapped_refs);
- }
}
+ refs = transport_get_remote_refs(transport);
+
if (refs) {
- clear_extra_refs();
+ mapped_refs = wanted_peer_refs(refs, refspec);
+ /*
+ * transport_get_remote_refs() may return refs with null sha-1
+ * in mapped_refs (see struct transport->get_refs_list
+ * comment). In that case we need fetch it early because
+ * remote_head code below relies on it.
+ *
+ * for normal clones, transport_get_remote_refs() should
+ * return reliable ref set, we can delay cloning until after
+ * remote HEAD check.
+ */
+ for (ref = refs; ref; ref = ref->next)
+ if (is_null_sha1(ref->old_sha1)) {
+ complete_refs_before_fetch = 0;
+ break;
+ }
- write_remote_refs(mapped_refs);
+ if (!is_local && !complete_refs_before_fetch)
+ transport_fetch_refs(transport, mapped_refs);
remote_head = find_ref_by_name(refs, "HEAD");
remote_head_points_at =
guess_remote_head(remote_head, mapped_refs, 0);
if (option_branch) {
- struct strbuf head = STRBUF_INIT;
- strbuf_addstr(&head, src_ref_prefix);
- strbuf_addstr(&head, option_branch);
our_head_points_at =
- find_ref_by_name(mapped_refs, head.buf);
- strbuf_release(&head);
-
- if (!our_head_points_at) {
- warning(_("Remote branch %s not found in "
- "upstream %s, using HEAD instead"),
- option_branch, option_origin);
- our_head_points_at = remote_head_points_at;
- }
+ find_remote_branch(mapped_refs, option_branch);
+
+ if (!our_head_points_at)
+ die(_("Remote branch %s not found in upstream %s"),
+ option_branch, option_origin);
}
else
our_head_points_at = remote_head_points_at;
}
else {
warning(_("You appear to have cloned an empty repository."));
+ mapped_refs = NULL;
our_head_points_at = NULL;
remote_head_points_at = NULL;
remote_head = NULL;
@@ -697,84 +850,20 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
"refs/heads/master");
}
- if (remote_head_points_at && !option_bare) {
- struct strbuf head_ref = STRBUF_INIT;
- strbuf_addstr(&head_ref, branch_top.buf);
- strbuf_addstr(&head_ref, "HEAD");
- create_symref(head_ref.buf,
- remote_head_points_at->peer_ref->name,
- reflog_msg.buf);
- }
+ if (is_local)
+ clone_local(path, git_dir);
+ else if (refs && complete_refs_before_fetch)
+ transport_fetch_refs(transport, mapped_refs);
- if (our_head_points_at) {
- /* Local default branch link */
- create_symref("HEAD", our_head_points_at->name, NULL);
- if (!option_bare) {
- const char *head = skip_prefix(our_head_points_at->name,
- "refs/heads/");
- update_ref(reflog_msg.buf, "HEAD",
- our_head_points_at->old_sha1,
- NULL, 0, DIE_ON_ERR);
- install_branch_config(0, head, option_origin,
- our_head_points_at->name);
- }
- } else if (remote_head) {
- /* Source had detached HEAD pointing somewhere. */
- if (!option_bare) {
- update_ref(reflog_msg.buf, "HEAD",
- remote_head->old_sha1,
- NULL, REF_NODEREF, DIE_ON_ERR);
- our_head_points_at = remote_head;
- }
- } else {
- /* Nothing to checkout out */
- if (!option_no_checkout)
- warning(_("remote HEAD refers to nonexistent ref, "
- "unable to checkout.\n"));
- option_no_checkout = 1;
- }
+ update_remote_refs(refs, mapped_refs, remote_head_points_at,
+ branch_top.buf, reflog_msg.buf);
- if (transport) {
- transport_unlock_pack(transport);
- transport_disconnect(transport);
- }
+ update_head(our_head_points_at, remote_head, reflog_msg.buf);
- if (!option_no_checkout) {
- struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
- struct unpack_trees_options opts;
- struct tree *tree;
- struct tree_desc t;
- int fd;
-
- /* We need to be in the new work tree for the checkout */
- setup_work_tree();
-
- fd = hold_locked_index(lock_file, 1);
-
- memset(&opts, 0, sizeof opts);
- opts.update = 1;
- opts.merge = 1;
- opts.fn = oneway_merge;
- opts.verbose_update = (option_verbosity > 0);
- opts.src_index = &the_index;
- opts.dst_index = &the_index;
-
- tree = parse_tree_indirect(our_head_points_at->old_sha1);
- parse_tree(tree);
- init_tree_desc(&t, tree->buffer, tree->size);
- unpack_trees(1, &t, &opts);
-
- if (write_cache(fd, active_cache, active_nr) ||
- commit_locked_index(lock_file))
- die(_("unable to write new index file"));
-
- err |= run_hook(NULL, "post-checkout", sha1_to_hex(null_sha1),
- sha1_to_hex(our_head_points_at->old_sha1), "1",
- NULL);
-
- if (!err && option_recursive)
- err = run_command_v_opt(argv_submodule, RUN_GIT_CMD);
- }
+ transport_unlock_pack(transport);
+ transport_disconnect(transport);
+
+ err = checkout();
strbuf_release(&reflog_msg);
strbuf_release(&branch_top);
diff --git a/builtin/commit.c b/builtin/commit.c
index eae5a29aeb..e2d9cbe3e3 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -109,13 +109,11 @@ static int show_ignored_in_status;
static const char *only_include_assumed;
static struct strbuf message = STRBUF_INIT;
-static int null_termination;
static enum {
STATUS_FORMAT_LONG,
STATUS_FORMAT_SHORT,
STATUS_FORMAT_PORCELAIN
} status_format = STATUS_FORMAT_LONG;
-static int status_show_branch;
static int opt_parse_m(const struct option *opt, const char *arg, int unset)
{
@@ -129,59 +127,6 @@ static int opt_parse_m(const struct option *opt, const char *arg, int unset)
return 0;
}
-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) "" },
- /* 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",
- STATUS_FORMAT_SHORT),
- OPT_BOOLEAN(0, "branch", &status_show_branch, "show branch information"),
- OPT_SET_INT(0, "porcelain", &status_format,
- "machine-readable output", STATUS_FORMAT_PORCELAIN),
- OPT_BOOLEAN('z', "null", &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" },
- /* end commit contents options */
-
- { OPTION_BOOLEAN, 0, "allow-empty", &allow_empty, NULL,
- "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",
- PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
-
- OPT_END()
-};
-
static void determine_whence(struct wt_status *s)
{
if (file_exists(git_path("MERGE_HEAD")))
@@ -400,7 +345,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,
fd = hold_locked_index(&index_lock, 1);
add_files_to_cache(also ? prefix : NULL, pathspec, 0);
refresh_cache_or_die(refresh_flags);
- update_main_cache_tree(1);
+ update_main_cache_tree(WRITE_TREE_SILENT);
if (write_cache(fd, active_cache, active_nr) ||
close_lock_file(&index_lock))
die(_("unable to write new_index file"));
@@ -421,7 +366,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,
fd = hold_locked_index(&index_lock, 1);
refresh_cache_or_die(refresh_flags);
if (active_cache_changed) {
- update_main_cache_tree(1);
+ update_main_cache_tree(WRITE_TREE_SILENT);
if (write_cache(fd, active_cache, active_nr) ||
commit_locked_index(&index_lock))
die(_("unable to write new_index file"));
@@ -513,10 +458,10 @@ static int run_status(FILE *fp, const char *index_file, const char *prefix, int
switch (status_format) {
case STATUS_FORMAT_SHORT:
- wt_shortstatus_print(s, null_termination, status_show_branch);
+ wt_shortstatus_print(s);
break;
case STATUS_FORMAT_PORCELAIN:
- wt_porcelain_print(s, null_termination);
+ wt_porcelain_print(s);
break;
case STATUS_FORMAT_LONG:
wt_status_print(s);
@@ -533,9 +478,20 @@ static int is_a_merge(const struct commit *current_head)
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;
+ if (hack)
+ strbuf_addch(&buf, hack);
+ strbuf_addf(&buf, "%.*s", (int)(e - s), s);
+ setenv(var, buf.buf, 1);
+ strbuf_release(&buf);
+}
+
static void determine_author_info(struct strbuf *author_ident)
{
char *name, *email, *date;
+ struct ident_split author;
name = getenv("GIT_AUTHOR_NAME");
email = getenv("GIT_AUTHOR_EMAIL");
@@ -585,6 +541,11 @@ static void determine_author_info(struct strbuf *author_ident)
date = force_date;
strbuf_addstr(author_ident, fmt_ident(name, email, date,
IDENT_ERROR_ON_NO_NAME));
+ if (!split_ident_line(&author, author_ident->buf, author_ident->len)) {
+ export_one("GIT_AUTHOR_NAME", author.name_begin, author.name_end, 0);
+ export_one("GIT_AUTHOR_EMAIL", author.mail_begin, author.mail_end, 0);
+ export_one("GIT_AUTHOR_DATE", author.date_begin, author.tz_end, '@');
+ }
}
static int ends_rfc2822_footer(struct strbuf *sb)
@@ -652,6 +613,9 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
int ident_shown = 0;
int clean_message_contents = (cleanup_mode != CLEANUP_NONE);
+ /* This checks and barfs if author is badly specified */
+ determine_author_info(author_ident);
+
if (!no_verify && run_hook(index_file, "pre-commit", NULL))
return 0;
@@ -771,9 +735,6 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
strbuf_release(&sb);
- /* This checks and barfs if author is badly specified */
- determine_author_info(author_ident);
-
/* This checks if committer ident is explicitly given */
strbuf_addstr(&committer_ident, git_committer_info(0));
if (use_editor && include_status) {
@@ -905,27 +866,10 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
return 1;
}
-/*
- * Find out if the message in the strbuf contains only whitespace and
- * Signed-off-by lines.
- */
-static int message_is_empty(struct strbuf *sb)
+static int rest_is_empty(struct strbuf *sb, int start)
{
- struct strbuf tmpl = STRBUF_INIT;
+ int i, eol;
const char *nl;
- int eol, i, start = 0;
-
- if (cleanup_mode == CLEANUP_NONE && sb->len)
- return 0;
-
- /* See if the template is just a prefix of the message. */
- if (template_file && strbuf_read_file(&tmpl, template_file, 0) > 0) {
- stripspace(&tmpl, cleanup_mode == CLEANUP_ALL);
- if (start + tmpl.len <= sb->len &&
- memcmp(tmpl.buf, sb->buf + start, tmpl.len) == 0)
- start += tmpl.len;
- }
- strbuf_release(&tmpl);
/* Check if the rest is just whitespace and Signed-of-by's. */
for (i = start; i < sb->len; i++) {
@@ -948,6 +892,40 @@ static int message_is_empty(struct strbuf *sb)
return 1;
}
+/*
+ * Find out if the message in the strbuf contains only whitespace and
+ * Signed-off-by lines.
+ */
+static int message_is_empty(struct strbuf *sb)
+{
+ if (cleanup_mode == CLEANUP_NONE && sb->len)
+ return 0;
+ return rest_is_empty(sb, 0);
+}
+
+/*
+ * See if the user edited the message in the editor or left what
+ * was in the template intact
+ */
+static int template_untouched(struct strbuf *sb)
+{
+ struct strbuf tmpl = STRBUF_INIT;
+ char *start;
+
+ if (cleanup_mode == CLEANUP_NONE && sb->len)
+ return 0;
+
+ if (!template_file || strbuf_read_file(&tmpl, template_file, 0) <= 0)
+ return 0;
+
+ stripspace(&tmpl, cleanup_mode == CLEANUP_ALL);
+ start = (char *)skip_prefix(sb->buf, tmpl.buf);
+ if (!start)
+ start = sb->buf;
+ strbuf_release(&tmpl);
+ return rest_is_empty(sb, start - sb->buf);
+}
+
static const char *find_author_by_nickname(const char *name)
{
struct rev_info revs;
@@ -1013,6 +991,7 @@ static const char *read_commit_message(const char *name)
}
static int parse_and_validate_options(int argc, const char *argv[],
+ const struct option *options,
const char * const usage[],
const char *prefix,
struct commit *current_head,
@@ -1020,8 +999,7 @@ static int parse_and_validate_options(int argc, const char *argv[],
{
int f = 0;
- argc = parse_options(argc, argv, prefix, builtin_commit_options, usage,
- 0);
+ argc = parse_options(argc, argv, prefix, options, usage, 0);
if (force_author && !strchr(force_author, '>'))
force_author = find_author_by_nickname(force_author);
@@ -1055,6 +1033,8 @@ static int parse_and_validate_options(int argc, const char *argv[],
die(_("Only one of -c/-C/-F/--fixup can be used."));
if (message.len && f > 0)
die((_("Option -m cannot be combined with -c/-C/-F/--fixup.")));
+ if (f || message.len)
+ template_file = NULL;
if (edit_message)
use_message = edit_message;
if (amend && !use_message && !fixup_message)
@@ -1100,7 +1080,7 @@ static int parse_and_validate_options(int argc, const char *argv[],
if (all && argc > 0)
die(_("Paths with -a does not make sense."));
- if (null_termination && status_format == STATUS_FORMAT_LONG)
+ if (s->null_termination && status_format == STATUS_FORMAT_LONG)
status_format = STATUS_FORMAT_PORCELAIN;
if (status_format != STATUS_FORMAT_LONG)
dry_run = 1;
@@ -1187,19 +1167,19 @@ static int git_status_config(const char *k, const char *v, void *cb)
int cmd_status(int argc, const char **argv, const char *prefix)
{
- struct wt_status s;
+ static struct wt_status s;
int fd;
unsigned char sha1[20];
static struct option builtin_status_options[] = {
OPT__VERBOSE(&verbose, "be verbose"),
OPT_SET_INT('s', "short", &status_format,
"show status concisely", STATUS_FORMAT_SHORT),
- OPT_BOOLEAN('b', "branch", &status_show_branch,
+ OPT_BOOLEAN('b', "branch", &s.show_branch,
"show branch information"),
OPT_SET_INT(0, "porcelain", &status_format,
"machine-readable output",
STATUS_FORMAT_PORCELAIN),
- OPT_BOOLEAN('z', "null", &null_termination,
+ OPT_BOOLEAN('z', "null", &s.null_termination,
"terminate entries with NUL"),
{ OPTION_STRING, 'u', "untracked-files", &untracked_files_arg,
"mode",
@@ -1224,7 +1204,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
builtin_status_options,
builtin_status_usage, 0);
- if (null_termination && status_format == STATUS_FORMAT_LONG)
+ if (s.null_termination && status_format == STATUS_FORMAT_LONG)
status_format = STATUS_FORMAT_PORCELAIN;
handle_untracked_files_arg(&s);
@@ -1249,10 +1229,10 @@ int cmd_status(int argc, const char **argv, const char *prefix)
switch (status_format) {
case STATUS_FORMAT_SHORT:
- wt_shortstatus_print(&s, null_termination, status_show_branch);
+ wt_shortstatus_print(&s);
break;
case STATUS_FORMAT_PORCELAIN:
- wt_porcelain_print(&s, null_termination);
+ wt_porcelain_print(&s);
break;
case STATUS_FORMAT_LONG:
s.verbose = verbose;
@@ -1387,6 +1367,60 @@ static int run_rewrite_hook(const unsigned char *oldsha1,
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) "" },
+ /* 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",
+ STATUS_FORMAT_SHORT),
+ OPT_BOOLEAN(0, "branch", &s.show_branch, "show branch information"),
+ OPT_SET_INT(0, "porcelain", &status_format,
+ "machine-readable output", STATUS_FORMAT_PORCELAIN),
+ 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" },
+ /* end commit contents options */
+
+ { OPTION_BOOLEAN, 0, "allow-empty", &allow_empty, NULL,
+ "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",
+ PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
+
+ OPT_END()
+ };
+
struct strbuf sb = STRBUF_INIT;
struct strbuf author_ident = STRBUF_INIT;
const char *index_file, *reflog_msg;
@@ -1396,7 +1430,6 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
struct commit_list *parents = NULL, **pptr = &parents;
struct stat statbuf;
int allow_fast_forward = 1;
- struct wt_status s;
struct commit *current_head = NULL;
struct commit_extra_header *extra = NULL;
@@ -1414,7 +1447,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
if (!current_head || parse_commit(current_head))
die(_("could not parse HEAD commit"));
}
- argc = parse_and_validate_options(argc, argv, builtin_commit_usage,
+ argc = parse_and_validate_options(argc, argv, builtin_commit_options,
+ builtin_commit_usage,
prefix, current_head, &s);
if (dry_run)
return dry_run_commit(argc, argv, prefix, current_head, &s);
@@ -1494,6 +1528,11 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
if (cleanup_mode != CLEANUP_NONE)
stripspace(&sb, cleanup_mode == CLEANUP_ALL);
+ if (template_untouched(&sb) && !allow_empty_message) {
+ rollback_index_files();
+ fprintf(stderr, _("Aborting commit; you did not edit the message.\n"));
+ exit(1);
+ }
if (message_is_empty(&sb) && !allow_empty_message) {
rollback_index_files();
fprintf(stderr, _("Aborting commit due to empty commit message.\n"));
diff --git a/builtin/config.c b/builtin/config.c
index d35c06ae51..33c8820af6 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -25,6 +25,7 @@ static const char *given_config_file;
static int actions, types;
static const char *get_color_slot, *get_colorbool_slot;
static int end_null;
+static int respect_includes = -1;
#define ACTION_GET (1<<0)
#define ACTION_GET_ALL (1<<1)
@@ -74,6 +75,7 @@ static struct option builtin_config_options[] = {
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_END(),
};
@@ -161,8 +163,11 @@ static int get_value(const char *key_, const char *regex_)
int ret = -1;
char *global = NULL, *repo_config = NULL;
const char *system_wide = NULL, *local;
+ struct config_include_data inc = CONFIG_INCLUDE_INIT;
+ config_fn_t fn;
+ void *data;
- local = config_exclusive_filename;
+ local = given_config_file;
if (!local) {
const char *home = getenv("HOME");
local = repo_config = git_pathdup("config");
@@ -213,19 +218,28 @@ static int get_value(const char *key_, const char *regex_)
}
}
+ fn = show_config;
+ data = NULL;
+ if (respect_includes) {
+ inc.fn = fn;
+ inc.data = data;
+ fn = git_config_include;
+ data = &inc;
+ }
+
if (do_all && system_wide)
- git_config_from_file(show_config, system_wide, NULL);
+ git_config_from_file(fn, system_wide, data);
if (do_all && global)
- git_config_from_file(show_config, global, NULL);
+ git_config_from_file(fn, global, data);
if (do_all)
- git_config_from_file(show_config, local, NULL);
- git_config_from_parameters(show_config, NULL);
+ git_config_from_file(fn, local, data);
+ git_config_from_parameters(fn, data);
if (!do_all && !seen)
- git_config_from_file(show_config, local, NULL);
+ git_config_from_file(fn, local, data);
if (!do_all && !seen && global)
- git_config_from_file(show_config, global, NULL);
+ git_config_from_file(fn, global, data);
if (!do_all && !seen && system_wide)
- git_config_from_file(show_config, system_wide, NULL);
+ git_config_from_file(fn, system_wide, data);
free(key);
if (regexp) {
@@ -301,7 +315,8 @@ static void get_color(const char *def_color)
{
get_color_found = 0;
parsed_color[0] = '\0';
- git_config(git_get_color_config, NULL);
+ git_config_with_options(git_get_color_config, NULL,
+ given_config_file, respect_includes);
if (!get_color_found && def_color)
color_parse(def_color, "command line", parsed_color);
@@ -328,7 +343,8 @@ static int get_colorbool(int print)
{
get_colorbool_found = -1;
get_diff_color_found = -1;
- git_config(git_get_colorbool_config, NULL);
+ git_config_with_options(git_get_colorbool_config, NULL,
+ given_config_file, respect_includes);
if (get_colorbool_found < 0) {
if (!strcmp(get_colorbool_slot, "color.diff"))
@@ -351,7 +367,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
int nongit = !startup_info->have_repository;
char *value;
- config_exclusive_filename = getenv(CONFIG_ENVIRONMENT);
+ given_config_file = getenv(CONFIG_ENVIRONMENT);
argc = parse_options(argc, argv, prefix, builtin_config_options,
builtin_config_usage,
@@ -366,24 +382,26 @@ int cmd_config(int argc, const char **argv, const char *prefix)
char *home = getenv("HOME");
if (home) {
char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
- config_exclusive_filename = user_config;
+ given_config_file = user_config;
} else {
die("$HOME not set");
}
}
else if (use_system_config)
- config_exclusive_filename = git_etc_gitconfig();
+ given_config_file = git_etc_gitconfig();
else if (use_local_config)
- config_exclusive_filename = git_pathdup("config");
+ given_config_file = git_pathdup("config");
else if (given_config_file) {
if (!is_absolute_path(given_config_file) && prefix)
- config_exclusive_filename = prefix_filename(prefix,
- strlen(prefix),
- given_config_file);
- else
- config_exclusive_filename = given_config_file;
+ given_config_file =
+ xstrdup(prefix_filename(prefix,
+ strlen(prefix),
+ given_config_file));
}
+ if (respect_includes == -1)
+ respect_includes = !given_config_file;
+
if (end_null) {
term = '\0';
delim = '\n';
@@ -420,28 +438,30 @@ int cmd_config(int argc, const char **argv, const char *prefix)
if (actions == ACTION_LIST) {
check_argc(argc, 0, 0);
- if (git_config(show_all_config, NULL) < 0) {
- if (config_exclusive_filename)
+ if (git_config_with_options(show_all_config, NULL,
+ given_config_file,
+ respect_includes) < 0) {
+ if (given_config_file)
die_errno("unable to read config file '%s'",
- config_exclusive_filename);
+ given_config_file);
else
die("error processing config file(s)");
}
}
else if (actions == ACTION_EDIT) {
check_argc(argc, 0, 0);
- if (!config_exclusive_filename && nongit)
+ if (!given_config_file && nongit)
die("not in a git directory");
git_config(git_default_config, NULL);
- launch_editor(config_exclusive_filename ?
- config_exclusive_filename : git_path("config"),
+ launch_editor(given_config_file ?
+ given_config_file : git_path("config"),
NULL, NULL);
}
else if (actions == ACTION_SET) {
int ret;
check_argc(argc, 2, 2);
value = normalize_value(argv[0], argv[1]);
- ret = git_config_set(argv[0], value);
+ ret = git_config_set_in_file(given_config_file, argv[0], value);
if (ret == CONFIG_NOTHING_SET)
error("cannot overwrite multiple values with a single value\n"
" Use a regexp, --add or --replace-all to change %s.", argv[0]);
@@ -450,17 +470,20 @@ int cmd_config(int argc, const char **argv, const char *prefix)
else if (actions == ACTION_SET_ALL) {
check_argc(argc, 2, 3);
value = normalize_value(argv[0], argv[1]);
- return git_config_set_multivar(argv[0], value, argv[2], 0);
+ return git_config_set_multivar_in_file(given_config_file,
+ argv[0], value, argv[2], 0);
}
else if (actions == ACTION_ADD) {
check_argc(argc, 2, 2);
value = normalize_value(argv[0], argv[1]);
- return git_config_set_multivar(argv[0], value, "^$", 0);
+ return git_config_set_multivar_in_file(given_config_file,
+ argv[0], value, "^$", 0);
}
else if (actions == ACTION_REPLACE_ALL) {
check_argc(argc, 2, 3);
value = normalize_value(argv[0], argv[1]);
- return git_config_set_multivar(argv[0], value, argv[2], 1);
+ return git_config_set_multivar_in_file(given_config_file,
+ argv[0], value, argv[2], 1);
}
else if (actions == ACTION_GET) {
check_argc(argc, 1, 2);
@@ -481,18 +504,22 @@ int cmd_config(int argc, const char **argv, const char *prefix)
else if (actions == ACTION_UNSET) {
check_argc(argc, 1, 2);
if (argc == 2)
- return git_config_set_multivar(argv[0], NULL, argv[1], 0);
+ return git_config_set_multivar_in_file(given_config_file,
+ argv[0], NULL, argv[1], 0);
else
- return git_config_set(argv[0], NULL);
+ return git_config_set_in_file(given_config_file,
+ argv[0], NULL);
}
else if (actions == ACTION_UNSET_ALL) {
check_argc(argc, 1, 2);
- return git_config_set_multivar(argv[0], NULL, argv[1], 1);
+ return git_config_set_multivar_in_file(given_config_file,
+ argv[0], NULL, argv[1], 1);
}
else if (actions == ACTION_RENAME_SECTION) {
int ret;
check_argc(argc, 2, 2);
- ret = git_config_rename_section(argv[0], argv[1]);
+ ret = git_config_rename_section_in_file(given_config_file,
+ argv[0], argv[1]);
if (ret < 0)
return ret;
if (ret == 0)
@@ -501,7 +528,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)
else if (actions == ACTION_REMOVE_SECTION) {
int ret;
check_argc(argc, 1, 1);
- ret = git_config_rename_section(argv[0], NULL);
+ ret = git_config_rename_section_in_file(given_config_file,
+ argv[0], NULL);
if (ret < 0)
return ret;
if (ret == 0)
diff --git a/builtin/diff.c b/builtin/diff.c
index 387afa7568..9069dc41be 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -285,6 +285,10 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
/* Otherwise, we are doing the usual "git" diff */
rev.diffopt.skip_stat_unmatch = !!diff_auto_refresh_index;
+ /* Scale to real terminal size and respect statGraphWidth config */
+ rev.diffopt.stat_width = -1;
+ rev.diffopt.stat_graph_width = -1;
+
/* Default to let external and textconv be used */
DIFF_OPT_SET(&rev.diffopt, ALLOW_EXTERNAL);
DIFF_OPT_SET(&rev.diffopt, ALLOW_TEXTCONV);
@@ -323,7 +327,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
add_head_to_pending(&rev);
if (!rev.pending.nr) {
struct tree *tree;
- tree = lookup_tree((const unsigned char*)EMPTY_TREE_SHA1_BIN);
+ tree = lookup_tree(EMPTY_TREE_SHA1_BIN);
add_pending_object(&rev, &tree->object, "HEAD");
}
break;
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 08fed989a4..19509ea754 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -647,9 +647,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
"Output full tree for each commit"),
OPT_BOOLEAN(0, "use-done-feature", &use_done_feature,
"Use the done feature to terminate the stream"),
- { OPTION_NEGBIT, 0, "data", &no_data, NULL,
- "Skip output of blob data",
- PARSE_OPT_NOARG | PARSE_OPT_NEGHELP, NULL, 1 },
+ OPT_BOOL(0, "no-data", &no_data, "Skip output of blob data"),
OPT_END()
};
diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c
index a4d3e90a86..10db15b184 100644
--- a/builtin/fetch-pack.c
+++ b/builtin/fetch-pack.c
@@ -23,7 +23,9 @@ static struct fetch_pack_args args = {
};
static const char fetch_pack_usage[] =
-"git fetch-pack [--all] [--quiet|-q] [--keep|-k] [--thin] [--include-tag] [--upload-pack=<git-upload-pack>] [--depth=<n>] [--no-progress] [-v] [<host>:]<directory> [<refs>...]";
+"git fetch-pack [--all] [--stdin] [--quiet|-q] [--keep|-k] [--thin] "
+"[--include-tag] [--upload-pack=<git-upload-pack>] [--depth=<n>] "
+"[--no-progress] [-v] [<host>:]<directory> [<refs>...]";
#define COMPLETE (1U << 0)
#define COMMON (1U << 1)
@@ -58,9 +60,9 @@ static void rev_list_push(struct commit *commit, int mark)
}
}
-static int rev_list_insert_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)
+static int rev_list_insert_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
{
- struct object *o = deref_tag(parse_object(sha1), path, 0);
+ struct object *o = deref_tag(parse_object(sha1), refname, 0);
if (o && o->type == OBJ_COMMIT)
rev_list_push((struct commit *)o, SEEN);
@@ -68,9 +70,9 @@ static int rev_list_insert_ref(const char *path, const unsigned char *sha1, int
return 0;
}
-static int clear_marks(const char *path, const unsigned char *sha1, int flag, void *cb_data)
+static int clear_marks(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
{
- struct object *o = deref_tag(parse_object(sha1), path, 0);
+ struct object *o = deref_tag(parse_object(sha1), refname, 0);
if (o && o->type == OBJ_COMMIT)
clear_commit_marks((struct commit *)o,
@@ -256,11 +258,6 @@ static void insert_one_alternate_ref(const struct ref *ref, void *unused)
rev_list_insert_ref(NULL, ref->old_sha1, 0, NULL);
}
-static void insert_alternate_refs(void)
-{
- for_each_alternate_ref(insert_one_alternate_ref, NULL);
-}
-
#define INITIAL_FLUSH 16
#define PIPESAFE_FLUSH 32
#define LARGE_FLUSH 1024
@@ -295,7 +292,7 @@ static int find_common(int fd[2], unsigned char *result_sha1,
marked = 1;
for_each_ref(rev_list_insert_ref, NULL);
- insert_alternate_refs();
+ for_each_alternate_ref(insert_one_alternate_ref, NULL);
fetching = 0;
for ( ; refs ; refs = refs->next) {
@@ -493,7 +490,7 @@ done:
static struct commit_list *complete;
-static int mark_complete(const char *path, const unsigned char *sha1, int flag, void *cb_data)
+static int mark_complete(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
{
struct object *o = parse_object(sha1);
@@ -586,6 +583,11 @@ static void filter_refs(struct ref **refs, int nr_match, char **match)
*refs = newlist;
}
+static void mark_alternate_complete(const struct ref *ref, void *unused)
+{
+ mark_complete(NULL, ref->old_sha1, 0, NULL);
+}
+
static int everything_local(struct ref **refs, int nr_match, char **match)
{
struct ref *ref;
@@ -614,6 +616,7 @@ static int everything_local(struct ref **refs, int nr_match, char **match)
if (!args.depth) {
for_each_ref(mark_complete, NULL);
+ for_each_alternate_ref(mark_alternate_complete, NULL);
if (cutoff)
mark_recent_complete_commits(cutoff);
}
@@ -941,6 +944,10 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
args.fetch_all = 1;
continue;
}
+ if (!strcmp("--stdin", arg)) {
+ args.stdin_refs = 1;
+ continue;
+ }
if (!strcmp("-v", arg)) {
args.verbose = 1;
continue;
@@ -972,6 +979,40 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
if (!dest)
usage(fetch_pack_usage);
+ if (args.stdin_refs) {
+ /*
+ * Copy refs from cmdline to new growable list, then
+ * append the refs from the standard input.
+ */
+ int alloc_heads = nr_heads;
+ int size = nr_heads * sizeof(*heads);
+ heads = memcpy(xmalloc(size), heads, size);
+ if (args.stateless_rpc) {
+ /* in stateless RPC mode we use pkt-line to read
+ * from stdin, until we get a flush packet
+ */
+ static char line[1000];
+ for (;;) {
+ int n = packet_read_line(0, line, sizeof(line));
+ if (!n)
+ break;
+ if (line[n-1] == '\n')
+ n--;
+ ALLOC_GROW(heads, nr_heads + 1, alloc_heads);
+ heads[nr_heads++] = 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);
+ }
+ strbuf_release(&line);
+ }
+ }
+
if (args.stateless_rpc) {
conn = NULL;
fd[0] = 0;
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 8ec4eae3eb..1c8cb62445 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -240,6 +240,7 @@ static int s_update_ref(const char *action,
static int update_local_ref(struct ref *ref,
const char *remote,
+ const struct ref *remote_ref,
struct strbuf *display)
{
struct commit *current = NULL, *updated;
@@ -293,18 +294,26 @@ static int update_local_ref(struct ref *ref,
const char *msg;
const char *what;
int r;
- if (!strncmp(ref->name, "refs/tags/", 10)) {
+ /*
+ * Nicely describe the new ref we're fetching.
+ * Base this on the remote's ref name, as it's
+ * more likely to follow a standard layout.
+ */
+ const char *name = remote_ref ? remote_ref->name : "";
+ if (!prefixcmp(name, "refs/tags/")) {
msg = "storing tag";
what = _("[new tag]");
- }
- else {
+ } else if (!prefixcmp(name, "refs/heads/")) {
msg = "storing head";
what = _("[new branch]");
- if ((recurse_submodules != RECURSE_SUBMODULES_OFF) &&
- (recurse_submodules != RECURSE_SUBMODULES_ON))
- check_for_new_submodule_commits(ref->new_sha1);
+ } else {
+ msg = "storing ref";
+ what = _("[new ref]");
}
+ if ((recurse_submodules != RECURSE_SUBMODULES_OFF) &&
+ (recurse_submodules != RECURSE_SUBMODULES_ON))
+ check_for_new_submodule_commits(ref->new_sha1);
r = s_update_ref(msg, ref, 0);
strbuf_addf(display, "%c %-*s %-*s -> %s%s",
r ? '!' : '*',
@@ -466,7 +475,7 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
strbuf_reset(&note);
if (ref) {
- rc |= update_local_ref(ref, what, &note);
+ rc |= update_local_ref(ref, what, rm, &note);
free(ref);
} else
strbuf_addf(&note, "* %-*s %-*s -> FETCH_HEAD",
@@ -585,7 +594,7 @@ static void find_non_local_tags(struct transport *transport,
for_each_ref(add_existing, &existing_refs);
for (ref = transport_get_remote_refs(transport); ref; ref = ref->next) {
- if (prefixcmp(ref->name, "refs/tags"))
+ if (prefixcmp(ref->name, "refs/tags/"))
continue;
/*
diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c
index c81a7fef26..fb1ebcbe68 100644
--- a/builtin/fmt-merge-msg.c
+++ b/builtin/fmt-merge-msg.c
@@ -53,7 +53,48 @@ static void init_src_data(struct src_data *data)
static struct string_list srcs = STRING_LIST_INIT_DUP;
static struct string_list origins = STRING_LIST_INIT_DUP;
-static int handle_line(char *line)
+struct merge_parents {
+ int alloc, nr;
+ struct merge_parent {
+ unsigned char given[20];
+ unsigned char commit[20];
+ unsigned char used;
+ } *item;
+};
+
+/*
+ * I know, I know, this is inefficient, but you won't be pulling and merging
+ * hundreds of heads at a time anyway.
+ */
+static struct merge_parent *find_merge_parent(struct merge_parents *table,
+ unsigned char *given,
+ unsigned char *commit)
+{
+ int i;
+ for (i = 0; i < table->nr; i++) {
+ if (given && hashcmp(table->item[i].given, given))
+ continue;
+ if (commit && hashcmp(table->item[i].commit, commit))
+ continue;
+ return &table->item[i];
+ }
+ return NULL;
+}
+
+static void add_merge_parent(struct merge_parents *table,
+ unsigned char *given,
+ unsigned char *commit)
+{
+ if (table->nr && find_merge_parent(table, given, commit))
+ return;
+ ALLOC_GROW(table->item, table->nr + 1, table->alloc);
+ hashcpy(table->item[table->nr].given, given);
+ hashcpy(table->item[table->nr].commit, commit);
+ table->item[table->nr].used = 0;
+ table->nr++;
+}
+
+static int handle_line(char *line, struct merge_parents *merge_parents)
{
int i, len = strlen(line);
struct origin_data *origin_data;
@@ -61,6 +102,7 @@ static int handle_line(char *line)
struct src_data *src_data;
struct string_list_item *item;
int pulling_head = 0;
+ unsigned char sha1[20];
if (len < 43 || line[40] != '\t')
return 1;
@@ -71,14 +113,15 @@ static int handle_line(char *line)
if (line[41] != '\t')
return 2;
- line[40] = 0;
- origin_data = xcalloc(1, sizeof(struct origin_data));
- i = get_sha1(line, origin_data->sha1);
- line[40] = '\t';
- if (i) {
- free(origin_data);
+ i = get_sha1_hex(line, sha1);
+ if (i)
return 3;
- }
+
+ if (!find_merge_parent(merge_parents, sha1, NULL))
+ return 0; /* subsumed by other parents */
+
+ origin_data = xcalloc(1, sizeof(struct origin_data));
+ hashcpy(origin_data->sha1, sha1);
if (line[len - 1] == '\n')
line[len - 1] = 0;
@@ -313,7 +356,10 @@ static void fmt_tag_signature(struct strbuf *tagbuf,
strbuf_add(tagbuf, tag_body, buf + len - tag_body);
}
strbuf_complete_line(tagbuf);
- strbuf_add_lines(tagbuf, "# ", sig->buf, sig->len);
+ if (sig->len) {
+ strbuf_addch(tagbuf, '\n');
+ strbuf_add_lines(tagbuf, "# ", sig->buf, sig->len);
+ }
}
static void fmt_merge_msg_sigs(struct strbuf *out)
@@ -366,6 +412,67 @@ static void fmt_merge_msg_sigs(struct strbuf *out)
strbuf_release(&tagbuf);
}
+static void find_merge_parents(struct merge_parents *result,
+ struct strbuf *in, unsigned char *head)
+{
+ struct commit_list *parents, *next;
+ struct commit *head_commit;
+ int pos = 0, i, j;
+
+ parents = NULL;
+ while (pos < in->len) {
+ int len;
+ char *p = in->buf + pos;
+ char *newline = strchr(p, '\n');
+ unsigned char sha1[20];
+ struct commit *parent;
+ struct object *obj;
+
+ len = newline ? newline - p : strlen(p);
+ pos += len + !!newline;
+
+ if (len < 43 ||
+ get_sha1_hex(p, sha1) ||
+ p[40] != '\t' ||
+ p[41] != '\t')
+ continue; /* skip not-for-merge */
+ /*
+ * Do not use get_merge_parent() here; we do not have
+ * "name" here and we do not want to contaminate its
+ * util field yet.
+ */
+ obj = parse_object(sha1);
+ parent = (struct commit *)peel_to_type(NULL, 0, obj, OBJ_COMMIT);
+ if (!parent)
+ continue;
+ commit_list_insert(parent, &parents);
+ add_merge_parent(result, obj->sha1, parent->object.sha1);
+ }
+ head_commit = lookup_commit(head);
+ if (head_commit)
+ commit_list_insert(head_commit, &parents);
+ parents = reduce_heads(parents);
+
+ while (parents) {
+ for (i = 0; i < result->nr; i++)
+ if (!hashcmp(result->item[i].commit,
+ parents->item->object.sha1))
+ result->item[i].used = 1;
+ next = parents->next;
+ free(parents);
+ parents = next;
+ }
+
+ for (i = j = 0; i < result->nr; i++) {
+ if (result->item[i].used) {
+ if (i != j)
+ result->item[j] = result->item[i];
+ j++;
+ }
+ }
+ result->nr = j;
+}
+
int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
struct fmt_merge_msg_opts *opts)
{
@@ -373,6 +480,9 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
unsigned char head_sha1[20];
const char *current_branch;
void *current_branch_to_free;
+ struct merge_parents merge_parents;
+
+ memset(&merge_parents, 0, sizeof(merge_parents));
/* get current branch */
current_branch = current_branch_to_free =
@@ -382,6 +492,8 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
if (!prefixcmp(current_branch, "refs/heads/"))
current_branch += 11;
+ find_merge_parents(&merge_parents, in, head_sha1);
+
/* get a line */
while (pos < in->len) {
int len;
@@ -392,7 +504,7 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
pos += len + !!newline;
i++;
p[len] = 0;
- if (handle_line(p))
+ if (handle_line(p, &merge_parents))
die ("Error in line %d: %.*s", i, len, p);
}
@@ -412,8 +524,7 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
rev.ignore_merges = 1;
rev.limited = 1;
- if (suffixcmp(out->buf, "\n"))
- strbuf_addch(out, '\n');
+ strbuf_complete_line(out);
for (i = 0; i < origins.nr; i++)
shortlog(origins.items[i].string,
@@ -423,6 +534,7 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
strbuf_complete_line(out);
free(current_branch_to_free);
+ free(merge_parents.item);
return 0;
}
diff --git a/builtin/fsck.c b/builtin/fsck.c
index 8c479a791b..67eb553c7d 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -29,6 +29,7 @@ static int errors_found;
static int write_lost_and_found;
static int verbose;
static int show_progress = -1;
+static int show_dangling = 1;
#define ERROR_OBJECT 01
#define ERROR_REACHABLE 02
#define ERROR_PACK 04
@@ -221,8 +222,9 @@ static void check_unreachable_object(struct object *obj)
* start looking at, for example.
*/
if (!obj->used) {
- printf("dangling %s %s\n", typename(obj->type),
- sha1_to_hex(obj->sha1));
+ if (show_dangling)
+ printf("dangling %s %s\n", typename(obj->type),
+ sha1_to_hex(obj->sha1));
if (write_lost_and_found) {
char *filename = git_path("lost-found/%s/%s",
obj->type == OBJ_COMMIT ? "commit" : "other",
@@ -614,6 +616,7 @@ static char const * const fsck_usage[] = {
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"),
diff --git a/builtin/gc.c b/builtin/gc.c
index 271376d82b..9b4232c8f3 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -14,6 +14,7 @@
#include "cache.h"
#include "parse-options.h"
#include "run-command.h"
+#include "argv-array.h"
#define FAILED_RUN "failed to run %s"
@@ -28,12 +29,11 @@ static int gc_auto_threshold = 6700;
static int gc_auto_pack_limit = 50;
static const char *prune_expire = "2.weeks.ago";
-#define MAX_ADD 10
-static const char *argv_pack_refs[] = {"pack-refs", "--all", "--prune", NULL};
-static const char *argv_reflog[] = {"reflog", "expire", "--all", NULL};
-static const char *argv_repack[MAX_ADD] = {"repack", "-d", "-l", NULL};
-static const char *argv_prune[] = {"prune", "--expire", NULL, NULL, NULL};
-static const char *argv_rerere[] = {"rerere", "gc", NULL};
+static struct argv_array pack_refs_cmd = ARGV_ARRAY_INIT;
+static struct argv_array reflog = ARGV_ARRAY_INIT;
+static struct argv_array repack = ARGV_ARRAY_INIT;
+static struct argv_array prune = ARGV_ARRAY_INIT;
+static struct argv_array rerere = ARGV_ARRAY_INIT;
static int gc_config(const char *var, const char *value, void *cb)
{
@@ -67,19 +67,6 @@ static int gc_config(const char *var, const char *value, void *cb)
return git_default_config(var, value, cb);
}
-static void append_option(const char **cmd, const char *opt, int max_length)
-{
- int i;
-
- for (i = 0; cmd[i]; i++)
- ;
-
- if (i + 2 >= max_length)
- die(_("Too many options specified"));
- cmd[i++] = opt;
- cmd[i] = NULL;
-}
-
static int too_many_loose_objects(void)
{
/*
@@ -144,6 +131,17 @@ static int too_many_packs(void)
return gc_auto_pack_limit <= cnt;
}
+static void add_repack_all_option(void)
+{
+ if (prune_expire && !strcmp(prune_expire, "now"))
+ argv_array_push(&repack, "-a");
+ else {
+ argv_array_push(&repack, "-A");
+ if (prune_expire)
+ argv_array_pushf(&repack, "--unpack-unreachable=%s", prune_expire);
+ }
+}
+
static int need_to_gc(void)
{
/*
@@ -160,10 +158,7 @@ static int need_to_gc(void)
* there is no need.
*/
if (too_many_packs())
- append_option(argv_repack,
- prune_expire && !strcmp(prune_expire, "now") ?
- "-a" : "-A",
- MAX_ADD);
+ add_repack_all_option();
else if (!too_many_loose_objects())
return 0;
@@ -177,7 +172,6 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
int aggressive = 0;
int auto_gc = 0;
int quiet = 0;
- char buf[80];
struct option builtin_gc_options[] = {
OPT__QUIET(&quiet, "suppress progress reporting"),
@@ -192,6 +186,12 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
if (argc == 2 && !strcmp(argv[1], "-h"))
usage_with_options(builtin_gc_usage, builtin_gc_options);
+ argv_array_pushl(&pack_refs_cmd, "pack-refs", "--all", "--prune", NULL);
+ argv_array_pushl(&reflog, "reflog", "expire", "--all", NULL);
+ argv_array_pushl(&repack, "repack", "-d", "-l", NULL);
+ argv_array_pushl(&prune, "prune", "--expire", NULL );
+ argv_array_pushl(&rerere, "rerere", "gc", NULL);
+
git_config(gc_config, NULL);
if (pack_refs < 0)
@@ -203,15 +203,13 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
usage_with_options(builtin_gc_usage, builtin_gc_options);
if (aggressive) {
- append_option(argv_repack, "-f", MAX_ADD);
- append_option(argv_repack, "--depth=250", MAX_ADD);
- if (aggressive_window > 0) {
- sprintf(buf, "--window=%d", aggressive_window);
- append_option(argv_repack, buf, MAX_ADD);
- }
+ argv_array_push(&repack, "-f");
+ argv_array_push(&repack, "--depth=250");
+ if (aggressive_window > 0)
+ argv_array_pushf(&repack, "--window=%d", aggressive_window);
}
if (quiet)
- append_option(argv_repack, "-q", MAX_ADD);
+ argv_array_push(&repack, "-q");
if (auto_gc) {
/*
@@ -227,30 +225,27 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
"run \"git gc\" manually. See "
"\"git help gc\" for more information.\n"));
} else
- append_option(argv_repack,
- prune_expire && !strcmp(prune_expire, "now")
- ? "-a" : "-A",
- MAX_ADD);
+ add_repack_all_option();
- if (pack_refs && run_command_v_opt(argv_pack_refs, RUN_GIT_CMD))
- return error(FAILED_RUN, argv_pack_refs[0]);
+ if (pack_refs && run_command_v_opt(pack_refs_cmd.argv, RUN_GIT_CMD))
+ return error(FAILED_RUN, pack_refs_cmd.argv[0]);
- if (run_command_v_opt(argv_reflog, RUN_GIT_CMD))
- return error(FAILED_RUN, argv_reflog[0]);
+ if (run_command_v_opt(reflog.argv, RUN_GIT_CMD))
+ return error(FAILED_RUN, reflog.argv[0]);
- if (run_command_v_opt(argv_repack, RUN_GIT_CMD))
- return error(FAILED_RUN, argv_repack[0]);
+ if (run_command_v_opt(repack.argv, RUN_GIT_CMD))
+ return error(FAILED_RUN, repack.argv[0]);
if (prune_expire) {
- argv_prune[2] = prune_expire;
+ argv_array_push(&prune, prune_expire);
if (quiet)
- argv_prune[3] = "--no-progress";
- if (run_command_v_opt(argv_prune, RUN_GIT_CMD))
- return error(FAILED_RUN, argv_prune[0]);
+ argv_array_push(&prune, "--no-progress");
+ if (run_command_v_opt(prune.argv, RUN_GIT_CMD))
+ return error(FAILED_RUN, prune.argv[0]);
}
- if (run_command_v_opt(argv_rerere, RUN_GIT_CMD))
- return error(FAILED_RUN, argv_rerere[0]);
+ if (run_command_v_opt(rerere.argv, RUN_GIT_CMD))
+ return error(FAILED_RUN, rerere.argv[0]);
if (auto_gc && too_many_loose_objects())
warning(_("There are too many unreachable loose objects; "
diff --git a/builtin/grep.c b/builtin/grep.c
index 9fc3e95cc6..643938d905 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -265,11 +265,8 @@ static int grep_config(const char *var, const char *value, void *cb)
struct grep_opt *opt = cb;
char *color = NULL;
- switch (userdiff_config(var, value)) {
- case 0: break;
- case -1: return -1;
- default: return 0;
- }
+ if (userdiff_config(var, value) < 0)
+ return -1;
if (!strcmp(var, "grep.extendedregexp")) {
if (git_config_bool(var, value))
@@ -687,9 +684,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
struct option options[] = {
OPT_BOOLEAN(0, "cached", &cached,
"search in index instead of in the work tree"),
- { OPTION_BOOLEAN, 0, "index", &use_index, NULL,
- "finds in contents not managed by git",
- PARSE_OPT_NOARG | PARSE_OPT_NEGHELP },
+ OPT_NEGBIT(0, "no-index", &use_index,
+ "finds in contents not managed by git", 1),
OPT_BOOLEAN(0, "untracked", &untracked,
"search in both tracked and untracked files"),
OPT_SET_INT(0, "exclude-standard", &opt_exclude,
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index af7dc37a44..dd1c5c961d 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -34,6 +34,8 @@ struct base_data {
struct object_entry *obj;
void *data;
unsigned long size;
+ int ref_first, ref_last;
+ int ofs_first, ofs_last;
};
/*
@@ -221,6 +223,15 @@ static NORETURN void bad_object(unsigned long offset, const char *format, ...)
die("pack has bad object at offset %lu: %s", offset, buf);
}
+static struct base_data *alloc_base_data(void)
+{
+ struct base_data *base = xmalloc(sizeof(struct base_data));
+ memset(base, 0, sizeof(*base));
+ base->ref_last = -1;
+ base->ofs_last = -1;
+ return base;
+}
+
static void free_base_data(struct base_data *c)
{
if (c->data) {
@@ -504,14 +515,52 @@ static int is_delta_type(enum object_type type)
return (type == OBJ_REF_DELTA || type == OBJ_OFS_DELTA);
}
+/*
+ * This function is part of find_unresolved_deltas(). There are two
+ * walkers going in the opposite ways.
+ *
+ * The first one in find_unresolved_deltas() traverses down from
+ * parent node to children, deflating nodes along the way. However,
+ * memory for deflated nodes is limited by delta_base_cache_limit, so
+ * at some point parent node's deflated content may be freed.
+ *
+ * The second walker is this function, which goes from current node up
+ * to top parent if necessary to deflate the node. In normal
+ * situation, its parent node would be already deflated, so it just
+ * needs to apply delta.
+ *
+ * In the worst case scenario, parent node is no longer deflated because
+ * we're running out of delta_base_cache_limit; we need to re-deflate
+ * parents, possibly up to the top base.
+ *
+ * All deflated objects here are subject to be freed if we exceed
+ * delta_base_cache_limit, just like in find_unresolved_deltas(), we
+ * just need to make sure the last node is not freed.
+ */
static void *get_base_data(struct base_data *c)
{
if (!c->data) {
struct object_entry *obj = c->obj;
+ struct base_data **delta = NULL;
+ int delta_nr = 0, delta_alloc = 0;
- if (is_delta_type(obj->type)) {
- void *base = get_base_data(c->base);
- void *raw = get_data_from_pack(obj);
+ while (is_delta_type(c->obj->type) && !c->data) {
+ ALLOC_GROW(delta, delta_nr + 1, delta_alloc);
+ delta[delta_nr++] = c;
+ c = c->base;
+ }
+ if (!delta_nr) {
+ c->data = get_data_from_pack(obj);
+ c->size = obj->size;
+ base_cache_used += c->size;
+ prune_base_data(c);
+ }
+ for (; delta_nr > 0; delta_nr--) {
+ void *base, *raw;
+ c = delta[delta_nr - 1];
+ obj = c->obj;
+ base = get_base_data(c->base);
+ raw = get_data_from_pack(obj);
c->data = patch_delta(
base, c->base->size,
raw, obj->size,
@@ -519,13 +568,10 @@ static void *get_base_data(struct base_data *c)
free(raw);
if (!c->data)
bad_object(obj->idx.offset, "failed to apply delta");
- } else {
- c->data = get_data_from_pack(obj);
- c->size = obj->size;
+ base_cache_used += c->size;
+ prune_base_data(c);
}
-
- base_cache_used += c->size;
- prune_base_data(c);
+ free(delta);
}
return c->data;
}
@@ -553,58 +599,76 @@ static void resolve_delta(struct object_entry *delta_obj,
nr_resolved_deltas++;
}
-static void find_unresolved_deltas(struct base_data *base,
- struct base_data *prev_base)
+static struct base_data *find_unresolved_deltas_1(struct base_data *base,
+ struct base_data *prev_base)
{
- int i, ref_first, ref_last, ofs_first, ofs_last;
-
- /*
- * This is a recursive function. Those brackets should help reducing
- * stack usage by limiting the scope of the delta_base union.
- */
- {
+ if (base->ref_last == -1 && base->ofs_last == -1) {
union delta_base base_spec;
hashcpy(base_spec.sha1, base->obj->idx.sha1);
find_delta_children(&base_spec,
- &ref_first, &ref_last, OBJ_REF_DELTA);
+ &base->ref_first, &base->ref_last, OBJ_REF_DELTA);
memset(&base_spec, 0, sizeof(base_spec));
base_spec.offset = base->obj->idx.offset;
find_delta_children(&base_spec,
- &ofs_first, &ofs_last, OBJ_OFS_DELTA);
- }
+ &base->ofs_first, &base->ofs_last, OBJ_OFS_DELTA);
- if (ref_last == -1 && ofs_last == -1) {
- free(base->data);
- return;
- }
+ if (base->ref_last == -1 && base->ofs_last == -1) {
+ free(base->data);
+ return NULL;
+ }
- link_base_data(prev_base, base);
+ link_base_data(prev_base, base);
+ }
- for (i = ref_first; i <= ref_last; i++) {
- struct object_entry *child = objects + deltas[i].obj_no;
- struct base_data result;
+ if (base->ref_first <= base->ref_last) {
+ struct object_entry *child = objects + deltas[base->ref_first].obj_no;
+ struct base_data *result = alloc_base_data();
assert(child->real_type == OBJ_REF_DELTA);
- resolve_delta(child, base, &result);
- if (i == ref_last && ofs_last == -1)
+ resolve_delta(child, base, result);
+ if (base->ref_first == base->ref_last && base->ofs_last == -1)
free_base_data(base);
- find_unresolved_deltas(&result, base);
+
+ base->ref_first++;
+ return result;
}
- for (i = ofs_first; i <= ofs_last; i++) {
- struct object_entry *child = objects + deltas[i].obj_no;
- struct base_data result;
+ if (base->ofs_first <= base->ofs_last) {
+ struct object_entry *child = objects + deltas[base->ofs_first].obj_no;
+ struct base_data *result = alloc_base_data();
assert(child->real_type == OBJ_OFS_DELTA);
- resolve_delta(child, base, &result);
- if (i == ofs_last)
+ resolve_delta(child, base, result);
+ if (base->ofs_first == base->ofs_last)
free_base_data(base);
- find_unresolved_deltas(&result, base);
+
+ base->ofs_first++;
+ return result;
}
unlink_base_data(base);
+ return NULL;
+}
+
+static void find_unresolved_deltas(struct base_data *base)
+{
+ struct base_data *new_base, *prev_base = NULL;
+ for (;;) {
+ new_base = find_unresolved_deltas_1(base, prev_base);
+
+ if (new_base) {
+ prev_base = base;
+ base = new_base;
+ } else {
+ free(base);
+ base = prev_base;
+ if (!base)
+ return;
+ prev_base = base->base;
+ }
+ }
}
static int compare_delta_entry(const void *a, const void *b)
@@ -684,13 +748,13 @@ static void parse_pack_objects(unsigned char *sha1)
progress = start_progress("Resolving deltas", nr_deltas);
for (i = 0; i < nr_objects; i++) {
struct object_entry *obj = &objects[i];
- struct base_data base_obj;
+ struct base_data *base_obj = alloc_base_data();
if (is_delta_type(obj->type))
continue;
- base_obj.obj = obj;
- base_obj.data = NULL;
- find_unresolved_deltas(&base_obj, NULL);
+ base_obj->obj = obj;
+ base_obj->data = NULL;
+ find_unresolved_deltas(base_obj);
display_progress(progress, nr_resolved_deltas);
}
}
@@ -783,20 +847,20 @@ static void fix_unresolved_deltas(struct sha1file *f, int nr_unresolved)
for (i = 0; i < n; i++) {
struct delta_entry *d = sorted_by_pos[i];
enum object_type type;
- struct base_data base_obj;
+ struct base_data *base_obj = alloc_base_data();
if (objects[d->obj_no].real_type != OBJ_REF_DELTA)
continue;
- base_obj.data = read_sha1_file(d->base.sha1, &type, &base_obj.size);
- if (!base_obj.data)
+ base_obj->data = read_sha1_file(d->base.sha1, &type, &base_obj->size);
+ if (!base_obj->data)
continue;
- if (check_sha1_signature(d->base.sha1, base_obj.data,
- base_obj.size, typename(type)))
+ if (check_sha1_signature(d->base.sha1, base_obj->data,
+ base_obj->size, typename(type)))
die("local object %s is corrupt", sha1_to_hex(d->base.sha1));
- base_obj.obj = append_obj_to_pack(f, d->base.sha1,
- base_obj.data, base_obj.size, type);
- find_unresolved_deltas(&base_obj, NULL);
+ base_obj->obj = append_obj_to_pack(f, d->base.sha1,
+ base_obj->data, base_obj->size, type);
+ find_unresolved_deltas(base_obj);
display_progress(progress, nr_resolved_deltas);
}
free(sorted_by_pos);
diff --git a/builtin/log.c b/builtin/log.c
index 7d1f6f88a0..8a47012b0b 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -77,6 +77,8 @@ static void cmd_log_init_defaults(struct rev_info *rev)
get_commit_format(fmt_pretty, rev);
rev->verbose_header = 1;
DIFF_OPT_SET(&rev->diffopt, RECURSIVE);
+ rev->diffopt.stat_width = -1; /* use full terminal width */
+ rev->diffopt.stat_graph_width = -1; /* respect statGraphWidth config */
rev->abbrev_commit = default_abbrev_commit;
rev->show_root_diff = default_show_root;
rev->subject_prefix = fmt_patch_subject_prefix;
@@ -447,6 +449,8 @@ int cmd_show(int argc, const char **argv, const char *prefix)
rev.diff = 1;
rev.always_show_header = 1;
rev.no_walk = 1;
+ rev.diffopt.stat_width = -1; /* Scale to real terminal size */
+
memset(&opt, 0, sizeof(opt));
opt.def = "HEAD";
opt.tweak = show_rev_tweak_rev;
diff --git a/builtin/mailinfo.c b/builtin/mailinfo.c
index bfb32b7233..eaf9e157a3 100644
--- a/builtin/mailinfo.c
+++ b/builtin/mailinfo.c
@@ -250,8 +250,17 @@ static void cleanup_subject(struct strbuf *subject)
(7 <= remove &&
memmem(subject->buf + at, remove, "PATCH", 5)))
strbuf_remove(subject, at, remove);
- else
+ else {
at += remove;
+ /*
+ * If the input had a space after the ], keep
+ * it. We don't bother with finding the end of
+ * the space, since we later normalize it
+ * anyway.
+ */
+ if (isspace(subject->buf[at]))
+ at += 1;
+ }
continue;
}
break;
diff --git a/builtin/merge.c b/builtin/merge.c
index 5126443fdf..470fc57c5d 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -52,7 +52,6 @@ static int fast_forward_only, option_edit = -1;
static int allow_trivial = 1, have_message;
static int overwrite_ignore = 1;
static struct strbuf merge_msg = STRBUF_INIT;
-static struct commit_list *remoteheads;
static struct strategy **use_strategies;
static size_t use_strategies_nr, use_strategies_alloc;
static const char **xopts;
@@ -318,7 +317,7 @@ static void finish_up_to_date(const char *msg)
drop_save();
}
-static void squash_message(struct commit *commit)
+static void squash_message(struct commit *commit, struct commit_list *remoteheads)
{
struct rev_info rev;
struct strbuf out = STRBUF_INIT;
@@ -366,6 +365,7 @@ static void squash_message(struct commit *commit)
}
static void finish(struct commit *head_commit,
+ struct commit_list *remoteheads,
const unsigned char *new_head, const char *msg)
{
struct strbuf reflog_message = STRBUF_INIT;
@@ -380,7 +380,7 @@ static void finish(struct commit *head_commit,
getenv("GIT_REFLOG_ACTION"), msg);
}
if (squash) {
- squash_message(head_commit);
+ squash_message(head_commit, remoteheads);
} else {
if (verbosity >= 0 && !merge_msg.len)
printf(_("No merge message -- not updating HEAD\n"));
@@ -399,6 +399,8 @@ static void finish(struct commit *head_commit,
if (new_head && show_diffstat) {
struct diff_options opts;
diff_setup(&opts);
+ opts.stat_width = -1; /* use full terminal width */
+ opts.stat_graph_width = -1; /* respect statGraphWidth config */
opts.output_format |=
DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
opts.detect_rename = DIFF_DETECT_RENAME;
@@ -681,6 +683,7 @@ int try_merge_command(const char *strategy, size_t xopts_nr,
}
static int try_merge_strategy(const char *strategy, struct commit_list *common,
+ struct commit_list *remoteheads,
struct commit *head, const char *head_arg)
{
int index_fd;
@@ -874,14 +877,14 @@ static void read_merge_msg(struct strbuf *msg)
die_errno(_("Could not read from '%s'"), filename);
}
-static void write_merge_state(void);
-static void abort_commit(const char *err_msg)
+static void write_merge_state(struct commit_list *);
+static void abort_commit(struct commit_list *remoteheads, const char *err_msg)
{
if (err_msg)
error("%s", err_msg);
fprintf(stderr,
_("Not committing merge; use 'git commit' to complete the merge.\n"));
- write_merge_state();
+ write_merge_state(remoteheads);
exit(1);
}
@@ -892,7 +895,7 @@ N_("Please enter a commit message to explain why this merge is necessary,\n"
"Lines starting with '#' will be ignored, and an empty message aborts\n"
"the commit.\n");
-static void prepare_to_commit(void)
+static void prepare_to_commit(struct commit_list *remoteheads)
{
struct strbuf msg = STRBUF_INIT;
const char *comment = _(merge_editor_comment);
@@ -903,20 +906,20 @@ static void prepare_to_commit(void)
write_merge_msg(&msg);
run_hook(get_index_file(), "prepare-commit-msg",
git_path("MERGE_MSG"), "merge", NULL, NULL);
- if (option_edit) {
+ if (0 < option_edit) {
if (launch_editor(git_path("MERGE_MSG"), NULL, NULL))
- abort_commit(NULL);
+ abort_commit(remoteheads, NULL);
}
read_merge_msg(&msg);
- stripspace(&msg, option_edit);
+ stripspace(&msg, 0 < option_edit);
if (!msg.len)
- abort_commit(_("Empty commit message."));
+ abort_commit(remoteheads, _("Empty commit message."));
strbuf_release(&merge_msg);
strbuf_addbuf(&merge_msg, &msg);
strbuf_release(&msg);
}
-static int merge_trivial(struct commit *head)
+static int merge_trivial(struct commit *head, struct commit_list *remoteheads)
{
unsigned char result_tree[20], result_commit[20];
struct commit_list *parent = xmalloc(sizeof(*parent));
@@ -927,45 +930,37 @@ static int merge_trivial(struct commit *head)
parent->next = xmalloc(sizeof(*parent->next));
parent->next->item = remoteheads->item;
parent->next->next = NULL;
- prepare_to_commit();
+ prepare_to_commit(remoteheads);
if (commit_tree(&merge_msg, result_tree, parent, result_commit, NULL,
sign_commit))
die(_("failed to write commit object"));
- finish(head, result_commit, "In-index merge");
+ finish(head, remoteheads, result_commit, "In-index merge");
drop_save();
return 0;
}
static int finish_automerge(struct commit *head,
+ int head_subsumed,
struct commit_list *common,
+ struct commit_list *remoteheads,
unsigned char *result_tree,
const char *wt_strategy)
{
- struct commit_list *parents = NULL, *j;
+ struct commit_list *parents = NULL;
struct strbuf buf = STRBUF_INIT;
unsigned char result_commit[20];
free_commit_list(common);
- if (allow_fast_forward) {
- parents = remoteheads;
+ parents = remoteheads;
+ if (!head_subsumed || !allow_fast_forward)
commit_list_insert(head, &parents);
- parents = reduce_heads(parents);
- } else {
- struct commit_list **pptr = &parents;
-
- pptr = &commit_list_insert(head,
- pptr)->next;
- for (j = remoteheads; j; j = j->next)
- pptr = &commit_list_insert(j->item, pptr)->next;
- }
strbuf_addch(&merge_msg, '\n');
- prepare_to_commit();
- free_commit_list(remoteheads);
+ prepare_to_commit(remoteheads);
if (commit_tree(&merge_msg, result_tree, parents, result_commit,
NULL, sign_commit))
die(_("failed to write commit object"));
strbuf_addf(&buf, "Merge made by the '%s' strategy.", wt_strategy);
- finish(head, result_commit, buf.buf);
+ finish(head, remoteheads, result_commit, buf.buf);
strbuf_release(&buf);
drop_save();
return 0;
@@ -1070,7 +1065,7 @@ static int setup_with_upstream(const char ***argv)
return i;
}
-static void write_merge_state(void)
+static void write_merge_state(struct commit_list *remoteheads)
{
const char *filename;
int fd;
@@ -1135,6 +1130,39 @@ static int default_edit_option(void)
st_stdin.st_mode == st_stdout.st_mode);
}
+static struct commit_list *collect_parents(struct commit *head_commit,
+ int *head_subsumed,
+ int argc, const char **argv)
+{
+ int i;
+ struct commit_list *remoteheads = NULL, *parents, *next;
+ struct commit_list **remotes = &remoteheads;
+
+ if (head_commit)
+ remotes = &commit_list_insert(head_commit, remotes)->next;
+ for (i = 0; i < argc; i++) {
+ struct commit *commit = get_merge_parent(argv[i]);
+ if (!commit)
+ die(_("%s - not something we can merge"), argv[i]);
+ remotes = &commit_list_insert(commit, remotes)->next;
+ }
+ *remotes = NULL;
+
+ parents = reduce_heads(remoteheads);
+
+ *head_subsumed = 1; /* we will flip this to 0 when we find it */
+ for (remoteheads = NULL, remotes = &remoteheads;
+ parents;
+ parents = next) {
+ struct commit *commit = parents->item;
+ next = parents->next;
+ if (commit == head_commit)
+ *head_subsumed = 0;
+ else
+ remotes = &commit_list_insert(commit, remotes)->next;
+ }
+ return remoteheads;
+}
int cmd_merge(int argc, const char **argv, const char *prefix)
{
@@ -1144,11 +1172,11 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
struct commit *head_commit;
struct strbuf buf = STRBUF_INIT;
const char *head_arg;
- int flag, i, ret = 0;
+ int flag, i, ret = 0, head_subsumed;
int best_cnt = -1, merge_was_ok = 0, automerge_was_ok = 0;
struct commit_list *common = NULL;
const char *best_strategy = NULL, *wt_strategy = NULL;
- struct commit_list **remotes = &remoteheads;
+ struct commit_list *remoteheads, *p;
void *branch_to_free;
if (argc == 2 && !strcmp(argv[1], "-h"))
@@ -1253,6 +1281,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
head_arg = argv[1];
argv += 2;
argc -= 2;
+ remoteheads = collect_parents(head_commit, &head_subsumed, argc, argv);
} else if (!head_commit) {
struct commit *remote_head;
/*
@@ -1268,7 +1297,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
if (!allow_fast_forward)
die(_("Non-fast-forward commit does not make sense into "
"an empty head"));
- remote_head = get_merge_parent(argv[0]);
+ remoteheads = collect_parents(head_commit, &head_subsumed, argc, argv);
+ remote_head = remoteheads->item;
if (!remote_head)
die(_("%s - not something we can merge"), argv[0]);
read_empty(remote_head->object.sha1, 0);
@@ -1286,8 +1316,9 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
* the standard merge summary message to be appended
* to the given message.
*/
- for (i = 0; i < argc; i++)
- merge_name(argv[i], &merge_names);
+ remoteheads = collect_parents(head_commit, &head_subsumed, argc, argv);
+ for (p = remoteheads; p; p = p->next)
+ merge_name(merge_remote_util(p->item)->name, &merge_names);
if (!have_message || shortlog_len) {
struct fmt_merge_msg_opts opts;
@@ -1306,35 +1337,31 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
builtin_merge_options);
strbuf_addstr(&buf, "merge");
- for (i = 0; i < argc; i++)
- strbuf_addf(&buf, " %s", argv[i]);
+ for (p = remoteheads; p; p = p->next)
+ strbuf_addf(&buf, " %s", merge_remote_util(p->item)->name);
setenv("GIT_REFLOG_ACTION", buf.buf, 0);
strbuf_reset(&buf);
- for (i = 0; i < argc; i++) {
- struct commit *commit = get_merge_parent(argv[i]);
- if (!commit)
- die(_("%s - not something we can merge"), argv[i]);
- remotes = &commit_list_insert(commit, remotes)->next;
+ for (p = remoteheads; p; p = p->next) {
+ struct commit *commit = p->item;
strbuf_addf(&buf, "GITHEAD_%s",
sha1_to_hex(commit->object.sha1));
- setenv(buf.buf, argv[i], 1);
+ setenv(buf.buf, merge_remote_util(commit)->name, 1);
strbuf_reset(&buf);
if (!fast_forward_only &&
merge_remote_util(commit) &&
merge_remote_util(commit)->obj &&
- merge_remote_util(commit)->obj->type == OBJ_TAG) {
- if (option_edit < 0)
- option_edit = default_edit_option();
+ merge_remote_util(commit)->obj->type == OBJ_TAG)
allow_fast_forward = 0;
- }
}
if (option_edit < 0)
- option_edit = 0;
+ option_edit = default_edit_option();
if (!use_strategies) {
- if (!remoteheads->next)
+ if (!remoteheads)
+ ; /* already up-to-date */
+ else if (!remoteheads->next)
add_strategies(pull_twohead, DEFAULT_TWOHEAD);
else
add_strategies(pull_octopus, DEFAULT_OCTOPUS);
@@ -1347,7 +1374,9 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
allow_trivial = 0;
}
- if (!remoteheads->next)
+ if (!remoteheads)
+ ; /* already up-to-date */
+ else if (!remoteheads->next)
common = get_merge_bases(head_commit, remoteheads->item, 1);
else {
struct commit_list *list = remoteheads;
@@ -1359,10 +1388,11 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
update_ref("updating ORIG_HEAD", "ORIG_HEAD", head_commit->object.sha1,
NULL, 0, DIE_ON_ERR);
- if (!common)
+ if (remoteheads && !common)
; /* No common ancestors found. We need a real merge. */
- else if (!remoteheads->next && !common->next &&
- common->item == remoteheads->item) {
+ else if (!remoteheads ||
+ (!remoteheads->next && !common->next &&
+ common->item == remoteheads->item)) {
/*
* If head can reach all the merge then we are up to date.
* but first the most common case of merging one remote.
@@ -1400,7 +1430,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
goto done;
}
- finish(head_commit, commit->object.sha1, msg.buf);
+ finish(head_commit, remoteheads, commit->object.sha1, msg.buf);
drop_save();
goto done;
} else if (!remoteheads->next && common->next)
@@ -1422,7 +1452,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
if (!read_tree_trivial(common->item->object.sha1,
head_commit->object.sha1,
remoteheads->item->object.sha1)) {
- ret = merge_trivial(head_commit);
+ ret = merge_trivial(head_commit, remoteheads);
goto done;
}
printf(_("Nope.\n"));
@@ -1493,7 +1523,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
wt_strategy = use_strategies[i]->name;
ret = try_merge_strategy(use_strategies[i]->name,
- common, head_commit, head_arg);
+ common, remoteheads,
+ head_commit, head_arg);
if (!option_commit && !ret) {
merge_was_ok = 1;
/*
@@ -1535,8 +1566,9 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
* auto resolved the merge cleanly.
*/
if (automerge_was_ok) {
- ret = finish_automerge(head_commit, common, result_tree,
- wt_strategy);
+ ret = finish_automerge(head_commit, head_subsumed,
+ common, remoteheads,
+ result_tree, wt_strategy);
goto done;
}
@@ -1561,13 +1593,14 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
restore_state(head_commit->object.sha1, stash);
printf(_("Using the %s to prepare resolving by hand.\n"),
best_strategy);
- try_merge_strategy(best_strategy, common, head_commit, head_arg);
+ try_merge_strategy(best_strategy, common, remoteheads,
+ head_commit, head_arg);
}
if (squash)
- finish(head_commit, NULL, NULL);
+ finish(head_commit, remoteheads, NULL, NULL);
else
- write_merge_state();
+ write_merge_state(remoteheads);
if (merge_was_ok)
fprintf(stderr, _("Automatic merge went well; "
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 0f2e7b8f5c..1861093e9d 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -18,16 +18,11 @@
#include "refs.h"
#include "thread-utils.h"
-static const char pack_usage[] =
- "git pack-objects [ -q | --progress | --all-progress ]\n"
- " [--all-progress-implied]\n"
- " [--max-pack-size=<n>] [--local] [--incremental]\n"
- " [--window=<n>] [--window-memory=<n>] [--depth=<n>]\n"
- " [--no-reuse-delta] [--no-reuse-object] [--delta-base-offset]\n"
- " [--threads=<n>] [--non-empty] [--revs [--unpacked | --all]]\n"
- " [--reflog] [--stdout | base-name] [--include-tag]\n"
- " [--keep-unreachable | --unpack-unreachable]\n"
- " [< ref-list | < object-list]";
+static const char *pack_usage[] = {
+ "git pack-objects --stdout [options...] [< ref-list | < object-list]",
+ "git pack-objects [options...] base-name [< ref-list | < object-list]",
+ NULL
+};
struct object_entry {
struct pack_idx_entry idx;
@@ -68,6 +63,7 @@ static uint32_t nr_objects, nr_alloc, nr_result, nr_written;
static int non_empty;
static int reuse_delta = 1, reuse_object = 1;
static int keep_unreachable, unpack_unreachable, include_tag;
+static unsigned long unpack_unreachable_expiration;
static int local;
static int incremental;
static int ignore_packed_keep;
@@ -2254,6 +2250,10 @@ static void loosen_unused_packed_objects(struct rev_info *revs)
if (!p->pack_local || p->pack_keep)
continue;
+ if (unpack_unreachable_expiration &&
+ p->mtime < unpack_unreachable_expiration)
+ continue;
+
if (open_pack_index(p))
die("cannot open pack index");
@@ -2305,204 +2305,175 @@ static void get_object_list(int ac, const char **av)
loosen_unused_packed_objects(&revs);
}
+static int option_parse_index_version(const struct option *opt,
+ const char *arg, int unset)
+{
+ char *c;
+ const char *val = arg;
+ pack_idx_opts.version = strtoul(val, &c, 10);
+ if (pack_idx_opts.version > 2)
+ die(_("unsupported index version %s"), val);
+ if (*c == ',' && c[1])
+ pack_idx_opts.off32_limit = strtoul(c+1, &c, 0);
+ if (*c || pack_idx_opts.off32_limit & 0x80000000)
+ die(_("bad index version '%s'"), val);
+ return 0;
+}
+
+static int option_parse_unpack_unreachable(const struct option *opt,
+ const char *arg, int unset)
+{
+ if (unset) {
+ unpack_unreachable = 0;
+ unpack_unreachable_expiration = 0;
+ }
+ else {
+ unpack_unreachable = 1;
+ if (arg)
+ unpack_unreachable_expiration = approxidate(arg);
+ }
+ return 0;
+}
+
+static int option_parse_ulong(const struct option *opt,
+ const char *arg, int unset)
+{
+ if (unset)
+ die(_("option %s does not accept negative form"),
+ opt->long_name);
+
+ if (!git_parse_ulong(arg, opt->value))
+ die(_("unable to parse value '%s' for option %s"),
+ arg, opt->long_name);
+ return 0;
+}
+
+#define OPT_ULONG(s, l, v, h) \
+ { OPTION_CALLBACK, (s), (l), (v), "n", (h), \
+ PARSE_OPT_NONEG, option_parse_ulong }
+
int cmd_pack_objects(int argc, const char **argv, const char *prefix)
{
int use_internal_rev_list = 0;
int thin = 0;
int all_progress_implied = 0;
- uint32_t i;
- const char **rp_av;
- int rp_ac_alloc = 64;
- int rp_ac;
+ const char *rp_av[6];
+ int rp_ac = 0;
+ 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),
+ OPT_SET_INT(0, "progress", &progress,
+ "show progress meter", 1),
+ OPT_SET_INT(0, "all-progress", &progress,
+ "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",
+ 0, option_parse_index_version },
+ OPT_ULONG(0, "max-pack-size", &pack_size_limit,
+ "maximum size of each output pack file"),
+ OPT_BOOL(0, "local", &local,
+ "ignore borrowed objects from alternate object store"),
+ OPT_BOOL(0, "incremental", &incremental,
+ "ignore packed objects"),
+ OPT_INTEGER(0, "window", &window,
+ "limit pack window by objects"),
+ OPT_ULONG(0, "window-memory", &window_memory_limit,
+ "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"),
+ OPT_BOOL(0, "reuse-delta", &reuse_delta,
+ "reuse existing deltas"),
+ OPT_BOOL(0, "reuse-object", &reuse_object,
+ "reuse existing objects"),
+ OPT_BOOL(0, "delta-base-offset", &allow_ofs_delta,
+ "use OFS_DELTA objects"),
+ OPT_INTEGER(0, "threads", &delta_search_threads,
+ "use threads when searching for best delta matches"),
+ OPT_BOOL(0, "non-empty", &non_empty,
+ "do not create an empty pack output"),
+ OPT_BOOL(0, "revs", &use_internal_rev_list,
+ "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",
+ PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 },
+ { OPTION_SET_INT, 0, "all", &rev_list_all, NULL,
+ "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",
+ PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 },
+ OPT_BOOL(0, "stdout", &pack_to_stdout,
+ "output pack to stdout"),
+ OPT_BOOL(0, "include-tag", &include_tag,
+ "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>",
+ PARSE_OPT_OPTARG, option_parse_unpack_unreachable },
+ OPT_BOOL(0, "thin", &thin,
+ "create thin packs"),
+ OPT_BOOL(0, "honor-pack-keep", &ignore_packed_keep,
+ "ignore packs that have companion .keep file"),
+ OPT_INTEGER(0, "compression", &pack_compression_level,
+ "pack compression level"),
+ OPT_SET_INT(0, "keep-true-parents", &grafts_replace_parents,
+ "do not hide commits by grafts", 0),
+ OPT_END(),
+ };
read_replace_refs = 0;
- rp_av = xcalloc(rp_ac_alloc, sizeof(*rp_av));
-
- rp_av[0] = "pack-objects";
- rp_av[1] = "--objects"; /* --thin will make it --objects-edge */
- rp_ac = 2;
-
reset_pack_idx_option(&pack_idx_opts);
git_config(git_pack_config, NULL);
if (!pack_compression_seen && core_compression_seen)
pack_compression_level = core_compression_level;
progress = isatty(2);
- for (i = 1; i < argc; i++) {
- const char *arg = argv[i];
-
- if (*arg != '-')
- break;
+ argc = parse_options(argc, argv, prefix, pack_objects_options,
+ pack_usage, 0);
- if (!strcmp("--non-empty", arg)) {
- non_empty = 1;
- continue;
- }
- if (!strcmp("--local", arg)) {
- local = 1;
- continue;
- }
- if (!strcmp("--incremental", arg)) {
- incremental = 1;
- continue;
- }
- if (!strcmp("--honor-pack-keep", arg)) {
- ignore_packed_keep = 1;
- continue;
- }
- if (!prefixcmp(arg, "--compression=")) {
- char *end;
- int level = strtoul(arg+14, &end, 0);
- if (!arg[14] || *end)
- usage(pack_usage);
- if (level == -1)
- level = Z_DEFAULT_COMPRESSION;
- else if (level < 0 || level > Z_BEST_COMPRESSION)
- die("bad pack compression level %d", level);
- pack_compression_level = level;
- continue;
- }
- if (!prefixcmp(arg, "--max-pack-size=")) {
- pack_size_limit_cfg = 0;
- if (!git_parse_ulong(arg+16, &pack_size_limit))
- usage(pack_usage);
- continue;
- }
- if (!prefixcmp(arg, "--window=")) {
- char *end;
- window = strtoul(arg+9, &end, 0);
- if (!arg[9] || *end)
- usage(pack_usage);
- continue;
- }
- if (!prefixcmp(arg, "--window-memory=")) {
- if (!git_parse_ulong(arg+16, &window_memory_limit))
- usage(pack_usage);
- continue;
- }
- if (!prefixcmp(arg, "--threads=")) {
- char *end;
- delta_search_threads = strtoul(arg+10, &end, 0);
- if (!arg[10] || *end || delta_search_threads < 0)
- usage(pack_usage);
-#ifdef NO_PTHREADS
- if (delta_search_threads != 1)
- warning("no threads support, "
- "ignoring %s", arg);
-#endif
- continue;
- }
- if (!prefixcmp(arg, "--depth=")) {
- char *end;
- depth = strtoul(arg+8, &end, 0);
- if (!arg[8] || *end)
- usage(pack_usage);
- continue;
- }
- if (!strcmp("--progress", arg)) {
- progress = 1;
- continue;
- }
- if (!strcmp("--all-progress", arg)) {
- progress = 2;
- continue;
- }
- if (!strcmp("--all-progress-implied", arg)) {
- all_progress_implied = 1;
- continue;
- }
- if (!strcmp("-q", arg)) {
- progress = 0;
- continue;
- }
- if (!strcmp("--no-reuse-delta", arg)) {
- reuse_delta = 0;
- continue;
- }
- if (!strcmp("--no-reuse-object", arg)) {
- reuse_object = reuse_delta = 0;
- continue;
- }
- if (!strcmp("--delta-base-offset", arg)) {
- allow_ofs_delta = 1;
- continue;
- }
- if (!strcmp("--stdout", arg)) {
- pack_to_stdout = 1;
- continue;
- }
- if (!strcmp("--revs", arg)) {
- use_internal_rev_list = 1;
- continue;
- }
- if (!strcmp("--keep-unreachable", arg)) {
- keep_unreachable = 1;
- continue;
- }
- if (!strcmp("--unpack-unreachable", arg)) {
- unpack_unreachable = 1;
- continue;
- }
- if (!strcmp("--include-tag", arg)) {
- include_tag = 1;
- continue;
- }
- if (!strcmp("--unpacked", arg) ||
- !strcmp("--reflog", arg) ||
- !strcmp("--all", arg)) {
- use_internal_rev_list = 1;
- if (rp_ac >= rp_ac_alloc - 1) {
- rp_ac_alloc = alloc_nr(rp_ac_alloc);
- rp_av = xrealloc(rp_av,
- rp_ac_alloc * sizeof(*rp_av));
- }
- rp_av[rp_ac++] = arg;
- continue;
- }
- if (!strcmp("--thin", arg)) {
- use_internal_rev_list = 1;
- thin = 1;
- rp_av[1] = "--objects-edge";
- continue;
- }
- if (!prefixcmp(arg, "--index-version=")) {
- char *c;
- pack_idx_opts.version = strtoul(arg + 16, &c, 10);
- if (pack_idx_opts.version > 2)
- die("bad %s", arg);
- if (*c == ',')
- pack_idx_opts.off32_limit = strtoul(c+1, &c, 0);
- if (*c || pack_idx_opts.off32_limit & 0x80000000)
- die("bad %s", arg);
- continue;
- }
- if (!strcmp(arg, "--keep-true-parents")) {
- grafts_replace_parents = 0;
- continue;
- }
- usage(pack_usage);
- }
-
- /* Traditionally "pack-objects [options] base extra" failed;
- * we would however want to take refs parameter that would
- * have been given to upstream rev-list ourselves, which means
- * we somehow want to say what the base name is. So the
- * syntax would be:
- *
- * pack-objects [options] base <refs...>
- *
- * in other words, we would treat the first non-option as the
- * base_name and send everything else to the internal revision
- * walker.
- */
+ if (argc) {
+ base_name = argv[0];
+ argc--;
+ }
+ if (pack_to_stdout != !base_name || argc)
+ usage_with_options(pack_usage, pack_objects_options);
- if (!pack_to_stdout)
- base_name = argv[i++];
+ rp_av[rp_ac++] = "pack-objects";
+ if (thin) {
+ use_internal_rev_list = 1;
+ rp_av[rp_ac++] = "--objects-edge";
+ } else
+ rp_av[rp_ac++] = "--objects";
- if (pack_to_stdout != !base_name)
- usage(pack_usage);
+ if (rev_list_all) {
+ use_internal_rev_list = 1;
+ rp_av[rp_ac++] = "--all";
+ }
+ if (rev_list_reflog) {
+ use_internal_rev_list = 1;
+ rp_av[rp_ac++] = "--reflog";
+ }
+ if (rev_list_unpacked) {
+ use_internal_rev_list = 1;
+ rp_av[rp_ac++] = "--unpacked";
+ }
+ if (!reuse_object)
+ reuse_delta = 0;
+ if (pack_compression_level == -1)
+ pack_compression_level = Z_DEFAULT_COMPRESSION;
+ else if (pack_compression_level < 0 || pack_compression_level > Z_BEST_COMPRESSION)
+ die("bad pack compression level %d", pack_compression_level);
+#ifdef NO_PTHREADS
+ if (delta_search_threads != 1)
+ warning("no threads support, ignoring --threads");
+#endif
if (!pack_to_stdout && !pack_size_limit)
pack_size_limit = pack_size_limit_cfg;
if (pack_to_stdout && pack_size_limit)
diff --git a/builtin/prune-packed.c b/builtin/prune-packed.c
index f9463deec2..b58a2e1eb2 100644
--- a/builtin/prune-packed.c
+++ b/builtin/prune-packed.c
@@ -35,8 +35,6 @@ static void prune_dir(int i, DIR *dir, char *pathname, int len, int opts)
unlink_or_warn(pathname);
display_progress(progress, i + 1);
}
- pathname[len] = 0;
- rmdir(pathname);
}
void prune_packed_objects(int opts)
@@ -65,6 +63,8 @@ void prune_packed_objects(int opts)
continue;
prune_dir(i, d, pathname, len + 3, opts);
closedir(d);
+ pathname[len + 2] = '\0';
+ rmdir(pathname);
}
stop_progress(&progress);
}
diff --git a/builtin/prune.c b/builtin/prune.c
index 58d7cb8324..b99b635e44 100644
--- a/builtin/prune.c
+++ b/builtin/prune.c
@@ -85,9 +85,9 @@ static int prune_dir(int i, char *path)
}
fprintf(stderr, "bad sha1 file: %s/%s\n", path, de->d_name);
}
+ closedir(dir);
if (!show_only)
rmdir(path);
- closedir(dir);
return 0;
}
diff --git a/builtin/push.c b/builtin/push.c
index 6c373cf28b..693671315e 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -24,6 +24,7 @@ static int progress = -1;
static const char **refspec;
static int refspec_nr;
static int refspec_alloc;
+static int default_matching_used;
static void add_refspec(const char *ref)
{
@@ -65,6 +66,16 @@ static void set_refspecs(const char **refs, int nr)
}
}
+static int push_url_of_remote(struct remote *remote, const char ***url_p)
+{
+ if (remote->pushurl_nr) {
+ *url_p = remote->pushurl;
+ return remote->pushurl_nr;
+ }
+ *url_p = remote->url;
+ return remote->url_nr;
+}
+
static void setup_push_upstream(struct remote *remote)
{
struct strbuf refspec = STRBUF_INIT;
@@ -76,7 +87,7 @@ static void setup_push_upstream(struct remote *remote)
"\n"
" git push %s HEAD:<name-of-remote-branch>\n"),
remote->name);
- if (!branch->merge_nr || !branch->merge)
+ if (!branch->merge_nr || !branch->merge || !branch->remote_name)
die(_("The current branch %s has no upstream branch.\n"
"To push the current branch and set the remote as upstream, use\n"
"\n"
@@ -87,6 +98,12 @@ static void setup_push_upstream(struct remote *remote)
if (branch->merge_nr != 1)
die(_("The current branch %s has multiple upstream branches, "
"refusing to push."), branch->name);
+ if (strcmp(branch->remote_name, remote->name))
+ die(_("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."),
+ remote->name, branch->name);
+
strbuf_addf(&refspec, "%s:%s", branch->name, branch->merge[0]->src);
add_refspec(refspec.buf);
}
@@ -95,6 +112,9 @@ static void setup_default_push_refspecs(struct remote *remote)
{
switch (push_default) {
default:
+ case PUSH_DEFAULT_UNSPECIFIED:
+ default_matching_used = 1;
+ /* fallthru */
case PUSH_DEFAULT_MATCHING:
add_refspec(":");
break;
@@ -114,6 +134,45 @@ static void setup_default_push_refspecs(struct remote *remote)
}
}
+static const char message_advice_pull_before_push[] =
+ N_("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.");
+
+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.");
+
+static const char message_advice_checkout_pull_push[] =
+ N_("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.");
+
+static void advise_pull_before_push(void)
+{
+ if (!advice_push_non_ff_current || !advice_push_nonfastforward)
+ return;
+ advise(_(message_advice_pull_before_push));
+}
+
+static void advise_use_upstream(void)
+{
+ if (!advice_push_non_ff_default || !advice_push_nonfastforward)
+ return;
+ advise(_(message_advice_use_upstream));
+}
+
+static void advise_checkout_pull_push(void)
+{
+ if (!advice_push_non_ff_matching || !advice_push_nonfastforward)
+ return;
+ advise(_(message_advice_checkout_pull_push));
+}
+
static int push_with_options(struct transport *transport, int flags)
{
int err;
@@ -135,14 +194,21 @@ static int push_with_options(struct transport *transport, int flags)
error(_("failed to push some refs to '%s'"), transport->url);
err |= transport_disconnect(transport);
-
if (!err)
return 0;
- if (nonfastforward && advice_push_nonfastforward) {
- fprintf(stderr, _("To prevent you from losing history, non-fast-forward updates were rejected\n"
- "Merge the remote changes (e.g. 'git pull') before pushing again. See the\n"
- "'Note about fast-forwards' section of 'git push --help' for details.\n"));
+ switch (nonfastforward) {
+ default:
+ break;
+ case NON_FF_HEAD:
+ advise_pull_before_push();
+ break;
+ case NON_FF_OTHER:
+ if (default_matching_used)
+ advise_use_upstream();
+ else
+ advise_checkout_pull_push();
+ break;
}
return 1;
@@ -196,13 +262,7 @@ static int do_push(const char *repo, int flags)
setup_default_push_refspecs(remote);
}
errs = 0;
- if (remote->pushurl_nr) {
- url = remote->pushurl;
- url_nr = remote->pushurl_nr;
- } else {
- url = remote->url;
- url_nr = remote->url_nr;
- }
+ url_nr = push_url_of_remote(remote, &url);
if (url_nr) {
for (i = 0; i < url_nr; i++) {
struct transport *transport =
@@ -261,6 +321,8 @@ int cmd_push(int argc, const char **argv, const char *prefix)
OPT_BIT('u', "set-upstream", &flags, "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",
+ TRANSPORT_PUSH_PRUNE),
OPT_END()
};
diff --git a/builtin/remote.c b/builtin/remote.c
index adc456ebef..fec92bc66e 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -534,7 +534,7 @@ static int add_branch_for_removal(const char *refname,
}
/* don't delete non-remote-tracking refs */
- if (prefixcmp(refname, "refs/remotes")) {
+ if (prefixcmp(refname, "refs/remotes/")) {
/* advise user how to delete local branches */
if (!prefixcmp(refname, "refs/heads/"))
string_list_append(branches->skipped,
diff --git a/builtin/rev-list.c b/builtin/rev-list.c
index 4c4d404afc..ff5a38372d 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -109,6 +109,7 @@ static void show_commit(struct commit *commit, void *data)
struct pretty_print_context ctx = {0};
ctx.abbrev = revs->abbrev;
ctx.date_mode = revs->date_mode;
+ ctx.date_mode_explicit = revs->date_mode_explicit;
ctx.fmt = revs->commit_format;
pretty_print_commit(&ctx, commit, &buf);
if (revs->graph) {
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index 98d1cbecca..733f626f6c 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -634,6 +634,8 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
if (!strcmp(arg, "--show-prefix")) {
if (prefix)
puts(prefix);
+ else
+ putchar('\n');
continue;
}
if (!strcmp(arg, "--show-cdup")) {
diff --git a/builtin/revert.c b/builtin/revert.c
index df63794e05..5462e676e2 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -1,18 +1,9 @@
#include "cache.h"
#include "builtin.h"
-#include "object.h"
-#include "commit.h"
-#include "tag.h"
-#include "run-command.h"
-#include "exec_cmd.h"
-#include "utf8.h"
#include "parse-options.h"
-#include "cache-tree.h"
#include "diff.h"
#include "revision.h"
#include "rerere.h"
-#include "merge-recursive.h"
-#include "refs.h"
#include "dir.h"
#include "sequencer.h"
@@ -39,49 +30,14 @@ static const char * const cherry_pick_usage[] = {
NULL
};
-enum replay_action { REVERT, CHERRY_PICK };
-enum replay_subcommand {
- REPLAY_NONE,
- REPLAY_REMOVE_STATE,
- REPLAY_CONTINUE,
- REPLAY_ROLLBACK
-};
-
-struct replay_opts {
- enum replay_action action;
- enum replay_subcommand subcommand;
-
- /* Boolean options */
- int edit;
- int record_origin;
- int no_commit;
- int signoff;
- int allow_ff;
- int allow_rerere_auto;
-
- int mainline;
-
- /* Merge strategy */
- const char *strategy;
- const char **xopts;
- size_t xopts_nr, xopts_alloc;
-
- /* Only used by REPLAY_NONE */
- struct rev_info *revs;
-};
-
-#define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
-
static const char *action_name(const struct replay_opts *opts)
{
- return opts->action == REVERT ? "revert" : "cherry-pick";
+ return opts->action == REPLAY_REVERT ? "revert" : "cherry-pick";
}
-static char *get_encoding(const char *message);
-
static const char * const *revert_or_cherry_pick_usage(struct replay_opts *opts)
{
- return opts->action == REVERT ? revert_usage : cherry_pick_usage;
+ return opts->action == REPLAY_REVERT ? revert_usage : cherry_pick_usage;
}
static int option_parse_x(const struct option *opt,
@@ -130,6 +86,7 @@ static void verify_opt_mutually_compatible(const char *me, ...)
break;
}
}
+ va_end(ap);
if (opt1 && opt2)
die(_("%s: %s cannot be used with %s"), me, opt1, opt2);
@@ -160,7 +117,7 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
OPT_END(),
};
- if (opts->action == CHERRY_PICK) {
+ 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"),
@@ -225,913 +182,21 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
if (opts->subcommand != REPLAY_NONE) {
opts->revs = NULL;
} else {
+ struct setup_revision_opt s_r_opt;
opts->revs = xmalloc(sizeof(*opts->revs));
init_revisions(opts->revs, NULL);
opts->revs->no_walk = 1;
if (argc < 2)
usage_with_options(usage_str, options);
- argc = setup_revisions(argc, argv, opts->revs, NULL);
+ memset(&s_r_opt, 0, sizeof(s_r_opt));
+ s_r_opt.assume_dashdash = 1;
+ argc = setup_revisions(argc, argv, opts->revs, &s_r_opt);
}
if (argc > 1)
usage_with_options(usage_str, options);
}
-struct commit_message {
- char *parent_label;
- const char *label;
- const char *subject;
- char *reencoded_message;
- const char *message;
-};
-
-static int get_message(struct commit *commit, struct commit_message *out)
-{
- const char *encoding;
- const char *abbrev, *subject;
- int abbrev_len, subject_len;
- char *q;
-
- if (!commit->buffer)
- return -1;
- encoding = get_encoding(commit->buffer);
- if (!encoding)
- encoding = "UTF-8";
- if (!git_commit_encoding)
- git_commit_encoding = "UTF-8";
-
- out->reencoded_message = NULL;
- out->message = commit->buffer;
- if (strcmp(encoding, git_commit_encoding))
- out->reencoded_message = reencode_string(commit->buffer,
- git_commit_encoding, encoding);
- if (out->reencoded_message)
- out->message = out->reencoded_message;
-
- abbrev = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV);
- abbrev_len = strlen(abbrev);
-
- subject_len = find_commit_subject(out->message, &subject);
-
- out->parent_label = xmalloc(strlen("parent of ") + abbrev_len +
- strlen("... ") + subject_len + 1);
- q = out->parent_label;
- q = mempcpy(q, "parent of ", strlen("parent of "));
- out->label = q;
- q = mempcpy(q, abbrev, abbrev_len);
- q = mempcpy(q, "... ", strlen("... "));
- out->subject = q;
- q = mempcpy(q, subject, subject_len);
- *q = '\0';
- return 0;
-}
-
-static void free_message(struct commit_message *msg)
-{
- free(msg->parent_label);
- free(msg->reencoded_message);
-}
-
-static char *get_encoding(const char *message)
-{
- const char *p = message, *eol;
-
- while (*p && *p != '\n') {
- for (eol = p + 1; *eol && *eol != '\n'; eol++)
- ; /* do nothing */
- if (!prefixcmp(p, "encoding ")) {
- char *result = xmalloc(eol - 8 - p);
- strlcpy(result, p + 9, eol - 8 - p);
- return result;
- }
- p = eol;
- if (*p == '\n')
- p++;
- }
- return NULL;
-}
-
-static void write_cherry_pick_head(struct commit *commit, const char *pseudoref)
-{
- const char *filename;
- int fd;
- struct strbuf buf = STRBUF_INIT;
-
- strbuf_addf(&buf, "%s\n", sha1_to_hex(commit->object.sha1));
-
- filename = git_path("%s", pseudoref);
- fd = open(filename, O_WRONLY | O_CREAT, 0666);
- if (fd < 0)
- die_errno(_("Could not open '%s' for writing"), filename);
- if (write_in_full(fd, buf.buf, buf.len) != buf.len || close(fd))
- die_errno(_("Could not write to '%s'"), filename);
- strbuf_release(&buf);
-}
-
-static void print_advice(int show_hint)
-{
- char *msg = getenv("GIT_CHERRY_PICK_HELP");
-
- if (msg) {
- fprintf(stderr, "%s\n", msg);
- /*
- * A conflict has occured but the porcelain
- * (typically rebase --interactive) wants to take care
- * of the commit itself so remove CHERRY_PICK_HEAD
- */
- unlink(git_path("CHERRY_PICK_HEAD"));
- return;
- }
-
- if (show_hint)
- advise(_("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'"));
-}
-
-static void write_message(struct strbuf *msgbuf, const char *filename)
-{
- static struct lock_file msg_file;
-
- int msg_fd = hold_lock_file_for_update(&msg_file, filename,
- LOCK_DIE_ON_ERROR);
- if (write_in_full(msg_fd, msgbuf->buf, msgbuf->len) < 0)
- die_errno(_("Could not write to %s"), filename);
- strbuf_release(msgbuf);
- if (commit_lock_file(&msg_file) < 0)
- die(_("Error wrapping up %s"), filename);
-}
-
-static struct tree *empty_tree(void)
-{
- return lookup_tree((const unsigned char *)EMPTY_TREE_SHA1_BIN);
-}
-
-static int error_dirty_index(struct replay_opts *opts)
-{
- if (read_cache_unmerged())
- return error_resolve_conflict(action_name(opts));
-
- /* Different translation strings for cherry-pick and revert */
- if (opts->action == CHERRY_PICK)
- error(_("Your local changes would be overwritten by cherry-pick."));
- else
- error(_("Your local changes would be overwritten by revert."));
-
- if (advice_commit_before_merge)
- advise(_("Commit your changes or stash them to proceed."));
- return -1;
-}
-
-static int fast_forward_to(const unsigned char *to, const unsigned char *from)
-{
- struct ref_lock *ref_lock;
-
- read_cache();
- if (checkout_fast_forward(from, to))
- exit(1); /* the callee should have complained already */
- ref_lock = lock_any_ref_for_update("HEAD", from, 0);
- return write_ref_sha1(ref_lock, to, "cherry-pick");
-}
-
-static int do_recursive_merge(struct commit *base, struct commit *next,
- const char *base_label, const char *next_label,
- unsigned char *head, struct strbuf *msgbuf,
- struct replay_opts *opts)
-{
- struct merge_options o;
- struct tree *result, *next_tree, *base_tree, *head_tree;
- int clean, index_fd;
- const char **xopt;
- static struct lock_file index_lock;
-
- index_fd = hold_locked_index(&index_lock, 1);
-
- read_cache();
-
- init_merge_options(&o);
- o.ancestor = base ? base_label : "(empty tree)";
- o.branch1 = "HEAD";
- o.branch2 = next ? next_label : "(empty tree)";
-
- head_tree = parse_tree_indirect(head);
- next_tree = next ? next->tree : empty_tree();
- base_tree = base ? base->tree : empty_tree();
-
- for (xopt = opts->xopts; xopt != opts->xopts + opts->xopts_nr; xopt++)
- parse_merge_opt(&o, *xopt);
-
- clean = merge_trees(&o,
- head_tree,
- next_tree, base_tree, &result);
-
- if (active_cache_changed &&
- (write_cache(index_fd, active_cache, active_nr) ||
- commit_locked_index(&index_lock)))
- /* TRANSLATORS: %s will be "revert" or "cherry-pick" */
- die(_("%s: Unable to write new index file"), action_name(opts));
- rollback_lock_file(&index_lock);
-
- if (!clean) {
- int i;
- strbuf_addstr(msgbuf, "\nConflicts:\n\n");
- for (i = 0; i < active_nr;) {
- struct cache_entry *ce = active_cache[i++];
- if (ce_stage(ce)) {
- strbuf_addch(msgbuf, '\t');
- strbuf_addstr(msgbuf, ce->name);
- strbuf_addch(msgbuf, '\n');
- while (i < active_nr && !strcmp(ce->name,
- active_cache[i]->name))
- i++;
- }
- }
- }
-
- return !clean;
-}
-
-/*
- * If we are cherry-pick, and if the merge did not result in
- * hand-editing, we will hit this commit and inherit the original
- * author date and name.
- * If we are revert, or if our cherry-pick results in a hand merge,
- * we had better say that the current user is responsible for that.
- */
-static int run_git_commit(const char *defmsg, struct replay_opts *opts)
-{
- /* 6 is max possible length of our args array including NULL */
- const char *args[6];
- int i = 0;
-
- args[i++] = "commit";
- args[i++] = "-n";
- if (opts->signoff)
- args[i++] = "-s";
- if (!opts->edit) {
- args[i++] = "-F";
- args[i++] = defmsg;
- }
- args[i] = NULL;
-
- return run_command_v_opt(args, RUN_GIT_CMD);
-}
-
-static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
-{
- unsigned char head[20];
- struct commit *base, *next, *parent;
- const char *base_label, *next_label;
- struct commit_message msg = { NULL, NULL, NULL, NULL, NULL };
- char *defmsg = NULL;
- struct strbuf msgbuf = STRBUF_INIT;
- int res;
-
- if (opts->no_commit) {
- /*
- * We do not intend to commit immediately. We just want to
- * merge the differences in, so let's compute the tree
- * that represents the "current" state for merge-recursive
- * to work on.
- */
- if (write_cache_as_tree(head, 0, NULL))
- die (_("Your index file is unmerged."));
- } else {
- if (get_sha1("HEAD", head))
- return error(_("You do not have a valid HEAD"));
- if (index_differs_from("HEAD", 0))
- return error_dirty_index(opts);
- }
- discard_cache();
-
- if (!commit->parents) {
- parent = NULL;
- }
- else if (commit->parents->next) {
- /* Reverting or cherry-picking a merge commit */
- int cnt;
- struct commit_list *p;
-
- if (!opts->mainline)
- return error(_("Commit %s is a merge but no -m option was given."),
- sha1_to_hex(commit->object.sha1));
-
- for (cnt = 1, p = commit->parents;
- cnt != opts->mainline && p;
- cnt++)
- p = p->next;
- if (cnt != opts->mainline || !p)
- return error(_("Commit %s does not have parent %d"),
- sha1_to_hex(commit->object.sha1), opts->mainline);
- parent = p->item;
- } else if (0 < opts->mainline)
- return error(_("Mainline was specified but commit %s is not a merge."),
- sha1_to_hex(commit->object.sha1));
- else
- parent = commit->parents->item;
-
- if (opts->allow_ff && parent && !hashcmp(parent->object.sha1, head))
- return fast_forward_to(commit->object.sha1, head);
-
- if (parent && parse_commit(parent) < 0)
- /* TRANSLATORS: The first %s will be "revert" or
- "cherry-pick", the second %s a SHA1 */
- return error(_("%s: cannot parse parent commit %s"),
- action_name(opts), sha1_to_hex(parent->object.sha1));
-
- if (get_message(commit, &msg) != 0)
- return error(_("Cannot get commit message for %s"),
- sha1_to_hex(commit->object.sha1));
-
- /*
- * "commit" is an existing commit. We would want to apply
- * the difference it introduces since its first parent "prev"
- * on top of the current HEAD if we are cherry-pick. Or the
- * reverse of it if we are revert.
- */
-
- defmsg = git_pathdup("MERGE_MSG");
-
- if (opts->action == REVERT) {
- base = commit;
- base_label = msg.label;
- next = parent;
- next_label = msg.parent_label;
- strbuf_addstr(&msgbuf, "Revert \"");
- strbuf_addstr(&msgbuf, msg.subject);
- strbuf_addstr(&msgbuf, "\"\n\nThis reverts commit ");
- strbuf_addstr(&msgbuf, sha1_to_hex(commit->object.sha1));
-
- if (commit->parents && commit->parents->next) {
- strbuf_addstr(&msgbuf, ", reversing\nchanges made to ");
- strbuf_addstr(&msgbuf, sha1_to_hex(parent->object.sha1));
- }
- strbuf_addstr(&msgbuf, ".\n");
- } else {
- const char *p;
-
- base = parent;
- base_label = msg.parent_label;
- next = commit;
- next_label = msg.label;
-
- /*
- * Append the commit log message to msgbuf; it starts
- * after the tree, parent, author, committer
- * information followed by "\n\n".
- */
- p = strstr(msg.message, "\n\n");
- if (p) {
- p += 2;
- strbuf_addstr(&msgbuf, p);
- }
-
- if (opts->record_origin) {
- strbuf_addstr(&msgbuf, "(cherry picked from commit ");
- strbuf_addstr(&msgbuf, sha1_to_hex(commit->object.sha1));
- strbuf_addstr(&msgbuf, ")\n");
- }
- }
-
- if (!opts->strategy || !strcmp(opts->strategy, "recursive") || opts->action == REVERT) {
- res = do_recursive_merge(base, next, base_label, next_label,
- head, &msgbuf, opts);
- write_message(&msgbuf, defmsg);
- } else {
- struct commit_list *common = NULL;
- struct commit_list *remotes = NULL;
-
- write_message(&msgbuf, defmsg);
-
- commit_list_insert(base, &common);
- commit_list_insert(next, &remotes);
- res = try_merge_command(opts->strategy, opts->xopts_nr, opts->xopts,
- common, sha1_to_hex(head), remotes);
- free_commit_list(common);
- free_commit_list(remotes);
- }
-
- /*
- * If the merge was clean or if it failed due to conflict, we write
- * CHERRY_PICK_HEAD for the subsequent invocation of commit to use.
- * However, if the merge did not even start, then we don't want to
- * write it at all.
- */
- if (opts->action == CHERRY_PICK && !opts->no_commit && (res == 0 || res == 1))
- write_cherry_pick_head(commit, "CHERRY_PICK_HEAD");
- if (opts->action == REVERT && ((opts->no_commit && res == 0) || res == 1))
- write_cherry_pick_head(commit, "REVERT_HEAD");
-
- if (res) {
- error(opts->action == REVERT
- ? _("could not revert %s... %s")
- : _("could not apply %s... %s"),
- find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV),
- msg.subject);
- print_advice(res == 1);
- rerere(opts->allow_rerere_auto);
- } else {
- if (!opts->no_commit)
- res = run_git_commit(defmsg, opts);
- }
-
- free_message(&msg);
- free(defmsg);
-
- return res;
-}
-
-static void prepare_revs(struct replay_opts *opts)
-{
- if (opts->action != REVERT)
- opts->revs->reverse ^= 1;
-
- if (prepare_revision_walk(opts->revs))
- die(_("revision walk setup failed"));
-
- if (!opts->revs->commits)
- die(_("empty commit set passed"));
-}
-
-static void read_and_refresh_cache(struct replay_opts *opts)
-{
- static struct lock_file index_lock;
- int index_fd = hold_locked_index(&index_lock, 0);
- if (read_index_preload(&the_index, NULL) < 0)
- die(_("git %s: failed to read the index"), action_name(opts));
- refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, NULL, NULL, NULL);
- if (the_index.cache_changed) {
- if (write_index(&the_index, index_fd) ||
- commit_locked_index(&index_lock))
- die(_("git %s: failed to refresh the index"), action_name(opts));
- }
- rollback_lock_file(&index_lock);
-}
-
-/*
- * Append a commit to the end of the commit_list.
- *
- * next starts by pointing to the variable that holds the head of an
- * empty commit_list, and is updated to point to the "next" field of
- * the last item on the list as new commits are appended.
- *
- * Usage example:
- *
- * struct commit_list *list;
- * struct commit_list **next = &list;
- *
- * next = commit_list_append(c1, next);
- * next = commit_list_append(c2, next);
- * assert(commit_list_count(list) == 2);
- * return list;
- */
-static struct commit_list **commit_list_append(struct commit *commit,
- struct commit_list **next)
-{
- struct commit_list *new = xmalloc(sizeof(struct commit_list));
- new->item = commit;
- *next = new;
- new->next = NULL;
- return &new->next;
-}
-
-static int format_todo(struct strbuf *buf, struct commit_list *todo_list,
- struct replay_opts *opts)
-{
- struct commit_list *cur = NULL;
- const char *sha1_abbrev = NULL;
- const char *action_str = opts->action == REVERT ? "revert" : "pick";
- const char *subject;
- int subject_len;
-
- for (cur = todo_list; cur; cur = cur->next) {
- sha1_abbrev = find_unique_abbrev(cur->item->object.sha1, DEFAULT_ABBREV);
- subject_len = find_commit_subject(cur->item->buffer, &subject);
- strbuf_addf(buf, "%s %s %.*s\n", action_str, sha1_abbrev,
- subject_len, subject);
- }
- return 0;
-}
-
-static struct commit *parse_insn_line(char *bol, char *eol, struct replay_opts *opts)
-{
- unsigned char commit_sha1[20];
- enum replay_action action;
- char *end_of_object_name;
- int saved, status, padding;
-
- if (!prefixcmp(bol, "pick")) {
- action = CHERRY_PICK;
- bol += strlen("pick");
- } else if (!prefixcmp(bol, "revert")) {
- action = REVERT;
- bol += strlen("revert");
- } else
- return NULL;
-
- /* Eat up extra spaces/ tabs before object name */
- padding = strspn(bol, " \t");
- if (!padding)
- return NULL;
- bol += padding;
-
- end_of_object_name = bol + strcspn(bol, " \t\n");
- saved = *end_of_object_name;
- *end_of_object_name = '\0';
- status = get_sha1(bol, commit_sha1);
- *end_of_object_name = saved;
-
- /*
- * Verify that the action matches up with the one in
- * opts; we don't support arbitrary instructions
- */
- if (action != opts->action) {
- const char *action_str;
- action_str = action == REVERT ? "revert" : "cherry-pick";
- error(_("Cannot %s during a %s"), action_str, action_name(opts));
- return NULL;
- }
-
- if (status < 0)
- return NULL;
-
- return lookup_commit_reference(commit_sha1);
-}
-
-static int parse_insn_buffer(char *buf, struct commit_list **todo_list,
- struct replay_opts *opts)
-{
- struct commit_list **next = todo_list;
- struct commit *commit;
- char *p = buf;
- int i;
-
- for (i = 1; *p; i++) {
- char *eol = strchrnul(p, '\n');
- commit = parse_insn_line(p, eol, opts);
- if (!commit)
- return error(_("Could not parse line %d."), i);
- next = commit_list_append(commit, next);
- p = *eol ? eol + 1 : eol;
- }
- if (!*todo_list)
- return error(_("No commits parsed."));
- return 0;
-}
-
-static void read_populate_todo(struct commit_list **todo_list,
- struct replay_opts *opts)
-{
- const char *todo_file = git_path(SEQ_TODO_FILE);
- struct strbuf buf = STRBUF_INIT;
- int fd, res;
-
- fd = open(todo_file, O_RDONLY);
- if (fd < 0)
- die_errno(_("Could not open %s"), todo_file);
- if (strbuf_read(&buf, fd, 0) < 0) {
- close(fd);
- strbuf_release(&buf);
- die(_("Could not read %s."), todo_file);
- }
- close(fd);
-
- res = parse_insn_buffer(buf.buf, todo_list, opts);
- strbuf_release(&buf);
- if (res)
- die(_("Unusable instruction sheet: %s"), todo_file);
-}
-
-static int populate_opts_cb(const char *key, const char *value, void *data)
-{
- struct replay_opts *opts = data;
- int error_flag = 1;
-
- if (!value)
- error_flag = 0;
- else if (!strcmp(key, "options.no-commit"))
- opts->no_commit = git_config_bool_or_int(key, value, &error_flag);
- else if (!strcmp(key, "options.edit"))
- opts->edit = git_config_bool_or_int(key, value, &error_flag);
- else if (!strcmp(key, "options.signoff"))
- opts->signoff = git_config_bool_or_int(key, value, &error_flag);
- else if (!strcmp(key, "options.record-origin"))
- opts->record_origin = git_config_bool_or_int(key, value, &error_flag);
- else if (!strcmp(key, "options.allow-ff"))
- opts->allow_ff = git_config_bool_or_int(key, value, &error_flag);
- else if (!strcmp(key, "options.mainline"))
- opts->mainline = git_config_int(key, value);
- else if (!strcmp(key, "options.strategy"))
- git_config_string(&opts->strategy, key, value);
- else if (!strcmp(key, "options.strategy-option")) {
- ALLOC_GROW(opts->xopts, opts->xopts_nr + 1, opts->xopts_alloc);
- opts->xopts[opts->xopts_nr++] = xstrdup(value);
- } else
- return error(_("Invalid key: %s"), key);
-
- if (!error_flag)
- return error(_("Invalid value for %s: %s"), key, value);
-
- return 0;
-}
-
-static void read_populate_opts(struct replay_opts **opts_ptr)
-{
- const char *opts_file = git_path(SEQ_OPTS_FILE);
-
- if (!file_exists(opts_file))
- return;
- if (git_config_from_file(populate_opts_cb, opts_file, *opts_ptr) < 0)
- die(_("Malformed options sheet: %s"), opts_file);
-}
-
-static void walk_revs_populate_todo(struct commit_list **todo_list,
- struct replay_opts *opts)
-{
- struct commit *commit;
- struct commit_list **next;
-
- prepare_revs(opts);
-
- next = todo_list;
- while ((commit = get_revision(opts->revs)))
- next = commit_list_append(commit, next);
-}
-
-static int create_seq_dir(void)
-{
- const char *seq_dir = git_path(SEQ_DIR);
-
- if (file_exists(seq_dir)) {
- error(_("a cherry-pick or revert is already in progress"));
- advise(_("try \"git cherry-pick (--continue | --quit | --abort)\""));
- return -1;
- }
- else if (mkdir(seq_dir, 0777) < 0)
- die_errno(_("Could not create sequencer directory %s"), seq_dir);
- return 0;
-}
-
-static void save_head(const char *head)
-{
- const char *head_file = git_path(SEQ_HEAD_FILE);
- static struct lock_file head_lock;
- struct strbuf buf = STRBUF_INIT;
- int fd;
-
- fd = hold_lock_file_for_update(&head_lock, head_file, LOCK_DIE_ON_ERROR);
- strbuf_addf(&buf, "%s\n", head);
- if (write_in_full(fd, buf.buf, buf.len) < 0)
- die_errno(_("Could not write to %s"), head_file);
- if (commit_lock_file(&head_lock) < 0)
- die(_("Error wrapping up %s."), head_file);
-}
-
-static int reset_for_rollback(const unsigned char *sha1)
-{
- const char *argv[4]; /* reset --merge <arg> + NULL */
- argv[0] = "reset";
- argv[1] = "--merge";
- argv[2] = sha1_to_hex(sha1);
- argv[3] = NULL;
- return run_command_v_opt(argv, RUN_GIT_CMD);
-}
-
-static int rollback_single_pick(void)
-{
- unsigned char head_sha1[20];
-
- if (!file_exists(git_path("CHERRY_PICK_HEAD")) &&
- !file_exists(git_path("REVERT_HEAD")))
- return error(_("no cherry-pick or revert in progress"));
- if (read_ref_full("HEAD", head_sha1, 0, NULL))
- return error(_("cannot resolve HEAD"));
- if (is_null_sha1(head_sha1))
- return error(_("cannot abort from a branch yet to be born"));
- return reset_for_rollback(head_sha1);
-}
-
-static int sequencer_rollback(struct replay_opts *opts)
-{
- const char *filename;
- FILE *f;
- unsigned char sha1[20];
- struct strbuf buf = STRBUF_INIT;
-
- filename = git_path(SEQ_HEAD_FILE);
- f = fopen(filename, "r");
- if (!f && errno == ENOENT) {
- /*
- * There is no multiple-cherry-pick in progress.
- * If CHERRY_PICK_HEAD or REVERT_HEAD indicates
- * a single-cherry-pick in progress, abort that.
- */
- return rollback_single_pick();
- }
- if (!f)
- return error(_("cannot open %s: %s"), filename,
- strerror(errno));
- if (strbuf_getline(&buf, f, '\n')) {
- error(_("cannot read %s: %s"), filename, ferror(f) ?
- strerror(errno) : _("unexpected end of file"));
- fclose(f);
- goto fail;
- }
- fclose(f);
- if (get_sha1_hex(buf.buf, sha1) || buf.buf[40] != '\0') {
- error(_("stored pre-cherry-pick HEAD file '%s' is corrupt"),
- filename);
- goto fail;
- }
- if (reset_for_rollback(sha1))
- goto fail;
- remove_sequencer_state();
- strbuf_release(&buf);
- return 0;
-fail:
- strbuf_release(&buf);
- return -1;
-}
-
-static void save_todo(struct commit_list *todo_list, struct replay_opts *opts)
-{
- const char *todo_file = git_path(SEQ_TODO_FILE);
- static struct lock_file todo_lock;
- struct strbuf buf = STRBUF_INIT;
- int fd;
-
- fd = hold_lock_file_for_update(&todo_lock, todo_file, LOCK_DIE_ON_ERROR);
- if (format_todo(&buf, todo_list, opts) < 0)
- die(_("Could not format %s."), todo_file);
- if (write_in_full(fd, buf.buf, buf.len) < 0) {
- strbuf_release(&buf);
- die_errno(_("Could not write to %s"), todo_file);
- }
- if (commit_lock_file(&todo_lock) < 0) {
- strbuf_release(&buf);
- die(_("Error wrapping up %s."), todo_file);
- }
- strbuf_release(&buf);
-}
-
-static void save_opts(struct replay_opts *opts)
-{
- const char *opts_file = git_path(SEQ_OPTS_FILE);
-
- if (opts->no_commit)
- git_config_set_in_file(opts_file, "options.no-commit", "true");
- if (opts->edit)
- git_config_set_in_file(opts_file, "options.edit", "true");
- if (opts->signoff)
- git_config_set_in_file(opts_file, "options.signoff", "true");
- if (opts->record_origin)
- git_config_set_in_file(opts_file, "options.record-origin", "true");
- if (opts->allow_ff)
- git_config_set_in_file(opts_file, "options.allow-ff", "true");
- if (opts->mainline) {
- struct strbuf buf = STRBUF_INIT;
- strbuf_addf(&buf, "%d", opts->mainline);
- git_config_set_in_file(opts_file, "options.mainline", buf.buf);
- strbuf_release(&buf);
- }
- if (opts->strategy)
- git_config_set_in_file(opts_file, "options.strategy", opts->strategy);
- if (opts->xopts) {
- int i;
- for (i = 0; i < opts->xopts_nr; i++)
- git_config_set_multivar_in_file(opts_file,
- "options.strategy-option",
- opts->xopts[i], "^$", 0);
- }
-}
-
-static int pick_commits(struct commit_list *todo_list, struct replay_opts *opts)
-{
- struct commit_list *cur;
- int res;
-
- setenv(GIT_REFLOG_ACTION, action_name(opts), 0);
- if (opts->allow_ff)
- assert(!(opts->signoff || opts->no_commit ||
- opts->record_origin || opts->edit));
- read_and_refresh_cache(opts);
-
- for (cur = todo_list; cur; cur = cur->next) {
- save_todo(cur, opts);
- res = do_pick_commit(cur->item, opts);
- if (res)
- return res;
- }
-
- /*
- * Sequence of picks finished successfully; cleanup by
- * removing the .git/sequencer directory
- */
- remove_sequencer_state();
- return 0;
-}
-
-static int continue_single_pick(void)
-{
- const char *argv[] = { "commit", NULL };
-
- if (!file_exists(git_path("CHERRY_PICK_HEAD")) &&
- !file_exists(git_path("REVERT_HEAD")))
- return error(_("no cherry-pick or revert in progress"));
- return run_command_v_opt(argv, RUN_GIT_CMD);
-}
-
-static int sequencer_continue(struct replay_opts *opts)
-{
- struct commit_list *todo_list = NULL;
-
- if (!file_exists(git_path(SEQ_TODO_FILE)))
- return continue_single_pick();
- read_populate_opts(&opts);
- read_populate_todo(&todo_list, opts);
-
- /* Verify that the conflict has been resolved */
- if (file_exists(git_path("CHERRY_PICK_HEAD")) ||
- file_exists(git_path("REVERT_HEAD"))) {
- int ret = continue_single_pick();
- if (ret)
- return ret;
- }
- if (index_differs_from("HEAD", 0))
- return error_dirty_index(opts);
- todo_list = todo_list->next;
- return pick_commits(todo_list, opts);
-}
-
-static int single_pick(struct commit *cmit, struct replay_opts *opts)
-{
- setenv(GIT_REFLOG_ACTION, action_name(opts), 0);
- return do_pick_commit(cmit, opts);
-}
-
-static int pick_revisions(struct replay_opts *opts)
-{
- struct commit_list *todo_list = NULL;
- unsigned char sha1[20];
-
- if (opts->subcommand == REPLAY_NONE)
- assert(opts->revs);
-
- read_and_refresh_cache(opts);
-
- /*
- * Decide what to do depending on the arguments; a fresh
- * cherry-pick should be handled differently from an existing
- * one that is being continued
- */
- if (opts->subcommand == REPLAY_REMOVE_STATE) {
- remove_sequencer_state();
- return 0;
- }
- if (opts->subcommand == REPLAY_ROLLBACK)
- return sequencer_rollback(opts);
- if (opts->subcommand == REPLAY_CONTINUE)
- return sequencer_continue(opts);
-
- /*
- * If we were called as "git cherry-pick <commit>", just
- * cherry-pick/revert it, set CHERRY_PICK_HEAD /
- * REVERT_HEAD, and don't touch the sequencer state.
- * This means it is possible to cherry-pick in the middle
- * of a cherry-pick sequence.
- */
- if (opts->revs->cmdline.nr == 1 &&
- opts->revs->cmdline.rev->whence == REV_CMD_REV &&
- opts->revs->no_walk &&
- !opts->revs->cmdline.rev->flags) {
- struct commit *cmit;
- if (prepare_revision_walk(opts->revs))
- die(_("revision walk setup failed"));
- cmit = get_revision(opts->revs);
- if (!cmit || get_revision(opts->revs))
- die("BUG: expected exactly one commit from walk");
- return single_pick(cmit, opts);
- }
-
- /*
- * Start a new cherry-pick/ revert sequence; but
- * first, make sure that an existing one isn't in
- * progress
- */
-
- walk_revs_populate_todo(&todo_list, opts);
- if (create_seq_dir() < 0)
- return -1;
- if (get_sha1("HEAD", sha1)) {
- if (opts->action == REVERT)
- return error(_("Can't revert as initial commit"));
- return error(_("Can't cherry-pick into empty head"));
- }
- save_head(sha1_to_hex(sha1));
- save_opts(opts);
- return pick_commits(todo_list, opts);
-}
-
int cmd_revert(int argc, const char **argv, const char *prefix)
{
struct replay_opts opts;
@@ -1140,10 +205,10 @@ int cmd_revert(int argc, const char **argv, const char *prefix)
memset(&opts, 0, sizeof(opts));
if (isatty(0))
opts.edit = 1;
- opts.action = REVERT;
+ opts.action = REPLAY_REVERT;
git_config(git_default_config, NULL);
parse_args(argc, argv, &opts);
- res = pick_revisions(&opts);
+ res = sequencer_pick_revisions(&opts);
if (res < 0)
die(_("revert failed"));
return res;
@@ -1155,10 +220,10 @@ int cmd_cherry_pick(int argc, const char **argv, const char *prefix)
int res;
memset(&opts, 0, sizeof(opts));
- opts.action = CHERRY_PICK;
+ opts.action = REPLAY_PICK;
git_config(git_default_config, NULL);
parse_args(argc, argv, &opts);
- res = pick_revisions(&opts);
+ res = sequencer_pick_revisions(&opts);
if (res < 0)
die(_("cherry-pick failed"));
return res;
diff --git a/builtin/send-pack.c b/builtin/send-pack.c
index 9df341c793..d5d7105ba2 100644
--- a/builtin/send-pack.c
+++ b/builtin/send-pack.c
@@ -410,6 +410,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
const char *receivepack = "git-receive-pack";
int flags;
int nonfastforward = 0;
+ int progress = -1;
argv++;
for (i = 1; i < argc; i++, argv++) {
@@ -452,6 +453,14 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
args.verbose = 1;
continue;
}
+ if (!strcmp(arg, "--progress")) {
+ progress = 1;
+ continue;
+ }
+ if (!strcmp(arg, "--no-progress")) {
+ progress = 0;
+ continue;
+ }
if (!strcmp(arg, "--thin")) {
args.use_thin_pack = 1;
continue;
@@ -492,6 +501,10 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
}
}
+ if (progress == -1)
+ progress = !args.quiet && isatty(2);
+ args.progress = progress;
+
if (args.stateless_rpc) {
conn = NULL;
fd[0] = 0;
diff --git a/builtin/symbolic-ref.c b/builtin/symbolic-ref.c
index 2ef5962386..801d62ece5 100644
--- a/builtin/symbolic-ref.c
+++ b/builtin/symbolic-ref.c
@@ -8,13 +8,15 @@ static const char * const git_symbolic_ref_usage[] = {
NULL
};
+static int shorten;
+
static void check_symref(const char *HEAD, int quiet)
{
unsigned char sha1[20];
int flag;
- const char *refs_heads_master = resolve_ref_unsafe(HEAD, sha1, 0, &flag);
+ const char *refname = resolve_ref_unsafe(HEAD, sha1, 0, &flag);
- if (!refs_heads_master)
+ if (!refname)
die("No such ref: %s", HEAD);
else if (!(flag & REF_ISSYMREF)) {
if (!quiet)
@@ -22,7 +24,9 @@ static void check_symref(const char *HEAD, int quiet)
else
exit(1);
}
- puts(refs_heads_master);
+ if (shorten)
+ refname = shorten_unambiguous_ref(refname, 0);
+ puts(refname);
}
int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
@@ -32,6 +36,7 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
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"),
OPT_END(),
};
diff --git a/builtin/tag.c b/builtin/tag.c
index 03df16ac6e..fe7e5e5b3d 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -15,11 +15,13 @@
#include "diff.h"
#include "revision.h"
#include "gpg-interface.h"
+#include "sha1-array.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>]] [<pattern>...]",
+ "git tag -l [-n[<num>]] [--contains <commit>] [--points-at <object>] "
+ "\n\t\t[<pattern>...]",
"git tag -v <tagname>...",
NULL
};
@@ -30,6 +32,8 @@ struct tag_filter {
struct commit_list *with_commit;
};
+static struct sha1_array points_at;
+
static int match_pattern(const char **patterns, const char *ref)
{
/* no pattern means match everything */
@@ -41,6 +45,24 @@ static int match_pattern(const char **patterns, const char *ref)
return 0;
}
+static const unsigned char *match_points_at(const char *refname,
+ const unsigned char *sha1)
+{
+ const unsigned char *tagged_sha1 = NULL;
+ struct object *obj;
+
+ if (sha1_array_lookup(&points_at, sha1) >= 0)
+ return sha1;
+ obj = parse_object(sha1);
+ if (!obj)
+ die(_("malformed object at '%s'"), refname);
+ if (obj->type == OBJ_TAG)
+ tagged_sha1 = ((struct tag *)obj)->tagged->sha1;
+ if (tagged_sha1 && sha1_array_lookup(&points_at, tagged_sha1) >= 0)
+ return tagged_sha1;
+ return NULL;
+}
+
static int in_commit_list(const struct commit_list *want, struct commit *c)
{
for (; want; want = want->next)
@@ -138,6 +160,9 @@ static int show_reference(const char *refname, const unsigned char *sha1,
return 0;
}
+ if (points_at.nr && !match_points_at(refname, sha1))
+ return 0;
+
if (!filter->lines) {
printf("%s\n", refname);
return 0;
@@ -383,6 +408,23 @@ static int strbuf_check_tag_ref(struct strbuf *sb, const char *name)
return check_refname_format(sb->buf, 0);
}
+static int parse_opt_points_at(const struct option *opt __attribute__((unused)),
+ const char *arg, int unset)
+{
+ unsigned char sha1[20];
+
+ if (unset) {
+ sha1_array_clear(&points_at);
+ return 0;
+ }
+ if (!arg)
+ return error(_("switch 'points-at' requires an object"));
+ if (get_sha1(arg, sha1))
+ return error(_("malformed object name '%s'"), arg);
+ sha1_array_append(&points_at, sha1);
+ return 0;
+}
+
int cmd_tag(int argc, const char **argv, const char *prefix)
{
struct strbuf buf = STRBUF_INIT;
@@ -425,6 +467,10 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
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
+ },
OPT_END()
};
@@ -456,6 +502,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
die(_("-n option is only allowed with -l."));
if (with_commit)
die(_("--contains option is only allowed with -l."));
+ if (points_at.nr)
+ die(_("--points-at option is only allowed with -l."));
if (delete)
return for_each_tag_name(argv, delete_tag);
if (verify)
diff --git a/builtin/verify-tag.c b/builtin/verify-tag.c
index 28c2174338..986789f706 100644
--- a/builtin/verify-tag.c
+++ b/builtin/verify-tag.c
@@ -58,6 +58,14 @@ static int verify_tag(const char *name, int verbose)
return ret;
}
+static int git_verify_tag_config(const char *var, const char *value, void *cb)
+{
+ int status = git_gpg_config(var, value, cb);
+ if (status)
+ return status;
+ return git_default_config(var, value, cb);
+}
+
int cmd_verify_tag(int argc, const char **argv, const char *prefix)
{
int i = 1, verbose = 0, had_error = 0;
@@ -66,7 +74,7 @@ int cmd_verify_tag(int argc, const char **argv, const char *prefix)
OPT_END()
};
- git_config(git_default_config, NULL);
+ git_config(git_verify_tag_config, NULL);
argc = parse_options(argc, argv, prefix, verify_tag_options,
verify_tag_usage, PARSE_OPT_KEEP_ARGV0);
diff --git a/cache-tree.c b/cache-tree.c
index bf03cb7fce..28ed6574a2 100644
--- a/cache-tree.c
+++ b/cache-tree.c
@@ -150,9 +150,10 @@ void cache_tree_invalidate_path(struct cache_tree *it, const char *path)
}
static int verify_cache(struct cache_entry **cache,
- int entries, int silent)
+ int entries, int flags)
{
int i, funny;
+ int silent = flags & WRITE_TREE_SILENT;
/* Verify that the tree is merged */
funny = 0;
@@ -241,10 +242,11 @@ static int update_one(struct cache_tree *it,
int entries,
const char *base,
int baselen,
- int missing_ok,
- int dryrun)
+ int flags)
{
struct strbuf buffer;
+ int missing_ok = flags & WRITE_TREE_MISSING_OK;
+ int dryrun = flags & WRITE_TREE_DRY_RUN;
int i;
if (0 <= it->entry_count && has_sha1_file(it->sha1))
@@ -288,8 +290,7 @@ static int update_one(struct cache_tree *it,
cache + i, entries - i,
path,
baselen + sublen + 1,
- missing_ok,
- dryrun);
+ flags);
if (subcnt < 0)
return subcnt;
i += subcnt - 1;
@@ -371,15 +372,13 @@ static int update_one(struct cache_tree *it,
int cache_tree_update(struct cache_tree *it,
struct cache_entry **cache,
int entries,
- int missing_ok,
- int dryrun,
- int silent)
+ int flags)
{
int i;
- i = verify_cache(cache, entries, silent);
+ i = verify_cache(cache, entries, flags);
if (i)
return i;
- i = update_one(it, cache, entries, "", 0, missing_ok, dryrun);
+ i = update_one(it, cache, entries, "", 0, flags);
if (i < 0)
return i;
return 0;
@@ -572,11 +571,9 @@ int write_cache_as_tree(unsigned char *sha1, int flags, const char *prefix)
was_valid = cache_tree_fully_valid(active_cache_tree);
if (!was_valid) {
- int missing_ok = flags & WRITE_TREE_MISSING_OK;
-
if (cache_tree_update(active_cache_tree,
active_cache, active_nr,
- missing_ok, 0, 0) < 0)
+ flags) < 0)
return WRITE_TREE_UNMERGED_INDEX;
if (0 <= newfd) {
if (!write_cache(newfd, active_cache, active_nr) &&
@@ -672,10 +669,10 @@ int cache_tree_matches_traversal(struct cache_tree *root,
return 0;
}
-int update_main_cache_tree (int silent)
+int update_main_cache_tree(int flags)
{
if (!the_index.cache_tree)
the_index.cache_tree = cache_tree();
return cache_tree_update(the_index.cache_tree,
- the_index.cache, the_index.cache_nr, 0, 0, silent);
+ the_index.cache, the_index.cache_nr, flags);
}
diff --git a/cache-tree.h b/cache-tree.h
index 0ec0b2a159..d8cb2e9e39 100644
--- a/cache-tree.h
+++ b/cache-tree.h
@@ -29,13 +29,15 @@ void cache_tree_write(struct strbuf *, struct cache_tree *root);
struct cache_tree *cache_tree_read(const char *buffer, unsigned long size);
int cache_tree_fully_valid(struct cache_tree *);
-int cache_tree_update(struct cache_tree *, struct cache_entry **, int, int, int, int);
+int cache_tree_update(struct cache_tree *, struct cache_entry **, int, int);
int update_main_cache_tree(int);
/* bitmasks to write_cache_as_tree flags */
#define WRITE_TREE_MISSING_OK 1
#define WRITE_TREE_IGNORE_CACHE_TREE 2
+#define WRITE_TREE_DRY_RUN 4
+#define WRITE_TREE_SILENT 8
/* error return codes */
#define WRITE_TREE_UNREADABLE_INDEX (-1)
diff --git a/cache.h b/cache.h
index 3a8e1258e7..84b8229748 100644
--- a/cache.h
+++ b/cache.h
@@ -625,7 +625,8 @@ enum push_default_type {
PUSH_DEFAULT_NOTHING = 0,
PUSH_DEFAULT_MATCHING,
PUSH_DEFAULT_UPSTREAM,
- PUSH_DEFAULT_CURRENT
+ PUSH_DEFAULT_CURRENT,
+ PUSH_DEFAULT_UNSPECIFIED
};
extern enum branch_track git_branch_track;
@@ -708,6 +709,19 @@ static inline void hashclr(unsigned char *hash)
#define EMPTY_TREE_SHA1_BIN \
((const unsigned char *) EMPTY_TREE_SHA1_BIN_LITERAL)
+#define EMPTY_BLOB_SHA1_HEX \
+ "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"
+#define EMPTY_BLOB_SHA1_BIN_LITERAL \
+ "\xe6\x9d\xe2\x9b\xb2\xd1\xd6\x43\x4b\x8b" \
+ "\x29\xae\x77\x5a\xd8\xc2\xe4\x8c\x53\x91"
+#define EMPTY_BLOB_SHA1_BIN \
+ ((const unsigned char *) EMPTY_BLOB_SHA1_BIN_LITERAL)
+
+static inline int is_empty_blob_sha1(const unsigned char *sha1)
+{
+ return !hashcmp(sha1, EMPTY_BLOB_SHA1_BIN);
+}
+
int git_mkstemp(char *path, size_t n, const char *template);
int git_mkstemps(char *path, size_t n, const char *template, int suffix_len);
@@ -928,6 +942,22 @@ extern const char *fmt_name(const char *name, const char *email);
extern const char *git_editor(void);
extern const char *git_pager(int stdout_is_tty);
+struct ident_split {
+ const char *name_begin;
+ const char *name_end;
+ const char *mail_begin;
+ const char *mail_end;
+ const char *date_begin;
+ const char *date_end;
+ const char *tz_begin;
+ const char *tz_end;
+};
+/*
+ * Signals an success with 0, but time part of the result may be NULL
+ * if the input lacks timestamp and zone
+ */
+extern int split_ident_line(struct ident_split *, const char *, int);
+
struct checkout {
const char *base_dir;
int base_dir_len;
@@ -950,7 +980,9 @@ 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);
@@ -960,6 +992,7 @@ extern struct alternate_object_database {
char base[FLEX_ARRAY]; /* more */
} *alt_odb_list;
extern void prepare_alt_odb(void);
+extern void read_info_alternates(const char * relative_base, int depth);
extern void add_to_alternates_file(const char *reference);
typedef int alt_odb_fn(struct alternate_object_database *, void *);
extern void foreach_alt_odb(alt_odb_fn, void*);
@@ -1115,6 +1148,8 @@ extern int git_config_from_file(config_fn_t fn, const char *, void *);
extern void git_config_push_parameter(const char *text);
extern int git_config_from_parameters(config_fn_t fn, void *data);
extern int git_config(config_fn_t fn, void *);
+extern int git_config_with_options(config_fn_t fn, void *,
+ const char *filename, int respect_includes);
extern int git_config_early(config_fn_t fn, void *, const char *repo_config);
extern int git_parse_ulong(const char *, unsigned long *);
extern int git_config_int(const char *, const char *);
@@ -1130,6 +1165,7 @@ extern int git_config_parse_key(const char *, char **, int *);
extern int git_config_set_multivar(const char *, const char *, const char *, int);
extern int git_config_set_multivar_in_file(const char *, const char *, const char *, const char *, int);
extern int git_config_rename_section(const char *, const char *);
+extern int git_config_rename_section_in_file(const char *, const char *, const char *);
extern const char *git_etc_gitconfig(void);
extern int check_repository_format_version(const char *var, const char *value, void *cb);
extern int git_env_bool(const char *, int);
@@ -1140,7 +1176,13 @@ extern const char *get_commit_output_encoding(void);
extern int git_config_parse_parameter(const char *, config_fn_t fn, void *data);
-extern const char *config_exclusive_filename;
+struct config_include_data {
+ int depth;
+ config_fn_t fn;
+ void *data;
+};
+#define CONFIG_INCLUDE_INIT { 0 }
+extern int git_config_include(const char *name, const char *value, void *data);
#define MAX_GITNAME (1000)
extern char git_default_email[MAX_GITNAME];
@@ -1178,6 +1220,7 @@ extern const char *pager_program;
extern int pager_in_use(void);
extern int pager_use_color;
extern int term_columns(void);
+extern int decimal_width(int);
extern const char *editor_program;
extern const char *askpass_program;
@@ -1264,4 +1307,6 @@ extern struct startup_info *startup_info;
/* builtin/merge.c */
int checkout_fast_forward(const unsigned char *from, const unsigned char *to);
+int sane_execvp(const char *file, char *const argv[]);
+
#endif /* CACHE_H */
diff --git a/combine-diff.c b/combine-diff.c
index a2e8dcf855..9786680368 100644
--- a/combine-diff.c
+++ b/combine-diff.c
@@ -423,7 +423,7 @@ static int make_hunks(struct sline *sline, unsigned long cnt,
hunk_begin, j);
la = (la + context < cnt + 1) ?
(la + context) : cnt + 1;
- while (j <= --la) {
+ while (la && j <= --la) {
if (sline[la].flag & mark) {
contin = 1;
break;
diff --git a/commit.c b/commit.c
index 35af4988f0..4b39c19123 100644
--- a/commit.c
+++ b/commit.c
@@ -422,7 +422,8 @@ struct commit *pop_most_recent_commit(struct commit_list **list,
return ret;
}
-void clear_commit_marks(struct commit *commit, unsigned int mark)
+static void clear_commit_marks_1(struct commit_list **plist,
+ struct commit *commit, unsigned int mark)
{
while (commit) {
struct commit_list *parents;
@@ -437,12 +438,20 @@ void clear_commit_marks(struct commit *commit, unsigned int mark)
return;
while ((parents = parents->next))
- clear_commit_marks(parents->item, mark);
+ commit_list_insert(parents->item, plist);
commit = commit->parents->item;
}
}
+void clear_commit_marks(struct commit *commit, unsigned int mark)
+{
+ struct commit_list *list = NULL;
+ commit_list_insert(commit, &list);
+ while (list)
+ clear_commit_marks_1(&list, pop_commit(&list), mark);
+}
+
void clear_commit_marks_for_object_array(struct object_array *a, unsigned mark)
{
struct object *object;
diff --git a/commit.h b/commit.h
index 154c0e34ff..205eea3382 100644
--- a/commit.h
+++ b/commit.h
@@ -82,6 +82,7 @@ struct pretty_print_context {
const char *after_subject;
int preserve_subject;
enum date_mode date_mode;
+ unsigned date_mode_explicit:1;
int need_8bit_cte;
int show_notes;
struct reflog_walk_info *reflog_info;
diff --git a/compat/mingw.c b/compat/mingw.c
index a0ac487c0c..afc892d6b1 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1003,7 +1003,7 @@ static void mingw_execve(const char *cmd, char *const *argv, char *const *env)
}
}
-void mingw_execvp(const char *cmd, char *const *argv)
+int mingw_execvp(const char *cmd, char *const *argv)
{
char **path = get_path_split();
char *prog = path_lookup(cmd, path, 0);
@@ -1015,11 +1015,13 @@ void mingw_execvp(const char *cmd, char *const *argv)
errno = ENOENT;
free_path_split(path);
+ return -1;
}
-void mingw_execv(const char *cmd, char *const *argv)
+int mingw_execv(const char *cmd, char *const *argv)
{
mingw_execve(cmd, argv, environ);
+ return -1;
}
int mingw_kill(pid_t pid, int sig)
diff --git a/compat/mingw.h b/compat/mingw.h
index 0ff1e04812..ef5b15014e 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -274,9 +274,9 @@ int mingw_utime(const char *file_name, const struct utimbuf *times);
pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
const char *dir,
int fhin, int fhout, int fherr);
-void mingw_execvp(const char *cmd, char *const *argv);
+int mingw_execvp(const char *cmd, char *const *argv);
#define execvp mingw_execvp
-void mingw_execv(const char *cmd, char *const *argv);
+int mingw_execv(const char *cmd, char *const *argv);
#define execv mingw_execv
static inline unsigned int git_ntohl(unsigned int x)
diff --git a/config.c b/config.c
index 818ba6df00..ac69cb6293 100644
--- a/config.c
+++ b/config.c
@@ -26,7 +26,74 @@ static config_file *cf;
static int zlib_compression_seen;
-const char *config_exclusive_filename = NULL;
+#define MAX_INCLUDE_DEPTH 10
+static const char include_depth_advice[] =
+"exceeded maximum include depth (%d) while including\n"
+" %s\n"
+"from\n"
+" %s\n"
+"Do you have circular includes?";
+static int handle_path_include(const char *path, struct config_include_data *inc)
+{
+ int ret = 0;
+ struct strbuf buf = STRBUF_INIT;
+ char *expanded = expand_user_path(path);
+
+ if (!expanded)
+ return error("Could not expand include path '%s'", path);
+ path = expanded;
+
+ /*
+ * Use an absolute path as-is, but interpret relative paths
+ * based on the including config file.
+ */
+ if (!is_absolute_path(path)) {
+ char *slash;
+
+ if (!cf || !cf->name)
+ return error("relative config includes must come from files");
+
+ slash = find_last_dir_sep(cf->name);
+ if (slash)
+ strbuf_add(&buf, cf->name, slash - cf->name + 1);
+ strbuf_addstr(&buf, path);
+ path = buf.buf;
+ }
+
+ if (!access(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");
+ ret = git_config_from_file(git_config_include, path, inc);
+ inc->depth--;
+ }
+ strbuf_release(&buf);
+ free(expanded);
+ return ret;
+}
+
+int git_config_include(const char *var, const char *value, void *data)
+{
+ struct config_include_data *inc = data;
+ const char *type;
+ int ret;
+
+ /*
+ * Pass along all values, including "include" directives; this makes it
+ * possible to query information on the includes themselves.
+ */
+ ret = inc->fn(var, value, inc->data);
+ if (ret < 0)
+ return ret;
+
+ type = skip_prefix(var, "include.");
+ if (!type)
+ return ret;
+
+ if (!strcmp(type, "path"))
+ ret = handle_path_include(value, inc);
+ return ret;
+}
static void lowercase(char *p)
{
@@ -884,9 +951,6 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
int ret = 0, found = 0;
const char *home = NULL;
- /* Setting $GIT_CONFIG makes git read _only_ the given config file. */
- if (config_exclusive_filename)
- return git_config_from_file(fn, config_exclusive_filename, data);
if (git_config_system() && !access(git_etc_gitconfig(), R_OK)) {
ret += git_config_from_file(fn, git_etc_gitconfig(),
data);
@@ -922,10 +986,26 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
return ret == 0 ? found : ret;
}
-int git_config(config_fn_t fn, void *data)
+int git_config_with_options(config_fn_t fn, void *data,
+ const char *filename, int respect_includes)
{
char *repo_config = NULL;
int ret;
+ struct config_include_data inc = CONFIG_INCLUDE_INIT;
+
+ if (respect_includes) {
+ inc.fn = fn;
+ inc.data = data;
+ fn = git_config_include;
+ data = &inc;
+ }
+
+ /*
+ * If we have a specific filename, use it. Otherwise, follow the
+ * regular lookup sequence.
+ */
+ if (filename)
+ return git_config_from_file(fn, filename, data);
repo_config = git_pathdup("config");
ret = git_config_early(fn, data, repo_config);
@@ -934,6 +1014,11 @@ int git_config(config_fn_t fn, void *data)
return ret;
}
+int git_config(config_fn_t fn, void *data)
+{
+ return git_config_with_options(fn, data, NULL, 1);
+}
+
/*
* Find all the stuff for git_config_set() below.
*/
@@ -1238,6 +1323,7 @@ int git_config_set_multivar_in_file(const char *config_filename,
int fd = -1, in_fd;
int ret;
struct lock_file *lock = NULL;
+ char *filename_buf = NULL;
/* parse-key returns negative; flip the sign to feed exit(3) */
ret = 0 - git_config_parse_key(key, &store.key, &store.baselen);
@@ -1246,6 +1332,8 @@ int git_config_set_multivar_in_file(const char *config_filename,
store.multi_replace = multi_replace;
+ if (!config_filename)
+ config_filename = filename_buf = git_pathdup("config");
/*
* The lock serves a purpose in addition to locking: the new
@@ -1415,6 +1503,7 @@ int git_config_set_multivar_in_file(const char *config_filename,
out_free:
if (lock)
rollback_lock_file(lock);
+ free(filename_buf);
return ret;
write_err_out:
@@ -1426,19 +1515,8 @@ write_err_out:
int git_config_set_multivar(const char *key, const char *value,
const char *value_regex, int multi_replace)
{
- const char *config_filename;
- char *buf = NULL;
- int ret;
-
- if (config_exclusive_filename)
- config_filename = config_exclusive_filename;
- else
- config_filename = buf = git_pathdup("config");
-
- ret = git_config_set_multivar_in_file(config_filename, key, value,
- value_regex, multi_replace);
- free(buf);
- return ret;
+ return git_config_set_multivar_in_file(NULL, key, value, value_regex,
+ multi_replace);
}
static int section_name_match (const char *buf, const char *name)
@@ -1480,20 +1558,42 @@ static int section_name_match (const char *buf, const char *name)
return 0;
}
+static int section_name_is_ok(const char *name)
+{
+ /* Empty section names are bogus. */
+ if (!*name)
+ return 0;
+
+ /*
+ * Before a dot, we must be alphanumeric or dash. After the first dot,
+ * anything goes, so we can stop checking.
+ */
+ for (; *name && *name != '.'; name++)
+ if (*name != '-' && !isalnum(*name))
+ return 0;
+ return 1;
+}
+
/* if new_name == NULL, the section is removed instead */
-int git_config_rename_section(const char *old_name, const char *new_name)
+int git_config_rename_section_in_file(const char *config_filename,
+ const char *old_name, const char *new_name)
{
int ret = 0, remove = 0;
- char *config_filename;
- struct lock_file *lock = xcalloc(sizeof(struct lock_file), 1);
+ char *filename_buf = NULL;
+ struct lock_file *lock;
int out_fd;
char buf[1024];
FILE *config_file;
- if (config_exclusive_filename)
- config_filename = xstrdup(config_exclusive_filename);
- else
- config_filename = git_pathdup("config");
+ if (new_name && !section_name_is_ok(new_name)) {
+ ret = error("invalid section name: %s", new_name);
+ goto out;
+ }
+
+ if (!config_filename)
+ config_filename = filename_buf = git_pathdup("config");
+
+ lock = xcalloc(sizeof(struct lock_file), 1);
out_fd = hold_lock_file_for_update(lock, config_filename, 0);
if (out_fd < 0) {
ret = error("could not lock config file %s", config_filename);
@@ -1557,10 +1657,15 @@ unlock_and_out:
if (commit_lock_file(lock) < 0)
ret = error("could not commit config file %s", config_filename);
out:
- free(config_filename);
+ free(filename_buf);
return ret;
}
+int git_config_rename_section(const char *old_name, const char *new_name)
+{
+ return git_config_rename_section_in_file(NULL, old_name, new_name);
+}
+
/*
* Call this to report error for your variable that should not
* get a boolean value (i.e. "[my] var" means "true").
diff --git a/configure.ac b/configure.ac
index 8bb0f44b48..72f7958824 100644
--- a/configure.ac
+++ b/configure.ac
@@ -137,6 +137,23 @@ if test -n "$1"; then
fi
])
+# Directories holding "saner" versions of common or POSIX binaries.
+AC_ARG_WITH([sane-tool-path],
+ [AS_HELP_STRING(
+ [--with-sane-tool-path=DIR-1[[:DIR-2...:DIR-n]]],
+ [Directories to prepend to PATH in build system and generated scripts])],
+ [if test "$withval" = "no"; then
+ withval=''
+ else
+ AC_MSG_NOTICE([Setting SANE_TOOL_PATH to '$withval'])
+ fi
+ GIT_CONF_APPEND_LINE([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
+ # Git build system when configure is used w.r.t. when it is not.
+ :])
+
## Site configuration related to programs (before tests)
## --with-PACKAGE[=ARG] and --without-PACKAGE
#
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 0acbdda3b8..31f714da92 100755
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -94,9 +94,10 @@ __gitdir ()
__git_ps1_show_upstream ()
{
local key value
- local svn_remote=() svn_url_pattern count n
+ 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
@@ -137,7 +138,7 @@ __git_ps1_show_upstream ()
svn_upstream=${svn_upstream[ ${#svn_upstream[@]} - 2 ]}
svn_upstream=${svn_upstream%@*}
local n_stop="${#svn_remote[@]}"
- for ((n=1; n <= n_stop; ++n)); do
+ for ((n=1; n <= n_stop; n++)); do
svn_upstream=${svn_upstream#${svn_remote[$n]}}
done
@@ -166,10 +167,8 @@ __git_ps1_show_upstream ()
for commit in $commits
do
case "$commit" in
- "<"*) let ++behind
- ;;
- *) let ++ahead
- ;;
+ "<"*) ((behind++)) ;;
+ *) ((ahead++)) ;;
esac
done
count="$behind $ahead"
@@ -726,6 +725,9 @@ __git_complete_remote_or_refspec ()
{
local cur_="$cur" cmd="${words[1]}"
local i c=2 remote="" pfx="" lhs=1 no_complete_refspec=0
+ if [ "$cmd" = "remote" ]; then
+ ((c++))
+ fi
while [ $c -lt $cword ]; do
i="${words[c]}"
case "$i" in
@@ -743,7 +745,7 @@ __git_complete_remote_or_refspec ()
-*) ;;
*) remote="$i"; break ;;
esac
- c=$((++c))
+ ((c++))
done
if [ -z "$remote" ]; then
__gitcomp_nl "$(__git_remotes)"
@@ -776,7 +778,7 @@ __git_complete_remote_or_refspec ()
__gitcomp_nl "$(__git_refs)" "$pfx" "$cur_"
fi
;;
- pull)
+ pull|remote)
if [ $lhs = 1 ]; then
__gitcomp_nl "$(__git_refs "$remote")" "$pfx" "$cur_"
else
@@ -983,7 +985,7 @@ __git_find_on_cmdline ()
return
fi
done
- c=$((++c))
+ ((c++))
done
}
@@ -994,7 +996,7 @@ __git_has_doubledash ()
if [ "--" = "${words[c]}" ]; then
return 0
fi
- c=$((++c))
+ ((c++))
done
return 1
}
@@ -1117,7 +1119,7 @@ _git_branch ()
-d|-m) only_local_ref="y" ;;
-r) has_r="y" ;;
esac
- c=$((++c))
+ ((c++))
done
case "$cur" in
@@ -2091,6 +2093,7 @@ _git_config ()
core.whitespace
core.worktree
diff.autorefreshindex
+ diff.statGraphWidth
diff.external
diff.ignoreSubmodules
diff.mnemonicprefix
@@ -2277,7 +2280,7 @@ _git_config ()
_git_remote ()
{
- local subcommands="add rename rm show prune update set-head"
+ local subcommands="add rename rm set-head set-branches set-url show prune update"
local subcommand="$(__git_find_on_cmdline "$subcommands")"
if [ -z "$subcommand" ]; then
__gitcomp "$subcommands"
@@ -2285,9 +2288,12 @@ _git_remote ()
fi
case "$subcommand" in
- rename|rm|show|prune)
+ rename|rm|set-url|show|prune)
__gitcomp_nl "$(__git_remotes)"
;;
+ set-head|set-branches)
+ __git_complete_remote_or_refspec
+ ;;
update)
local i c='' IFS=$'\n'
for i in $(git --git-dir="$(__gitdir)" config --get-regexp "remotes\..*" 2>/dev/null); do
@@ -2500,7 +2506,7 @@ _git_svn ()
__gitcomp "
--merge --strategy= --verbose --dry-run
--fetch-all --no-rebase --commit-url
- --revision $cmt_opts $fc_opts
+ --revision --interactive $cmt_opts $fc_opts
"
;;
set-tree,--*)
@@ -2568,7 +2574,7 @@ _git_tag ()
f=1
;;
esac
- c=$((++c))
+ ((c++))
done
case "$prev" in
@@ -2621,7 +2627,7 @@ _git ()
--help) command="help"; break ;;
*) command="$i"; break ;;
esac
- c=$((++c))
+ ((c++))
done
if [ -z "$command" ]; then
diff --git a/contrib/credential/osxkeychain/Makefile b/contrib/credential/osxkeychain/Makefile
index 75c07f8be4..4b3a08a2ba 100644
--- a/contrib/credential/osxkeychain/Makefile
+++ b/contrib/credential/osxkeychain/Makefile
@@ -2,10 +2,13 @@ all:: git-credential-osxkeychain
CC = gcc
RM = rm -f
-CFLAGS = -g -Wall
+CFLAGS = -g -O2 -Wall
+
+-include ../../../config.mak.autogen
+-include ../../../config.mak
git-credential-osxkeychain: git-credential-osxkeychain.o
- $(CC) -o $@ $< -Wl,-framework -Wl,Security
+ $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) -Wl,-framework -Wl,Security
git-credential-osxkeychain.o: git-credential-osxkeychain.c
$(CC) -c $(CFLAGS) $<
diff --git a/contrib/diff-highlight/README b/contrib/diff-highlight/README
index 1b7b6df8eb..502e03b305 100644
--- a/contrib/diff-highlight/README
+++ b/contrib/diff-highlight/README
@@ -14,13 +14,15 @@ Instead, this script post-processes the line-oriented diff, finds pairs
of lines, and highlights the differing segments. It's currently very
simple and stupid about doing these tasks. In particular:
- 1. It will only highlight a pair of lines if they are the only two
- lines in a hunk. It could instead try to match up "before" and
- "after" lines for a given hunk into pairs of similar lines.
- However, this may end up visually distracting, as the paired
- lines would have other highlighted lines in between them. And in
- practice, the lines which most need attention called to their
- small, hard-to-see changes are touching only a single line.
+ 1. It will only highlight hunks in which the number of removed and
+ added lines is the same, and it will pair lines within the hunk by
+ position (so the first removed line is compared to the first added
+ line, and so forth). This is simple and tends to work well in
+ practice. More complex changes don't highlight well, so we tend to
+ exclude them due to the "same number of removed and added lines"
+ restriction. Or even if we do try to highlight them, they end up
+ not highlighting because of our "don't highlight if the whole line
+ would be highlighted" rule.
2. It will find the common prefix and suffix of two lines, and
consider everything in the middle to be "different". It could
@@ -55,3 +57,96 @@ following in your git configuration:
show = diff-highlight | less
diff = diff-highlight | less
---------------------------------------------
+
+Bugs
+----
+
+Because diff-highlight relies on heuristics to guess which parts of
+changes are important, there are some cases where the highlighting is
+more distracting than useful. Fortunately, these cases are rare in
+practice, and when they do occur, the worst case is simply a little
+extra highlighting. This section documents some cases known to be
+sub-optimal, in case somebody feels like working on improving the
+heuristics.
+
+1. Two changes on the same line get highlighted in a blob. For example,
+ highlighting:
+
+----------------------------------------------
+-foo(buf, size);
++foo(obj->buf, obj->size);
+----------------------------------------------
+
+ yields (where the inside of "+{}" would be highlighted):
+
+----------------------------------------------
+-foo(buf, size);
++foo(+{obj->buf, obj->}size);
+----------------------------------------------
+
+ whereas a more semantically meaningful output would be:
+
+----------------------------------------------
+-foo(buf, size);
++foo(+{obj->}buf, +{obj->}size);
+----------------------------------------------
+
+ Note that doing this right would probably involve a set of
+ content-specific boundary patterns, similar to word-diff. Otherwise
+ you get junk like:
+
+-----------------------------------------------------
+-this line has some -{i}nt-{ere}sti-{ng} text on it
++this line has some +{fa}nt+{a}sti+{c} text on it
+-----------------------------------------------------
+
+ which is less readable than the current output.
+
+2. The multi-line matching assumes that lines in the pre- and post-image
+ match by position. This is often the case, but can be fooled when a
+ line is removed from the top and a new one added at the bottom (or
+ vice versa). Unless the lines in the middle are also changed, diffs
+ will show this as two hunks, and it will not get highlighted at all
+ (which is good). But if the lines in the middle are changed, the
+ highlighting can be misleading. Here's a pathological case:
+
+-----------------------------------------------------
+-one
+-two
+-three
+-four
++two 2
++three 3
++four 4
++five 5
+-----------------------------------------------------
+
+ which gets highlighted as:
+
+-----------------------------------------------------
+-one
+-t-{wo}
+-three
+-f-{our}
++two 2
++t+{hree 3}
++four 4
++f+{ive 5}
+-----------------------------------------------------
+
+ because it matches "two" to "three 3", and so forth. It would be
+ nicer as:
+
+-----------------------------------------------------
+-one
+-two
+-three
+-four
++two +{2}
++three +{3}
++four +{4}
++five 5
+-----------------------------------------------------
+
+ which would probably involve pre-matching the lines into pairs
+ according to some heuristic.
diff --git a/contrib/diff-highlight/diff-highlight b/contrib/diff-highlight/diff-highlight
index d8938982e4..c4404d49c9 100755
--- a/contrib/diff-highlight/diff-highlight
+++ b/contrib/diff-highlight/diff-highlight
@@ -1,28 +1,37 @@
#!/usr/bin/perl
+use warnings FATAL => 'all';
+use strict;
+
# Highlight by reversing foreground and background. You could do
# other things like bold or underline if you prefer.
my $HIGHLIGHT = "\x1b[7m";
my $UNHIGHLIGHT = "\x1b[27m";
my $COLOR = qr/\x1b\[[0-9;]*m/;
+my $BORING = qr/$COLOR|\s/;
-my @window;
+my @removed;
+my @added;
+my $in_hunk;
while (<>) {
- # We highlight only single-line changes, so we need
- # a 4-line window to make a decision on whether
- # to highlight.
- push @window, $_;
- next if @window < 4;
- if ($window[0] =~ /^$COLOR*(\@| )/ &&
- $window[1] =~ /^$COLOR*-/ &&
- $window[2] =~ /^$COLOR*\+/ &&
- $window[3] !~ /^$COLOR*\+/) {
- print shift @window;
- show_pair(shift @window, shift @window);
+ if (!$in_hunk) {
+ print;
+ $in_hunk = /^$COLOR*\@/;
+ }
+ elsif (/^$COLOR*-/) {
+ push @removed, $_;
+ }
+ elsif (/^$COLOR*\+/) {
+ push @added, $_;
}
else {
- print shift @window;
+ show_hunk(\@removed, \@added);
+ @removed = ();
+ @added = ();
+
+ print;
+ $in_hunk = /^$COLOR*[\@ ]/;
}
# Most of the time there is enough output to keep things streaming,
@@ -38,23 +47,40 @@ while (<>) {
}
}
-# Special case a single-line hunk at the end of file.
-if (@window == 3 &&
- $window[0] =~ /^$COLOR*(\@| )/ &&
- $window[1] =~ /^$COLOR*-/ &&
- $window[2] =~ /^$COLOR*\+/) {
- print shift @window;
- show_pair(shift @window, shift @window);
-}
-
-# And then flush any remaining lines.
-while (@window) {
- print shift @window;
-}
+# Flush any queued hunk (this can happen when there is no trailing context in
+# the final diff of the input).
+show_hunk(\@removed, \@added);
exit 0;
-sub show_pair {
+sub show_hunk {
+ my ($a, $b) = @_;
+
+ # If one side is empty, then there is nothing to compare or highlight.
+ if (!@$a || !@$b) {
+ print @$a, @$b;
+ return;
+ }
+
+ # If we have mismatched numbers of lines on each side, we could try to
+ # be clever and match up similar lines. But for now we are simple and
+ # stupid, and only handle multi-line hunks that remove and add the same
+ # number of lines.
+ if (@$a != @$b) {
+ print @$a, @$b;
+ return;
+ }
+
+ my @queue;
+ for (my $i = 0; $i < @$a; $i++) {
+ my ($rm, $add) = highlight_pair($a->[$i], $b->[$i]);
+ print $rm;
+ push @queue, $add;
+ }
+ print @queue;
+}
+
+sub highlight_pair {
my @a = split_line(shift);
my @b = split_line(shift);
@@ -101,8 +127,14 @@ sub show_pair {
}
}
- print highlight(\@a, $pa, $sa);
- print highlight(\@b, $pb, $sb);
+ if (is_pair_interesting(\@a, $pa, $sa, \@b, $pb, $sb)) {
+ return highlight_line(\@a, $pa, $sa),
+ highlight_line(\@b, $pb, $sb);
+ }
+ else {
+ return join('', @a),
+ join('', @b);
+ }
}
sub split_line {
@@ -111,7 +143,7 @@ sub split_line {
split /($COLOR*)/;
}
-sub highlight {
+sub highlight_line {
my ($line, $prefix, $suffix) = @_;
return join('',
@@ -122,3 +154,20 @@ sub highlight {
@{$line}[($suffix+1)..$#$line]
);
}
+
+# Pairs are interesting to highlight only if we are going to end up
+# highlighting a subset (i.e., not the whole line). Otherwise, the highlighting
+# is just useless noise. We can detect this by finding either a matching prefix
+# or suffix (disregarding boring bits like whitespace and colorization).
+sub is_pair_interesting {
+ my ($a, $pa, $sa, $b, $pb, $sb) = @_;
+ my $prefix_a = join('', @$a[0..($pa-1)]);
+ my $prefix_b = join('', @$b[0..($pb-1)]);
+ my $suffix_a = join('', @$a[($sa+1)..$#$a]);
+ my $suffix_b = join('', @$b[($sb+1)..$#$b]);
+
+ return $prefix_a !~ /^$COLOR*-$BORING*$/ ||
+ $prefix_b !~ /^$COLOR*\+$BORING*$/ ||
+ $suffix_a !~ /^$BORING*$/ ||
+ $suffix_b !~ /^$BORING*$/;
+}
diff --git a/contrib/diffall/README b/contrib/diffall/README
new file mode 100644
index 0000000000..507f17dcd6
--- /dev/null
+++ b/contrib/diffall/README
@@ -0,0 +1,31 @@
+The git-diffall script provides a directory based diff mechanism
+for git.
+
+To determine what diff viewer is used, the script requires either
+the 'diff.tool' or 'merge.tool' configuration option to be set.
+
+This script is compatible with most common forms used to specify a
+range of revisions to diff:
+
+ 1. git diffall: shows diff between working tree and staged changes
+ 2. git diffall --cached [<commit>]: shows diff between staged
+ changes and HEAD (or other named commit)
+ 3. git diffall <commit>: shows diff between working tree and named
+ commit
+ 4. git diffall <commit> <commit>: show diff between two named commits
+ 5. git diffall <commit>..<commit>: same as above
+ 6. git diffall <commit>...<commit>: show the changes on the branch
+ containing and up to the second, starting at a common ancestor
+ of both <commit>
+
+Note: all forms take an optional path limiter [-- <path>*]
+
+The '--extcmd=<command>' option allows the user to specify a custom
+command for viewing diffs. When given, configured defaults are
+ignored and the script runs $command $LOCAL $REMOTE. Additionally,
+$BASE is set in the environment.
+
+This script is based on an example provided by Thomas Rast on the
+Git list [1]:
+
+[1] http://thread.gmane.org/gmane.comp.version-control.git/124807
diff --git a/contrib/diffall/git-diffall b/contrib/diffall/git-diffall
new file mode 100755
index 0000000000..84f2b654d7
--- /dev/null
+++ b/contrib/diffall/git-diffall
@@ -0,0 +1,257 @@
+#!/bin/sh
+# Copyright 2010 - 2012, Tim Henigan <tim.henigan@gmail.com>
+#
+# Perform a directory diff between commits in the repository using
+# the external diff or merge tool specified in the user's config.
+
+USAGE='[--cached] [--copy-back] [-x|--extcmd=<command>] <commit>{0,2} [-- <path>*]
+
+ --cached Compare to the index rather than the working tree.
+
+ --copy-back Copy files back to the working tree when the diff
+ tool exits (in case they were modified by the
+ user). This option is only valid if the diff
+ compared with the working tree.
+
+ -x=<command>
+ --extcmd=<command> Specify a custom command for viewing diffs.
+ git-diffall ignores the configured defaults and
+ runs $command $LOCAL $REMOTE when this option is
+ specified. Additionally, $BASE is set in the
+ environment.
+'
+
+SUBDIRECTORY_OK=1
+. "$(git --exec-path)/git-sh-setup"
+
+TOOL_MODE=diff
+. "$(git --exec-path)/git-mergetool--lib"
+
+merge_tool="$(get_merge_tool)"
+if test -z "$merge_tool"
+then
+ echo "Error: Either the 'diff.tool' or 'merge.tool' option must be set."
+ usage
+fi
+
+start_dir=$(pwd)
+
+# All the file paths returned by the diff command are relative to the root
+# of the working copy. So if the script is called from a subdirectory, it
+# must switch to the root of working copy before trying to use those paths.
+cdup=$(git rev-parse --show-cdup) &&
+cd "$cdup" || {
+ echo >&2 "Cannot chdir to $cdup, the toplevel of the working tree"
+ exit 1
+}
+
+# set up temp dir
+tmp=$(perl -e 'use File::Temp qw(tempdir);
+ $t=tempdir("/tmp/git-diffall.XXXXX") or exit(1);
+ print $t') || exit 1
+trap 'rm -rf "$tmp"' EXIT
+
+left=
+right=
+paths=
+dashdash_seen=
+compare_staged=
+merge_base=
+left_dir=
+right_dir=
+diff_tool=
+copy_back=
+
+while test $# != 0
+do
+ case "$1" in
+ -h|--h|--he|--hel|--help)
+ usage
+ ;;
+ --cached)
+ compare_staged=1
+ ;;
+ --copy-back)
+ copy_back=1
+ ;;
+ -x|--e|--ex|--ext|--extc|--extcm|--extcmd)
+ if test $# = 1
+ then
+ echo You must specify the tool for use with --extcmd
+ usage
+ else
+ diff_tool=$2
+ shift
+ fi
+ ;;
+ --)
+ dashdash_seen=1
+ ;;
+ -*)
+ echo Invalid option: "$1"
+ usage
+ ;;
+ *)
+ # could be commit, commit range or path limiter
+ case "$1" in
+ *...*)
+ left=${1%...*}
+ right=${1#*...}
+ merge_base=1
+ ;;
+ *..*)
+ left=${1%..*}
+ right=${1#*..}
+ ;;
+ *)
+ if test -n "$dashdash_seen"
+ then
+ paths="$paths$1 "
+ elif test -z "$left"
+ then
+ left=$1
+ elif test -z "$right"
+ then
+ right=$1
+ else
+ paths="$paths$1 "
+ fi
+ ;;
+ esac
+ ;;
+ esac
+ shift
+done
+
+# Determine the set of files which changed
+if test -n "$left" && test -n "$right"
+then
+ left_dir="cmt-$(git rev-parse --short $left)"
+ right_dir="cmt-$(git rev-parse --short $right)"
+
+ if test -n "$compare_staged"
+ then
+ usage
+ elif test -n "$merge_base"
+ then
+ git diff --name-only "$left"..."$right" -- $paths >"$tmp/filelist"
+ else
+ git diff --name-only "$left" "$right" -- $paths >"$tmp/filelist"
+ fi
+elif test -n "$left"
+then
+ left_dir="cmt-$(git rev-parse --short $left)"
+
+ if test -n "$compare_staged"
+ then
+ right_dir="staged"
+ git diff --name-only --cached "$left" -- $paths >"$tmp/filelist"
+ else
+ right_dir="working_tree"
+ git diff --name-only "$left" -- $paths >"$tmp/filelist"
+ fi
+else
+ left_dir="HEAD"
+
+ if test -n "$compare_staged"
+ then
+ right_dir="staged"
+ git diff --name-only --cached -- $paths >"$tmp/filelist"
+ else
+ right_dir="working_tree"
+ git diff --name-only -- $paths >"$tmp/filelist"
+ fi
+fi
+
+# Exit immediately if there are no diffs
+if test ! -s "$tmp/filelist"
+then
+ exit 0
+fi
+
+if test -n "$copy_back" && test "$right_dir" != "working_tree"
+then
+ echo "--copy-back is only valid when diff includes the working tree."
+ exit 1
+fi
+
+# Create the named tmp directories that will hold the files to be compared
+mkdir -p "$tmp/$left_dir" "$tmp/$right_dir"
+
+# Populate the tmp/right_dir directory with the files to be compared
+while read name
+do
+ if test -n "$right"
+ then
+ ls_list=$(git ls-tree $right "$name")
+ if test -n "$ls_list"
+ then
+ mkdir -p "$tmp/$right_dir/$(dirname "$name")"
+ git show "$right":"$name" >"$tmp/$right_dir/$name" || true
+ fi
+ elif test -n "$compare_staged"
+ then
+ ls_list=$(git ls-files -- "$name")
+ if test -n "$ls_list"
+ then
+ mkdir -p "$tmp/$right_dir/$(dirname "$name")"
+ git show :"$name" >"$tmp/$right_dir/$name"
+ fi
+ else
+ if test -e "$name"
+ then
+ mkdir -p "$tmp/$right_dir/$(dirname "$name")"
+ cp "$name" "$tmp/$right_dir/$name"
+ fi
+ fi
+done < "$tmp/filelist"
+
+# Populate the tmp/left_dir directory with the files to be compared
+while read name
+do
+ if test -n "$left"
+ then
+ ls_list=$(git ls-tree $left "$name")
+ if test -n "$ls_list"
+ then
+ mkdir -p "$tmp/$left_dir/$(dirname "$name")"
+ git show "$left":"$name" >"$tmp/$left_dir/$name" || true
+ fi
+ else
+ if test -n "$compare_staged"
+ then
+ ls_list=$(git ls-tree HEAD "$name")
+ if test -n "$ls_list"
+ then
+ mkdir -p "$tmp/$left_dir/$(dirname "$name")"
+ git show HEAD:"$name" >"$tmp/$left_dir/$name"
+ fi
+ else
+ mkdir -p "$tmp/$left_dir/$(dirname "$name")"
+ git show :"$name" >"$tmp/$left_dir/$name"
+ fi
+ fi
+done < "$tmp/filelist"
+
+LOCAL="$tmp/$left_dir"
+REMOTE="$tmp/$right_dir"
+
+if test -n "$diff_tool"
+then
+ export BASE
+ eval $diff_tool '"$LOCAL"' '"$REMOTE"'
+else
+ run_merge_tool "$merge_tool" false
+fi
+
+# Copy files back to the working dir, if requested
+if test -n "$copy_back" && test "$right_dir" = "working_tree"
+then
+ cd "$start_dir"
+ git_top_dir=$(git rev-parse --show-toplevel)
+ find "$tmp/$right_dir" -type f |
+ while read file
+ do
+ cp "$file" "$git_top_dir/${file#$tmp/$right_dir/}"
+ done
+fi
diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4
index 9ccc87b205..c5362c4c11 100755
--- a/contrib/fast-import/git-p4
+++ b/contrib/fast-import/git-p4
@@ -10,7 +10,7 @@
import optparse, sys, os, marshal, subprocess, shelve
import tempfile, getopt, os.path, time, platform
-import re
+import re, shutil
verbose = False
@@ -38,7 +38,7 @@ def p4_build_cmd(cmd):
host = gitConfig("git-p4.host")
if len(host) > 0:
- real_cmd += ["-h", host]
+ real_cmd += ["-H", host]
client = gitConfig("git-p4.client")
if len(client) > 0:
@@ -186,6 +186,47 @@ def split_p4_type(p4type):
mods = s[1]
return (base, mods)
+#
+# return the raw p4 type of a file (text, text+ko, etc)
+#
+def p4_type(file):
+ results = p4CmdList(["fstat", "-T", "headType", file])
+ return results[0]['headType']
+
+#
+# Given a type base and modifier, return a regexp matching
+# the keywords that can be expanded in the file
+#
+def p4_keywords_regexp_for_type(base, type_mods):
+ if base in ("text", "unicode", "binary"):
+ kwords = None
+ if "ko" in type_mods:
+ kwords = 'Id|Header'
+ elif "k" in type_mods:
+ kwords = 'Id|Header|Author|Date|DateTime|Change|File|Revision'
+ else:
+ return None
+ pattern = r"""
+ \$ # Starts with a dollar, followed by...
+ (%s) # one of the keywords, followed by...
+ (:[^$]+)? # possibly an old expansion, followed by...
+ \$ # another dollar
+ """ % kwords
+ return pattern
+ else:
+ return None
+
+#
+# Given a file, return a regexp matching the possible
+# RCS keywords that will be expanded, or None for files
+# with kw expansion turned off.
+#
+def p4_keywords_regexp_for_file(file):
+ if not os.path.exists(file):
+ return None
+ else:
+ (type_base, type_mods) = split_p4_type(p4_type(file))
+ return p4_keywords_regexp_for_type(type_base, type_mods)
def setP4ExecBit(file, mode):
# Reopens an already open file and changes the execute bit to match
@@ -603,6 +644,26 @@ class Command:
class P4UserMap:
def __init__(self):
self.userMapFromPerforceServer = False
+ self.myP4UserId = None
+
+ def p4UserId(self):
+ if self.myP4UserId:
+ return self.myP4UserId
+
+ results = p4CmdList("user -o")
+ for r in results:
+ if r.has_key('User'):
+ self.myP4UserId = r['User']
+ return r['User']
+ die("Could not find your p4 user id")
+
+ def p4UserIsMe(self, p4User):
+ # return True if the given p4 user is actually me
+ me = self.p4UserId()
+ if not p4User or p4User != me:
+ return False
+ else:
+ return True
def getUserCacheFilename(self):
home = os.environ.get("HOME", os.environ.get("USERPROFILE"))
@@ -740,7 +801,6 @@ class P4Submit(Command, P4UserMap):
self.verbose = False
self.preserveUser = gitConfig("git-p4.preserveUser").lower() == "true"
self.isWindows = (platform.system() == "Windows")
- self.myP4UserId = None
def check(self):
if len(p4CmdList("opened ...")) > 0:
@@ -774,6 +834,29 @@ class P4Submit(Command, P4UserMap):
return result
+ def patchRCSKeywords(self, file, pattern):
+ # Attempt to zap the RCS keywords in a p4 controlled file matching the given pattern
+ (handle, outFileName) = tempfile.mkstemp(dir='.')
+ try:
+ outFile = os.fdopen(handle, "w+")
+ inFile = open(file, "r")
+ regexp = re.compile(pattern, re.VERBOSE)
+ for line in inFile.readlines():
+ line = regexp.sub(r'$\1$', line)
+ outFile.write(line)
+ inFile.close()
+ outFile.close()
+ # Forcibly overwrite the original file
+ os.unlink(file)
+ shutil.move(outFileName, file)
+ except:
+ # cleanup our temporary file
+ os.unlink(outFileName)
+ print "Failed to strip RCS keywords in %s" % file
+ raise
+
+ print "Patched up RCS keywords in %s" % file
+
def p4UserForCommit(self,id):
# Return the tuple (perforce user,git email) for a given git commit id
self.getUserMapFromPerforceServer()
@@ -839,7 +922,7 @@ class P4Submit(Command, P4UserMap):
def canChangeChangelists(self):
# check to see if we have p4 admin or super-user permissions, either of
# which are required to modify changelists.
- results = p4CmdList("protects %s" % self.depotPath)
+ results = p4CmdList(["protects", self.depotPath])
for r in results:
if r.has_key('perm'):
if r['perm'] == 'admin':
@@ -848,25 +931,6 @@ class P4Submit(Command, P4UserMap):
return 1
return 0
- def p4UserId(self):
- if self.myP4UserId:
- return self.myP4UserId
-
- results = p4CmdList("user -o")
- for r in results:
- if r.has_key('User'):
- self.myP4UserId = r['User']
- return r['User']
- die("Could not find your p4 user id")
-
- def p4UserIsMe(self, p4User):
- # return True if the given p4 user is actually me
- me = self.p4UserId()
- if not p4User or p4User != me:
- return False
- else:
- return True
-
def prepareSubmitTemplate(self):
# remove lines in the Files section that show changes to files outside the depot path we're committing into
template = ""
@@ -958,6 +1022,7 @@ class P4Submit(Command, P4UserMap):
filesToDelete = set()
editedFiles = set()
filesToChangeExecBit = {}
+
for line in diff:
diff = parseDiffTreeEntry(line)
modifier = diff['status']
@@ -1004,9 +1069,45 @@ class P4Submit(Command, P4UserMap):
patchcmd = diffcmd + " | git apply "
tryPatchCmd = patchcmd + "--check -"
applyPatchCmd = patchcmd + "--check --apply -"
+ patch_succeeded = True
if os.system(tryPatchCmd) != 0:
+ fixed_rcs_keywords = False
+ patch_succeeded = False
print "Unfortunately applying the change failed!"
+
+ # Patch failed, maybe it's just RCS keyword woes. Look through
+ # the patch to see if that's possible.
+ if gitConfig("git-p4.attemptRCSCleanup","--bool") == "true":
+ file = None
+ pattern = None
+ kwfiles = {}
+ for file in editedFiles | filesToDelete:
+ # did this file's delta contain RCS keywords?
+ pattern = p4_keywords_regexp_for_file(file)
+
+ if pattern:
+ # this file is a possibility...look for RCS keywords.
+ regexp = re.compile(pattern, re.VERBOSE)
+ for line in read_pipe_lines(["git", "diff", "%s^..%s" % (id, id), file]):
+ if regexp.search(line):
+ if verbose:
+ print "got keyword match on %s in %s in %s" % (pattern, line, file)
+ kwfiles[file] = pattern
+ break
+
+ for file in kwfiles:
+ if verbose:
+ print "zapping %s with %s" % (line,pattern)
+ self.patchRCSKeywords(file, kwfiles[file])
+ fixed_rcs_keywords = True
+
+ if fixed_rcs_keywords:
+ print "Retrying the patch with RCS keywords cleaned up"
+ if os.system(tryPatchCmd) == 0:
+ 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":
@@ -1256,8 +1357,8 @@ class View(object):
die("Can't handle * wildcards in view: %s" % self.path)
triple_dot_index = self.path.find("...")
if triple_dot_index >= 0:
- if not self.path.endswith("..."):
- die("Can handle ... wildcard only at end of path: %s" %
+ if triple_dot_index != len(self.path) - 3:
+ die("Can handle only single ... wildcard, at end: %s" %
self.path)
self.ends_triple_dot = True
@@ -1312,7 +1413,7 @@ class View(object):
if self.exclude:
c = "-"
return "View.Mapping: %s%s -> %s" % \
- (c, self.depot_side, self.client_side)
+ (c, self.depot_side.path, self.client_side.path)
def map_depot_to_client(self, depot_path):
"""Calculate the client path if using this mapping on the
@@ -1412,7 +1513,8 @@ class View(object):
else:
# This mapping matched; no need to search any further.
# But, the mapping could be rejected if the client path
- # has already been claimed by an earlier mapping.
+ # has already been claimed by an earlier mapping (i.e.
+ # one later in the list, which we are walking backwards).
already_mapped_in_client = False
for f in paths_filled:
# this is View.Path.match
@@ -1479,6 +1581,8 @@ class P4Sync(Command, P4UserMap):
self.useClientSpec = False
self.useClientSpec_from_options = False
self.clientSpecDirs = None
+ self.tempBranches = []
+ self.tempBranchLocation = "git-p4-tmp"
if gitConfig("git-p4.syncFromOrigin") == "false":
self.syncWithOrigin = False
@@ -1500,6 +1604,14 @@ class P4Sync(Command, P4UserMap):
.replace("%25", "%")
return path
+ # Force a checkpoint in fast-import and wait for it to finish
+ def checkpoint(self):
+ self.gitStream.write("checkpoint\n\n")
+ self.gitStream.write("progress checkpoint\n\n")
+ out = self.gitOutput.readline()
+ if self.verbose:
+ print "checkpoint finished: " + out
+
def extractFilesFromCommit(self, commit):
self.cloneExclude = [re.sub(r"\.\.\.$", "", path)
for path in self.cloneExclude]
@@ -1624,15 +1736,12 @@ class P4Sync(Command, P4UserMap):
# Note that we do not try to de-mangle keywords on utf16 files,
# even though in theory somebody may want that.
- if type_base in ("text", "unicode", "binary"):
- if "ko" in type_mods:
- text = ''.join(contents)
- text = re.sub(r'\$(Id|Header):[^$]*\$', r'$\1$', text)
- contents = [ text ]
- elif "k" in type_mods:
- text = ''.join(contents)
- text = re.sub(r'\$(Id|Header|Author|Date|DateTime|Change|File|Revision):[^$]*\$', r'$\1$', text)
- contents = [ text ]
+ pattern = p4_keywords_regexp_for_type(type_base, type_mods)
+ if pattern:
+ regexp = re.compile(pattern, re.VERBOSE)
+ text = ''.join(contents)
+ text = regexp.sub(r'$\1$', text)
+ contents = [ text ]
self.gitStream.write("M %s inline %s\n" % (git_mode, relPath))
@@ -1714,6 +1823,12 @@ class P4Sync(Command, P4UserMap):
if self.stream_file.has_key('depotFile'):
self.streamOneP4File(self.stream_file, self.stream_contents)
+ def make_email(self, userid):
+ if userid in self.users:
+ return self.users[userid]
+ else:
+ return "%s <a@b>" % userid
+
def commit(self, details, files, branch, branchPrefixes, parent = ""):
epoch = details["time"]
author = details["user"]
@@ -1737,10 +1852,7 @@ class P4Sync(Command, P4UserMap):
committer = ""
if author not in self.users:
self.getUserMapFromPerforceServer()
- if author in self.users:
- committer = "%s %s %s" % (self.users[author], epoch, self.tz)
- else:
- committer = "%s <a@b> %s %s" % (author, epoch, self.tz)
+ committer = "%s %s %s" % (self.make_email(author), epoch, self.tz)
self.gitStream.write("committer %s\n" % committer)
@@ -1785,15 +1897,21 @@ class P4Sync(Command, P4UserMap):
self.gitStream.write("from %s\n" % branch)
owner = labelDetails["Owner"]
- tagger = ""
- if author in self.users:
- tagger = "%s %s %s" % (self.users[owner], epoch, self.tz)
+
+ # Try to use the owner of the p4 label, or failing that,
+ # the current p4 user id.
+ if owner:
+ email = self.make_email(owner)
else:
- tagger = "%s <a@b> %s %s" % (owner, epoch, self.tz)
+ email = self.make_email(self.p4UserId())
+ tagger = "%s %s %s" % (email, epoch, self.tz)
+
self.gitStream.write("tagger %s\n" % tagger)
- self.gitStream.write("data <<EOT\n")
- self.gitStream.write(labelDetails["Description"])
- self.gitStream.write("EOT\n\n")
+
+ description = labelDetails["Description"]
+ self.gitStream.write("data %d\n" % len(description))
+ self.gitStream.write(description)
+ self.gitStream.write("\n")
else:
if not self.silent:
@@ -1808,7 +1926,7 @@ class P4Sync(Command, P4UserMap):
def getLabels(self):
self.labels = {}
- l = p4CmdList("labels %s..." % ' '.join (self.depotPaths))
+ l = p4CmdList(["labels"] + ["%s..." % p for p in self.depotPaths])
if len(l) > 0 and not self.silent:
print "Finding files belonging to labels in %s" % `self.depotPaths`
@@ -1850,7 +1968,7 @@ class P4Sync(Command, P4UserMap):
command = "branches"
for info in p4CmdList(command):
- details = p4Cmd("branch -o %s" % info["branch"])
+ details = p4Cmd(["branch", "-o", info["branch"]])
viewIdx = 0
while details.has_key("View%s" % viewIdx):
paths = details["View%s" % viewIdx].split(" ")
@@ -1988,7 +2106,7 @@ class P4Sync(Command, P4UserMap):
sourceRef = self.gitRefForBranch(sourceBranch)
#print "source " + sourceBranch
- branchParentChange = int(p4Cmd("changes -m 1 %s...@1,%s" % (sourceDepotPath, firstChange))["change"])
+ branchParentChange = int(p4Cmd(["changes", "-m", "1", "%s...@1,%s" % (sourceDepotPath, firstChange)])["change"])
#print "branch parent: %s" % branchParentChange
gitParent = self.gitCommitByP4Change(sourceRef, branchParentChange)
if len(gitParent) > 0:
@@ -1998,10 +2116,24 @@ class P4Sync(Command, P4UserMap):
self.importChanges(changes)
return True
+ def searchParent(self, parent, branch, target):
+ parentFound = False
+ for blob in read_pipe_lines(["git", "rev-list", "--reverse", "--no-merges", parent]):
+ blob = blob.strip()
+ if len(read_pipe(["git", "diff-tree", blob, target])) == 0:
+ parentFound = True
+ if self.verbose:
+ print "Found parent of %s in commit %s" % (branch, blob)
+ break
+ if parentFound:
+ return blob
+ else:
+ return None
+
def importChanges(self, changes):
cnt = 1
for change in changes:
- description = p4Cmd("describe %s" % change)
+ description = p4Cmd(["describe", str(change)])
self.updateOptionDict(description)
if not self.silent:
@@ -2054,7 +2186,21 @@ class P4Sync(Command, P4UserMap):
parent = self.initialParents[branch]
del self.initialParents[branch]
- self.commit(description, filesForCommit, branch, [branchPrefix], parent)
+ blob = None
+ if len(parent) > 0:
+ tempBranch = os.path.join(self.tempBranchLocation, "%d" % (change))
+ if self.verbose:
+ print "Creating temporary branch: " + tempBranch
+ self.commit(description, filesForCommit, tempBranch, [branchPrefix])
+ self.tempBranches.append(tempBranch)
+ self.checkpoint()
+ blob = self.searchParent(parent, branch, tempBranch)
+ if blob:
+ self.commit(description, filesForCommit, branch, [branchPrefix], 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)
else:
files = self.extractFilesFromCommit(description)
self.commit(description, files, self.branch, self.depotPaths,
@@ -2366,6 +2512,12 @@ class P4Sync(Command, P4UserMap):
self.gitOutput.close()
self.gitError.close()
+ # Cleanup temporary branches created during import
+ if self.tempBranches != []:
+ for branch in self.tempBranches:
+ read_pipe("git update-ref -d %s" % branch)
+ os.rmdir(os.path.join(os.environ.get("GIT_DIR", ".git"), self.tempBranchLocation))
+
return True
class P4Rebase(Command):
diff --git a/contrib/rerere-train.sh b/contrib/rerere-train.sh
index 2cfe1b936b..36b6feebe0 100755
--- a/contrib/rerere-train.sh
+++ b/contrib/rerere-train.sh
@@ -7,7 +7,7 @@ USAGE="$me rev-list-args"
SUBDIRECTORY_OK=Yes
OPTIONS_SPEC=
-. git-sh-setup
+. $(git --exec-path)/git-sh-setup
require_work_tree
cd_to_toplevel
diff --git a/contrib/svn-fe/svn-fe.txt b/contrib/svn-fe/svn-fe.txt
index 72ffea0b3a..1128ab2ce4 100644
--- a/contrib/svn-fe/svn-fe.txt
+++ b/contrib/svn-fe/svn-fe.txt
@@ -8,7 +8,10 @@ svn-fe - convert an SVN "dumpfile" to a fast-import stream
SYNOPSIS
--------
[verse]
-svnadmin dump --incremental REPO | svn-fe [url] | git fast-import
+mkfifo backchannel &&
+svnadmin dump --deltas REPO |
+ svn-fe [url] 3<backchannel |
+ git fast-import --cat-blob-fd=3 3>backchannel
DESCRIPTION
-----------
@@ -29,9 +32,6 @@ Subversion's repository dump format is documented in full in
Files in this format can be generated using the 'svnadmin dump' or
'svk admin dump' command.
-Dumps produced with 'svnadmin dump --deltas' (dumpfile format v3)
-are not supported.
-
OUTPUT FORMAT
-------------
The fast-import format is documented by the git-fast-import(1)
@@ -51,7 +51,7 @@ as committer, where 'user' is the value of the `svn:author` property
and 'UUID' the repository's identifier.
To support incremental imports, 'svn-fe' puts a `git-svn-id` line at
-the end of each commit log message if passed an url on the command
+the end of each commit log message if passed a URL on the command
line. This line has the form `git-svn-id: URL@REVNO UUID`.
The resulting repository will generally require further processing
diff --git a/convert.c b/convert.c
index 4534e2c2b0..66021550c3 100644
--- a/convert.c
+++ b/convert.c
@@ -452,6 +452,7 @@ static struct convert_driver {
struct convert_driver *next;
const char *smudge;
const char *clean;
+ int required;
} *user_convert, **user_convert_tail;
static int read_convert_config(const char *var, const char *value, void *cb)
@@ -495,6 +496,11 @@ static int read_convert_config(const char *var, const char *value, void *cb)
if (!strcmp("clean", ep))
return git_config_string(&drv->clean, var, value);
+ if (!strcmp("required", ep)) {
+ drv->required = git_config_bool(var, value);
+ return 0;
+ }
+
return 0;
}
@@ -773,13 +779,19 @@ int convert_to_git(const char *path, const char *src, size_t len,
{
int ret = 0;
const char *filter = NULL;
+ int required = 0;
struct conv_attrs ca;
convert_attrs(&ca, path);
- if (ca.drv)
+ if (ca.drv) {
filter = ca.drv->clean;
+ required = ca.drv->required;
+ }
ret |= apply_filter(path, src, len, dst, filter);
+ if (!ret && required)
+ die("%s: clean filter '%s' failed", path, ca.drv->name);
+
if (ret && dst) {
src = dst->buf;
len = dst->len;
@@ -797,13 +809,16 @@ static int convert_to_working_tree_internal(const char *path, const char *src,
size_t len, struct strbuf *dst,
int normalizing)
{
- int ret = 0;
+ int ret = 0, ret_filter = 0;
const char *filter = NULL;
+ int required = 0;
struct conv_attrs ca;
convert_attrs(&ca, path);
- if (ca.drv)
+ if (ca.drv) {
filter = ca.drv->smudge;
+ required = ca.drv->required;
+ }
ret |= ident_to_worktree(path, src, len, dst, ca.ident);
if (ret) {
@@ -822,7 +837,12 @@ static int convert_to_working_tree_internal(const char *path, const char *src,
len = dst->len;
}
}
- return ret | apply_filter(path, src, len, dst, filter);
+
+ ret_filter = apply_filter(path, src, len, dst, filter);
+ if (!ret_filter && required)
+ die("%s: smudge filter %s failed", path, ca.drv->name);
+
+ return ret | ret_filter;
}
int convert_to_working_tree(const char *path, const char *src, size_t len, struct strbuf *dst)
diff --git a/ctype.c b/ctype.c
index af722f957f..935327164b 100644
--- a/ctype.c
+++ b/ctype.c
@@ -25,3 +25,39 @@ unsigned char sane_ctype[256] = {
A, A, A, A, A, A, A, A, A, A, A, R, R, 0, P, 0, /* 112..127 */
/* Nothing in the 128.. range */
};
+
+/* For case-insensitive kwset */
+const char tolower_trans_tbl[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ ' ', '!', '"', '#', '$', '%', '&', 0x27,
+ '(', ')', '*', '+', ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', ':', ';', '<', '=', '>', '?',
+ '@', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+ 'x', 'y', 'z', '[', 0x5c, ']', '^', '_',
+ '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+ 'x', 'y', 'z', '{', '|', '}', '~', 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+};
diff --git a/daemon.c b/daemon.c
index 15ce918a21..ab21e66b2f 100644
--- a/daemon.c
+++ b/daemon.c
@@ -1086,6 +1086,8 @@ static int serve(struct string_list *listen_addr, int listen_port,
drop_privileges(cred);
+ loginfo("Ready to rumble");
+
return service_loop(&socklist);
}
@@ -1270,10 +1272,8 @@ int main(int argc, char **argv)
if (inetd_mode || serve_mode)
return execute();
- if (detach) {
+ if (detach)
daemonize();
- loginfo("Ready to rumble");
- }
else
sanitize_stdfds();
diff --git a/diff-no-index.c b/diff-no-index.c
index 3a36144687..f0b0010aed 100644
--- a/diff-no-index.c
+++ b/diff-no-index.c
@@ -52,7 +52,7 @@ static int get_mode(const char *path, int *mode)
}
static int queue_diff(struct diff_options *o,
- const char *name1, const char *name2)
+ const char *name1, const char *name2)
{
int mode1 = 0, mode2 = 0;
@@ -63,10 +63,12 @@ static int queue_diff(struct diff_options *o,
return error("file/directory conflict: %s, %s", name1, name2);
if (S_ISDIR(mode1) || S_ISDIR(mode2)) {
- char buffer1[PATH_MAX], buffer2[PATH_MAX];
+ struct strbuf buffer1 = STRBUF_INIT;
+ struct strbuf buffer2 = STRBUF_INIT;
struct string_list p1 = STRING_LIST_INIT_DUP;
struct string_list p2 = STRING_LIST_INIT_DUP;
- int len1 = 0, len2 = 0, i1, i2, ret = 0;
+ int i1, i2, ret = 0;
+ size_t len1 = 0, len2 = 0;
if (name1 && read_directory(name1, &p1))
return -1;
@@ -76,53 +78,53 @@ static int queue_diff(struct diff_options *o,
}
if (name1) {
- len1 = strlen(name1);
- if (len1 > 0 && name1[len1 - 1] == '/')
- len1--;
- memcpy(buffer1, name1, len1);
- buffer1[len1++] = '/';
+ strbuf_addstr(&buffer1, name1);
+ if (buffer1.len && buffer1.buf[buffer1.len - 1] != '/')
+ strbuf_addch(&buffer1, '/');
+ len1 = buffer1.len;
}
if (name2) {
- len2 = strlen(name2);
- if (len2 > 0 && name2[len2 - 1] == '/')
- len2--;
- memcpy(buffer2, name2, len2);
- buffer2[len2++] = '/';
+ strbuf_addstr(&buffer2, name2);
+ if (buffer2.len && buffer2.buf[buffer2.len - 1] != '/')
+ strbuf_addch(&buffer2, '/');
+ len2 = buffer2.len;
}
for (i1 = i2 = 0; !ret && (i1 < p1.nr || i2 < p2.nr); ) {
const char *n1, *n2;
int comp;
+ strbuf_setlen(&buffer1, len1);
+ strbuf_setlen(&buffer2, len2);
+
if (i1 == p1.nr)
comp = 1;
else if (i2 == p2.nr)
comp = -1;
else
- comp = strcmp(p1.items[i1].string,
- p2.items[i2].string);
+ comp = strcmp(p1.items[i1].string, p2.items[i2].string);
if (comp > 0)
n1 = NULL;
else {
- n1 = buffer1;
- strncpy(buffer1 + len1, p1.items[i1++].string,
- PATH_MAX - len1);
+ strbuf_addstr(&buffer1, p1.items[i1++].string);
+ n1 = buffer1.buf;
}
if (comp < 0)
n2 = NULL;
else {
- n2 = buffer2;
- strncpy(buffer2 + len2, p2.items[i2++].string,
- PATH_MAX - len2);
+ strbuf_addstr(&buffer2, p2.items[i2++].string);
+ n2 = buffer2.buf;
}
ret = queue_diff(o, n1, n2);
}
string_list_clear(&p1, 0);
string_list_clear(&p2, 0);
+ strbuf_release(&buffer1);
+ strbuf_release(&buffer2);
return ret;
} else {
diff --git a/diff.c b/diff.c
index 5388ded214..7da16c9590 100644
--- a/diff.c
+++ b/diff.c
@@ -31,6 +31,7 @@ static const char *external_diff_cmd_cfg;
int diff_auto_refresh_index = 1;
static int diff_mnemonic_prefix;
static int diff_no_prefix;
+static int diff_stat_graph_width;
static int diff_dirstat_permille_default = 30;
static struct diff_options default_diff_options;
@@ -156,6 +157,10 @@ int git_diff_ui_config(const char *var, const char *value, void *cb)
diff_no_prefix = git_config_bool(var, value);
return 0;
}
+ if (!strcmp(var, "diff.statgraphwidth")) {
+ diff_stat_graph_width = git_config_int(var, value);
+ return 0;
+ }
if (!strcmp(var, "diff.external"))
return git_config_string(&external_diff_cmd_cfg, var, value);
if (!strcmp(var, "diff.wordregex"))
@@ -177,11 +182,8 @@ int git_diff_basic_config(const char *var, const char *value, void *cb)
return 0;
}
- switch (userdiff_config(var, value)) {
- case 0: break;
- case -1: return -1;
- default: return 0;
- }
+ if (userdiff_config(var, value) < 0)
+ return -1;
if (!prefixcmp(var, "diff.color.") || !prefixcmp(var, "color.diff.")) {
int slot = parse_diff_color_slot(var, 11);
@@ -987,10 +989,74 @@ static void diff_words_flush(struct emit_callback *ecbdata)
diff_words_show(ecbdata->diff_words);
}
+static void diff_filespec_load_driver(struct diff_filespec *one)
+{
+ /* Use already-loaded driver */
+ if (one->driver)
+ return;
+
+ if (S_ISREG(one->mode))
+ one->driver = userdiff_find_by_path(one->path);
+
+ /* Fallback to default settings */
+ if (!one->driver)
+ one->driver = userdiff_find_by_name("default");
+}
+
+static const char *userdiff_word_regex(struct diff_filespec *one)
+{
+ diff_filespec_load_driver(one);
+ return one->driver->word_regex;
+}
+
+static void init_diff_words_data(struct emit_callback *ecbdata,
+ struct diff_options *orig_opts,
+ struct diff_filespec *one,
+ struct diff_filespec *two)
+{
+ int i;
+ struct diff_options *o = xmalloc(sizeof(struct diff_options));
+ memcpy(o, orig_opts, sizeof(struct diff_options));
+
+ ecbdata->diff_words =
+ xcalloc(1, sizeof(struct diff_words_data));
+ ecbdata->diff_words->type = o->word_diff;
+ ecbdata->diff_words->opt = o;
+ if (!o->word_regex)
+ o->word_regex = userdiff_word_regex(one);
+ if (!o->word_regex)
+ o->word_regex = userdiff_word_regex(two);
+ if (!o->word_regex)
+ o->word_regex = diff_word_regex_cfg;
+ if (o->word_regex) {
+ ecbdata->diff_words->word_regex = (regex_t *)
+ xmalloc(sizeof(regex_t));
+ if (regcomp(ecbdata->diff_words->word_regex,
+ o->word_regex,
+ REG_EXTENDED | REG_NEWLINE))
+ die ("Invalid regular expression: %s",
+ o->word_regex);
+ }
+ for (i = 0; i < ARRAY_SIZE(diff_words_styles); i++) {
+ if (o->word_diff == diff_words_styles[i].type) {
+ ecbdata->diff_words->style =
+ &diff_words_styles[i];
+ break;
+ }
+ }
+ if (want_color(o->use_color)) {
+ struct diff_words_style *st = ecbdata->diff_words->style;
+ st->old.color = diff_get_color_opt(o, DIFF_FILE_OLD);
+ st->new.color = diff_get_color_opt(o, DIFF_FILE_NEW);
+ st->ctx.color = diff_get_color_opt(o, DIFF_PLAIN);
+ }
+}
+
static void free_diff_words_data(struct emit_callback *ecbdata)
{
if (ecbdata->diff_words) {
diff_words_flush(ecbdata);
+ free (ecbdata->diff_words->opt);
free (ecbdata->diff_words->minus.text.ptr);
free (ecbdata->diff_words->minus.orig);
free (ecbdata->diff_words->plus.text.ptr);
@@ -1378,7 +1444,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
int i, len, add, del, adds = 0, dels = 0;
uintmax_t max_change = 0, max_len = 0;
int total_files = data->nr;
- int width, name_width, count;
+ int width, name_width, graph_width, number_width = 4, count;
const char *reset, *add_c, *del_c;
const char *line_prefix = "";
int extra_shown = 0;
@@ -1392,25 +1458,15 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
line_prefix = msg->buf;
}
- width = options->stat_width ? options->stat_width : 80;
- name_width = options->stat_name_width ? options->stat_name_width : 50;
count = options->stat_count ? options->stat_count : data->nr;
- /* Sanity: give at least 5 columns to the graph,
- * but leave at least 10 columns for the name.
- */
- if (width < 25)
- width = 25;
- if (name_width < 10)
- name_width = 10;
- else if (width < name_width + 15)
- name_width = width - 15;
-
- /* Find the longest filename and max number of changes */
reset = diff_get_color_opt(options, DIFF_RESET);
add_c = diff_get_color_opt(options, DIFF_FILE_NEW);
del_c = diff_get_color_opt(options, DIFF_FILE_OLD);
+ /*
+ * Find the longest filename and max number of changes
+ */
for (i = 0; (i < count) && (i < data->nr); i++) {
struct diffstat_file *file = data->files[i];
uintmax_t change = file->added + file->deleted;
@@ -1431,19 +1487,76 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
}
count = i; /* min(count, data->nr) */
- /* Compute the width of the graph part;
- * 10 is for one blank at the beginning of the line plus
- * " | count " between the name and the graph.
+ /*
+ * We have width = stat_width or term_columns() columns total.
+ * We want a maximum of min(max_len, stat_name_width) for the name part.
+ * We want a maximum of min(max_change, stat_graph_width) for the +- part.
+ * We also need 1 for " " and 4 + decimal_width(max_change)
+ * for " | NNNN " and one the empty column at the end, altogether
+ * 6 + decimal_width(max_change).
+ *
+ * If there's not enough space, we will use the smaller of
+ * stat_name_width (if set) and 5/8*width for the filename,
+ * and the rest for constant elements + graph part, but no more
+ * than stat_graph_width for the graph part.
+ * (5/8 gives 50 for filename and 30 for the constant parts + graph
+ * for the standard terminal size).
*
- * From here on, name_width is the width of the name area,
- * and width is the width of the graph area.
+ * In other words: stat_width limits the maximum width, and
+ * stat_name_width fixes the maximum width of the filename,
+ * and is also used to divide available columns if there
+ * aren't enough.
*/
- name_width = (name_width < max_len) ? name_width : max_len;
- if (width < (name_width + 10) + max_change)
- width = width - (name_width + 10);
+
+ if (options->stat_width == -1)
+ width = term_columns() - options->output_prefix_length;
else
- width = max_change;
+ width = options->stat_width ? options->stat_width : 80;
+
+ if (options->stat_graph_width == -1)
+ options->stat_graph_width = diff_stat_graph_width;
+
+ /*
+ * Guarantee 3/8*16==6 for the graph part
+ * and 5/8*16==10 for the filename part
+ */
+ if (width < 16 + 6 + number_width)
+ width = 16 + 6 + number_width;
+ /*
+ * First assign sizes that are wanted, ignoring available width.
+ */
+ graph_width = (options->stat_graph_width &&
+ options->stat_graph_width < max_change) ?
+ options->stat_graph_width : max_change;
+ name_width = (options->stat_name_width > 0 &&
+ options->stat_name_width < max_len) ?
+ options->stat_name_width : max_len;
+
+ /*
+ * Adjust adjustable widths not to exceed maximum width
+ */
+ if (name_width + number_width + 6 + graph_width > width) {
+ if (graph_width > width * 3/8 - number_width - 6) {
+ graph_width = width * 3/8 - number_width - 6;
+ if (graph_width < 6)
+ graph_width = 6;
+ }
+
+ if (options->stat_graph_width &&
+ graph_width > options->stat_graph_width)
+ graph_width = options->stat_graph_width;
+ if (name_width > width - number_width - 6 - graph_width)
+ name_width = width - number_width - 6 - graph_width;
+ else
+ graph_width = width - number_width - 6 - name_width;
+ }
+
+ /*
+ * From here name_width is the width of the name area,
+ * and graph_width is the width of the graph area.
+ * max_change is used to scale graph properly.
+ */
for (i = 0; i < count; i++) {
const char *prefix = "";
char *name = data->files[i]->print_name;
@@ -1499,18 +1612,18 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
adds += add;
dels += del;
- if (width <= max_change) {
+ if (graph_width <= max_change) {
int total = add + del;
- total = scale_linear(add + del, width, max_change);
+ total = scale_linear(add + del, graph_width, max_change);
if (total < 2 && add && del)
/* width >= 2 due to the sanity check */
total = 2;
if (add < del) {
- add = scale_linear(add, width, max_change);
+ add = scale_linear(add, graph_width, max_change);
del = total - add;
} else {
- del = scale_linear(del, width, max_change);
+ del = scale_linear(del, graph_width, max_change);
add = total - del;
}
}
@@ -2016,20 +2129,6 @@ static void emit_binary_diff(FILE *file, mmfile_t *one, mmfile_t *two, char *pre
emit_binary_diff_body(file, two, one, prefix);
}
-static void diff_filespec_load_driver(struct diff_filespec *one)
-{
- /* Use already-loaded driver */
- if (one->driver)
- return;
-
- if (S_ISREG(one->mode))
- one->driver = userdiff_find_by_path(one->path);
-
- /* Fallback to default settings */
- if (!one->driver)
- one->driver = userdiff_find_by_name("default");
-}
-
int diff_filespec_is_binary(struct diff_filespec *one)
{
if (one->is_binary == -1) {
@@ -2055,12 +2154,6 @@ static const struct userdiff_funcname *diff_funcname_pattern(struct diff_filespe
return one->driver->funcname.pattern ? &one->driver->funcname : NULL;
}
-static const char *userdiff_word_regex(struct diff_filespec *one)
-{
- diff_filespec_load_driver(one);
- return one->driver->word_regex;
-}
-
void diff_set_mnemonic_prefix(struct diff_options *options, const char *a, const char *b)
{
if (!options->a_prefix)
@@ -2247,42 +2340,8 @@ static void builtin_diff(const char *name_a,
xecfg.ctxlen = strtoul(diffopts + 10, NULL, 10);
else if (!prefixcmp(diffopts, "-u"))
xecfg.ctxlen = strtoul(diffopts + 2, NULL, 10);
- if (o->word_diff) {
- int i;
-
- ecbdata.diff_words =
- xcalloc(1, sizeof(struct diff_words_data));
- ecbdata.diff_words->type = o->word_diff;
- ecbdata.diff_words->opt = o;
- if (!o->word_regex)
- o->word_regex = userdiff_word_regex(one);
- if (!o->word_regex)
- o->word_regex = userdiff_word_regex(two);
- if (!o->word_regex)
- o->word_regex = diff_word_regex_cfg;
- if (o->word_regex) {
- ecbdata.diff_words->word_regex = (regex_t *)
- xmalloc(sizeof(regex_t));
- if (regcomp(ecbdata.diff_words->word_regex,
- o->word_regex,
- REG_EXTENDED | REG_NEWLINE))
- die ("Invalid regular expression: %s",
- o->word_regex);
- }
- for (i = 0; i < ARRAY_SIZE(diff_words_styles); i++) {
- if (o->word_diff == diff_words_styles[i].type) {
- ecbdata.diff_words->style =
- &diff_words_styles[i];
- break;
- }
- }
- if (want_color(o->use_color)) {
- struct diff_words_style *st = ecbdata.diff_words->style;
- st->old.color = diff_get_color_opt(o, DIFF_FILE_OLD);
- st->new.color = diff_get_color_opt(o, DIFF_FILE_NEW);
- st->ctx.color = diff_get_color_opt(o, DIFF_PLAIN);
- }
- }
+ if (o->word_diff)
+ init_diff_words_data(&ecbdata, o, one, two);
xdi_diff_outf(&mf1, &mf2, fn_out_consume, &ecbdata,
&xpp, &xecfg);
if (o->word_diff)
@@ -3091,6 +3150,7 @@ void diff_setup(struct diff_options *options)
options->rename_limit = -1;
options->dirstat_permille = diff_dirstat_permille_default;
options->context = 3;
+ DIFF_OPT_SET(options, RENAME_EMPTY);
options->change = diff_change;
options->add_remove = diff_addremove;
@@ -3302,6 +3362,7 @@ static int stat_opt(struct diff_options *options, const char **av)
char *end;
int width = options->stat_width;
int name_width = options->stat_name_width;
+ int graph_width = options->stat_graph_width;
int count = options->stat_count;
int argcount = 1;
@@ -3330,6 +3391,16 @@ static int stat_opt(struct diff_options *options, const char **av)
name_width = strtoul(av[1], &end, 10);
argcount = 2;
}
+ } else if (!prefixcmp(arg, "-graph-width")) {
+ arg += strlen("-graph-width");
+ if (*arg == '=')
+ graph_width = strtoul(arg + 1, &end, 10);
+ else if (!*arg && !av[1])
+ die("Option '--stat-graph-width' requires a value");
+ else if (!*arg) {
+ graph_width = strtoul(av[1], &end, 10);
+ argcount = 2;
+ }
} else if (!prefixcmp(arg, "-count")) {
arg += strlen("-count");
if (*arg == '=')
@@ -3355,6 +3426,7 @@ static int stat_opt(struct diff_options *options, const char **av)
return 0;
options->output_format |= DIFF_FORMAT_DIFFSTAT;
options->stat_name_width = name_width;
+ options->stat_graph_width = graph_width;
options->stat_width = width;
options->stat_count = count;
return argcount;
@@ -3449,6 +3521,10 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
}
else if (!strcmp(arg, "--no-renames"))
options->detect_rename = 0;
+ else if (!strcmp(arg, "--rename-empty"))
+ DIFF_OPT_SET(options, RENAME_EMPTY);
+ else if (!strcmp(arg, "--no-rename-empty"))
+ DIFF_OPT_CLR(options, RENAME_EMPTY);
else if (!strcmp(arg, "--relative"))
DIFF_OPT_SET(options, RELATIVE_NAME);
else if (!prefixcmp(arg, "--relative=")) {
@@ -3468,9 +3544,9 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
else if (!strcmp(arg, "--ignore-space-at-eol"))
DIFF_XDL_SET(options, IGNORE_WHITESPACE_AT_EOL);
else if (!strcmp(arg, "--patience"))
- DIFF_XDL_SET(options, PATIENCE_DIFF);
+ options->xdl_opts = DIFF_WITH_ALG(options, PATIENCE_DIFF);
else if (!strcmp(arg, "--histogram"))
- DIFF_XDL_SET(options, HISTOGRAM_DIFF);
+ options->xdl_opts = DIFF_WITH_ALG(options, HISTOGRAM_DIFF);
/* flags options */
else if (!strcmp(arg, "--binary")) {
@@ -4342,6 +4418,12 @@ void diff_flush(struct diff_options *options)
if (output_format & DIFF_FORMAT_PATCH) {
if (separator) {
+ if (options->output_prefix) {
+ struct strbuf *msg = NULL;
+ msg = options->output_prefix(options,
+ options->output_prefix_data);
+ fwrite(msg->buf, msg->len, 1, stdout);
+ }
putc(options->line_termination, options->file);
if (options->stat_sep) {
/* attach patch instead of inline */
diff --git a/diff.h b/diff.h
index 7af5f1e2a7..e027650cb0 100644
--- a/diff.h
+++ b/diff.h
@@ -60,7 +60,7 @@ typedef struct strbuf *(*diff_prefix_fn_t)(struct diff_options *opt, void *data)
#define DIFF_OPT_SILENT_ON_REMOVE (1 << 5)
#define DIFF_OPT_FIND_COPIES_HARDER (1 << 6)
#define DIFF_OPT_FOLLOW_RENAMES (1 << 7)
-/* (1 << 8) unused */
+#define DIFF_OPT_RENAME_EMPTY (1 << 8)
/* (1 << 9) unused */
#define DIFF_OPT_HAS_CHANGES (1 << 10)
#define DIFF_OPT_QUICK (1 << 11)
@@ -82,6 +82,7 @@ typedef struct strbuf *(*diff_prefix_fn_t)(struct diff_options *opt, void *data)
#define DIFF_OPT_OVERRIDE_SUBMODULE_CONFIG (1 << 27)
#define DIFF_OPT_DIRSTAT_BY_LINE (1 << 28)
#define DIFF_OPT_FUNCCONTEXT (1 << 29)
+#define DIFF_OPT_PICKAXE_IGNORE_CASE (1 << 30)
#define DIFF_OPT_TST(opts, flag) ((opts)->flags & DIFF_OPT_##flag)
#define DIFF_OPT_SET(opts, flag) ((opts)->flags |= DIFF_OPT_##flag)
@@ -90,6 +91,8 @@ typedef struct strbuf *(*diff_prefix_fn_t)(struct diff_options *opt, void *data)
#define DIFF_XDL_SET(opts, flag) ((opts)->xdl_opts |= XDF_##flag)
#define DIFF_XDL_CLR(opts, flag) ((opts)->xdl_opts &= ~XDF_##flag)
+#define DIFF_WITH_ALG(opts, flag) (((opts)->xdl_opts & ~XDF_DIFF_ALGORITHM_MASK) | XDF_##flag)
+
enum diff_words_type {
DIFF_WORDS_NONE = 0,
DIFF_WORDS_PORCELAIN,
@@ -129,6 +132,7 @@ struct diff_options {
int stat_width;
int stat_name_width;
+ int stat_graph_width;
int stat_count;
const char *word_regex;
enum diff_words_type word_diff;
@@ -148,6 +152,7 @@ struct diff_options {
diff_format_fn_t format_callback;
void *format_callback_data;
diff_prefix_fn_t output_prefix;
+ int output_prefix_length;
void *output_prefix_data;
};
diff --git a/diffcore-pickaxe.c b/diffcore-pickaxe.c
index 380a837b5b..ed23eb4bdd 100644
--- a/diffcore-pickaxe.c
+++ b/diffcore-pickaxe.c
@@ -138,8 +138,12 @@ static void diffcore_pickaxe_grep(struct diff_options *o)
{
int err;
regex_t regex;
+ int cflags = REG_EXTENDED | REG_NEWLINE;
- err = regcomp(&regex, o->pickaxe, REG_EXTENDED | REG_NEWLINE);
+ if (DIFF_OPT_TST(o, PICKAXE_IGNORE_CASE))
+ cflags |= REG_ICASE;
+
+ err = regcomp(&regex, o->pickaxe, cflags);
if (err) {
char errbuf[1024];
regerror(err, &regex, errbuf, 1024);
@@ -237,7 +241,8 @@ static void diffcore_pickaxe_count(struct diff_options *o)
}
regexp = &regex;
} else {
- kws = kwsalloc(NULL);
+ kws = kwsalloc(DIFF_OPT_TST(o, PICKAXE_IGNORE_CASE)
+ ? tolower_trans_tbl : NULL);
kwsincr(kws, needle, len);
kwsprep(kws);
}
diff --git a/diffcore-rename.c b/diffcore-rename.c
index f639601c76..216a7a4bbc 100644
--- a/diffcore-rename.c
+++ b/diffcore-rename.c
@@ -512,9 +512,15 @@ void diffcore_rename(struct diff_options *options)
else if (options->single_follow &&
strcmp(options->single_follow, p->two->path))
continue; /* not interested */
+ else if (!DIFF_OPT_TST(options, RENAME_EMPTY) &&
+ is_empty_blob_sha1(p->two->sha1))
+ continue;
else
locate_rename_dst(p->two, 1);
}
+ else if (!DIFF_OPT_TST(options, RENAME_EMPTY) &&
+ is_empty_blob_sha1(p->one->sha1))
+ continue;
else if (!DIFF_PAIR_UNMERGED(p) && !DIFF_FILE_VALID(p->two)) {
/*
* If the source is a broken "delete", and
diff --git a/dir.c b/dir.c
index 0a78d00b54..e98760c72d 100644
--- a/dir.c
+++ b/dir.c
@@ -1172,22 +1172,32 @@ int is_empty_dir(const char *path)
return ret;
}
-int remove_dir_recursively(struct strbuf *path, int flag)
+static int remove_dir_recurse(struct strbuf *path, int flag, int *kept_up)
{
DIR *dir;
struct dirent *e;
- int ret = 0, original_len = path->len, len;
+ int ret = 0, original_len = path->len, len, kept_down = 0;
int only_empty = (flag & REMOVE_DIR_EMPTY_ONLY);
+ int keep_toplevel = (flag & REMOVE_DIR_KEEP_TOPLEVEL);
unsigned char submodule_head[20];
if ((flag & REMOVE_DIR_KEEP_NESTED_GIT) &&
- !resolve_gitlink_ref(path->buf, "HEAD", submodule_head))
+ !resolve_gitlink_ref(path->buf, "HEAD", submodule_head)) {
/* Do not descend and nuke a nested git work tree. */
+ if (kept_up)
+ *kept_up = 1;
return 0;
+ }
+ flag &= ~REMOVE_DIR_KEEP_TOPLEVEL;
dir = opendir(path->buf);
- if (!dir)
- return rmdir(path->buf);
+ if (!dir) {
+ /* an empty dir could be removed even if it is unreadble */
+ if (!keep_toplevel)
+ return rmdir(path->buf);
+ else
+ return -1;
+ }
if (path->buf[original_len - 1] != '/')
strbuf_addch(path, '/');
@@ -1202,7 +1212,7 @@ int remove_dir_recursively(struct strbuf *path, int flag)
if (lstat(path->buf, &st))
; /* fall thru */
else if (S_ISDIR(st.st_mode)) {
- if (!remove_dir_recursively(path, only_empty))
+ if (!remove_dir_recurse(path, flag, &kept_down))
continue; /* happy */
} else if (!only_empty && !unlink(path->buf))
continue; /* happy, too */
@@ -1214,11 +1224,22 @@ int remove_dir_recursively(struct strbuf *path, int flag)
closedir(dir);
strbuf_setlen(path, original_len);
- if (!ret)
+ if (!ret && !keep_toplevel && !kept_down)
ret = rmdir(path->buf);
+ else if (kept_up)
+ /*
+ * report the uplevel that it is not an error that we
+ * did not rmdir() our directory.
+ */
+ *kept_up = !ret;
return ret;
}
+int remove_dir_recursively(struct strbuf *path, int flag)
+{
+ return remove_dir_recurse(path, flag, NULL);
+}
+
void setup_standard_excludes(struct dir_struct *dir)
{
const char *path;
diff --git a/dir.h b/dir.h
index dd6947e1d4..58b6fc7c86 100644
--- a/dir.h
+++ b/dir.h
@@ -102,6 +102,7 @@ extern void setup_standard_excludes(struct dir_struct *dir);
#define REMOVE_DIR_EMPTY_ONLY 01
#define REMOVE_DIR_KEEP_NESTED_GIT 02
+#define REMOVE_DIR_KEEP_TOPLEVEL 04
extern int remove_dir_recursively(struct strbuf *path, int flag);
/* tries to remove the path with empty directories along it, ignores ENOENT */
diff --git a/environment.c b/environment.c
index c93b8f44df..d7e6c65763 100644
--- a/environment.c
+++ b/environment.c
@@ -52,7 +52,7 @@ enum safe_crlf safe_crlf = SAFE_CRLF_WARN;
unsigned whitespace_rule_cfg = WS_DEFAULT_RULE;
enum branch_track git_branch_track = BRANCH_TRACK_REMOTE;
enum rebase_setup_type autorebase = AUTOREBASE_NEVER;
-enum push_default_type push_default = PUSH_DEFAULT_MATCHING;
+enum push_default_type push_default = PUSH_DEFAULT_UNSPECIFIED;
#ifndef OBJECT_CREATION_MODE
#define OBJECT_CREATION_MODE OBJECT_CREATION_USES_HARDLINKS
#endif
diff --git a/exec_cmd.c b/exec_cmd.c
index 171e841531..125fa6fabf 100644
--- a/exec_cmd.c
+++ b/exec_cmd.c
@@ -134,7 +134,7 @@ int execv_git_cmd(const char **argv) {
trace_argv_printf(nargv, "trace: exec:");
/* execvp() can only ever return if it fails */
- execvp("git", (char **)nargv);
+ sane_execvp("git", (char **)nargv);
trace_printf("trace: exec failed: %s\n", strerror(errno));
diff --git a/fast-import.c b/fast-import.c
index a85275dc68..eed97c8fa9 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -2207,6 +2207,59 @@ static uintmax_t change_note_fanout(struct tree_entry *root,
return do_change_note_fanout(root, root, hex_sha1, 0, path, 0, fanout);
}
+/*
+ * Given a pointer into a string, parse a mark reference:
+ *
+ * idnum ::= ':' bigint;
+ *
+ * Return the first character after the value in *endptr.
+ *
+ * Complain if the following character is not what is expected,
+ * either a space or end of the string.
+ */
+static uintmax_t parse_mark_ref(const char *p, char **endptr)
+{
+ uintmax_t mark;
+
+ assert(*p == ':');
+ p++;
+ mark = strtoumax(p, endptr, 10);
+ if (*endptr == p)
+ die("No value after ':' in mark: %s", command_buf.buf);
+ return mark;
+}
+
+/*
+ * Parse the mark reference, and complain if this is not the end of
+ * the string.
+ */
+static uintmax_t parse_mark_ref_eol(const char *p)
+{
+ char *end;
+ uintmax_t mark;
+
+ mark = parse_mark_ref(p, &end);
+ if (*end != '\0')
+ die("Garbage after mark: %s", command_buf.buf);
+ return mark;
+}
+
+/*
+ * Parse the mark reference, demanding a trailing space. Return a
+ * pointer to the space.
+ */
+static uintmax_t parse_mark_ref_space(const char **p)
+{
+ uintmax_t mark;
+ char *end;
+
+ mark = parse_mark_ref(*p, &end);
+ if (*end != ' ')
+ die("Missing space after mark: %s", command_buf.buf);
+ *p = end;
+ return mark;
+}
+
static void file_change_m(struct branch *b)
{
const char *p = command_buf.buf + 2;
@@ -2235,21 +2288,21 @@ static void file_change_m(struct branch *b)
}
if (*p == ':') {
- char *x;
- oe = find_mark(strtoumax(p + 1, &x, 10));
+ oe = find_mark(parse_mark_ref_space(&p));
hashcpy(sha1, oe->idx.sha1);
- p = x;
- } else if (!prefixcmp(p, "inline")) {
+ } else if (!prefixcmp(p, "inline ")) {
inline_data = 1;
- p += 6;
+ p += strlen("inline"); /* advance to space */
} else {
if (get_sha1_hex(p, sha1))
- die("Invalid SHA1: %s", command_buf.buf);
+ die("Invalid dataref: %s", command_buf.buf);
oe = find_object(sha1);
p += 40;
+ if (*p != ' ')
+ die("Missing space after SHA1: %s", command_buf.buf);
}
- if (*p++ != ' ')
- die("Missing space after SHA1: %s", command_buf.buf);
+ assert(*p == ' ');
+ p++; /* skip space */
strbuf_reset(&uq);
if (!unquote_c_style(&uq, p, &endp)) {
@@ -2407,21 +2460,21 @@ static void note_change_n(struct branch *b, unsigned char *old_fanout)
/* Now parse the notemodify command. */
/* <dataref> or 'inline' */
if (*p == ':') {
- char *x;
- oe = find_mark(strtoumax(p + 1, &x, 10));
+ oe = find_mark(parse_mark_ref_space(&p));
hashcpy(sha1, oe->idx.sha1);
- p = x;
- } else if (!prefixcmp(p, "inline")) {
+ } else if (!prefixcmp(p, "inline ")) {
inline_data = 1;
- p += 6;
+ p += strlen("inline"); /* advance to space */
} else {
if (get_sha1_hex(p, sha1))
- die("Invalid SHA1: %s", command_buf.buf);
+ die("Invalid dataref: %s", command_buf.buf);
oe = find_object(sha1);
p += 40;
+ if (*p != ' ')
+ die("Missing space after SHA1: %s", command_buf.buf);
}
- if (*p++ != ' ')
- die("Missing space after SHA1: %s", command_buf.buf);
+ assert(*p == ' ');
+ p++; /* skip space */
/* <committish> */
s = lookup_branch(p);
@@ -2430,7 +2483,7 @@ static void note_change_n(struct branch *b, unsigned char *old_fanout)
die("Can't add a note on empty branch.");
hashcpy(commit_sha1, s->sha1);
} else if (*p == ':') {
- uintmax_t commit_mark = strtoumax(p + 1, NULL, 10);
+ uintmax_t commit_mark = parse_mark_ref_eol(p);
struct object_entry *commit_oe = find_mark(commit_mark);
if (commit_oe->type != OBJ_COMMIT)
die("Mark :%" PRIuMAX " not a commit", commit_mark);
@@ -2537,7 +2590,7 @@ static int parse_from(struct branch *b)
hashcpy(b->branch_tree.versions[0].sha1, t);
hashcpy(b->branch_tree.versions[1].sha1, t);
} else if (*from == ':') {
- uintmax_t idnum = strtoumax(from + 1, NULL, 10);
+ uintmax_t idnum = parse_mark_ref_eol(from);
struct object_entry *oe = find_mark(idnum);
if (oe->type != OBJ_COMMIT)
die("Mark :%" PRIuMAX " not a commit", idnum);
@@ -2572,7 +2625,7 @@ static struct hash_list *parse_merge(unsigned int *count)
if (s)
hashcpy(n->sha1, s->sha1);
else if (*from == ':') {
- uintmax_t idnum = strtoumax(from + 1, NULL, 10);
+ uintmax_t idnum = parse_mark_ref_eol(from);
struct object_entry *oe = find_mark(idnum);
if (oe->type != OBJ_COMMIT)
die("Mark :%" PRIuMAX " not a commit", idnum);
@@ -2735,7 +2788,7 @@ static void parse_new_tag(void)
type = OBJ_COMMIT;
} else if (*from == ':') {
struct object_entry *oe;
- from_mark = strtoumax(from + 1, NULL, 10);
+ from_mark = parse_mark_ref_eol(from);
oe = find_mark(from_mark);
type = oe->type;
hashcpy(sha1, oe->idx.sha1);
@@ -2867,18 +2920,13 @@ static void parse_cat_blob(void)
/* cat-blob SP <object> LF */
p = command_buf.buf + strlen("cat-blob ");
if (*p == ':') {
- char *x;
- oe = find_mark(strtoumax(p + 1, &x, 10));
- if (x == p + 1)
- die("Invalid mark: %s", command_buf.buf);
+ oe = find_mark(parse_mark_ref_eol(p));
if (!oe)
die("Unknown mark: %s", command_buf.buf);
- if (*x)
- die("Garbage after mark: %s", command_buf.buf);
hashcpy(sha1, oe->idx.sha1);
} else {
if (get_sha1_hex(p, sha1))
- die("Invalid SHA1: %s", command_buf.buf);
+ die("Invalid dataref: %s", command_buf.buf);
if (p[40])
die("Garbage after SHA1: %s", command_buf.buf);
oe = find_object(sha1);
@@ -2944,17 +2992,13 @@ static struct object_entry *parse_treeish_dataref(const char **p)
struct object_entry *e;
if (**p == ':') { /* <mark> */
- char *endptr;
- e = find_mark(strtoumax(*p + 1, &endptr, 10));
- if (endptr == *p + 1)
- die("Invalid mark: %s", command_buf.buf);
+ e = find_mark(parse_mark_ref_space(p));
if (!e)
die("Unknown mark: %s", command_buf.buf);
- *p = endptr;
hashcpy(sha1, e->idx.sha1);
} else { /* <sha1> */
if (get_sha1_hex(*p, sha1))
- die("Invalid SHA1: %s", command_buf.buf);
+ die("Invalid dataref: %s", command_buf.buf);
e = find_object(sha1);
*p += 40;
}
diff --git a/fetch-pack.h b/fetch-pack.h
index 0608edae3f..7c2069c972 100644
--- a/fetch-pack.h
+++ b/fetch-pack.h
@@ -10,6 +10,7 @@ struct fetch_pack_args {
lock_pack:1,
use_thin_pack:1,
fetch_all:1,
+ stdin_refs:1,
verbose:1,
no_progress:1,
include_tag:1,
diff --git a/git-add--interactive.perl b/git-add--interactive.perl
index 8f0839d205..d948aa88db 100755
--- a/git-add--interactive.perl
+++ b/git-add--interactive.perl
@@ -268,6 +268,7 @@ sub get_empty_tree {
# FILE: is file different from index?
# INDEX_ADDDEL: is it add/delete between HEAD and index?
# FILE_ADDDEL: is it add/delete between index and file?
+# UNMERGED: is the path unmerged
sub list_modified {
my ($only) = @_;
@@ -318,16 +319,10 @@ sub list_modified {
}
}
- for (run_cmd_pipe(qw(git diff-files --numstat --summary --), @tracked)) {
+ for (run_cmd_pipe(qw(git diff-files --numstat --summary --raw --), @tracked)) {
if (($add, $del, $file) =
/^([-\d]+) ([-\d]+) (.*)/) {
$file = unquote_path($file);
- if (!exists $data{$file}) {
- $data{$file} = +{
- INDEX => 'unchanged',
- BINARY => 0,
- };
- }
my ($change, $bin);
if ($add eq '-' && $del eq '-') {
$change = 'binary';
@@ -346,6 +341,18 @@ sub list_modified {
$file = unquote_path($file);
$data{$file}{FILE_ADDDEL} = $adddel;
}
+ elsif (/^:[0-7]+ [0-7]+ [0-9a-f]+ [0-9a-f]+ (.) (.*)$/) {
+ $file = unquote_path($2);
+ if (!exists $data{$file}) {
+ $data{$file} = +{
+ INDEX => 'unchanged',
+ BINARY => 0,
+ };
+ }
+ if ($1 eq 'U') {
+ $data{$file}{UNMERGED} = 1;
+ }
+ }
}
for (sort keys %data) {
@@ -1190,6 +1197,10 @@ sub apply_patch_for_checkout_commit {
sub patch_update_cmd {
my @all_mods = list_modified($patch_mode_flavour{FILTER});
+ error_msg "ignoring unmerged: $_->{VALUE}\n"
+ for grep { $_->{UNMERGED} } @all_mods;
+ @all_mods = grep { !$_->{UNMERGED} } @all_mods;
+
my @mods = grep { !($_->{BINARY}) } @all_mods;
my @them;
diff --git a/git-am.sh b/git-am.sh
index cb833e217a..4da0ddafc4 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -15,6 +15,7 @@ q,quiet be quiet
s,signoff add a Signed-off-by line to the commit message
u,utf8 recode into utf8 (default)
k,keep pass -k flag to git-mailinfo
+keep-non-patch pass -b flag to git-mailinfo
keep-cr pass --keep-cr flag to git-mailsplit for mbox format
no-keep-cr do not pass --keep-cr flag to git-mailsplit independent of am.keepcr
c,scissors strip everything before a scissors line
@@ -379,7 +380,9 @@ 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."
+ ;;
-3|--3way)
threeway=t ;;
-s|--signoff)
@@ -390,6 +393,8 @@ do
utf8= ;;
-k|--keep)
keep=t ;;
+ --keep-non-patch)
+ keep=b ;;
-c|--scissors)
scissors=t ;;
--no-scissors)
@@ -568,16 +573,25 @@ case "$resolved" in
fi
esac
+# Now, decide what command line options we will give to the git
+# commands we invoke, based on the result of parsing command line
+# options and previous invocation state stored in $dotest/ files.
+
if test "$(cat "$dotest/utf8")" = t
then
utf8=-u
else
utf8=-n
fi
-if test "$(cat "$dotest/keep")" = t
-then
- keep=-k
-fi
+keep=$(cat "$dotest/keep")
+case "$keep" in
+t)
+ keep=-k ;;
+b)
+ keep=-b ;;
+*)
+ keep= ;;
+esac
case "$(cat "$dotest/scissors")" in
t)
scissors=--scissors ;;
diff --git a/git-compat-util.h b/git-compat-util.h
index 426ae43be9..ed11ad8119 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -457,6 +457,9 @@ static inline int has_extension(const char *filename, const char *ext)
return len > extlen && !memcmp(filename + len - extlen, ext, extlen);
}
+/* in ctype.c, for kwset users */
+extern const char tolower_trans_tbl[256];
+
/* Sane ctype - no locale, and works with signed chars */
#undef isascii
#undef isspace
diff --git a/git-parse-remote.sh b/git-parse-remote.sh
index b24119d69c..484b2e61cc 100644
--- a/git-parse-remote.sh
+++ b/git-parse-remote.sh
@@ -57,34 +57,31 @@ error_on_missing_default_upstream () {
op_prep="$3"
example="$4"
branch_name=$(git symbolic-ref -q HEAD)
+ # If there's only one remote, use that in the suggestion
+ remote="<remote>"
+ if test $(git remote | wc -l) = 1
+ then
+ remote=$(git remote)
+ fi
+
if test -z "$branch_name"
then
- echo "You are not currently on a branch, so I cannot use any
-'branch.<branchname>.merge' in your configuration file.
-Please specify which branch you want to $op_type $op_prep on the command
-line and try again (e.g. '$example').
-See git-${cmd}(1) for details."
+ echo "You are not currently on a branch. Please specify which
+branch you want to $op_type $op_prep. See git-${cmd}(1) for details.
+
+ $example
+"
else
- echo "You asked me to $cmd without telling me which branch you
-want to $op_type $op_prep, and 'branch.${branch_name#refs/heads/}.merge' in
-your configuration file does not tell me, either. Please
-specify which branch you want to use on the command line and
-try again (e.g. '$example').
-See git-${cmd}(1) for details.
+ echo "There is no tracking information for the current branch.
+Please specify which branch you want to $op_type $op_prep.
+See git-${cmd}(1) for details
+
+ $example
-If you often $op_type $op_prep the same branch, you may want to
-use something like the following in your configuration file:
- [branch \"${branch_name#refs/heads/}\"]
- remote = <nickname>
- merge = <remote-ref>"
- test rebase = "$op_type" &&
- echo " rebase = true"
- echo "
- [remote \"<nickname>\"]
- url = <url>
- fetch = <refspec>
+If you wish to set tracking information for this branch you can do so with:
-See git-config(1) for details."
+ git branch --set-upstream ${branch_name#refs/heads/} $remote/<branch>
+"
fi
exit 1
}
diff --git a/git-pull.sh b/git-pull.sh
index d8b64d7a67..2a10047eb7 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -40,7 +40,7 @@ test -f "$GIT_DIR/MERGE_HEAD" && die_merge
strategy_args= diffstat= no_commit= squash= no_ff= ff_only=
log_arg= verbosity= progress= recurse_submodules=
-merge_args=
+merge_args= edit=
curr_branch=$(git symbolic-ref -q HEAD)
curr_branch_short="${curr_branch#refs/heads/}"
rebase=$(git config --bool branch.$curr_branch_short.rebase)
@@ -70,6 +70,10 @@ do
no_commit=--no-commit ;;
--c|--co|--com|--comm|--commi|--commit)
no_commit=--commit ;;
+ -e|--edit)
+ edit=--edit ;;
+ --no-edit)
+ edit=--no-edit ;;
--sq|--squ|--squa|--squas|--squash)
squash=--squash ;;
--no-sq|--no-squ|--no-squa|--no-squas|--no-squash)
@@ -176,7 +180,7 @@ error_on_no_merge_candidates () {
elif [ -z "$curr_branch" -o -z "$upstream" ]; then
. git-parse-remote
error_on_missing_default_upstream "pull" $op_type $op_prep \
- "git pull <repository> <refspec>"
+ "git pull <remote> <branch>"
else
echo "Your configuration specifies to $op_type $op_prep the ref '${upstream#refs/heads/}'"
echo "from the remote, but no such ref was fetched."
@@ -278,7 +282,7 @@ true)
eval="$eval --onto $merge_head ${oldremoteref:-$merge_head}"
;;
*)
- eval="git-merge $diffstat $no_commit $squash $no_ff $ff_only"
+ eval="git-merge $diffstat $no_commit $edit $squash $no_ff $ff_only"
eval="$eval $log_arg $strategy_args $merge_args $verbosity $progress"
eval="$eval \"\$merge_name\" HEAD $merge_head"
;;
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 5812222eb9..2e1325824c 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -672,7 +672,7 @@ rearrange_squash () {
case "$action" in
continue)
# do we have anything to commit?
- if git diff-index --cached --quiet --ignore-submodules HEAD --
+ if git diff-index --cached --quiet HEAD --
then
: Nothing to commit -- skip this
else
@@ -846,6 +846,8 @@ cat >> "$todo" << EOF
# 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.
#
diff --git a/git-rebase.sh b/git-rebase.sh
index 00ca7b99fe..69c1374823 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -380,7 +380,7 @@ then
then
. git-parse-remote
error_on_missing_default_upstream "rebase" "rebase" \
- "against" "git rebase <upstream branch>"
+ "against" "git rebase <branch>"
fi
;;
*) upstream_name="$1"
diff --git a/git-relink.perl b/git-relink.perl
index e136732cea..f29285c411 100755
--- a/git-relink.perl
+++ b/git-relink.perl
@@ -1,4 +1,4 @@
-#!/usr/bin/env perl
+#!/usr/bin/perl
# Copyright 2005, Ryan Anderson <ryan@michonline.com>
# Distribution permitted under the GPL v2, as distributed
# by the Free Software Foundation.
diff --git a/git-remote-testgit.py b/git-remote-testgit.py
index 3dc4851cfc..5f3ebd244d 100644
--- a/git-remote-testgit.py
+++ b/git-remote-testgit.py
@@ -22,6 +22,7 @@ except ImportError:
_digest = sha.new
import sys
import os
+import time
sys.path.insert(0, os.getenv("GITPYTHONLIB","."))
from git_remote_helpers.util import die, debug, warn
@@ -204,6 +205,11 @@ def read_one_line(repo):
"""Reads and processes one command.
"""
+ sleepy = os.environ.get("GIT_REMOTE_TESTGIT_SLEEPY")
+ if sleepy:
+ debug("Sleeping %d sec before readline" % int(sleepy))
+ time.sleep(int(sleepy))
+
line = sys.stdin.readline()
cmdline = line
@@ -258,6 +264,7 @@ def main(args):
more = True
+ sys.stdin = os.fdopen(sys.stdin.fileno(), 'r', 0)
while (more):
more = read_one_line(repo)
diff --git a/git-repack.sh b/git-repack.sh
index 624feec26f..757933174e 100755
--- a/git-repack.sh
+++ b/git-repack.sh
@@ -15,6 +15,7 @@ F pass --no-reuse-object to git-pack-objects
n do not run git-update-server-info
q,quiet be quiet
l pass --local to git-pack-objects
+unpack-unreachable= with -A, do not loosen objects older than this
Packing constraints
window= size of the window used for delta compression
window-memory= same as the above, but limit memory size instead of entries count
@@ -33,6 +34,8 @@ do
-a) all_into_one=t ;;
-A) all_into_one=t
unpack_unreachable=--unpack-unreachable ;;
+ --unpack-unreachable)
+ unpack_unreachable="--unpack-unreachable=$2"; shift ;;
-d) remove_redundant=t ;;
-q) GIT_QUIET=t ;;
-f) no_reuse=--no-reuse-delta ;;
@@ -76,7 +79,12 @@ case ",$all_into_one," in
if test -n "$existing" -a -n "$unpack_unreachable" -a \
-n "$remove_redundant"
then
- args="$args $unpack_unreachable"
+ # This may have arbitrary user arguments, so we
+ # have to protect it against whitespace splitting
+ # when it gets run as "pack-objects $args" later.
+ # Fortunately, we know it's an approxidate, so we
+ # can just use dots instead.
+ args="$args $(echo "$unpack_unreachable" | tr ' ' .)"
fi
fi
;;
diff --git a/git-sh-i18n.sh b/git-sh-i18n.sh
index b4575fb3a1..6a27f68136 100644
--- a/git-sh-i18n.sh
+++ b/git-sh-i18n.sh
@@ -16,61 +16,48 @@ else
fi
export TEXTDOMAINDIR
-if test -z "$GIT_GETTEXT_POISON"
+# First decide what scheme to use...
+GIT_INTERNAL_GETTEXT_SH_SCHEME=fallthrough
+if test -n "@@USE_GETTEXT_SCHEME@@"
+then
+ GIT_INTERNAL_GETTEXT_SH_SCHEME="@@USE_GETTEXT_SCHEME@@"
+elif test -n "$GIT_INTERNAL_GETTEXT_TEST_FALLBACKS"
+then
+ : no probing necessary
+elif test -n "$GIT_GETTEXT_POISON"
then
- if test -z "$GIT_INTERNAL_GETTEXT_TEST_FALLBACKS" && type gettext.sh >/dev/null 2>&1
- then
- # This is GNU libintl's gettext.sh, we don't need to do anything
- # else than setting up the environment and loading gettext.sh
- GIT_INTERNAL_GETTEXT_SH_SCHEME=gnu
- export GIT_INTERNAL_GETTEXT_SH_SCHEME
-
- # Try to use libintl's gettext.sh, or fall back to English if we
- # can't.
- . gettext.sh
-
- elif test -z "$GIT_INTERNAL_GETTEXT_TEST_FALLBACKS" && test "$(gettext -h 2>&1)" = "-h"
- then
- # We don't have gettext.sh, but there's a gettext binary in our
- # path. This is probably Solaris or something like it which has a
- # gettext implementation that isn't GNU libintl.
- GIT_INTERNAL_GETTEXT_SH_SCHEME=solaris
- export GIT_INTERNAL_GETTEXT_SH_SCHEME
-
- # Solaris has a gettext(1) but no eval_gettext(1)
- eval_gettext () {
- gettext "$1" | (
- export PATH $(git sh-i18n--envsubst --variables "$1");
- git sh-i18n--envsubst "$1"
- )
- }
-
- else
- # Since gettext.sh isn't available we'll have to define our own
- # dummy pass-through functions.
-
- # Tell our tests that we don't have the real gettext.sh
- GIT_INTERNAL_GETTEXT_SH_SCHEME=fallthrough
- export GIT_INTERNAL_GETTEXT_SH_SCHEME
-
- gettext () {
- printf "%s" "$1"
- }
-
- eval_gettext () {
- printf "%s" "$1" | (
- export PATH $(git sh-i18n--envsubst --variables "$1");
- git sh-i18n--envsubst "$1"
- )
- }
- fi
-else
- # Emit garbage under GETTEXT_POISON=YesPlease. Unlike the C tests
- # this relies on an environment variable
-
GIT_INTERNAL_GETTEXT_SH_SCHEME=poison
- export GIT_INTERNAL_GETTEXT_SH_SCHEME
+elif type gettext.sh >/dev/null 2>&1
+then
+ # GNU libintl's gettext.sh
+ GIT_INTERNAL_GETTEXT_SH_SCHEME=gnu
+elif test "$(gettext -h 2>&1)" = "-h"
+then
+ # gettext binary exists but no gettext.sh. likely to be a gettext
+ # binary on a Solaris or something that is not GNU libintl and
+ # lack eval_gettext.
+ GIT_INTERNAL_GETTEXT_SH_SCHEME=gettext_without_eval_gettext
+fi
+export GIT_INTERNAL_GETTEXT_SH_SCHEME
+# ... and then follow that decision.
+case "$GIT_INTERNAL_GETTEXT_SH_SCHEME" in
+gnu)
+ # Use libintl's gettext.sh, or fall back to English if we can't.
+ . gettext.sh
+ ;;
+gettext_without_eval_gettext)
+ # Solaris has a gettext(1) but no eval_gettext(1)
+ eval_gettext () {
+ gettext "$1" | (
+ export PATH $(git sh-i18n--envsubst --variables "$1");
+ git sh-i18n--envsubst "$1"
+ )
+ }
+ ;;
+poison)
+ # Emit garbage so that tests that incorrectly rely on translatable
+ # strings will fail.
gettext () {
printf "%s" "# GETTEXT POISON #"
}
@@ -78,7 +65,20 @@ else
eval_gettext () {
printf "%s" "# GETTEXT POISON #"
}
-fi
+ ;;
+*)
+ gettext () {
+ printf "%s" "$1"
+ }
+
+ eval_gettext () {
+ printf "%s" "$1" | (
+ export PATH $(git sh-i18n--envsubst --variables "$1");
+ git sh-i18n--envsubst "$1"
+ )
+ }
+ ;;
+esac
# Git-specific wrapper functions
gettextln () {
diff --git a/git-stash.sh b/git-stash.sh
index fe4ab28b2e..4e2c7f8331 100755
--- a/git-stash.sh
+++ b/git-stash.sh
@@ -199,8 +199,8 @@ save_stash () {
# $ git stash save --blah-blah 2>&1 | head -n 2
# error: unknown option for 'stash save': --blah-blah
# To provide a message, use git stash save -- '--blah-blah'
- eval_gettextln "$("error: unknown option for 'stash save': \$option
- To provide a message, use git stash save -- '\$option'")"
+ eval_gettextln "error: unknown option for 'stash save': \$option
+ To provide a message, use git stash save -- '\$option'"
usage
;;
*)
diff --git a/git-submodule.sh b/git-submodule.sh
index 9bb2e13e92..3d94a14079 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -132,46 +132,47 @@ module_clone()
gitdir_base=
name=$(module_name "$path" 2>/dev/null)
test -n "$name" || name="$path"
- base_path=$(dirname "$path")
+ base_name=$(dirname "$name")
gitdir=$(git rev-parse --git-dir)
- gitdir_base="$gitdir/modules/$base_path"
- gitdir="$gitdir/modules/$path"
-
- case $gitdir in
- /*)
- a="$(cd_to_toplevel && pwd)/"
- b=$gitdir
- while [ "$b" ] && [ "${a%%/*}" = "${b%%/*}" ]
- do
- a=${a#*/} b=${b#*/};
- done
-
- rel="$a$name"
- rel=`echo $rel | sed -e 's|[^/]*|..|g'`
- rel_gitdir="$rel/$b"
- ;;
- *)
- rel=`echo $name | sed -e 's|[^/]*|..|g'`
- rel_gitdir="$rel/$gitdir"
- ;;
- esac
+ gitdir_base="$gitdir/modules/$base_name"
+ gitdir="$gitdir/modules/$name"
if test -d "$gitdir"
then
mkdir -p "$path"
- echo "gitdir: $rel_gitdir" >"$path/.git"
rm -f "$gitdir/index"
else
mkdir -p "$gitdir_base"
- if test -n "$reference"
- then
- git-clone $quiet "$reference" -n "$url" "$path" --separate-git-dir "$gitdir"
- else
- git-clone $quiet -n "$url" "$path" --separate-git-dir "$gitdir"
- fi ||
+ git clone $quiet -n ${reference:+"$reference"} \
+ --separate-git-dir "$gitdir" "$url" "$path" ||
die "$(eval_gettext "Clone of '\$url' into submodule path '\$path' failed")"
fi
+
+ a=$(cd "$gitdir" && pwd)/
+ b=$(cd "$path" && pwd)/
+ # normalize Windows-style absolute paths to POSIX-style absolute paths
+ case $a in [a-zA-Z]:/*) a=/${a%%:*}${a#*:} ;; esac
+ case $b in [a-zA-Z]:/*) b=/${b%%:*}${b#*:} ;; esac
+ # Remove all common leading directories after a sanity check
+ if test "${a#$b}" != "$a" || test "${b#$a}" != "$b"; then
+ die "$(eval_gettext "Gitdir '\$a' is part of the submodule path '\$b' or vice versa")"
+ fi
+ while test "${a%%/*}" = "${b%%/*}"
+ do
+ a=${a#*/}
+ b=${b#*/}
+ done
+ # Now chop off the trailing '/'s that were added in the beginning
+ a=${a%/}
+ b=${b%/}
+
+ # Turn each leading "*/" component into "../"
+ rel=$(echo $b | sed -e 's|[^/][^/]*|..|g')
+ echo "gitdir: $rel/$a" >"$path/.git"
+
+ rel=$(echo $a | sed -e 's|[^/][^/]*|..|g')
+ (clear_local_git_env; cd "$path" && GIT_WORK_TREE=. git config core.worktree "$rel/$b")
}
#
diff --git a/git-svn.perl b/git-svn.perl
index eeb83d3759..ca038ec842 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -1,4 +1,4 @@
-#!/usr/bin/env perl
+#!/usr/bin/perl
# Copyright (C) 2006, Eric Wong <normalperson@yhbt.net>
# License: GPL v2 or later
use 5.008;
@@ -1878,8 +1878,7 @@ sub cmt_sha2rev_batch {
sub working_head_info {
my ($head, $refs) = @_;
- my @args = qw/log --no-color --no-decorate --first-parent
- --pretty=medium/;
+ my @args = qw/rev-list --first-parent --pretty=medium/;
my ($fh, $ctx) = command_output_pipe(@args, $head);
my $hash;
my %max;
@@ -2029,6 +2028,7 @@ 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;
@@ -3287,6 +3287,14 @@ sub get_untracked {
\@out;
}
+sub get_tz {
+ # some systmes don't handle or mishandle %z, so be creative.
+ my $t = shift || time;
+ my $gm = timelocal(gmtime($t));
+ my $sign = qw( + + - )[ $t <=> $gm ];
+ return sprintf("%s%02d%02d", $sign, (gmtime(abs($t - $gm)))[2,1]);
+}
+
# parse_svn_date(DATE)
# --------------------
# Given a date (in UTC) from Subversion, return a string in the format
@@ -3319,8 +3327,7 @@ sub parse_svn_date {
delete $ENV{TZ};
}
- my $our_TZ =
- POSIX::strftime('%Z', $S, $M, $H, $d, $m - 1, $Y - 1900);
+ my $our_TZ = get_tz();
# This converts $epoch_in_UTC into our local timezone.
my ($sec, $min, $hour, $mday, $mon, $year,
@@ -3920,7 +3927,7 @@ sub rebuild {
my ($base_rev, $head) = ($partial ? $self->rev_map_max_norebuild(1) :
(undef, undef));
my ($log, $ctx) =
- command_output_pipe(qw/rev-list --pretty=raw --no-color --reverse/,
+ command_output_pipe(qw/rev-list --pretty=raw --reverse/,
($head ? "$head.." : "") . $self->refname,
'--');
my $metadata_url = $self->metadata_url;
@@ -5130,7 +5137,7 @@ sub rmdirs {
}
sub open_or_add_dir {
- my ($self, $full_path, $baton) = @_;
+ my ($self, $full_path, $baton, $deletions) = @_;
my $t = $self->{types}->{$full_path};
if (!defined $t) {
die "$full_path not known in r$self->{r} or we have a bug!\n";
@@ -5139,7 +5146,7 @@ sub open_or_add_dir {
no warnings 'once';
# SVN::Node::none and SVN::Node::file are used only once,
# so we're shutting up Perl's warnings about them.
- if ($t == $SVN::Node::none) {
+ if ($t == $SVN::Node::none || defined($deletions->{$full_path})) {
return $self->add_directory($full_path, $baton,
undef, -1, $self->{pool});
} elsif ($t == $SVN::Node::dir) {
@@ -5154,17 +5161,18 @@ sub open_or_add_dir {
}
sub ensure_path {
- my ($self, $path) = @_;
+ my ($self, $path, $deletions) = @_;
my $bat = $self->{bat};
my $repo_path = $self->repo_path($path);
return $bat->{''} unless (length $repo_path);
+
my @p = split m#/+#, $repo_path;
my $c = shift @p;
- $bat->{$c} ||= $self->open_or_add_dir($c, $bat->{''});
+ $bat->{$c} ||= $self->open_or_add_dir($c, $bat->{''}, $deletions);
while (@p) {
my $c0 = $c;
$c .= '/' . shift @p;
- $bat->{$c} ||= $self->open_or_add_dir($c, $bat->{$c0});
+ $bat->{$c} ||= $self->open_or_add_dir($c, $bat->{$c0}, $deletions);
}
return $bat->{$c};
}
@@ -5221,9 +5229,9 @@ sub apply_autoprops {
}
sub A {
- my ($self, $m) = @_;
+ my ($self, $m, $deletions) = @_;
my ($dir, $file) = split_path($m->{file_b});
- my $pbat = $self->ensure_path($dir);
+ my $pbat = $self->ensure_path($dir, $deletions);
my $fbat = $self->add_file($self->repo_path($m->{file_b}), $pbat,
undef, -1);
print "\tA\t$m->{file_b}\n" unless $::_q;
@@ -5233,9 +5241,9 @@ sub A {
}
sub C {
- my ($self, $m) = @_;
+ my ($self, $m, $deletions) = @_;
my ($dir, $file) = split_path($m->{file_b});
- my $pbat = $self->ensure_path($dir);
+ my $pbat = $self->ensure_path($dir, $deletions);
my $fbat = $self->add_file($self->repo_path($m->{file_b}), $pbat,
$self->url_path($m->{file_a}), $self->{r});
print "\tC\t$m->{file_a} => $m->{file_b}\n" unless $::_q;
@@ -5252,9 +5260,9 @@ sub delete_entry {
}
sub R {
- my ($self, $m) = @_;
+ my ($self, $m, $deletions) = @_;
my ($dir, $file) = split_path($m->{file_b});
- my $pbat = $self->ensure_path($dir);
+ my $pbat = $self->ensure_path($dir, $deletions);
my $fbat = $self->add_file($self->repo_path($m->{file_b}), $pbat,
$self->url_path($m->{file_a}), $self->{r});
print "\tR\t$m->{file_a} => $m->{file_b}\n" unless $::_q;
@@ -5263,14 +5271,14 @@ sub R {
$self->close_file($fbat,undef,$self->{pool});
($dir, $file) = split_path($m->{file_a});
- $pbat = $self->ensure_path($dir);
+ $pbat = $self->ensure_path($dir, $deletions);
$self->delete_entry($m->{file_a}, $pbat);
}
sub M {
- my ($self, $m) = @_;
+ my ($self, $m, $deletions) = @_;
my ($dir, $file) = split_path($m->{file_b});
- my $pbat = $self->ensure_path($dir);
+ my $pbat = $self->ensure_path($dir, $deletions);
my $fbat = $self->open_file($self->repo_path($m->{file_b}),
$pbat,$self->{r},$self->{pool});
print "\t$m->{chg}\t$m->{file_b}\n" unless $::_q;
@@ -5340,9 +5348,9 @@ sub chg_file {
}
sub D {
- my ($self, $m) = @_;
+ my ($self, $m, $deletions) = @_;
my ($dir, $file) = split_path($m->{file_b});
- my $pbat = $self->ensure_path($dir);
+ my $pbat = $self->ensure_path($dir, $deletions);
print "\tD\t$m->{file_b}\n" unless $::_q;
$self->delete_entry($m->{file_b}, $pbat);
}
@@ -5374,11 +5382,19 @@ sub DESTROY {
sub apply_diff {
my ($self) = @_;
my $mods = $self->{mods};
- my %o = ( D => 1, R => 0, C => -1, A => 3, M => 3, T => 3 );
+ my %o = ( D => 0, C => 1, R => 2, A => 3, M => 4, T => 5 );
+ my %deletions;
+
+ foreach my $m (@$mods) {
+ if ($m->{chg} eq "D") {
+ $deletions{$m->{file_b}} = 1;
+ }
+ }
+
foreach my $m (sort { $o{$a->{chg}} <=> $o{$b->{chg}} } @$mods) {
my $f = $m->{chg};
if (defined $o{$f}) {
- $self->$f($m);
+ $self->$f($m, \%deletions);
} else {
fatal("Invalid change type: $f");
}
@@ -5994,7 +6010,6 @@ package Git::SVN::Log;
use strict;
use warnings;
use POSIX qw/strftime/;
-use Time::Local;
use constant commit_log_separator => ('-' x 72) . "\n";
use vars qw/$TZ $limit $color $pager $non_recursive $verbose $oneline
%rusers $show_commit $incremental/;
@@ -6104,11 +6119,8 @@ sub run_pager {
}
sub format_svn_date {
- # 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 ];
- my $gmoff = sprintf("%s%02d%02d", $sign, (gmtime(abs($t - $gm)))[2,1]);
+ my $gmoff = Git::SVN::get_tz($t);
return strftime("%Y-%m-%d %H:%M:%S $gmoff (%a, %d %b %Y)", localtime($t));
}
diff --git a/git.spec.in b/git.spec.in
index b93df109c8..d61d537ef0 100644
--- a/git.spec.in
+++ b/git.spec.in
@@ -101,6 +101,7 @@ Group: Development/Libraries
Requires: git = %{version}-%{release}
Requires: perl(:MODULE_COMPAT_%(eval "`%{__perl} -V:version`"; echo $version))
BuildRequires: perl(Error)
+BuildRequires: perl(ExtUtils::MakeMaker)
%description -n perl-Git
Perl interface to Git
diff --git a/gitk-git/gitk b/gitk-git/gitk
index 64ef3c4013..22270ce46b 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -14,6 +14,35 @@ proc hasworktree {} {
[exec git rev-parse --is-inside-git-dir] == "false"}]
}
+proc reponame {} {
+ global gitdir
+ set n [file normalize $gitdir]
+ if {[string match "*/.git" $n]} {
+ set n [string range $n 0 end-5]
+ }
+ return [file tail $n]
+}
+
+proc gitworktree {} {
+ variable _gitworktree
+ if {[info exists _gitworktree]} {
+ return $_gitworktree
+ }
+ # v1.7.0 introduced --show-toplevel to return the canonical work-tree
+ if {[catch {set _gitworktree [exec git rev-parse --show-toplevel]}]} {
+ # try to set work tree from environment, core.worktree or use
+ # cdup to obtain a relative path to the top of the worktree. If
+ # run from the top, the ./ prefix ensures normalize expands pwd.
+ if {[catch { set _gitworktree $env(GIT_WORK_TREE) }]} {
+ catch {set _gitworktree [exec git config --get core.worktree]}
+ if {$_gitworktree eq ""} {
+ set _gitworktree [file normalize ./[exec git rev-parse --show-cdup]]
+ }
+ }
+ }
+ return $_gitworktree
+}
+
# A simple scheduler for compute-intensive stuff.
# The aim is to make sure that event handlers for GUI actions can
# run at least every 50-100 ms. Unfortunately fileevent handlers are
@@ -612,12 +641,16 @@ proc varcinit {view} {
proc resetvarcs {view} {
global varcid varccommits parents children vseedcount ordertok
+ global vshortids
foreach vid [array names varcid $view,*] {
unset varcid($vid)
unset children($vid)
unset parents($vid)
}
+ foreach vid [array names vshortids $view,*] {
+ unset vshortids($vid)
+ }
# some commits might have children but haven't been seen yet
foreach vid [array names children $view,*] {
unset children($vid)
@@ -904,7 +937,7 @@ proc fix_reversal {p a v} {
proc insertrow {id p v} {
global cmitlisted children parents varcid varctok vtokmod
global varccommits ordertok commitidx numcommits curview
- global targetid targetrow
+ global targetid targetrow vshortids
readcommit $id
set vid $v,$id
@@ -913,6 +946,7 @@ proc insertrow {id p v} {
set parents($vid) [list $p]
set a [newvarc $v $id]
set varcid($vid) $a
+ lappend vshortids($v,[string range $id 0 3]) $id
if {[string compare [lindex $varctok($v) $a] $vtokmod($v)] < 0} {
modify_arc $v $a
}
@@ -1368,7 +1402,7 @@ proc getcommitlines {fd inst view updating} {
global commitidx commitdata vdatemode
global parents children curview hlview
global idpending ordertok
- global varccommits varcid varctok vtokmod vfilelimit
+ global varccommits varcid varctok vtokmod vfilelimit vshortids
set stuff [read $fd 500000]
# git log doesn't terminate the last commit with a null...
@@ -1468,6 +1502,8 @@ proc getcommitlines {fd inst view updating} {
set id [lindex $ids 0]
set vid $view,$id
+ lappend vshortids($view,[string range $id 0 3]) $id
+
if {!$listed && $updating && ![info exists varcid($vid)] &&
$vfilelimit($view) ne {}} {
# git log doesn't rewrite parents for unlisted commits
@@ -1690,11 +1726,26 @@ proc getcommit {id} {
# and are present in the current view.
# This is fairly slow...
proc longid {prefix} {
- global varcid curview
+ global varcid curview vshortids
set ids {}
- foreach match [array names varcid "$curview,$prefix*"] {
- lappend ids [lindex [split $match ","] 1]
+ if {[string length $prefix] >= 4} {
+ set vshortid $curview,[string range $prefix 0 3]
+ if {[info exists vshortids($vshortid)]} {
+ foreach id $vshortids($vshortid) {
+ if {[string match "$prefix*" $id]} {
+ if {[lsearch -exact $ids $id] < 0} {
+ lappend ids $id
+ if {[llength $ids] >= 2} break
+ }
+ }
+ }
+ }
+ } else {
+ foreach match [array names varcid "$curview,$prefix*"] {
+ lappend ids [lindex [split $match ","] 1]
+ if {[llength $ids] >= 2} break
+ }
}
return $ids
}
@@ -2491,6 +2542,8 @@ proc makewindow {} {
{mc "Return to mark" command gotomark}
{mc "Find descendant of this and mark" command find_common_desc}
{mc "Compare with marked commit" command compare_commits}
+ {mc "Diff this -> marked commit" command {diffvsmark 0}}
+ {mc "Diff marked commit -> this" command {diffvsmark 1}}
}
$rowctxmenu configure -tearoff 0
@@ -2499,6 +2552,8 @@ proc makewindow {} {
{mc "Diff this -> selected" command {diffvssel 0}}
{mc "Diff selected -> this" command {diffvssel 1}}
{mc "Make patch" command mkpatch}
+ {mc "Diff this -> marked commit" command {diffvsmark 0}}
+ {mc "Diff marked commit -> this" command {diffvsmark 1}}
}
$fakerowmenu configure -tearoff 0
@@ -4630,8 +4685,9 @@ proc askfindhighlight {row id} {
}
set info $commitinfo($id)
set isbold 0
- set fldtypes [list [mc Headline] [mc Author] [mc Date] [mc Committer] [mc CDate] [mc Comments]]
+ set fldtypes [list [mc Headline] [mc Author] "" [mc Committer] "" [mc Comments]]
foreach f $info ty $fldtypes {
+ if {$ty eq ""} continue
if {($findloc eq [mc "All fields"] || $findloc eq $ty) &&
[doesmatch $f]} {
if {$ty eq [mc "Author"]} {
@@ -6492,7 +6548,7 @@ proc findmore {} {
if {![info exists find_dirn]} {
return 0
}
- set fldtypes [list [mc "Headline"] [mc "Author"] [mc "Date"] [mc "Committer"] [mc "CDate"] [mc "Comments"]]
+ set fldtypes [list [mc "Headline"] [mc "Author"] "" [mc "Committer"] "" [mc "Comments"]]
set l $findcurline
set moretodo 0
if {$find_dirn > 0} {
@@ -6553,6 +6609,7 @@ proc findmore {} {
}
set info $commitinfo($id)
foreach f $info ty $fldtypes {
+ if {$ty eq ""} continue
if {($findloc eq [mc "All fields"] || $findloc eq $ty) &&
[doesmatch $f]} {
set found 1
@@ -6705,7 +6762,7 @@ proc appendwithlinks {text tags} {
set start [$ctext index "end - 1c"]
$ctext insert end $text $tags
- set links [regexp -indices -all -inline {\m[0-9a-f]{6,40}\M} $text]
+ set links [regexp -indices -all -inline {(?:\m|-g)[0-9a-f]{6,40}\M} $text]
foreach l $links {
set s [lindex $l 0]
set e [lindex $l 1]
@@ -6721,6 +6778,10 @@ proc appendwithlinks {text tags} {
proc setlink {id lk} {
global curview ctext pendinglinks
+ if {[string range $id 0 1] eq "-g"} {
+ set id [string range $id 2 end]
+ }
+
set known 0
if {[string length $id] < 40} {
set matches [longid $id]
@@ -7393,19 +7454,15 @@ proc startdiff {ids} {
}
}
+# If the filename (name) is under any of the passed filter paths
+# then return true to include the file in the listing.
proc path_filter {filter name} {
+ set worktree [gitworktree]
foreach p $filter {
- set l [string length $p]
- if {[string index $p end] eq "/"} {
- if {[string compare -length $l $p $name] == 0} {
- return 1
- }
- } else {
- if {[string compare -length $l $p $name] == 0 &&
- ([string length $name] == $l ||
- [string index $name $l] eq "/")} {
- return 1
- }
+ set fq_p [file normalize $p]
+ set fq_n [file normalize [file join $worktree $name]]
+ if {[string match [file normalize $fq_p]* $fq_n]} {
+ return 1
}
}
return 0
@@ -7419,7 +7476,7 @@ proc addtocflist {ids} {
}
proc diffcmd {ids flags} {
- global nullid nullid2
+ global log_showroot nullid nullid2
set i [lsearch -exact $ids $nullid]
set j [lsearch -exact $ids $nullid2]
@@ -7453,6 +7510,9 @@ proc diffcmd {ids flags} {
lappend cmd HEAD
}
} else {
+ if {$log_showroot} {
+ lappend flags --root
+ }
set cmd [concat | git diff-tree -r $flags $ids]
}
return $cmd
@@ -8442,6 +8502,11 @@ proc rowmenu {x y id} {
} else {
set state normal
}
+ if {[info exists markedid] && $markedid ne $id} {
+ set mstate normal
+ } else {
+ set mstate disabled
+ }
if {$id ne $nullid && $id ne $nullid2} {
set menu $rowctxmenu
if {$mainhead ne {}} {
@@ -8449,21 +8514,17 @@ proc rowmenu {x y id} {
} else {
$menu entryconfigure 7 -label [mc "Detached head: can't reset" $mainhead] -state disabled
}
- if {[info exists markedid] && $markedid ne $id} {
- $menu entryconfigure 9 -state normal
- $menu entryconfigure 10 -state normal
- $menu entryconfigure 11 -state normal
- } else {
- $menu entryconfigure 9 -state disabled
- $menu entryconfigure 10 -state disabled
- $menu entryconfigure 11 -state disabled
- }
+ $menu entryconfigure 9 -state $mstate
+ $menu entryconfigure 10 -state $mstate
+ $menu entryconfigure 11 -state $mstate
} else {
set menu $fakerowmenu
}
$menu entryconfigure [mca "Diff this -> selected"] -state $state
$menu entryconfigure [mca "Diff selected -> this"] -state $state
$menu entryconfigure [mca "Make patch"] -state $state
+ $menu entryconfigure [mca "Diff this -> marked commit"] -state $mstate
+ $menu entryconfigure [mca "Diff marked commit -> this"] -state $mstate
tk_popup $menu $x $y
}
@@ -8667,6 +8728,21 @@ proc diffvssel {dirn} {
doseldiff $oldid $newid
}
+proc diffvsmark {dirn} {
+ global rowmenuid markedid
+
+ if {![info exists markedid]} return
+ if {$dirn} {
+ set oldid $markedid
+ set newid $rowmenuid
+ } else {
+ set oldid $rowmenuid
+ set newid $markedid
+ }
+ addtohistory [list doseldiff $oldid $newid] savectextpos
+ doseldiff $oldid $newid
+}
+
proc doseldiff {oldid newid} {
global ctext
global commitinfo
@@ -10719,7 +10795,7 @@ proc fontok {} {
if {$fontparam(slant) eq "italic"} {
lappend fontpref($f) "italic"
}
- set w $prefstop.$f
+ set w $prefstop.notebook.fonts.$f
$w conf -text $fontparam(family) -font $fontpref($f)
fontcan
@@ -10773,6 +10849,139 @@ proc chg_fontparam {v sub op} {
font config sample -$sub $fontparam($sub)
}
+# Create a property sheet tab page
+proc create_prefs_page {w} {
+ global NS
+ set parent [join [lrange [split $w .] 0 end-1] .]
+ if {[winfo class $parent] eq "TNotebook"} {
+ ${NS}::frame $w
+ } else {
+ ${NS}::labelframe $w
+ }
+}
+
+proc prefspage_general {notebook} {
+ global NS maxwidth maxgraphpct showneartags showlocalchanges
+ global tabstop limitdiffs autoselect autosellen extdifftool perfile_attrs
+ global hideremotes want_ttk have_ttk
+
+ set page [create_prefs_page $notebook.general]
+
+ ${NS}::label $page.ldisp -text [mc "Commit list display options"]
+ grid $page.ldisp - -sticky w -pady 10
+ ${NS}::label $page.spacer -text " "
+ ${NS}::label $page.maxwidthl -text [mc "Maximum graph width (lines)"]
+ spinbox $page.maxwidth -from 0 -to 100 -width 4 -textvariable maxwidth
+ grid $page.spacer $page.maxwidthl $page.maxwidth -sticky w
+ ${NS}::label $page.maxpctl -text [mc "Maximum graph width (% of pane)"]
+ spinbox $page.maxpct -from 1 -to 100 -width 4 -textvariable maxgraphpct
+ grid x $page.maxpctl $page.maxpct -sticky w
+ ${NS}::checkbutton $page.showlocal -text [mc "Show local changes"] \
+ -variable showlocalchanges
+ grid x $page.showlocal -sticky w
+ ${NS}::checkbutton $page.autoselect -text [mc "Auto-select SHA1 (length)"] \
+ -variable autoselect
+ spinbox $page.autosellen -from 1 -to 40 -width 4 -textvariable autosellen
+ grid x $page.autoselect $page.autosellen -sticky w
+ ${NS}::checkbutton $page.hideremotes -text [mc "Hide remote refs"] \
+ -variable hideremotes
+ grid x $page.hideremotes -sticky w
+
+ ${NS}::label $page.ddisp -text [mc "Diff display options"]
+ grid $page.ddisp - -sticky w -pady 10
+ ${NS}::label $page.tabstopl -text [mc "Tab spacing"]
+ spinbox $page.tabstop -from 1 -to 20 -width 4 -textvariable tabstop
+ grid x $page.tabstopl $page.tabstop -sticky w
+ ${NS}::checkbutton $page.ntag -text [mc "Display nearby tags"] \
+ -variable showneartags
+ grid x $page.ntag -sticky w
+ ${NS}::checkbutton $page.ldiff -text [mc "Limit diffs to listed paths"] \
+ -variable limitdiffs
+ grid x $page.ldiff -sticky w
+ ${NS}::checkbutton $page.lattr -text [mc "Support per-file encodings"] \
+ -variable perfile_attrs
+ grid x $page.lattr -sticky w
+
+ ${NS}::entry $page.extdifft -textvariable extdifftool
+ ${NS}::frame $page.extdifff
+ ${NS}::label $page.extdifff.l -text [mc "External diff tool" ]
+ ${NS}::button $page.extdifff.b -text [mc "Choose..."] -command choose_extdiff
+ pack $page.extdifff.l $page.extdifff.b -side left
+ pack configure $page.extdifff.l -padx 10
+ grid x $page.extdifff $page.extdifft -sticky ew
+
+ ${NS}::label $page.lgen -text [mc "General options"]
+ grid $page.lgen - -sticky w -pady 10
+ ${NS}::checkbutton $page.want_ttk -variable want_ttk \
+ -text [mc "Use themed widgets"]
+ if {$have_ttk} {
+ ${NS}::label $page.ttk_note -text [mc "(change requires restart)"]
+ } else {
+ ${NS}::label $page.ttk_note -text [mc "(currently unavailable)"]
+ }
+ grid x $page.want_ttk $page.ttk_note -sticky w
+ return $page
+}
+
+proc prefspage_colors {notebook} {
+ global NS uicolor bgcolor fgcolor ctext diffcolors selectbgcolor markbgcolor
+
+ set page [create_prefs_page $notebook.colors]
+
+ ${NS}::label $page.cdisp -text [mc "Colors: press to choose"]
+ grid $page.cdisp - -sticky w -pady 10
+ label $page.ui -padx 40 -relief sunk -background $uicolor
+ ${NS}::button $page.uibut -text [mc "Interface"] \
+ -command [list choosecolor uicolor {} $page.ui [mc "interface"] setui]
+ grid x $page.uibut $page.ui -sticky w
+ label $page.bg -padx 40 -relief sunk -background $bgcolor
+ ${NS}::button $page.bgbut -text [mc "Background"] \
+ -command [list choosecolor bgcolor {} $page.bg [mc "background"] setbg]
+ grid x $page.bgbut $page.bg -sticky w
+ label $page.fg -padx 40 -relief sunk -background $fgcolor
+ ${NS}::button $page.fgbut -text [mc "Foreground"] \
+ -command [list choosecolor fgcolor {} $page.fg [mc "foreground"] setfg]
+ grid x $page.fgbut $page.fg -sticky w
+ label $page.diffold -padx 40 -relief sunk -background [lindex $diffcolors 0]
+ ${NS}::button $page.diffoldbut -text [mc "Diff: old lines"] \
+ -command [list choosecolor diffcolors 0 $page.diffold [mc "diff old lines"] \
+ [list $ctext tag conf d0 -foreground]]
+ grid x $page.diffoldbut $page.diffold -sticky w
+ label $page.diffnew -padx 40 -relief sunk -background [lindex $diffcolors 1]
+ ${NS}::button $page.diffnewbut -text [mc "Diff: new lines"] \
+ -command [list choosecolor diffcolors 1 $page.diffnew [mc "diff new lines"] \
+ [list $ctext tag conf dresult -foreground]]
+ grid x $page.diffnewbut $page.diffnew -sticky w
+ label $page.hunksep -padx 40 -relief sunk -background [lindex $diffcolors 2]
+ ${NS}::button $page.hunksepbut -text [mc "Diff: hunk header"] \
+ -command [list choosecolor diffcolors 2 $page.hunksep \
+ [mc "diff hunk header"] \
+ [list $ctext tag conf hunksep -foreground]]
+ grid x $page.hunksepbut $page.hunksep -sticky w
+ label $page.markbgsep -padx 40 -relief sunk -background $markbgcolor
+ ${NS}::button $page.markbgbut -text [mc "Marked line bg"] \
+ -command [list choosecolor markbgcolor {} $page.markbgsep \
+ [mc "marked line background"] \
+ [list $ctext tag conf omark -background]]
+ grid x $page.markbgbut $page.markbgsep -sticky w
+ label $page.selbgsep -padx 40 -relief sunk -background $selectbgcolor
+ ${NS}::button $page.selbgbut -text [mc "Select bg"] \
+ -command [list choosecolor selectbgcolor {} $page.selbgsep [mc "background"] setselbg]
+ grid x $page.selbgbut $page.selbgsep -sticky w
+ return $page
+}
+
+proc prefspage_fonts {notebook} {
+ global NS
+ set page [create_prefs_page $notebook.fonts]
+ ${NS}::label $page.cfont -text [mc "Fonts: press to choose"]
+ grid $page.cfont - -sticky w -pady 10
+ mkfontdisp mainfont $page [mc "Main font"]
+ mkfontdisp textfont $page [mc "Diff display font"]
+ mkfontdisp uifont $page [mc "User interface font"]
+ return $page
+}
+
proc doprefs {} {
global maxwidth maxgraphpct use_ttk NS
global oldprefs prefstop showneartags showlocalchanges
@@ -10793,106 +11002,38 @@ proc doprefs {} {
ttk_toplevel $top
wm title $top [mc "Gitk preferences"]
make_transient $top .
- ${NS}::label $top.ldisp -text [mc "Commit list display options"]
- grid $top.ldisp - -sticky w -pady 10
- ${NS}::label $top.spacer -text " "
- ${NS}::label $top.maxwidthl -text [mc "Maximum graph width (lines)"]
- spinbox $top.maxwidth -from 0 -to 100 -width 4 -textvariable maxwidth
- grid $top.spacer $top.maxwidthl $top.maxwidth -sticky w
- ${NS}::label $top.maxpctl -text [mc "Maximum graph width (% of pane)"]
- spinbox $top.maxpct -from 1 -to 100 -width 4 -textvariable maxgraphpct
- grid x $top.maxpctl $top.maxpct -sticky w
- ${NS}::checkbutton $top.showlocal -text [mc "Show local changes"] \
- -variable showlocalchanges
- grid x $top.showlocal -sticky w
- ${NS}::checkbutton $top.autoselect -text [mc "Auto-select SHA1 (length)"] \
- -variable autoselect
- spinbox $top.autosellen -from 1 -to 40 -width 4 -textvariable autosellen
- grid x $top.autoselect $top.autosellen -sticky w
- ${NS}::checkbutton $top.hideremotes -text [mc "Hide remote refs"] \
- -variable hideremotes
- grid x $top.hideremotes -sticky w
-
- ${NS}::label $top.ddisp -text [mc "Diff display options"]
- grid $top.ddisp - -sticky w -pady 10
- ${NS}::label $top.tabstopl -text [mc "Tab spacing"]
- spinbox $top.tabstop -from 1 -to 20 -width 4 -textvariable tabstop
- grid x $top.tabstopl $top.tabstop -sticky w
- ${NS}::checkbutton $top.ntag -text [mc "Display nearby tags"] \
- -variable showneartags
- grid x $top.ntag -sticky w
- ${NS}::checkbutton $top.ldiff -text [mc "Limit diffs to listed paths"] \
- -variable limitdiffs
- grid x $top.ldiff -sticky w
- ${NS}::checkbutton $top.lattr -text [mc "Support per-file encodings"] \
- -variable perfile_attrs
- grid x $top.lattr -sticky w
-
- ${NS}::entry $top.extdifft -textvariable extdifftool
- ${NS}::frame $top.extdifff
- ${NS}::label $top.extdifff.l -text [mc "External diff tool" ]
- ${NS}::button $top.extdifff.b -text [mc "Choose..."] -command choose_extdiff
- pack $top.extdifff.l $top.extdifff.b -side left
- pack configure $top.extdifff.l -padx 10
- grid x $top.extdifff $top.extdifft -sticky ew
-
- ${NS}::label $top.lgen -text [mc "General options"]
- grid $top.lgen - -sticky w -pady 10
- ${NS}::checkbutton $top.want_ttk -variable want_ttk \
- -text [mc "Use themed widgets"]
- if {$have_ttk} {
- ${NS}::label $top.ttk_note -text [mc "(change requires restart)"]
+
+ if {[set use_notebook [expr {$use_ttk && [info command ::ttk::notebook] ne ""}]]} {
+ set notebook [ttk::notebook $top.notebook]
} else {
- ${NS}::label $top.ttk_note -text [mc "(currently unavailable)"]
- }
- grid x $top.want_ttk $top.ttk_note -sticky w
-
- ${NS}::label $top.cdisp -text [mc "Colors: press to choose"]
- grid $top.cdisp - -sticky w -pady 10
- label $top.ui -padx 40 -relief sunk -background $uicolor
- ${NS}::button $top.uibut -text [mc "Interface"] \
- -command [list choosecolor uicolor {} $top.ui [mc "interface"] setui]
- grid x $top.uibut $top.ui -sticky w
- label $top.bg -padx 40 -relief sunk -background $bgcolor
- ${NS}::button $top.bgbut -text [mc "Background"] \
- -command [list choosecolor bgcolor {} $top.bg [mc "background"] setbg]
- grid x $top.bgbut $top.bg -sticky w
- label $top.fg -padx 40 -relief sunk -background $fgcolor
- ${NS}::button $top.fgbut -text [mc "Foreground"] \
- -command [list choosecolor fgcolor {} $top.fg [mc "foreground"] setfg]
- grid x $top.fgbut $top.fg -sticky w
- label $top.diffold -padx 40 -relief sunk -background [lindex $diffcolors 0]
- ${NS}::button $top.diffoldbut -text [mc "Diff: old lines"] \
- -command [list choosecolor diffcolors 0 $top.diffold [mc "diff old lines"] \
- [list $ctext tag conf d0 -foreground]]
- grid x $top.diffoldbut $top.diffold -sticky w
- label $top.diffnew -padx 40 -relief sunk -background [lindex $diffcolors 1]
- ${NS}::button $top.diffnewbut -text [mc "Diff: new lines"] \
- -command [list choosecolor diffcolors 1 $top.diffnew [mc "diff new lines"] \
- [list $ctext tag conf dresult -foreground]]
- grid x $top.diffnewbut $top.diffnew -sticky w
- label $top.hunksep -padx 40 -relief sunk -background [lindex $diffcolors 2]
- ${NS}::button $top.hunksepbut -text [mc "Diff: hunk header"] \
- -command [list choosecolor diffcolors 2 $top.hunksep \
- [mc "diff hunk header"] \
- [list $ctext tag conf hunksep -foreground]]
- grid x $top.hunksepbut $top.hunksep -sticky w
- label $top.markbgsep -padx 40 -relief sunk -background $markbgcolor
- ${NS}::button $top.markbgbut -text [mc "Marked line bg"] \
- -command [list choosecolor markbgcolor {} $top.markbgsep \
- [mc "marked line background"] \
- [list $ctext tag conf omark -background]]
- grid x $top.markbgbut $top.markbgsep -sticky w
- label $top.selbgsep -padx 40 -relief sunk -background $selectbgcolor
- ${NS}::button $top.selbgbut -text [mc "Select bg"] \
- -command [list choosecolor selectbgcolor {} $top.selbgsep [mc "background"] setselbg]
- grid x $top.selbgbut $top.selbgsep -sticky w
-
- ${NS}::label $top.cfont -text [mc "Fonts: press to choose"]
- grid $top.cfont - -sticky w -pady 10
- mkfontdisp mainfont $top [mc "Main font"]
- mkfontdisp textfont $top [mc "Diff display font"]
- mkfontdisp uifont $top [mc "User interface font"]
+ set notebook [${NS}::frame $top.notebook -borderwidth 0 -relief flat]
+ }
+
+ lappend pages [prefspage_general $notebook] [mc "General"]
+ lappend pages [prefspage_colors $notebook] [mc "Colors"]
+ lappend pages [prefspage_fonts $notebook] [mc "Fonts"]
+ set col 0
+ foreach {page title} $pages {
+ if {$use_notebook} {
+ $notebook add $page -text $title
+ } else {
+ set btn [${NS}::button $notebook.b_[string map {. X} $page] \
+ -text $title -command [list raise $page]]
+ $page configure -text $title
+ grid $btn -row 0 -column [incr col] -sticky w
+ grid $page -row 1 -column 0 -sticky news -columnspan 100
+ }
+ }
+
+ if {!$use_notebook} {
+ grid columnconfigure $notebook 0 -weight 1
+ grid rowconfigure $notebook 1 -weight 1
+ raise [lindex $pages 0]
+ }
+
+ grid $notebook -sticky news -padx 2 -pady 2
+ grid rowconfigure $top 0 -weight 1
+ grid columnconfigure $top 0 -weight 1
${NS}::frame $top.buts
${NS}::button $top.buts.ok -text [mc "OK"] -command prefsok -default active
@@ -10904,7 +11045,7 @@ proc doprefs {} {
grid columnconfigure $top.buts 1 -weight 1 -uniform a
grid $top.buts - - -pady 10 -sticky ew
grid columnconfigure $top 2 -weight 1
- bind $top <Visibility> "focus $top.buts.ok"
+ bind $top <Visibility> [list focus $top.buts.ok]
}
proc choose_extdiff {} {
@@ -11422,10 +11563,20 @@ catch {
}
}
+set log_showroot true
+catch {
+ set log_showroot [exec git config --bool --get log.showroot]
+}
+
if {[tk windowingsystem] eq "aqua"} {
set mainfont {{Lucida Grande} 9}
set textfont {Monaco 9}
set uifont {{Lucida Grande} 9 bold}
+} elseif {![catch {::tk::pkgconfig get fontsystem} xft] && $xft eq "xft"} {
+ # fontconfig!
+ set mainfont {sans 9}
+ set textfont {monospace 9}
+ set uifont {sans 9 bold}
} else {
set mainfont {Helvetica 9}
set textfont {Courier 9}
@@ -11607,6 +11758,8 @@ if {[package vcompare $git_version "1.6.6.2"] >= 0} {
set show_notes "--show-notes"
}
+set appname "gitk"
+
set runq {}
set history {}
set historyindex 0
@@ -11676,7 +11829,7 @@ catch {
}
# wait for the window to become visible
tkwait visibility .
-wm title . "[file tail $argv0]: [file tail [pwd]]"
+wm title . "$appname: [reponame]"
update
readrefs
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index b67972ec5d..a8b5fad266 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -760,6 +760,7 @@ our @cgi_param_mapping = (
search_use_regexp => "sr",
ctag => "by_tag",
diff_style => "ds",
+ project_filter => "pf",
# this must be last entry (for manipulation from JavaScript)
javascript => "js"
);
@@ -976,7 +977,7 @@ sub evaluate_path_info {
our ($action, $project, $file_name, $file_parent, $hash, $hash_parent, $hash_base,
$hash_parent_base, @extra_options, $page, $searchtype, $search_use_regexp,
- $searchtext, $search_regexp);
+ $searchtext, $search_regexp, $project_filter);
sub evaluate_and_validate_params {
our $action = $input_params{'action'};
if (defined $action) {
@@ -994,6 +995,13 @@ sub evaluate_and_validate_params {
}
}
+ our $project_filter = $input_params{'project_filter'};
+ if (defined $project_filter) {
+ if (!validate_pathname($project_filter)) {
+ die_error(404, "Invalid project_filter parameter");
+ }
+ }
+
our $file_name = $input_params{'file_name'};
if (defined $file_name) {
if (!validate_pathname($file_name)) {
@@ -1716,6 +1724,88 @@ sub chop_and_escape_str {
}
}
+# Highlight selected fragments of string, using given CSS class,
+# and escape HTML. It is assumed that fragments do not overlap.
+# Regions are passed as list of pairs (array references).
+#
+# Example: esc_html_hl_regions("foobar", "mark", [ 0, 3 ]) returns
+# '<span class="mark">foo</span>bar'
+sub esc_html_hl_regions {
+ my ($str, $css_class, @sel) = @_;
+ return esc_html($str) unless @sel;
+
+ my $out = '';
+ my $pos = 0;
+
+ for my $s (@sel) {
+ $out .= esc_html(substr($str, $pos, $s->[0] - $pos))
+ if ($s->[0] - $pos > 0);
+ $out .= $cgi->span({-class => $css_class},
+ esc_html(substr($str, $s->[0], $s->[1] - $s->[0])));
+
+ $pos = $s->[1];
+ }
+ $out .= esc_html(substr($str, $pos))
+ if ($pos < length($str));
+
+ return $out;
+}
+
+# return positions of beginning and end of each match
+sub matchpos_list {
+ my ($str, $regexp) = @_;
+ return unless (defined $str && defined $regexp);
+
+ my @matches;
+ while ($str =~ /$regexp/g) {
+ push @matches, [$-[0], $+[0]];
+ }
+ return @matches;
+}
+
+# highlight match (if any), and escape HTML
+sub esc_html_match_hl {
+ my ($str, $regexp) = @_;
+ return esc_html($str) unless defined $regexp;
+
+ my @matches = matchpos_list($str, $regexp);
+ return esc_html($str) unless @matches;
+
+ return esc_html_hl_regions($str, 'match', @matches);
+}
+
+
+# highlight match (if any) of shortened string, and escape HTML
+sub esc_html_match_hl_chopped {
+ my ($str, $chopped, $regexp) = @_;
+ return esc_html_match_hl($str, $regexp) unless defined $chopped;
+
+ my @matches = matchpos_list($str, $regexp);
+ return esc_html($chopped) unless @matches;
+
+ # filter matches so that we mark chopped string
+ my $tail = "... "; # see chop_str
+ unless ($chopped =~ s/\Q$tail\E$//) {
+ $tail = '';
+ }
+ my $chop_len = length($chopped);
+ my $tail_len = length($tail);
+ my @filtered;
+
+ for my $m (@matches) {
+ if ($m->[0] > $chop_len) {
+ push @filtered, [ $chop_len, $chop_len + $tail_len ] if ($tail_len > 0);
+ last;
+ } elsif ($m->[1] > $chop_len) {
+ push @filtered, [ $m->[0], $chop_len + $tail_len ];
+ last;
+ }
+ push @filtered, $m;
+ }
+
+ return esc_html_hl_regions($chopped . $tail, 'match', @filtered);
+}
+
## ----------------------------------------------------------------------
## functions returning short strings
@@ -2838,10 +2928,9 @@ sub git_get_project_url_list {
sub git_get_projects_list {
my $filter = shift || '';
+ my $paranoid = shift;
my @list;
- $filter =~ s/\.git$//;
-
if (-d $projects_list) {
# search in directory
my $dir = $projects_list;
@@ -2850,7 +2939,7 @@ sub git_get_projects_list {
my $pfxlen = length("$dir");
my $pfxdepth = ($dir =~ tr!/!!);
# when filtering, search only given subdirectory
- if ($filter) {
+ if ($filter && !$paranoid) {
$dir .= "/$filter";
$dir =~ s!/+$!!;
}
@@ -2875,6 +2964,10 @@ sub git_get_projects_list {
}
my $path = substr($File::Find::name, $pfxlen + 1);
+ # paranoidly only filter here
+ if ($paranoid && $filter && $path !~ m!^\Q$filter\E/!) {
+ next;
+ }
# we check related file in $projectroot
if (check_export_ok("$projectroot/$path")) {
push @list, { path => $path };
@@ -2985,6 +3078,10 @@ sub search_projects_list {
return @$projlist
unless ($tagfilter || $search_re);
+ # searching projects require filling to be run before it;
+ fill_project_list_info($projlist,
+ $tagfilter ? 'ctags' : (),
+ $search_re ? ('path', 'descr') : ());
my @projects;
PROJECT:
foreach my $pr (@$projlist) {
@@ -3740,7 +3837,12 @@ sub run_highlighter {
sub get_page_title {
my $title = to_utf8($site_name);
- return $title unless (defined $project);
+ unless (defined $project) {
+ if (defined $project_filter) {
+ $title .= " - projects in '" . esc_path($project_filter) . "'";
+ }
+ return $title;
+ }
$title .= " - " . to_utf8($project);
return $title unless (defined $action);
@@ -3834,12 +3936,27 @@ sub print_header_links {
}
}
+sub print_nav_breadcrumbs_path {
+ my $dirprefix = undef;
+ while (my $part = shift) {
+ $dirprefix .= "/" if defined $dirprefix;
+ $dirprefix .= $part;
+ print $cgi->a({-href => href(project => undef,
+ project_filter => $dirprefix,
+ action => "project_list")},
+ esc_html($part)) . " / ";
+ }
+}
+
sub print_nav_breadcrumbs {
my %opts = @_;
print $cgi->a({-href => esc_url($home_link)}, $home_link_str) . " / ";
if (defined $project) {
- print $cgi->a({-href => href(action=>"summary")}, esc_html($project));
+ my @dirname = split '/', $project;
+ my $projectbasename = pop @dirname;
+ print_nav_breadcrumbs_path(@dirname);
+ print $cgi->a({-href => href(action=>"summary")}, esc_html($projectbasename));
if (defined $action) {
my $action_print = $action ;
if (defined $opts{-action_extra}) {
@@ -3852,6 +3969,8 @@ sub print_nav_breadcrumbs {
print " / $opts{-action_extra}";
}
print "\n";
+ } elsif (defined $project_filter) {
+ print_nav_breadcrumbs_path(split '/', $project_filter);
}
}
@@ -3974,9 +4093,11 @@ sub git_footer_html {
}
} else {
- print $cgi->a({-href => href(project=>undef, action=>"opml"),
+ print $cgi->a({-href => href(project=>undef, action=>"opml",
+ project_filter => $project_filter),
-class => $feed_class}, "OPML") . " ";
- print $cgi->a({-href => href(project=>undef, action=>"project_index"),
+ print $cgi->a({-href => href(project=>undef, action=>"project_index",
+ project_filter => $project_filter),
-class => $feed_class}, "TXT") . "\n";
}
print "</div>\n"; # class="page_footer"
@@ -5134,35 +5255,98 @@ sub git_patchset_body {
# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
-# fills project list info (age, description, owner, category, forks)
+sub git_project_search_form {
+ my ($searchtext, $search_use_regexp) = @_;
+
+ my $limit = '';
+ if ($project_filter) {
+ $limit = " in '$project_filter/'";
+ }
+
+ print "<div class=\"projsearch\">\n";
+ print $cgi->startform(-method => 'get', -action => $my_uri) .
+ $cgi->hidden(-name => 'a', -value => 'project_list') . "\n";
+ print $cgi->hidden(-name => 'pf', -value => $project_filter). "\n"
+ if (defined $project_filter);
+ print $cgi->textfield(-name => 's', -value => $searchtext,
+ -title => "Search project by name and description$limit",
+ -size => 60) . "\n" .
+ "<span title=\"Extended regular expression\">" .
+ $cgi->checkbox(-name => 'sr', -value => 1, -label => 're',
+ -checked => $search_use_regexp) .
+ "</span>\n" .
+ $cgi->submit(-name => 'btnS', -value => 'Search') .
+ $cgi->end_form() . "\n" .
+ $cgi->a({-href => href(project => undef, searchtext => undef,
+ project_filter => $project_filter)},
+ esc_html("List all projects$limit")) . "<br />\n";
+ print "</div>\n";
+}
+
+# entry for given @keys needs filling if at least one of keys in list
+# is not present in %$project_info
+sub project_info_needs_filling {
+ my ($project_info, @keys) = @_;
+
+ # return List::MoreUtils::any { !exists $project_info->{$_} } @keys;
+ foreach my $key (@keys) {
+ if (!exists $project_info->{$key}) {
+ return 1;
+ }
+ }
+ return;
+}
+
+# fills project list info (age, description, owner, category, forks, etc.)
# for each project in the list, removing invalid projects from
-# returned list
+# returned list, or fill only specified info.
+#
+# Invalid projects are removed from the returned list if and only if you
+# ask 'age' or 'age_string' to be filled, because they are the only fields
+# that run unconditionally git command that requires repository, and
+# therefore do always check if project repository is invalid.
+#
+# USAGE:
+# * fill_project_list_info(\@project_list, 'descr_long', 'ctags')
+# ensures that 'descr_long' and 'ctags' fields are filled
+# * @project_list = fill_project_list_info(\@project_list)
+# ensures that all fields are filled (and invalid projects removed)
+#
# NOTE: modifies $projlist, but does not remove entries from it
sub fill_project_list_info {
- my $projlist = shift;
+ my ($projlist, @wanted_keys) = @_;
my @projects;
+ my $filter_set = sub { return @_; };
+ if (@wanted_keys) {
+ my %wanted_keys = map { $_ => 1 } @wanted_keys;
+ $filter_set = sub { return grep { $wanted_keys{$_} } @_; };
+ }
my $show_ctags = gitweb_check_feature('ctags');
PROJECT:
foreach my $pr (@$projlist) {
- my (@activity) = git_get_last_activity($pr->{'path'});
- unless (@activity) {
- next PROJECT;
+ if (project_info_needs_filling($pr, $filter_set->('age', 'age_string'))) {
+ my (@activity) = git_get_last_activity($pr->{'path'});
+ unless (@activity) {
+ next PROJECT;
+ }
+ ($pr->{'age'}, $pr->{'age_string'}) = @activity;
}
- ($pr->{'age'}, $pr->{'age_string'}) = @activity;
- if (!defined $pr->{'descr'}) {
+ if (project_info_needs_filling($pr, $filter_set->('descr', 'descr_long'))) {
my $descr = git_get_project_description($pr->{'path'}) || "";
$descr = to_utf8($descr);
$pr->{'descr_long'} = $descr;
$pr->{'descr'} = chop_str($descr, $projects_list_description_width, 5);
}
- if (!defined $pr->{'owner'}) {
+ if (project_info_needs_filling($pr, $filter_set->('owner'))) {
$pr->{'owner'} = git_get_project_owner("$pr->{'path'}") || "";
}
- if ($show_ctags) {
+ if ($show_ctags &&
+ project_info_needs_filling($pr, $filter_set->('ctags'))) {
$pr->{'ctags'} = git_get_project_ctags($pr->{'path'});
}
- if ($projects_list_group_categories && !defined $pr->{'category'}) {
+ if ($projects_list_group_categories &&
+ project_info_needs_filling($pr, $filter_set->('category'))) {
my $cat = git_get_project_category($pr->{'path'}) ||
$project_list_default_category;
$pr->{'category'} = to_utf8($cat);
@@ -5266,10 +5450,17 @@ sub git_project_list_rows {
print "</td>\n";
}
print "<td>" . $cgi->a({-href => href(project=>$pr->{'path'}, action=>"summary"),
- -class => "list"}, esc_html($pr->{'path'})) . "</td>\n" .
+ -class => "list"},
+ esc_html_match_hl($pr->{'path'}, $search_regexp)) .
+ "</td>\n" .
"<td>" . $cgi->a({-href => href(project=>$pr->{'path'}, action=>"summary"),
- -class => "list", -title => $pr->{'descr_long'}},
- esc_html($pr->{'descr'})) . "</td>\n" .
+ -class => "list",
+ -title => $pr->{'descr_long'}},
+ $search_regexp
+ ? esc_html_match_hl_chopped($pr->{'descr_long'},
+ $pr->{'descr'}, $search_regexp)
+ : esc_html($pr->{'descr'})) .
+ "</td>\n" .
"<td><i>" . chop_and_escape_str($pr->{'owner'}, 15) . "</i></td>\n";
print "<td class=\"". age_class($pr->{'age'}) . "\">" .
(defined $pr->{'age_string'} ? $pr->{'age_string'} : "No commits") . "</td>\n" .
@@ -5298,12 +5489,13 @@ sub git_project_list_body {
# filtering out forks before filling info allows to do less work
@projects = filter_forks_from_projects_list(\@projects)
if ($check_forks);
- @projects = fill_project_list_info(\@projects);
- # searching projects require filling to be run before it
+ # search_projects_list pre-fills required info
@projects = search_projects_list(\@projects,
'search_regexp' => $search_regexp,
'tagfilter' => $tagfilter)
if ($tagfilter || $search_regexp);
+ # fill the rest
+ @projects = fill_project_list_info(\@projects);
$order ||= $default_projects_order;
$from = 0 unless defined $from;
@@ -5991,7 +6183,7 @@ sub git_project_list {
die_error(400, "Unknown order parameter");
}
- my @list = git_get_projects_list();
+ my @list = git_get_projects_list($project_filter, $strict_export);
if (!@list) {
die_error(404, "No projects found");
}
@@ -6002,11 +6194,8 @@ sub git_project_list {
insert_file($home_text);
print "</div>\n";
}
- print $cgi->startform(-method => "get") .
- "<p class=\"projsearch\">Search:\n" .
- $cgi->textfield(-name => "s", -value => $searchtext, -override => 1) . "\n" .
- "</p>" .
- $cgi->end_form() . "\n";
+
+ git_project_search_form($searchtext, $search_use_regexp);
git_project_list_body(\@list, $order);
git_footer_html();
}
@@ -6017,7 +6206,9 @@ sub git_forks {
die_error(400, "Unknown order parameter");
}
- my @list = git_get_projects_list($project);
+ my $filter = $project;
+ $filter =~ s/\.git$//;
+ my @list = git_get_projects_list($filter);
if (!@list) {
die_error(404, "No forks found");
}
@@ -6030,7 +6221,7 @@ sub git_forks {
}
sub git_project_index {
- my @projects = git_get_projects_list();
+ my @projects = git_get_projects_list($project_filter, $strict_export);
if (!@projects) {
die_error(404, "No projects found");
}
@@ -6076,7 +6267,9 @@ sub git_summary {
if ($check_forks) {
# find forks of a project
- @forklist = git_get_projects_list($project);
+ my $filter = $project;
+ $filter =~ s/\.git$//;
+ @forklist = git_get_projects_list($filter);
# filter out forks of forks
@forklist = filter_forks_from_projects_list(\@forklist)
if (@forklist);
@@ -7867,7 +8060,7 @@ sub git_atom {
}
sub git_opml {
- my @list = git_get_projects_list();
+ my @list = git_get_projects_list($project_filter, $strict_export);
if (!@list) {
die_error(404, "No projects found");
}
@@ -7878,11 +8071,17 @@ sub git_opml {
-content_disposition => 'inline; filename="opml.xml"');
my $title = esc_html($site_name);
+ my $filter = " within subdirectory ";
+ if (defined $project_filter) {
+ $filter .= esc_html($project_filter);
+ } else {
+ $filter = "";
+ }
print <<XML;
<?xml version="1.0" encoding="utf-8"?>
<opml version="1.0">
<head>
- <title>$title OPML Export</title>
+ <title>$title OPML Export$filter</title>
</head>
<body>
<outline text="git RSS feeds">
diff --git a/gitweb/static/gitweb.css b/gitweb/static/gitweb.css
index c7827e8f1d..c530355a7c 100644
--- a/gitweb/static/gitweb.css
+++ b/gitweb/static/gitweb.css
@@ -520,8 +520,13 @@ div.search {
right: 12px
}
-p.projsearch {
+div.projsearch {
text-align: center;
+ margin: 20px 0px;
+}
+
+div.projsearch form {
+ margin-bottom: 2px;
}
td.linenr {
diff --git a/gitweb/static/js/lib/cookies.js b/gitweb/static/js/lib/cookies.js
index 72b51cd1b4..66b9a072a4 100644
--- a/gitweb/static/js/lib/cookies.js
+++ b/gitweb/static/js/lib/cookies.js
@@ -30,7 +30,7 @@
* If a negative value is specified or a date in the past),
* the cookie will be deleted.
* If set to null or omitted, the cookie will be a session cookie
- * and will not be retained when the the browser exits.
+ * and will not be retained when the browser exits.
* @param {String} [options.path] Restrict access of a cookie to particular directory
* (default: path of page that created the cookie).
* @param {String} [options.domain] Override what web sites are allowed to access cookie
diff --git a/graph.c b/graph.c
index 7358416a72..7e0a099f83 100644
--- a/graph.c
+++ b/graph.c
@@ -194,8 +194,10 @@ static struct strbuf *diff_output_prefix_callback(struct diff_options *opt, void
struct git_graph *graph = data;
static struct strbuf msgbuf = STRBUF_INIT;
+ assert(opt);
assert(graph);
+ opt->output_prefix_length = graph->width;
strbuf_reset(&msgbuf);
graph_padding_line(graph, &msgbuf);
return &msgbuf;
@@ -245,6 +247,7 @@ struct git_graph *graph_init(struct rev_info *opt)
*/
opt->diffopt.output_prefix = diff_output_prefix_callback;
opt->diffopt.output_prefix_data = graph;
+ opt->diffopt.output_prefix_length = 0;
return graph;
}
diff --git a/grep.c b/grep.c
index f492d267cc..f8ffa46209 100644
--- a/grep.c
+++ b/grep.c
@@ -168,15 +168,10 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)
p->fixed = 0;
if (p->fixed) {
- if (opt->regflags & REG_ICASE || p->ignore_case) {
- static char trans[256];
- int i;
- for (i = 0; i < 256; i++)
- trans[i] = tolower(i);
- p->kws = kwsalloc(trans);
- } else {
+ if (opt->regflags & REG_ICASE || p->ignore_case)
+ p->kws = kwsalloc(tolower_trans_tbl);
+ else
p->kws = kwsalloc(NULL);
- }
kwsincr(p->kws, p->pattern, p->patternlen);
kwsprep(p->kws);
return;
@@ -323,7 +318,7 @@ static struct grep_expr *prep_header_patterns(struct grep_opt *opt)
if (!opt->header_list)
return NULL;
- p = opt->header_list;
+
for (p = opt->header_list; p; p = p->next) {
if (p->token != GREP_PATTERN_HEAD)
die("bug: a non-header pattern in grep header list.");
diff --git a/http-backend.c b/http-backend.c
index 869d515383..f50e77fb28 100644
--- a/http-backend.c
+++ b/http-backend.c
@@ -7,6 +7,7 @@
#include "run-command.h"
#include "string-list.h"
#include "url.h"
+#include "argv-array.h"
static const char content_type[] = "Content-Type";
static const char content_length[] = "Content-Length";
@@ -317,8 +318,7 @@ static void run_service(const char **argv)
const char *encoding = getenv("HTTP_CONTENT_ENCODING");
const char *user = getenv("REMOTE_USER");
const char *host = getenv("REMOTE_ADDR");
- char *env[3];
- struct strbuf buf = STRBUF_INIT;
+ struct argv_array env = ARGV_ARRAY_INIT;
int gzipped_request = 0;
struct child_process cld;
@@ -332,17 +332,15 @@ static void run_service(const char **argv)
if (!host || !*host)
host = "(none)";
- memset(&env, 0, sizeof(env));
- strbuf_addf(&buf, "GIT_COMMITTER_NAME=%s", user);
- env[0] = strbuf_detach(&buf, NULL);
-
- strbuf_addf(&buf, "GIT_COMMITTER_EMAIL=%s@http.%s", user, host);
- env[1] = strbuf_detach(&buf, NULL);
- env[2] = NULL;
+ if (!getenv("GIT_COMMITTER_NAME"))
+ argv_array_pushf(&env, "GIT_COMMITTER_NAME=%s", user);
+ if (!getenv("GIT_COMMITTER_EMAIL"))
+ argv_array_pushf(&env, "GIT_COMMITTER_EMAIL=%s@http.%s",
+ user, host);
memset(&cld, 0, sizeof(cld));
cld.argv = argv;
- cld.env = (const char *const *)env;
+ cld.env = env.argv;
if (gzipped_request)
cld.in = -1;
cld.git_cmd = 1;
@@ -357,9 +355,7 @@ static void run_service(const char **argv)
if (finish_command(&cld))
exit(1);
- free(env[0]);
- free(env[1]);
- strbuf_release(&buf);
+ argv_array_clear(&env);
}
static int show_text_ref(const char *name, const unsigned char *sha1,
diff --git a/http.c b/http.c
index 0ffd79cd81..2ec37891f3 100644
--- a/http.c
+++ b/http.c
@@ -210,14 +210,23 @@ static int http_options(const char *var, const char *value, void *cb)
static void init_curl_http_auth(CURL *result)
{
- if (http_auth.username) {
- struct strbuf up = STRBUF_INIT;
- credential_fill(&http_auth);
+ if (!http_auth.username)
+ return;
+
+ credential_fill(&http_auth);
+
+#if LIBCURL_VERSION_NUM >= 0x071301
+ curl_easy_setopt(result, CURLOPT_USERNAME, http_auth.username);
+ curl_easy_setopt(result, CURLOPT_PASSWORD, http_auth.password);
+#else
+ {
+ static struct strbuf up = STRBUF_INIT;
+ strbuf_reset(&up);
strbuf_addf(&up, "%s:%s",
http_auth.username, http_auth.password);
- curl_easy_setopt(result, CURLOPT_USERPWD,
- strbuf_detach(&up, NULL));
+ curl_easy_setopt(result, CURLOPT_USERPWD, up.buf);
}
+#endif
}
static int has_cert_password(void)
@@ -295,8 +304,10 @@ static CURL *get_curl_handle(void)
if (curl_ftp_no_epsv)
curl_easy_setopt(result, CURLOPT_FTP_USE_EPSV, 0);
- if (curl_http_proxy)
+ if (curl_http_proxy) {
curl_easy_setopt(result, CURLOPT_PROXY, curl_http_proxy);
+ curl_easy_setopt(result, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
+ }
return result;
}
@@ -492,6 +503,8 @@ struct active_request_slot *get_active_slot(void)
curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, NULL);
curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 0);
curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);
+ if (http_auth.password)
+ init_curl_http_auth(slot->curl);
return slot;
}
@@ -827,7 +840,7 @@ int http_get_strbuf(const char *url, struct strbuf *result, int options)
}
/*
- * Downloads an url and stores the result in the given file.
+ * Downloads a URL and stores the result in the given file.
*
* If a previous interrupted download is detected (i.e. a previous temporary
* file is still around) the download is resumed.
diff --git a/http.h b/http.h
index 0b61653894..915c2862a6 100644
--- a/http.h
+++ b/http.h
@@ -127,7 +127,7 @@ extern char *get_remote_object_url(const char *url, const char *hex,
#define HTTP_NOAUTH 5
/*
- * Requests an url and stores the result in a strbuf.
+ * Requests a URL and stores the result in a strbuf.
*
* If the result pointer is NULL, a HTTP HEAD request is made instead of GET.
*/
diff --git a/ident.c b/ident.c
index f619619b82..87c697c2b0 100644
--- a/ident.c
+++ b/ident.c
@@ -220,6 +220,74 @@ static int copy(char *buf, size_t size, int offset, const char *src)
return offset;
}
+/*
+ * Reverse of fmt_ident(); given an ident line, split the fields
+ * to allow the caller to parse it.
+ * Signal a success by returning 0, but date/tz fields of the result
+ * can still be NULL if the input line only has the name/email part
+ * (e.g. reading from a reflog entry).
+ */
+int split_ident_line(struct ident_split *split, const char *line, int len)
+{
+ const char *cp;
+ size_t span;
+ int status = -1;
+
+ memset(split, 0, sizeof(*split));
+
+ split->name_begin = line;
+ for (cp = line; *cp && cp < line + len; cp++)
+ if (*cp == '<') {
+ split->mail_begin = cp + 1;
+ break;
+ }
+ if (!split->mail_begin)
+ return status;
+
+ for (cp = split->mail_begin - 2; line < cp; cp--)
+ if (!isspace(*cp)) {
+ split->name_end = cp + 1;
+ break;
+ }
+ if (!split->name_end)
+ return status;
+
+ for (cp = split->mail_begin; cp < line + len; cp++)
+ if (*cp == '>') {
+ split->mail_end = cp;
+ break;
+ }
+ if (!split->mail_end)
+ return status;
+
+ for (cp = split->mail_end + 1; cp < line + len && isspace(*cp); cp++)
+ ;
+ if (line + len <= cp)
+ goto person_only;
+ split->date_begin = cp;
+ span = strspn(cp, "0123456789");
+ if (!span)
+ goto person_only;
+ split->date_end = split->date_begin + span;
+ for (cp = split->date_end; cp < line + len && isspace(*cp); cp++)
+ ;
+ if (line + len <= cp || (*cp != '+' && *cp != '-'))
+ goto person_only;
+ split->tz_begin = cp;
+ span = strspn(cp + 1, "0123456789");
+ if (!span)
+ goto person_only;
+ split->tz_end = split->tz_begin + 1 + span;
+ return 0;
+
+person_only:
+ split->date_begin = NULL;
+ split->date_end = NULL;
+ split->tz_begin = NULL;
+ split->tz_end = NULL;
+ return 0;
+}
+
static const char *env_hint =
"\n"
"*** Please tell me who you are.\n"
diff --git a/log-tree.c b/log-tree.c
index c719a6e385..376d973176 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -120,9 +120,9 @@ static int add_ref_decoration(const char *refname, const unsigned char *sha1, in
type = DECORATION_REF_REMOTE;
else if (!prefixcmp(refname, "refs/tags/"))
type = DECORATION_REF_TAG;
- else if (!prefixcmp(refname, "refs/stash"))
+ else if (!strcmp(refname, "refs/stash"))
type = DECORATION_REF_STASH;
- else if (!prefixcmp(refname, "HEAD"))
+ else if (!strcmp(refname, "HEAD"))
type = DECORATION_REF_HEAD;
if (!cb_data || *(int *)cb_data == DECORATE_SHORT_REFS)
@@ -629,10 +629,9 @@ void show_log(struct rev_info *opt)
* graph info here.
*/
show_reflog_message(opt->reflog_info,
- opt->commit_format == CMIT_FMT_ONELINE,
- opt->date_mode_explicit ?
- opt->date_mode :
- DATE_NORMAL);
+ opt->commit_format == CMIT_FMT_ONELINE,
+ opt->date_mode,
+ opt->date_mode_explicit);
if (opt->commit_format == CMIT_FMT_ONELINE)
return;
}
@@ -652,6 +651,7 @@ void show_log(struct rev_info *opt)
if (ctx.need_8bit_cte >= 0)
ctx.need_8bit_cte = has_non_ascii(opt->add_signoff);
ctx.date_mode = opt->date_mode;
+ ctx.date_mode_explicit = opt->date_mode_explicit;
ctx.abbrev = opt->diffopt.abbrev;
ctx.after_subject = extra_headers;
ctx.preserve_subject = opt->preserve_subject;
@@ -682,7 +682,7 @@ void show_log(struct rev_info *opt)
if (opt->use_terminator) {
if (!opt->missing_newline)
graph_show_padding(opt->graph);
- putchar('\n');
+ putchar(opt->diffopt.line_termination);
}
strbuf_release(&msgbuf);
@@ -711,14 +711,15 @@ int log_tree_diff_flush(struct rev_info *opt)
opt->verbose_header &&
opt->commit_format != CMIT_FMT_ONELINE) {
int pch = DIFF_FORMAT_DIFFSTAT | DIFF_FORMAT_PATCH;
- if ((pch & opt->diffopt.output_format) == pch)
- printf("---");
if (opt->diffopt.output_prefix) {
struct strbuf *msg = NULL;
msg = opt->diffopt.output_prefix(&opt->diffopt,
opt->diffopt.output_prefix_data);
fwrite(msg->buf, msg->len, 1, stdout);
}
+ if ((pch & opt->diffopt.output_format) == pch) {
+ printf("---");
+ }
putchar('\n');
}
}
diff --git a/merge-recursive.c b/merge-recursive.c
index d83cd6c662..680937c39e 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -264,7 +264,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, 0) < 0)
+ active_cache, active_nr, 0) < 0)
die("error building trees");
result = lookup_tree(active_cache_tree->sha1);
@@ -485,6 +485,7 @@ static struct string_list *get_renames(struct merge_options *o,
renames = xcalloc(1, sizeof(struct string_list));
diff_setup(&opts);
DIFF_OPT_SET(&opts, RECURSIVE);
+ DIFF_OPT_CLR(&opts, RENAME_EMPTY);
opts.detect_rename = DIFF_DETECT_RENAME;
opts.rename_limit = o->merge_rename_limit >= 0 ? o->merge_rename_limit :
o->diff_rename_limit >= 0 ? o->diff_rename_limit :
@@ -1914,7 +1915,7 @@ int merge_recursive(struct merge_options *o,
/* if there is no common ancestor, use an empty tree */
struct tree *tree;
- tree = lookup_tree((const unsigned char *)EMPTY_TREE_SHA1_BIN);
+ tree = lookup_tree(EMPTY_TREE_SHA1_BIN);
merged_common_ancestors = make_virtual_commit(tree, "ancestor");
}
@@ -2068,9 +2069,9 @@ int parse_merge_opt(struct merge_options *o, const char *s)
else if (!prefixcmp(s, "subtree="))
o->subtree_shift = s + strlen("subtree=");
else if (!strcmp(s, "patience"))
- o->xdl_opts |= XDF_PATIENCE_DIFF;
+ o->xdl_opts = DIFF_WITH_ALG(o, PATIENCE_DIFF);
else if (!strcmp(s, "histogram"))
- o->xdl_opts |= XDF_HISTOGRAM_DIFF;
+ o->xdl_opts = DIFF_WITH_ALG(o, HISTOGRAM_DIFF);
else if (!strcmp(s, "ignore-space-change"))
o->xdl_opts |= XDF_IGNORE_WHITESPACE_CHANGE;
else if (!strcmp(s, "ignore-all-space"))
diff --git a/mergetools/deltawalker b/mergetools/deltawalker
new file mode 100644
index 0000000000..b3c71b6236
--- /dev/null
+++ b/mergetools/deltawalker
@@ -0,0 +1,21 @@
+diff_cmd () {
+ "$merge_tool_path" "$LOCAL" "$REMOTE" >/dev/null 2>&1
+}
+
+merge_cmd () {
+ # Adding $(pwd)/ in front of $MERGED should not be necessary.
+ # However without it, DeltaWalker (at least v1.9.8 on Windows)
+ # crashes with a JRE exception. The DeltaWalker user manual,
+ # shows $(pwd)/ whenever the '-merged' options is given.
+ # Adding it here seems to work around the problem.
+ if $base_present
+ then
+ "$merge_tool_path" "$LOCAL" "$REMOTE" "$BASE" -merged="$(pwd)/$MERGED"
+ else
+ "$merge_tool_path" "$LOCAL" "$REMOTE" -merged="$(pwd)/$MERGED"
+ fi >/dev/null 2>&1
+}
+
+translate_merge_tool_path() {
+ echo DeltaWalker
+}
diff --git a/notes-merge.c b/notes-merge.c
index fb0832f97d..74aa77ce4b 100644
--- a/notes-merge.c
+++ b/notes-merge.c
@@ -267,7 +267,8 @@ static void check_notes_merge_worktree(struct notes_merge_options *o)
* Must establish NOTES_MERGE_WORKTREE.
* Abort if NOTES_MERGE_WORKTREE already exists
*/
- if (file_exists(git_path(NOTES_MERGE_WORKTREE))) {
+ if (file_exists(git_path(NOTES_MERGE_WORKTREE)) &&
+ !is_empty_dir(git_path(NOTES_MERGE_WORKTREE))) {
if (advice_resolve_conflict)
die("You have not concluded your previous "
"notes merge (%s exists).\nPlease, use "
@@ -687,51 +688,60 @@ int notes_merge_commit(struct notes_merge_options *o,
{
/*
* Iterate through files in .git/NOTES_MERGE_WORKTREE and add all
- * found notes to 'partial_tree'. Write the updates notes tree to
+ * found notes to 'partial_tree'. Write the updated notes tree to
* the DB, and commit the resulting tree object while reusing the
* commit message and parents from 'partial_commit'.
* Finally store the new commit object SHA1 into 'result_sha1'.
*/
- struct dir_struct dir;
- char *path = xstrdup(git_path(NOTES_MERGE_WORKTREE "/"));
- int path_len = strlen(path), i;
+ DIR *dir;
+ struct dirent *e;
+ struct strbuf path = STRBUF_INIT;
char *msg = strstr(partial_commit->buffer, "\n\n");
struct strbuf sb_msg = STRBUF_INIT;
+ int baselen;
+ strbuf_addstr(&path, git_path(NOTES_MERGE_WORKTREE));
if (o->verbosity >= 3)
- printf("Committing notes in notes merge worktree at %.*s\n",
- path_len - 1, path);
+ printf("Committing notes in notes merge worktree at %s\n",
+ path.buf);
if (!msg || msg[2] == '\0')
die("partial notes commit has empty message");
msg += 2;
- memset(&dir, 0, sizeof(dir));
- read_directory(&dir, path, path_len, NULL);
- for (i = 0; i < dir.nr; i++) {
- struct dir_entry *ent = dir.entries[i];
+ dir = opendir(path.buf);
+ if (!dir)
+ die_errno("could not open %s", path.buf);
+
+ strbuf_addch(&path, '/');
+ baselen = path.len;
+ while ((e = readdir(dir)) != NULL) {
struct stat st;
- const char *relpath = ent->name + path_len;
unsigned char obj_sha1[20], blob_sha1[20];
- if (ent->len - path_len != 40 || get_sha1_hex(relpath, obj_sha1)) {
+ if (is_dot_or_dotdot(e->d_name))
+ continue;
+
+ if (strlen(e->d_name) != 40 || get_sha1_hex(e->d_name, obj_sha1)) {
if (o->verbosity >= 3)
- printf("Skipping non-SHA1 entry '%s'\n",
- ent->name);
+ printf("Skipping non-SHA1 entry '%s%s'\n",
+ path.buf, e->d_name);
continue;
}
+ strbuf_addstr(&path, e->d_name);
/* write file as blob, and add to partial_tree */
- if (stat(ent->name, &st))
- die_errno("Failed to stat '%s'", ent->name);
- if (index_path(blob_sha1, ent->name, &st, HASH_WRITE_OBJECT))
- die("Failed to write blob object from '%s'", ent->name);
+ if (stat(path.buf, &st))
+ die_errno("Failed to stat '%s'", path.buf);
+ if (index_path(blob_sha1, path.buf, &st, HASH_WRITE_OBJECT))
+ die("Failed to write blob object from '%s'", path.buf);
if (add_note(partial_tree, obj_sha1, blob_sha1, NULL))
die("Failed to add resolved note '%s' to notes tree",
- ent->name);
+ path.buf);
if (o->verbosity >= 4)
printf("Added resolved note for object %s: %s\n",
sha1_to_hex(obj_sha1), sha1_to_hex(blob_sha1));
+ strbuf_setlen(&path, baselen);
}
strbuf_attach(&sb_msg, msg, strlen(msg), strlen(msg) + 1);
@@ -740,20 +750,25 @@ int notes_merge_commit(struct notes_merge_options *o,
if (o->verbosity >= 4)
printf("Finalized notes merge commit: %s\n",
sha1_to_hex(result_sha1));
- free(path);
+ strbuf_release(&path);
+ closedir(dir);
return 0;
}
int notes_merge_abort(struct notes_merge_options *o)
{
- /* Remove .git/NOTES_MERGE_WORKTREE directory and all files within */
+ /*
+ * Remove all files within .git/NOTES_MERGE_WORKTREE. We do not remove
+ * the .git/NOTES_MERGE_WORKTREE directory itself, since it might be
+ * the current working directory of the user.
+ */
struct strbuf buf = STRBUF_INIT;
int ret;
strbuf_addstr(&buf, git_path(NOTES_MERGE_WORKTREE));
if (o->verbosity >= 3)
- printf("Removing notes merge worktree at %s\n", buf.buf);
- ret = remove_dir_recursively(&buf, 0);
+ printf("Removing notes merge worktree at %s/*\n", buf.buf);
+ ret = remove_dir_recursively(&buf, REMOVE_DIR_KEEP_TOPLEVEL);
strbuf_release(&buf);
return ret;
}
diff --git a/object.c b/object.c
index d8d09f92aa..6b06297a5f 100644
--- a/object.c
+++ b/object.c
@@ -191,10 +191,15 @@ struct object *parse_object(const unsigned char *sha1)
enum object_type type;
int eaten;
const unsigned char *repl = lookup_replace_object(sha1);
- void *buffer = read_sha1_file(sha1, &type, &size);
+ void *buffer;
+ struct object *obj;
+
+ obj = lookup_object(sha1);
+ if (obj && obj->parsed)
+ return obj;
+ buffer = read_sha1_file(sha1, &type, &size);
if (buffer) {
- struct object *obj;
if (check_sha1_signature(repl, buffer, size, typename(type)) < 0) {
free(buffer);
error("sha1 mismatch %s\n", sha1_to_hex(repl));
diff --git a/pack-refs.c b/pack-refs.c
index 23bbd00e3e..f09a054228 100644
--- a/pack-refs.c
+++ b/pack-refs.c
@@ -143,7 +143,6 @@ int pack_refs(unsigned int flags)
packed.fd = -1;
if (commit_lock_file(&packed) < 0)
die_errno("unable to overwrite old ref-pack file");
- if (cbdata.flags & PACK_REFS_PRUNE)
- prune_refs(cbdata.ref_to_prune);
+ prune_refs(cbdata.ref_to_prune);
return 0;
}
diff --git a/pager.c b/pager.c
index b7909678f4..05584dead6 100644
--- a/pager.c
+++ b/pager.c
@@ -147,3 +147,15 @@ int term_columns(void)
return term_columns_at_startup;
}
+
+/*
+ * How many columns do we need to show this number in decimal?
+ */
+int decimal_width(int number)
+{
+ int i, width;
+
+ for (width = 1, i = 10; i <= number; width++)
+ i *= 10;
+ return width;
+}
diff --git a/parse-options.c b/parse-options.c
index f0098eb8ea..850cfa78c9 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -193,13 +193,14 @@ static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
arg_end = arg + strlen(arg);
for (; options->type != OPTION_END; options++) {
- const char *rest;
- int flags = 0;
+ const char *rest, *long_name = options->long_name;
+ int flags = 0, opt_flags = 0;
- if (!options->long_name)
+ if (!long_name)
continue;
- rest = skip_prefix(arg, options->long_name);
+again:
+ rest = skip_prefix(arg, long_name);
if (options->type == OPTION_ARGUMENT) {
if (!rest)
continue;
@@ -212,7 +213,7 @@ static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
}
if (!rest) {
/* abbreviated? */
- if (!strncmp(options->long_name, arg, arg_end - arg)) {
+ if (!strncmp(long_name, arg, arg_end - arg)) {
is_abbreviated:
if (abbrev_option) {
/*
@@ -227,7 +228,7 @@ is_abbreviated:
if (!(flags & OPT_UNSET) && *arg_end)
p->opt = arg_end + 1;
abbrev_option = options;
- abbrev_flags = flags;
+ abbrev_flags = flags ^ opt_flags;
continue;
}
/* negation allowed? */
@@ -239,12 +240,18 @@ is_abbreviated:
goto is_abbreviated;
}
/* negated? */
- if (strncmp(arg, "no-", 3))
+ if (prefixcmp(arg, "no-")) {
+ if (!prefixcmp(long_name, "no-")) {
+ long_name += 3;
+ opt_flags |= OPT_UNSET;
+ goto again;
+ }
continue;
+ }
flags |= OPT_UNSET;
- rest = skip_prefix(arg + 3, options->long_name);
+ rest = skip_prefix(arg + 3, long_name);
/* abbreviated and negated? */
- if (!rest && !prefixcmp(options->long_name, arg + 3))
+ if (!rest && !prefixcmp(long_name, arg + 3))
goto is_abbreviated;
if (!rest)
continue;
@@ -254,7 +261,7 @@ is_abbreviated:
continue;
p->opt = rest + 1;
}
- return get_value(p, options, flags);
+ return get_value(p, options, flags ^ opt_flags);
}
if (ambiguous_option)
@@ -386,6 +393,8 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
case -1:
return parse_options_usage(ctx, usagestr, options, 1);
case -2:
+ if (ctx->opt)
+ check_typos(arg + 1, options);
goto unknown;
}
if (ctx->opt)
@@ -526,7 +535,7 @@ static int usage_with_options_internal(struct parse_opt_ctx_t *ctx,
continue;
pos = fprintf(outfile, " ");
- if (opts->short_name && !(opts->flags & PARSE_OPT_NEGHELP)) {
+ if (opts->short_name) {
if (opts->flags & PARSE_OPT_NODASH)
pos += fprintf(outfile, "%c", opts->short_name);
else
@@ -535,9 +544,7 @@ static int usage_with_options_internal(struct parse_opt_ctx_t *ctx,
if (opts->long_name && opts->short_name)
pos += fprintf(outfile, ", ");
if (opts->long_name)
- pos += fprintf(outfile, "--%s%s",
- (opts->flags & PARSE_OPT_NEGHELP) ? "no-" : "",
- opts->long_name);
+ pos += fprintf(outfile, "--%s", opts->long_name);
if (opts->type == OPTION_NUMBER)
pos += fprintf(outfile, "-NUM");
diff --git a/parse-options.h b/parse-options.h
index 2e811dc7da..def9ced739 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -40,7 +40,6 @@ enum parse_opt_option_flags {
PARSE_OPT_LASTARG_DEFAULT = 16,
PARSE_OPT_NODASH = 32,
PARSE_OPT_LITERAL_ARGHELP = 64,
- PARSE_OPT_NEGHELP = 128,
PARSE_OPT_SHELL_EVAL = 256
};
@@ -90,9 +89,6 @@ typedef int parse_opt_ll_cb(struct parse_opt_ctx_t *ctx,
* PARSE_OPT_LITERAL_ARGHELP: says that argh shouldn't be enclosed in brackets
* (i.e. '<argh>') in the help message.
* Useful for options with multiple parameters.
- * PARSE_OPT_NEGHELP: says that the long option should always be shown with
- * the --no prefix in the usage message. Sometimes
- * useful for users of OPTION_NEGBIT.
*
* `callback`::
* pointer to the callback to use for OPTION_CALLBACK or
diff --git a/perl/Git.pm b/perl/Git.pm
index f7ce511bbb..497f420178 100644
--- a/perl/Git.pm
+++ b/perl/Git.pm
@@ -691,7 +691,7 @@ The hash is in the format C<refname =\> hash>. For tags, the C<refname> entry
contains the tag object while a C<refname^{}> entry gives the tagged objects.
C<REPOSITORY> has the same meaning as the appropriate C<git-ls-remote>
-argument; either an URL or a remote name (if called on a repository instance).
+argument; either a URL or a remote name (if called on a repository instance).
C<GROUPS> is an optional arrayref that can contain 'tags' to return all the
tags and/or 'heads' to return all the heads. C<REFGLOB> is an optional array
of strings containing a shell-like glob to further limit the refs returned in
diff --git a/perl/Git/I18N.pm b/perl/Git/I18N.pm
index 07597dcb93..40dd897191 100644
--- a/perl/Git/I18N.pm
+++ b/perl/Git/I18N.pm
@@ -2,7 +2,16 @@ package Git::I18N;
use 5.008;
use strict;
use warnings;
-use Exporter 'import';
+BEGIN {
+ require Exporter;
+ if ($] < 5.008003) {
+ *import = \&Exporter::import;
+ } else {
+ # Exporter 5.57 which supports this invocation was
+ # released with perl 5.8.3
+ Exporter->import('import');
+ }
+}
our @EXPORT = qw(__);
our @EXPORT_OK = @EXPORT;
diff --git a/perl/Makefile b/perl/Makefile
index b2977cd0bc..3e21766d8f 100644
--- a/perl/Makefile
+++ b/perl/Makefile
@@ -23,15 +23,18 @@ clean:
ifdef NO_PERL_MAKEMAKER
instdir_SQ = $(subst ','\'',$(prefix)/lib)
$(makfile): ../GIT-CFLAGS Makefile
- echo all: private-Error.pm Git.pm > $@
- echo ' mkdir -p blib/lib' >> $@
+ echo all: private-Error.pm Git.pm Git/I18N.pm > $@
+ echo ' mkdir -p blib/lib/Git' >> $@
echo ' $(RM) blib/lib/Git.pm; cp Git.pm blib/lib/' >> $@
+ echo ' $(RM) blib/lib/Git/I18N.pm; cp Git/I18N.pm blib/lib/Git/' >> $@
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)"' >> $@
+ echo ' mkdir -p "$$(DESTDIR)$(instdir_SQ)/Git"' >> $@
echo ' $(RM) "$$(DESTDIR)$(instdir_SQ)/Git.pm"; cp Git.pm "$$(DESTDIR)$(instdir_SQ)"' >> $@
+ echo ' $(RM) "$$(DESTDIR)$(instdir_SQ)/Git/I18N.pm"; cp Git/I18N.pm "$$(DESTDIR)$(instdir_SQ)/Git"' >> $@
echo ' $(RM) "$$(DESTDIR)$(instdir_SQ)/Error.pm"' >> $@
'$(PERL_PATH_SQ)' -MError -e 'exit($$Error::VERSION < 0.15009)' || \
echo ' cp private-Error.pm "$$(DESTDIR)$(instdir_SQ)/Error.pm"' >> $@
diff --git a/po/.gitignore b/po/.gitignore
index 4caa631ff0..796b96d1c4 100644
--- a/po/.gitignore
+++ b/po/.gitignore
@@ -1,2 +1 @@
-/git.pot
/build
diff --git a/po/README b/po/README
index 10b0ad2ce8..c1520e8cde 100644
--- a/po/README
+++ b/po/README
@@ -1,33 +1,79 @@
Core GIT Translations
=====================
-This directory holds the translations for the core of Git. This
-document describes how to add to and maintain these translations, and
-how to mark source strings for translation.
-
+This directory holds the translations for the core of Git. This document
+describes how you can contribute to the effort of enhancing the language
+coverage and maintaining the translation.
+
+The localization (l10n) coordinator, Jiang Xin <worldhello.net@gmail.com>,
+coordinates our localization effort in the l10 coordinator repository:
+
+ https://github.com/git-l10n/git-po/
+
+As a contributor for a language XX, you should first check TEAMS file in
+this directory to see whether a dedicated repository for your language XX
+exists. Fork the dedicated repository and start to work if it exists.
+
+If you are the first contributor for the language XX, please fork this
+repository, prepare and/or update the translated message file po/XX.po
+(described later), and ask the l10n coordinator to pull your work.
+
+If there are multiple contributors for the same language, please first
+coordinate among yourselves and nominate the team leader for your
+language, so that the l10n coordinator only needs to interact with one
+person per language.
+
+The overall data-flow looks like this:
+
+ +-------------------+ +------------------+
+ | Git source code | ---(1)---> | L10n coordinator |
+ | repository | <---(4)--- | repository |
+ +-------------------+ +------------------+
+ | ^
+ (2) (3)
+ V |
+ +------------------+
+ | Language Team XX |
+ +------------------+
+
+ * Translatable strings are marked in the source file.
+ * L10n coordinator pulls from the source (1)
+ * L10n coordinator updates the message template po/git.pot
+ * Language team pulls from L10n coordinator (2)
+ * Language team updates the message file po/XX.po
+ * L10n coordinator pulls from Language team (3)
+ * L10n coordinator asks the result to be pulled (4).
+
+
+Maintaining the po/git.pot file
+-------------------------------
-Generating a .pot file
-----------------------
+(This is done by the l10n coordinator).
The po/git.pot file contains a message catalog extracted from Git's
-sources. You need to generate it to add new translations with
-msginit(1), or update existing ones with msgmerge(1).
+sources. The l10n coordinator maintains it by adding new translations with
+msginit(1), or update existing ones with msgmerge(1). In order to update
+the Git sources to extract the messages from, the l10n coordinator is
+expected to pull from the main git repository at strategic point in
+history (e.g. when a major release and release candidates are tagged),
+and then run "make pot" at the top-level directory.
-Since the file can be automatically generated it's not checked into
-git.git. To generate it do, at the top-level:
+Language contributors use this file to prepare translations for their
+language, but they are not expected to modify it.
- make pot
+Initializing a XX.po file
+-------------------------
-Initializing a .po file
------------------------
+(This is done by the language teams).
-To add a new translation first generate git.pot (see above) and then
-in the po/ directory do:
+If your language XX does not have translated message file po/XX.po yet,
+you add a translation for the first time by running:
msginit --locale=XX
-Where XX is your locale, e.g. "is", "de" or "pt_BR".
+in the po/ directory, where XX is the locale, e.g. "de", "is", "pt_BR",
+"zh_CN", etc.
Then edit the automatically generated copyright info in your new XX.po
to be correct, e.g. for Icelandic:
@@ -46,21 +92,36 @@ just "Git":
perl -pi -e 's/(?<="Project-Id-Version: )PACKAGE VERSION/Git/' XX.po
+Once you are done testing the translation (see below), commit the result
+and ask the l10n coordinator to pull from you.
+
+
+Updating a XX.po file
+---------------------
-Updating a .po file
--------------------
+(This is done by the language teams).
-If there's an existing *.po file for your language but you need to
-update the translation you first need to generate git.pot (see above)
-and then in the po/ directory do:
+If you are replacing translation strings in an existing XX.po file to
+improve the translation, just edit the file.
+
+If there's an existing XX.po file for your language, but the repository
+of the l10n coordinator has newer po/git.pot file, you would need to first
+pull from the l10n coordinator (see the beginning of this document for its
+URL), and then update the existing translation by running:
msgmerge --add-location --backup=off -U XX.po git.pot
-Where XX.po is the file you want to update.
+in the po/ directory, where XX.po is the file you want to update.
+
+Once you are done testing the translation (see below), commit the result
+and ask the l10n coordinator to pull from you.
+
Testing your changes
--------------------
+(This is done by the language teams, after creating or updating XX.po file).
+
Before you submit your changes go back to the top-level and do:
make
@@ -75,6 +136,8 @@ with a newline or not.
Marking strings for translation
-------------------------------
+(This is done by the core developers).
+
Before strings can be translated they first have to be marked for
translation.
@@ -115,7 +178,7 @@ used:
C:
- - Include builtin.h at the top, it'll pull in in gettext.h, which
+ - Include builtin.h at the top, it'll pull in gettext.h, which
defines the gettext interface. Consult with the list if you need to
use gettext.h directly.
diff --git a/po/TEAMS b/po/TEAMS
new file mode 100644
index 0000000000..cd3440ef59
--- /dev/null
+++ b/po/TEAMS
@@ -0,0 +1,38 @@
+Core Git translation language teams
+(please keep the list sorted alphabetically on language field)
+
+Language: da (Danish)
+Repository: https://github.com/git-da/git-po/
+Leader: Byrial Jensen <byrial@vip.cybercity.dk>
+
+Language: de (German)
+Repository: https://github.com/ralfth/git-po-de
+Leader: Ralf Thielow <ralf.thielow@googlemail.com>
+Members: Thomas Rast <trast@student.ethz.ch>
+ Jan Krüger <jk@jk.gs>
+ Christian Stimming <stimming@tuhh.de>
+
+Language: is (Icelandic)
+Leader: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
+
+Language: nl (Dutch)
+Repository: https://github.com/vfr-nl/git-po/
+Leader: Vincent van Ravesteijn <vfr@lyx.org>
+
+Language: pt_PT (Portuguese - Portugal)
+Repository: https://github.com/marcomsousa/git-l10n-pt_PT/
+Leader: Marco Sousa <marcomsousa AT gmail.com>
+
+Language: sv (Swedish)
+Repository: https://github.com/nafmo/git-l10n-sv/
+Leader: Peter Krefting <peter@softwolves.pp.se>
+
+Language: zh_CN (Simplified Chinese)
+Repository: https://github.com/gotgit/git-po-zh_CN/
+Leader: Jiang Xin <worldhello.net@gmail.com>
+Members: Riku <lu.riku AT gmail.com>
+ Zhuang Ya <zhuangya AT me.com>
+ Lian Cheng <rhythm.mail AT gmail.com>
+ Yichao Yu <yyc1992 AT gmail.com>
+ ws3389 <willsmith3389 AT gmail.com>
+ Thynson <lanxingcan AT gmail.com>
diff --git a/po/da.po b/po/da.po
new file mode 100644
index 0000000000..20a88ea529
--- /dev/null
+++ b/po/da.po
@@ -0,0 +1,3503 @@
+# Danish translations for Git.
+# This file is distributed under the same license as the PACKAGE package.
+# Byrial Jensen <byrial@vip.cybercity.dk>, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Git\n"
+"Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
+"POT-Creation-Date: 2012-03-16 20:18+0800\n"
+"PO-Revision-Date: 2012-04-10 18:41+0200\n"
+"Last-Translator: Byrial Jensen <byrial@vip.cybercity.dk>\n"
+"Language-Team: Danish <dansk@dansk-gruppen.dk>\n"
+"Language: da\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: advice.c:34
+#, c-format
+msgid "hint: %.*s\n"
+msgstr ""
+
+#.
+#. * Message used both when 'git commit' fails and when
+#. * other commands doing a merge do.
+#.
+#: advice.c:64
+msgid ""
+"Fix them up in the work tree,\n"
+"and then use 'git add/rm <file>' as\n"
+"appropriate to mark resolution and make a commit,\n"
+"or use 'git commit -a'."
+msgstr ""
+
+#: commit.c:47
+#, c-format
+msgid "could not parse %s"
+msgstr ""
+
+#: commit.c:49
+#, c-format
+msgid "%s %s is not a commit!"
+msgstr ""
+
+#: compat/obstack.c:406 compat/obstack.c:408
+msgid "memory exhausted"
+msgstr ""
+
+#: connected.c:39
+msgid "Could not run 'git rev-list'"
+msgstr ""
+
+#: connected.c:48
+#, c-format
+msgid "failed write to rev-list: %s"
+msgstr ""
+
+#: connected.c:56
+#, c-format
+msgid "failed to close rev-list's stdin: %s"
+msgstr ""
+
+#: diff.c:105
+#, c-format
+msgid " Failed to parse dirstat cut-off percentage '%.*s'\n"
+msgstr ""
+
+#: diff.c:110
+#, c-format
+msgid " Unknown dirstat parameter '%.*s'\n"
+msgstr ""
+
+#: diff.c:210
+#, c-format
+msgid ""
+"Found errors in 'diff.dirstat' config variable:\n"
+"%s"
+msgstr ""
+
+#: diff.c:1336
+msgid " 0 files changed\n"
+msgstr ""
+
+#: diff.c:1340
+#, c-format
+msgid " %d file changed"
+msgid_plural " %d files changed"
+msgstr[0] ""
+msgstr[1] ""
+
+#: diff.c:1357
+#, c-format
+msgid ", %d insertion(+)"
+msgid_plural ", %d insertions(+)"
+msgstr[0] ""
+msgstr[1] ""
+
+#: diff.c:1368
+#, c-format
+msgid ", %d deletion(-)"
+msgid_plural ", %d deletions(-)"
+msgstr[0] ""
+msgstr[1] ""
+
+#: diff.c:3424
+#, c-format
+msgid ""
+"Failed to parse --dirstat/-X option parameter:\n"
+"%s"
+msgstr ""
+
+#: gpg-interface.c:59
+msgid "could not run gpg."
+msgstr ""
+
+#: gpg-interface.c:71
+msgid "gpg did not accept the data"
+msgstr ""
+
+#: gpg-interface.c:82
+msgid "gpg failed to sign the data"
+msgstr ""
+
+#: grep.c:1280
+#, c-format
+msgid "'%s': unable to read %s"
+msgstr ""
+
+#: grep.c:1297
+#, c-format
+msgid "'%s': %s"
+msgstr ""
+
+#: grep.c:1308
+#, c-format
+msgid "'%s': short read %s"
+msgstr ""
+
+#: help.c:287
+#, 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 ""
+
+#: remote.c:1607
+#, 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:1613
+#, 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] ""
+msgstr[1] ""
+
+#: remote.c:1621
+#, c-format
+msgid ""
+"Your branch and '%s' have diverged,\n"
+"and have %d and %d different commit each, respectively.\n"
+msgid_plural ""
+"Your branch and '%s' have diverged,\n"
+"and have %d and %d different commits each, respectively.\n"
+msgstr[0] ""
+msgstr[1] ""
+
+#: sequencer.c:120 builtin/merge.c:864 builtin/merge.c:985
+#: builtin/merge.c:1095 builtin/merge.c:1105
+#, c-format
+msgid "Could not open '%s' for writing"
+msgstr ""
+
+#: sequencer.c:122 builtin/merge.c:334 builtin/merge.c:867
+#: builtin/merge.c:1097 builtin/merge.c:1110
+#, c-format
+msgid "Could not write to '%s'"
+msgstr ""
+
+#: sequencer.c:143
+msgid ""
+"after resolving the conflicts, mark the corrected paths\n"
+"with 'git add <paths>' or 'git rm <paths>'"
+msgstr ""
+
+#: sequencer.c:146
+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:159 sequencer.c:685 sequencer.c:768
+#, c-format
+msgid "Could not write to %s"
+msgstr ""
+
+#: sequencer.c:162
+#, c-format
+msgid "Error wrapping up %s"
+msgstr ""
+
+#: sequencer.c:177
+msgid "Your local changes would be overwritten by cherry-pick."
+msgstr ""
+
+#: sequencer.c:179
+msgid "Your local changes would be overwritten by revert."
+msgstr ""
+
+#: sequencer.c:182
+msgid "Commit your changes or stash them to proceed."
+msgstr ""
+
+#. TRANSLATORS: %s will be "revert" or "cherry-pick"
+#: sequencer.c:232
+#, c-format
+msgid "%s: Unable to write new index file"
+msgstr ""
+
+#: sequencer.c:298
+msgid "Your index file is unmerged."
+msgstr ""
+
+#: sequencer.c:301
+msgid "You do not have a valid HEAD"
+msgstr ""
+
+#: sequencer.c:316
+#, c-format
+msgid "Commit %s is a merge but no -m option was given."
+msgstr ""
+
+#: sequencer.c:324
+#, c-format
+msgid "Commit %s does not have parent %d"
+msgstr ""
+
+#: sequencer.c:328
+#, 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:339
+#, c-format
+msgid "%s: cannot parse parent commit %s"
+msgstr ""
+
+#: sequencer.c:343
+#, c-format
+msgid "Cannot get commit message for %s"
+msgstr ""
+
+#: sequencer.c:427
+#, c-format
+msgid "could not revert %s... %s"
+msgstr ""
+
+#: sequencer.c:428
+#, c-format
+msgid "could not apply %s... %s"
+msgstr ""
+
+#: sequencer.c:450 sequencer.c:909 builtin/log.c:288 builtin/log.c:713
+#: builtin/log.c:1329 builtin/log.c:1548 builtin/merge.c:348
+#: builtin/shortlog.c:181
+msgid "revision walk setup failed"
+msgstr ""
+
+#: sequencer.c:453
+msgid "empty commit set passed"
+msgstr ""
+
+#: sequencer.c:461
+#, c-format
+msgid "git %s: failed to read the index"
+msgstr ""
+
+#: sequencer.c:466
+#, c-format
+msgid "git %s: failed to refresh the index"
+msgstr ""
+
+#: sequencer.c:551
+#, c-format
+msgid "Cannot %s during a %s"
+msgstr ""
+
+#: sequencer.c:573
+#, c-format
+msgid "Could not parse line %d."
+msgstr ""
+
+#: sequencer.c:578
+msgid "No commits parsed."
+msgstr ""
+
+#: sequencer.c:591
+#, c-format
+msgid "Could not open %s"
+msgstr ""
+
+#: sequencer.c:595
+#, c-format
+msgid "Could not read %s."
+msgstr ""
+
+#: sequencer.c:602
+#, c-format
+msgid "Unusable instruction sheet: %s"
+msgstr ""
+
+#: sequencer.c:630
+#, c-format
+msgid "Invalid key: %s"
+msgstr ""
+
+#: sequencer.c:633
+#, c-format
+msgid "Invalid value for %s: %s"
+msgstr ""
+
+#: sequencer.c:645
+#, c-format
+msgid "Malformed options sheet: %s"
+msgstr ""
+
+#: sequencer.c:666
+msgid "a cherry-pick or revert is already in progress"
+msgstr ""
+
+#: sequencer.c:667
+msgid "try \"git cherry-pick (--continue | --quit | --abort)\""
+msgstr ""
+
+#: sequencer.c:671
+#, c-format
+msgid "Could not create sequencer directory %s"
+msgstr ""
+
+#: sequencer.c:687 sequencer.c:772
+#, c-format
+msgid "Error wrapping up %s."
+msgstr ""
+
+#: sequencer.c:706 sequencer.c:840
+msgid "no cherry-pick or revert in progress"
+msgstr ""
+
+#: sequencer.c:708
+msgid "cannot resolve HEAD"
+msgstr ""
+
+#: sequencer.c:710
+msgid "cannot abort from a branch yet to be born"
+msgstr ""
+
+#: sequencer.c:732
+#, c-format
+msgid "cannot open %s: %s"
+msgstr ""
+
+#: sequencer.c:735
+#, c-format
+msgid "cannot read %s: %s"
+msgstr ""
+
+#: sequencer.c:736
+msgid "unexpected end of file"
+msgstr ""
+
+#: sequencer.c:742
+#, c-format
+msgid "stored pre-cherry-pick HEAD file '%s' is corrupt"
+msgstr ""
+
+#: sequencer.c:765
+#, c-format
+msgid "Could not format %s."
+msgstr ""
+
+#: sequencer.c:927
+msgid "Can't revert as initial commit"
+msgstr ""
+
+#: sequencer.c:928
+msgid "Can't cherry-pick into empty head"
+msgstr ""
+
+#: wt-status.c:134
+msgid "Unmerged paths:"
+msgstr ""
+
+#: wt-status.c:140 wt-status.c:157
+#, c-format
+msgid " (use \"git reset %s <file>...\" to unstage)"
+msgstr ""
+
+#: wt-status.c:142 wt-status.c:159
+msgid " (use \"git rm --cached <file>...\" to unstage)"
+msgstr ""
+
+#: wt-status.c:143
+msgid " (use \"git add/rm <file>...\" as appropriate to mark resolution)"
+msgstr ""
+
+#: wt-status.c:151
+msgid "Changes to be committed:"
+msgstr ""
+
+#: wt-status.c:169
+msgid "Changes not staged for commit:"
+msgstr ""
+
+#: wt-status.c:173
+msgid " (use \"git add <file>...\" to update what will be committed)"
+msgstr ""
+
+#: wt-status.c:175
+msgid " (use \"git add/rm <file>...\" to update what will be committed)"
+msgstr ""
+
+#: wt-status.c:176
+msgid ""
+" (use \"git checkout -- <file>...\" to discard changes in working directory)"
+msgstr ""
+
+#: wt-status.c:178
+msgid " (commit or discard the untracked or modified content in submodules)"
+msgstr ""
+
+#: wt-status.c:187
+#, c-format
+msgid "%s files:"
+msgstr ""
+
+#: wt-status.c:190
+#, c-format
+msgid " (use \"git %s <file>...\" to include in what will be committed)"
+msgstr ""
+
+#: wt-status.c:207
+msgid "bug"
+msgstr ""
+
+#: wt-status.c:212
+msgid "both deleted:"
+msgstr ""
+
+#: wt-status.c:213
+msgid "added by us:"
+msgstr ""
+
+#: wt-status.c:214
+msgid "deleted by them:"
+msgstr ""
+
+#: wt-status.c:215
+msgid "added by them:"
+msgstr ""
+
+#: wt-status.c:216
+msgid "deleted by us:"
+msgstr ""
+
+#: wt-status.c:217
+msgid "both added:"
+msgstr ""
+
+#: wt-status.c:218
+msgid "both modified:"
+msgstr ""
+
+#: wt-status.c:248
+msgid "new commits, "
+msgstr ""
+
+#: wt-status.c:250
+msgid "modified content, "
+msgstr ""
+
+#: wt-status.c:252
+msgid "untracked content, "
+msgstr ""
+
+#: wt-status.c:266
+#, c-format
+msgid "new file: %s"
+msgstr ""
+
+#: wt-status.c:269
+#, c-format
+msgid "copied: %s -> %s"
+msgstr ""
+
+#: wt-status.c:272
+#, c-format
+msgid "deleted: %s"
+msgstr ""
+
+#: wt-status.c:275
+#, c-format
+msgid "modified: %s"
+msgstr ""
+
+#: wt-status.c:278
+#, c-format
+msgid "renamed: %s -> %s"
+msgstr ""
+
+#: wt-status.c:281
+#, c-format
+msgid "typechange: %s"
+msgstr ""
+
+#: wt-status.c:284
+#, c-format
+msgid "unknown: %s"
+msgstr ""
+
+#: wt-status.c:287
+#, c-format
+msgid "unmerged: %s"
+msgstr ""
+
+#: wt-status.c:290
+#, c-format
+msgid "bug: unhandled diff status %c"
+msgstr ""
+
+#: wt-status.c:713
+msgid "On branch "
+msgstr ""
+
+#: wt-status.c:720
+msgid "Not currently on any branch."
+msgstr ""
+
+#: wt-status.c:731
+msgid "Initial commit"
+msgstr ""
+
+#: wt-status.c:745
+msgid "Untracked"
+msgstr ""
+
+#: wt-status.c:747
+msgid "Ignored"
+msgstr ""
+
+#: wt-status.c:749
+#, c-format
+msgid "Untracked files not listed%s"
+msgstr ""
+
+#: wt-status.c:751
+msgid " (use -u option to show untracked files)"
+msgstr ""
+
+#: wt-status.c:757
+msgid "No changes"
+msgstr ""
+
+#: wt-status.c:761
+#, c-format
+msgid "no changes added to commit%s\n"
+msgstr ""
+
+#: wt-status.c:763
+msgid " (use \"git add\" and/or \"git commit -a\")"
+msgstr ""
+
+#: wt-status.c:765
+#, c-format
+msgid "nothing added to commit but untracked files present%s\n"
+msgstr ""
+
+#: wt-status.c:767
+msgid " (use \"git add\" to track)"
+msgstr ""
+
+#: wt-status.c:769 wt-status.c:772 wt-status.c:775
+#, c-format
+msgid "nothing to commit%s\n"
+msgstr ""
+
+#: wt-status.c:770
+msgid " (create/copy files and use \"git add\" to track)"
+msgstr ""
+
+#: wt-status.c:773
+msgid " (use -u to show untracked files)"
+msgstr ""
+
+#: wt-status.c:776
+msgid " (working directory clean)"
+msgstr ""
+
+#: wt-status.c:884
+msgid "HEAD (no branch)"
+msgstr ""
+
+#: wt-status.c:890
+msgid "Initial commit on "
+msgstr ""
+
+#: wt-status.c:905
+msgid "behind "
+msgstr ""
+
+#: wt-status.c:908 wt-status.c:911
+msgid "ahead "
+msgstr ""
+
+#: wt-status.c:913
+msgid ", behind "
+msgstr ""
+
+#: builtin/add.c:62
+#, c-format
+msgid "unexpected diff status %c"
+msgstr ""
+
+#: builtin/add.c:67 builtin/commit.c:298
+msgid "updating files failed"
+msgstr ""
+
+#: builtin/add.c:77
+#, c-format
+msgid "remove '%s'\n"
+msgstr ""
+
+#: builtin/add.c:176
+#, c-format
+msgid "Path '%s' is in submodule '%.*s'"
+msgstr ""
+
+#: builtin/add.c:192
+msgid "Unstaged changes after refreshing the index:"
+msgstr ""
+
+#: builtin/add.c:195 builtin/add.c:456 builtin/rm.c:186
+#, c-format
+msgid "pathspec '%s' did not match any files"
+msgstr ""
+
+#: builtin/add.c:209
+#, c-format
+msgid "'%s' is beyond a symbolic link"
+msgstr ""
+
+#: builtin/add.c:276
+msgid "Could not read the index"
+msgstr ""
+
+#: builtin/add.c:286
+#, c-format
+msgid "Could not open '%s' for writing."
+msgstr ""
+
+#: builtin/add.c:290
+msgid "Could not write patch"
+msgstr ""
+
+#: builtin/add.c:295
+#, c-format
+msgid "Could not stat '%s'"
+msgstr ""
+
+#: builtin/add.c:297
+msgid "Empty patch. Aborted."
+msgstr ""
+
+#: builtin/add.c:303
+#, c-format
+msgid "Could not apply '%s'"
+msgstr ""
+
+#: builtin/add.c:312
+msgid "The following paths are ignored by one of your .gitignore files:\n"
+msgstr ""
+
+#: builtin/add.c:352
+#, c-format
+msgid "Use -f if you really want to add them.\n"
+msgstr ""
+
+#: builtin/add.c:353
+msgid "no files added"
+msgstr ""
+
+#: builtin/add.c:359
+msgid "adding files failed"
+msgstr ""
+
+#: builtin/add.c:391
+msgid "-A and -u are mutually incompatible"
+msgstr ""
+
+#: builtin/add.c:393
+msgid "Option --ignore-missing can only be used together with --dry-run"
+msgstr ""
+
+#: builtin/add.c:413
+#, c-format
+msgid "Nothing specified, nothing added.\n"
+msgstr ""
+
+#: builtin/add.c:414
+#, c-format
+msgid "Maybe you wanted to say 'git add .'?\n"
+msgstr ""
+
+#: builtin/add.c:420 builtin/clean.c:95 builtin/commit.c:358 builtin/mv.c:82
+#: builtin/rm.c:162
+msgid "index file corrupt"
+msgstr ""
+
+#: builtin/add.c:476 builtin/mv.c:229 builtin/rm.c:260
+msgid "Unable to write new index file"
+msgstr ""
+
+#: builtin/archive.c:17
+#, c-format
+msgid "could not create archive file '%s'"
+msgstr ""
+
+#: builtin/archive.c:20
+msgid "could not redirect output"
+msgstr ""
+
+#: builtin/archive.c:37
+msgid "git archive: Remote with no URL"
+msgstr ""
+
+#: builtin/archive.c:58
+msgid "git archive: expected ACK/NAK, got EOF"
+msgstr ""
+
+#: builtin/archive.c:63
+#, c-format
+msgid "git archive: NACK %s"
+msgstr ""
+
+#: builtin/archive.c:65
+#, c-format
+msgid "remote error: %s"
+msgstr ""
+
+#: builtin/archive.c:66
+msgid "git archive: protocol error"
+msgstr ""
+
+#: builtin/archive.c:71
+msgid "git archive: expected a flush"
+msgstr ""
+
+#: builtin/branch.c:137
+#, c-format
+msgid ""
+"deleting branch '%s' that has been merged to\n"
+" '%s', but not yet merged to HEAD."
+msgstr ""
+
+#: builtin/branch.c:141
+#, c-format
+msgid ""
+"not deleting branch '%s' that is not yet merged to\n"
+" '%s', even though it is merged to HEAD."
+msgstr ""
+
+#. TRANSLATORS: This is "remote " in "remote branch '%s' not found"
+#: builtin/branch.c:163
+msgid "remote "
+msgstr ""
+
+#: builtin/branch.c:171
+msgid "cannot use -a with -d"
+msgstr ""
+
+#: builtin/branch.c:177
+msgid "Couldn't look up commit object for HEAD"
+msgstr ""
+
+#: builtin/branch.c:182
+#, c-format
+msgid "Cannot delete the branch '%s' which you are currently on."
+msgstr ""
+
+#: builtin/branch.c:192
+#, c-format
+msgid "%sbranch '%s' not found."
+msgstr ""
+
+#: builtin/branch.c:200
+#, c-format
+msgid "Couldn't look up commit object for '%s'"
+msgstr ""
+
+#: builtin/branch.c:206
+#, 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:214
+#, c-format
+msgid "Error deleting %sbranch '%s'"
+msgstr ""
+
+#: builtin/branch.c:219
+#, c-format
+msgid "Deleted %sbranch %s (was %s).\n"
+msgstr ""
+
+#: builtin/branch.c:224
+msgid "Update of config-file failed"
+msgstr ""
+
+#: builtin/branch.c:322
+#, c-format
+msgid "branch '%s' does not point at a commit"
+msgstr ""
+
+#: builtin/branch.c:394
+#, c-format
+msgid "behind %d] "
+msgstr ""
+
+#: builtin/branch.c:396
+#, c-format
+msgid "ahead %d] "
+msgstr ""
+
+#: builtin/branch.c:398
+#, c-format
+msgid "ahead %d, behind %d] "
+msgstr ""
+
+#: builtin/branch.c:501
+msgid "(no branch)"
+msgstr ""
+
+#: builtin/branch.c:566
+msgid "some refs could not be read"
+msgstr ""
+
+#: builtin/branch.c:579
+msgid "cannot rename the current branch while not on any."
+msgstr ""
+
+#: builtin/branch.c:589
+#, c-format
+msgid "Invalid branch name: '%s'"
+msgstr ""
+
+#: builtin/branch.c:604
+msgid "Branch rename failed"
+msgstr ""
+
+#: builtin/branch.c:608
+#, c-format
+msgid "Renamed a misnamed branch '%s' away"
+msgstr ""
+
+#: builtin/branch.c:612
+#, c-format
+msgid "Branch renamed to %s, but HEAD is not updated!"
+msgstr ""
+
+#: builtin/branch.c:619
+msgid "Branch is renamed, but update of config-file failed"
+msgstr ""
+
+#: builtin/branch.c:634
+#, c-format
+msgid "malformed object name %s"
+msgstr ""
+
+#: builtin/branch.c:658
+#, c-format
+msgid "could not write branch description template: %s\n"
+msgstr ""
+
+#: builtin/branch.c:746
+msgid "Failed to resolve HEAD as a valid ref."
+msgstr ""
+
+#: builtin/branch.c:751 builtin/clone.c:558
+msgid "HEAD not found below refs/heads!"
+msgstr ""
+
+#: builtin/branch.c:809
+msgid "-a and -r options to 'git branch' do not make sense with a branch name"
+msgstr ""
+
+#: builtin/bundle.c:47
+#, c-format
+msgid "%s is okay\n"
+msgstr ""
+
+#: builtin/bundle.c:56
+msgid "Need a repository to create a bundle."
+msgstr ""
+
+#: builtin/bundle.c:60
+msgid "Need a repository to unbundle."
+msgstr ""
+
+#: builtin/checkout.c:113 builtin/checkout.c:146
+#, c-format
+msgid "path '%s' does not have our version"
+msgstr ""
+
+#: builtin/checkout.c:115 builtin/checkout.c:148
+#, c-format
+msgid "path '%s' does not have their version"
+msgstr ""
+
+#: builtin/checkout.c:131
+#, c-format
+msgid "path '%s' does not have all necessary versions"
+msgstr ""
+
+#: builtin/checkout.c:175
+#, c-format
+msgid "path '%s' does not have necessary versions"
+msgstr ""
+
+#: builtin/checkout.c:192
+#, c-format
+msgid "path '%s': cannot merge"
+msgstr ""
+
+#: builtin/checkout.c:209
+#, c-format
+msgid "Unable to add merge result for '%s'"
+msgstr ""
+
+#: builtin/checkout.c:212 builtin/reset.c:158
+#, c-format
+msgid "make_cache_entry failed for path '%s'"
+msgstr ""
+
+#: builtin/checkout.c:234 builtin/checkout.c:392
+msgid "corrupt index file"
+msgstr ""
+
+#: builtin/checkout.c:264 builtin/checkout.c:271
+#, c-format
+msgid "path '%s' is unmerged"
+msgstr ""
+
+#: builtin/checkout.c:302 builtin/checkout.c:498 builtin/clone.c:583
+#: 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 ""
+
+#: builtin/checkout.c:414
+msgid "you need to resolve your current index first"
+msgstr ""
+
+#: builtin/checkout.c:533
+#, c-format
+msgid "Can not do reflog for '%s'\n"
+msgstr ""
+
+#: builtin/checkout.c:565
+msgid "HEAD is now at"
+msgstr ""
+
+#: builtin/checkout.c:572
+#, c-format
+msgid "Reset branch '%s'\n"
+msgstr ""
+
+#: builtin/checkout.c:575
+#, c-format
+msgid "Already on '%s'\n"
+msgstr ""
+
+#: builtin/checkout.c:579
+#, c-format
+msgid "Switched to and reset branch '%s'\n"
+msgstr ""
+
+#: builtin/checkout.c:581
+#, c-format
+msgid "Switched to a new branch '%s'\n"
+msgstr ""
+
+#: builtin/checkout.c:583
+#, c-format
+msgid "Switched to branch '%s'\n"
+msgstr ""
+
+#: builtin/checkout.c:639
+#, c-format
+msgid " ... and %d more.\n"
+msgstr ""
+
+#. The singular version
+#: builtin/checkout.c:645
+#, 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"
+"\n"
+"%s\n"
+msgstr[0] ""
+msgstr[1] ""
+
+#: builtin/checkout.c:663
+#, 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"
+msgstr ""
+
+#: builtin/checkout.c:692
+msgid "internal error in revision walk"
+msgstr ""
+
+#: builtin/checkout.c:696
+msgid "Previous HEAD position was"
+msgstr ""
+
+#: builtin/checkout.c:722
+msgid "You are on a branch yet to be born"
+msgstr ""
+
+#. case (1)
+#: builtin/checkout.c:853
+#, c-format
+msgid "invalid reference: %s"
+msgstr ""
+
+#. case (1): want a tree
+#: builtin/checkout.c:892
+#, c-format
+msgid "reference is not a tree: %s"
+msgstr ""
+
+#: builtin/checkout.c:972
+msgid "-B cannot be used with -b"
+msgstr ""
+
+#: builtin/checkout.c:981
+msgid "--patch is incompatible with all other options"
+msgstr ""
+
+#: builtin/checkout.c:984
+msgid "--detach cannot be used with -b/-B/--orphan"
+msgstr ""
+
+#: builtin/checkout.c:986
+msgid "--detach cannot be used with -t"
+msgstr ""
+
+#: builtin/checkout.c:992
+msgid "--track needs a branch name"
+msgstr ""
+
+#: builtin/checkout.c:999
+msgid "Missing branch name; try -b"
+msgstr ""
+
+#: builtin/checkout.c:1005
+msgid "--orphan and -b|-B are mutually exclusive"
+msgstr ""
+
+#: builtin/checkout.c:1007
+msgid "--orphan cannot be used with -t"
+msgstr ""
+
+#: builtin/checkout.c:1017
+msgid "git checkout: -f and -m are incompatible"
+msgstr ""
+
+#: builtin/checkout.c:1051
+msgid "invalid path specification"
+msgstr ""
+
+#: builtin/checkout.c:1059
+#, 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?"
+msgstr ""
+
+#: builtin/checkout.c:1061
+msgid "git checkout: updating paths is incompatible with switching branches."
+msgstr ""
+
+#: builtin/checkout.c:1066
+msgid "git checkout: --detach does not take a path argument"
+msgstr ""
+
+#: builtin/checkout.c:1069
+msgid ""
+"git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
+"checking out of the index."
+msgstr ""
+
+#: builtin/checkout.c:1088
+msgid "Cannot switch branch to a non-commit."
+msgstr ""
+
+#: builtin/checkout.c:1091
+msgid "--ours/--theirs is incompatible with switching branches."
+msgstr ""
+
+#: builtin/clean.c:78
+msgid "-x and -X cannot be used together"
+msgstr ""
+
+#: builtin/clean.c:82
+msgid ""
+"clean.requireForce set to true and neither -n nor -f given; refusing to clean"
+msgstr ""
+
+#: builtin/clean.c:85
+msgid ""
+"clean.requireForce defaults to true and neither -n nor -f given; refusing to "
+"clean"
+msgstr ""
+
+#: builtin/clean.c:155 builtin/clean.c:176
+#, c-format
+msgid "Would remove %s\n"
+msgstr ""
+
+#: builtin/clean.c:159 builtin/clean.c:179
+#, c-format
+msgid "Removing %s\n"
+msgstr ""
+
+#: builtin/clean.c:162 builtin/clean.c:182
+#, c-format
+msgid "failed to remove %s"
+msgstr ""
+
+#: builtin/clean.c:166
+#, c-format
+msgid "Would not remove %s\n"
+msgstr ""
+
+#: builtin/clean.c:168
+#, c-format
+msgid "Not removing %s\n"
+msgstr ""
+
+#: builtin/clone.c:243
+#, c-format
+msgid "reference repository '%s' is not a local directory."
+msgstr ""
+
+#: builtin/clone.c:302
+#, c-format
+msgid "failed to open '%s'"
+msgstr ""
+
+#: builtin/clone.c:306
+#, c-format
+msgid "failed to create directory '%s'"
+msgstr ""
+
+#: builtin/clone.c:308 builtin/diff.c:75
+#, c-format
+msgid "failed to stat '%s'"
+msgstr ""
+
+#: builtin/clone.c:310
+#, c-format
+msgid "%s exists and is not a directory"
+msgstr ""
+
+#: builtin/clone.c:324
+#, c-format
+msgid "failed to stat %s\n"
+msgstr ""
+
+#: builtin/clone.c:341
+#, c-format
+msgid "failed to unlink '%s'"
+msgstr ""
+
+#: builtin/clone.c:346
+#, c-format
+msgid "failed to create link '%s'"
+msgstr ""
+
+#: builtin/clone.c:350
+#, c-format
+msgid "failed to copy file to '%s'"
+msgstr ""
+
+#: builtin/clone.c:373
+#, c-format
+msgid "done.\n"
+msgstr ""
+
+#: builtin/clone.c:440
+#, c-format
+msgid "Could not find remote branch %s to clone."
+msgstr ""
+
+#: builtin/clone.c:549
+msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n"
+msgstr ""
+
+#: builtin/clone.c:639
+msgid "Too many arguments."
+msgstr ""
+
+#: builtin/clone.c:643
+msgid "You must specify a repository to clone."
+msgstr ""
+
+#: builtin/clone.c:654
+#, c-format
+msgid "--bare and --origin %s options are incompatible."
+msgstr ""
+
+#: builtin/clone.c:668
+#, c-format
+msgid "repository '%s' does not exist"
+msgstr ""
+
+#: builtin/clone.c:673
+msgid "--depth is ignored in local clones; use file:// instead."
+msgstr ""
+
+#: builtin/clone.c:683
+#, c-format
+msgid "destination path '%s' already exists and is not an empty directory."
+msgstr ""
+
+#: builtin/clone.c:693
+#, c-format
+msgid "working tree '%s' already exists."
+msgstr ""
+
+#: builtin/clone.c:706 builtin/clone.c:720
+#, c-format
+msgid "could not create leading directories of '%s'"
+msgstr ""
+
+#: builtin/clone.c:709
+#, c-format
+msgid "could not create work tree dir '%s'."
+msgstr ""
+
+#: builtin/clone.c:728
+#, c-format
+msgid "Cloning into bare repository '%s'...\n"
+msgstr ""
+
+#: builtin/clone.c:730
+#, c-format
+msgid "Cloning into '%s'...\n"
+msgstr ""
+
+#: builtin/clone.c:786
+#, c-format
+msgid "Don't know how to clone %s"
+msgstr ""
+
+#: builtin/clone.c:835
+#, 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/commit.c:42
+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/commit.c:54
+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 ""
+
+#: builtin/commit.c:59
+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/commit.c:205 builtin/reset.c:33
+msgid "merge"
+msgstr ""
+
+#: builtin/commit.c:208
+msgid "cherry-pick"
+msgstr ""
+
+#: builtin/commit.c:325
+msgid "failed to unpack HEAD tree object"
+msgstr ""
+
+#: builtin/commit.c:367
+msgid "unable to create temporary index"
+msgstr ""
+
+#: builtin/commit.c:373
+msgid "interactive add failed"
+msgstr ""
+
+#: builtin/commit.c:406 builtin/commit.c:427 builtin/commit.c:473
+msgid "unable to write new_index file"
+msgstr ""
+
+#: builtin/commit.c:457
+#, c-format
+msgid "cannot do a partial commit during a %s."
+msgstr ""
+
+#: builtin/commit.c:466
+msgid "cannot read the index"
+msgstr ""
+
+#: builtin/commit.c:486
+msgid "unable to write temporary index file"
+msgstr ""
+
+#: builtin/commit.c:550 builtin/commit.c:556
+#, c-format
+msgid "invalid commit: %s"
+msgstr ""
+
+#: builtin/commit.c:579
+msgid "malformed --author parameter"
+msgstr ""
+
+#: builtin/commit.c:635
+#, c-format
+msgid "Malformed ident string: '%s'"
+msgstr ""
+
+#: builtin/commit.c:670 builtin/commit.c:703 builtin/commit.c:1000
+#, c-format
+msgid "could not lookup commit %s"
+msgstr ""
+
+#: builtin/commit.c:682 builtin/shortlog.c:296
+#, c-format
+msgid "(reading log message from standard input)\n"
+msgstr ""
+
+#: builtin/commit.c:684
+msgid "could not read log from standard input"
+msgstr ""
+
+#: builtin/commit.c:688
+#, c-format
+msgid "could not read log file '%s'"
+msgstr ""
+
+#: builtin/commit.c:694
+msgid "commit has empty message"
+msgstr ""
+
+#: builtin/commit.c:710
+msgid "could not read MERGE_MSG"
+msgstr ""
+
+#: builtin/commit.c:714
+msgid "could not read SQUASH_MSG"
+msgstr ""
+
+#: builtin/commit.c:718
+#, c-format
+msgid "could not read '%s'"
+msgstr ""
+
+#: builtin/commit.c:746
+#, c-format
+msgid "could not open '%s'"
+msgstr ""
+
+#: builtin/commit.c:770
+msgid "could not write commit template"
+msgstr ""
+
+#: builtin/commit.c:783
+#, c-format
+msgid ""
+"\n"
+"It looks like you may be committing a %s.\n"
+"If this is not correct, please remove the file\n"
+"\t%s\n"
+"and try again.\n"
+msgstr ""
+
+#: builtin/commit.c:796
+msgid "Please enter the commit message for your changes."
+msgstr ""
+
+#: builtin/commit.c:799
+msgid ""
+" Lines starting\n"
+"with '#' will be ignored, and an empty message aborts the commit.\n"
+msgstr ""
+
+#: builtin/commit.c:804
+msgid ""
+" Lines starting\n"
+"with '#' will be kept; you may remove them yourself if you want to.\n"
+"An empty message aborts the commit.\n"
+msgstr ""
+
+#: builtin/commit.c:816
+#, c-format
+msgid "%sAuthor: %s"
+msgstr ""
+
+#: builtin/commit.c:823
+#, c-format
+msgid "%sCommitter: %s"
+msgstr ""
+
+#: builtin/commit.c:843
+msgid "Cannot read index"
+msgstr ""
+
+#: builtin/commit.c:880
+msgid "Error building trees"
+msgstr ""
+
+#: builtin/commit.c:895 builtin/tag.c:357
+#, c-format
+msgid "Please supply the message using either -m or -F option.\n"
+msgstr ""
+
+#: builtin/commit.c:975
+#, c-format
+msgid "No existing author found with '%s'"
+msgstr ""
+
+#: builtin/commit.c:990 builtin/commit.c:1182
+#, c-format
+msgid "Invalid untracked files mode '%s'"
+msgstr ""
+
+#: builtin/commit.c:1030
+msgid "Using both --reset-author and --author does not make sense"
+msgstr ""
+
+#: builtin/commit.c:1041
+msgid "You have nothing to amend."
+msgstr ""
+
+#: builtin/commit.c:1043
+#, c-format
+msgid "You are in the middle of a %s -- cannot amend."
+msgstr ""
+
+#: builtin/commit.c:1045
+msgid "Options --squash and --fixup cannot be used together"
+msgstr ""
+
+#: builtin/commit.c:1055
+msgid "Only one of -c/-C/-F/--fixup can be used."
+msgstr ""
+
+#: builtin/commit.c:1057
+msgid "Option -m cannot be combined with -c/-C/-F/--fixup."
+msgstr ""
+
+#: builtin/commit.c:1063
+msgid "--reset-author can be used only with -C, -c or --amend."
+msgstr ""
+
+#: builtin/commit.c:1080
+msgid "Only one of --include/--only/--all/--interactive/--patch can be used."
+msgstr ""
+
+#: builtin/commit.c:1082
+msgid "No paths with --include/--only does not make sense."
+msgstr ""
+
+#: builtin/commit.c:1084
+msgid "Clever... amending the last one with dirty index."
+msgstr ""
+
+#: builtin/commit.c:1086
+msgid "Explicit paths specified without -i nor -o; assuming --only paths..."
+msgstr ""
+
+#: builtin/commit.c:1096 builtin/tag.c:556
+#, c-format
+msgid "Invalid cleanup mode %s"
+msgstr ""
+
+#: builtin/commit.c:1101
+msgid "Paths with -a does not make sense."
+msgstr ""
+
+#: builtin/commit.c:1280
+msgid "couldn't look up newly created commit"
+msgstr ""
+
+#: builtin/commit.c:1282
+msgid "could not parse newly created commit"
+msgstr ""
+
+#: builtin/commit.c:1323
+msgid "detached HEAD"
+msgstr ""
+
+#: builtin/commit.c:1325
+msgid " (root-commit)"
+msgstr ""
+
+#: builtin/commit.c:1415
+msgid "could not parse HEAD commit"
+msgstr ""
+
+#: builtin/commit.c:1452 builtin/merge.c:509
+#, c-format
+msgid "could not open '%s' for reading"
+msgstr ""
+
+#: builtin/commit.c:1459
+#, c-format
+msgid "Corrupt MERGE_HEAD file (%s)"
+msgstr ""
+
+#: builtin/commit.c:1466
+msgid "could not read MERGE_MODE"
+msgstr ""
+
+#: builtin/commit.c:1485
+#, c-format
+msgid "could not read commit message: %s"
+msgstr ""
+
+#: builtin/commit.c:1499
+#, c-format
+msgid "Aborting commit due to empty commit message.\n"
+msgstr ""
+
+#: builtin/commit.c:1514 builtin/merge.c:935 builtin/merge.c:968
+msgid "failed to write commit object"
+msgstr ""
+
+#: builtin/commit.c:1535
+msgid "cannot lock HEAD ref"
+msgstr ""
+
+#: builtin/commit.c:1539
+msgid "cannot update HEAD ref"
+msgstr ""
+
+#: builtin/commit.c:1550
+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/describe.c:234
+#, c-format
+msgid "annotated tag %s not available"
+msgstr ""
+
+#: builtin/describe.c:238
+#, c-format
+msgid "annotated tag %s has no embedded name"
+msgstr ""
+
+#: builtin/describe.c:240
+#, c-format
+msgid "tag '%s' is really '%s' here"
+msgstr ""
+
+#: builtin/describe.c:267
+#, c-format
+msgid "Not a valid object name %s"
+msgstr ""
+
+#: builtin/describe.c:270
+#, c-format
+msgid "%s is not a valid '%s' object"
+msgstr ""
+
+#: builtin/describe.c:287
+#, c-format
+msgid "no tag exactly matches '%s'"
+msgstr ""
+
+#: builtin/describe.c:289
+#, c-format
+msgid "searching to describe %s\n"
+msgstr ""
+
+#: builtin/describe.c:329
+#, c-format
+msgid "finished search at %s\n"
+msgstr ""
+
+#: builtin/describe.c:353
+#, c-format
+msgid ""
+"No annotated tags can describe '%s'.\n"
+"However, there were unannotated tags: try --tags."
+msgstr ""
+
+#: builtin/describe.c:357
+#, c-format
+msgid ""
+"No tags can describe '%s'.\n"
+"Try --always, or create some tags."
+msgstr ""
+
+#: builtin/describe.c:378
+#, c-format
+msgid "traversed %lu commits\n"
+msgstr ""
+
+#: builtin/describe.c:381
+#, c-format
+msgid ""
+"more than %i tags found; listed %i most recent\n"
+"gave up search at %s\n"
+msgstr ""
+
+#: builtin/describe.c:436
+msgid "--long is incompatible with --abbrev=0"
+msgstr ""
+
+#: builtin/describe.c:462
+msgid "No names found, cannot describe anything."
+msgstr ""
+
+#: builtin/describe.c:482
+msgid "--dirty is incompatible with committishes"
+msgstr ""
+
+#: builtin/diff.c:77
+#, c-format
+msgid "'%s': not a regular file or symlink"
+msgstr ""
+
+#: builtin/diff.c:220
+#, c-format
+msgid "invalid option: %s"
+msgstr ""
+
+#: builtin/diff.c:297
+msgid "Not a git repository"
+msgstr ""
+
+#: builtin/diff.c:347
+#, c-format
+msgid "invalid object '%s' given."
+msgstr ""
+
+#: builtin/diff.c:352
+#, c-format
+msgid "more than %d trees given: '%s'"
+msgstr ""
+
+#: builtin/diff.c:362
+#, c-format
+msgid "more than two blobs given: '%s'"
+msgstr ""
+
+#: builtin/diff.c:370
+#, c-format
+msgid "unhandled object '%s' given."
+msgstr ""
+
+#: builtin/fetch.c:200
+msgid "Couldn't find remote ref HEAD"
+msgstr ""
+
+#: builtin/fetch.c:252
+#, c-format
+msgid "object %s not found"
+msgstr ""
+
+#: builtin/fetch.c:258
+msgid "[up to date]"
+msgstr ""
+
+#: builtin/fetch.c:272
+#, c-format
+msgid "! %-*s %-*s -> %s (can't fetch in current branch)"
+msgstr ""
+
+#: builtin/fetch.c:273 builtin/fetch.c:351
+msgid "[rejected]"
+msgstr ""
+
+#: builtin/fetch.c:284
+msgid "[tag update]"
+msgstr ""
+
+#: builtin/fetch.c:286 builtin/fetch.c:313 builtin/fetch.c:331
+msgid " (unable to update local ref)"
+msgstr ""
+
+#: builtin/fetch.c:298
+msgid "[new tag]"
+msgstr ""
+
+#: builtin/fetch.c:302
+msgid "[new branch]"
+msgstr ""
+
+#: builtin/fetch.c:347
+msgid "unable to update local ref"
+msgstr ""
+
+#: builtin/fetch.c:347
+msgid "forced update"
+msgstr ""
+
+#: builtin/fetch.c:353
+msgid "(non-fast-forward)"
+msgstr ""
+
+#: builtin/fetch.c:384 builtin/fetch.c:676
+#, c-format
+msgid "cannot open %s: %s\n"
+msgstr ""
+
+#: builtin/fetch.c:393
+#, c-format
+msgid "%s did not send all necessary objects\n"
+msgstr ""
+
+#: builtin/fetch.c:479
+#, c-format
+msgid "From %.*s\n"
+msgstr ""
+
+#: builtin/fetch.c:490
+#, c-format
+msgid ""
+"some local refs could not be updated; try running\n"
+" 'git remote prune %s' to remove any old, conflicting branches"
+msgstr ""
+
+#: builtin/fetch.c:540
+#, c-format
+msgid " (%s will become dangling)\n"
+msgstr ""
+
+#: builtin/fetch.c:541
+#, c-format
+msgid " (%s has become dangling)\n"
+msgstr ""
+
+#: builtin/fetch.c:548
+msgid "[deleted]"
+msgstr ""
+
+#: builtin/fetch.c:549
+msgid "(none)"
+msgstr ""
+
+#: builtin/fetch.c:666
+#, c-format
+msgid "Refusing to fetch into current branch %s of non-bare repository"
+msgstr ""
+
+#: builtin/fetch.c:700
+#, c-format
+msgid "Don't know how to fetch from %s"
+msgstr ""
+
+#: builtin/fetch.c:777
+#, c-format
+msgid "Option \"%s\" value \"%s\" is not valid for %s"
+msgstr ""
+
+#: builtin/fetch.c:780
+#, c-format
+msgid "Option \"%s\" is ignored for %s\n"
+msgstr ""
+
+#: builtin/fetch.c:879
+#, c-format
+msgid "Fetching %s\n"
+msgstr ""
+
+#: builtin/fetch.c:881
+#, c-format
+msgid "Could not fetch %s"
+msgstr ""
+
+#: builtin/fetch.c:898
+msgid ""
+"No remote repository specified. Please, specify either a URL or a\n"
+"remote name from which new revisions should be fetched."
+msgstr ""
+
+#: builtin/fetch.c:918
+msgid "You need to specify a tag name."
+msgstr ""
+
+#: builtin/fetch.c:970
+msgid "fetch --all does not take a repository argument"
+msgstr ""
+
+#: builtin/fetch.c:972
+msgid "fetch --all does not make sense with refspecs"
+msgstr ""
+
+#: builtin/fetch.c:983
+#, c-format
+msgid "No such remote or remote group: %s"
+msgstr ""
+
+#: builtin/fetch.c:991
+msgid "Fetching a group and specifying refspecs does not make sense"
+msgstr ""
+
+#: builtin/gc.c:63
+#, c-format
+msgid "Invalid %s: '%s'"
+msgstr ""
+
+#: builtin/gc.c:78
+msgid "Too many options specified"
+msgstr ""
+
+#: builtin/gc.c:103
+#, c-format
+msgid "insanely long object directory %.*s"
+msgstr ""
+
+#: builtin/gc.c:223
+#, c-format
+msgid "Auto packing the repository for optimum performance.\n"
+msgstr ""
+
+#: builtin/gc.c:226
+#, 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/gc.c:256
+msgid ""
+"There are too many unreachable loose objects; run 'git prune' to remove them."
+msgstr ""
+
+#: builtin/grep.c:216
+#, c-format
+msgid "grep: failed to create thread: %s"
+msgstr ""
+
+#: builtin/grep.c:402
+#, c-format
+msgid "Failed to chdir: %s"
+msgstr ""
+
+#: builtin/grep.c:478 builtin/grep.c:512
+#, c-format
+msgid "unable to read tree (%s)"
+msgstr ""
+
+#: builtin/grep.c:526
+#, c-format
+msgid "unable to grep from object of type %s"
+msgstr ""
+
+#: builtin/grep.c:584
+#, c-format
+msgid "switch `%c' expects a numerical value"
+msgstr ""
+
+#: builtin/grep.c:601
+#, c-format
+msgid "cannot open '%s'"
+msgstr ""
+
+#: builtin/grep.c:888
+msgid "no pattern given."
+msgstr ""
+
+#: builtin/grep.c:902
+#, c-format
+msgid "bad object %s"
+msgstr ""
+
+#: builtin/grep.c:943
+msgid "--open-files-in-pager only works on the worktree"
+msgstr ""
+
+#: builtin/grep.c:966
+msgid "--cached or --untracked cannot be used with --no-index."
+msgstr ""
+
+#: builtin/grep.c:971
+msgid "--no-index or --untracked cannot be used with revs."
+msgstr ""
+
+#: builtin/grep.c:974
+msgid "--[no-]exclude-standard cannot be used for tracked contents."
+msgstr ""
+
+#: builtin/grep.c:982
+msgid "both --cached and trees are 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:322 builtin/init-db.c:325
+#, c-format
+msgid "%s already exists"
+msgstr ""
+
+#: builtin/init-db.c:354
+#, c-format
+msgid "unable to handle file type %d"
+msgstr ""
+
+#: builtin/init-db.c:357
+#, c-format
+msgid "unable to move %s to %s"
+msgstr ""
+
+#: builtin/init-db.c:362
+#, 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:419
+#, c-format
+msgid "%s%s Git repository in %s%s\n"
+msgstr ""
+
+#: builtin/init-db.c:420
+msgid "Reinitialized existing"
+msgstr ""
+
+#: builtin/init-db.c:420
+msgid "Initialized empty"
+msgstr ""
+
+#: builtin/init-db.c:421
+msgid " shared"
+msgstr ""
+
+#: builtin/init-db.c:440
+msgid "cannot tell cwd"
+msgstr ""
+
+#: builtin/init-db.c:521 builtin/init-db.c:528
+#, c-format
+msgid "cannot mkdir %s"
+msgstr ""
+
+#: builtin/init-db.c:532
+#, c-format
+msgid "cannot chdir to %s"
+msgstr ""
+
+#: builtin/init-db.c:554
+#, c-format
+msgid ""
+"%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-"
+"dir=<directory>)"
+msgstr ""
+
+#: builtin/init-db.c:578
+msgid "Cannot access current working directory"
+msgstr ""
+
+#: builtin/init-db.c:585
+#, c-format
+msgid "Cannot access work tree '%s'"
+msgstr ""
+
+#: builtin/log.c:187
+#, c-format
+msgid "Final output: %d %s\n"
+msgstr ""
+
+#: builtin/log.c:395 builtin/log.c:483
+#, c-format
+msgid "Could not read object %s"
+msgstr ""
+
+#: builtin/log.c:507
+#, c-format
+msgid "Unknown type: %d"
+msgstr ""
+
+#: builtin/log.c:596
+msgid "format.headers without value"
+msgstr ""
+
+#: builtin/log.c:669
+msgid "name of output directory is too long"
+msgstr ""
+
+#: builtin/log.c:680
+#, c-format
+msgid "Cannot open patch file %s"
+msgstr ""
+
+#: builtin/log.c:694
+msgid "Need exactly one range."
+msgstr ""
+
+#: builtin/log.c:702
+msgid "Not a range."
+msgstr ""
+
+#: builtin/log.c:739
+msgid "Could not extract email from committer identity."
+msgstr ""
+
+#: builtin/log.c:785
+msgid "Cover letter needs email format"
+msgstr ""
+
+#: builtin/log.c:879
+#, c-format
+msgid "insane in-reply-to: %s"
+msgstr ""
+
+#: builtin/log.c:952
+msgid "Two output directories?"
+msgstr ""
+
+#: builtin/log.c:1173
+#, c-format
+msgid "bogus committer info %s"
+msgstr ""
+
+#: builtin/log.c:1218
+msgid "-n and -k are mutually exclusive."
+msgstr ""
+
+#: builtin/log.c:1220
+msgid "--subject-prefix and -k are mutually exclusive."
+msgstr ""
+
+#: builtin/log.c:1225 builtin/shortlog.c:284
+#, c-format
+msgid "unrecognized argument: %s"
+msgstr ""
+
+#: builtin/log.c:1228
+msgid "--name-only does not make sense"
+msgstr ""
+
+#: builtin/log.c:1230
+msgid "--name-status does not make sense"
+msgstr ""
+
+#: builtin/log.c:1232
+msgid "--check does not make sense"
+msgstr ""
+
+#: builtin/log.c:1255
+msgid "standard output, or directory, which one?"
+msgstr ""
+
+#: builtin/log.c:1257
+#, c-format
+msgid "Could not create directory '%s'"
+msgstr ""
+
+#: builtin/log.c:1410
+msgid "Failed to create output files"
+msgstr ""
+
+#: builtin/log.c:1514
+#, c-format
+msgid ""
+"Could not find a tracked remote branch, please specify <upstream> manually.\n"
+msgstr ""
+
+#: builtin/log.c:1530 builtin/log.c:1532 builtin/log.c:1544
+#, c-format
+msgid "Unknown commit %s"
+msgstr ""
+
+#: builtin/merge.c:91
+msgid "switch `m' requires a value"
+msgstr ""
+
+#: builtin/merge.c:128
+#, c-format
+msgid "Could not find merge strategy '%s'.\n"
+msgstr ""
+
+#: builtin/merge.c:129
+#, c-format
+msgid "Available strategies are:"
+msgstr ""
+
+#: builtin/merge.c:134
+#, c-format
+msgid "Available custom strategies are:"
+msgstr ""
+
+#: builtin/merge.c:241
+msgid "could not run stash."
+msgstr ""
+
+#: builtin/merge.c:246
+msgid "stash failed"
+msgstr ""
+
+#: builtin/merge.c:251
+#, c-format
+msgid "not a valid object: %s"
+msgstr ""
+
+#: builtin/merge.c:270 builtin/merge.c:287
+msgid "read-tree failed"
+msgstr ""
+
+#: builtin/merge.c:317
+msgid " (nothing to squash)"
+msgstr ""
+
+#: builtin/merge.c:330
+#, c-format
+msgid "Squash commit -- not updating HEAD\n"
+msgstr ""
+
+#: builtin/merge.c:362
+msgid "Writing SQUASH_MSG"
+msgstr ""
+
+#: builtin/merge.c:364
+msgid "Finishing SQUASH_MSG"
+msgstr ""
+
+#: builtin/merge.c:386
+#, c-format
+msgid "No merge message -- not updating HEAD\n"
+msgstr ""
+
+#: builtin/merge.c:437
+#, c-format
+msgid "'%s' does not point to a commit"
+msgstr ""
+
+#: builtin/merge.c:536
+#, c-format
+msgid "Bad branch.%s.mergeoptions string: %s"
+msgstr ""
+
+#: builtin/merge.c:629
+msgid "git write-tree failed to write a tree"
+msgstr ""
+
+#: builtin/merge.c:679
+msgid "failed to read the cache"
+msgstr ""
+
+#: builtin/merge.c:696
+msgid "Unable to write index."
+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:1000
+#, c-format
+msgid "Automatic merge failed; fix conflicts and then commit the result.\n"
+msgstr ""
+
+#: builtin/merge.c:1016
+#, c-format
+msgid "'%s' is not a commit"
+msgstr ""
+
+#: builtin/merge.c:1057
+msgid "No current branch."
+msgstr ""
+
+#: builtin/merge.c:1059
+msgid "No remote for the current branch."
+msgstr ""
+
+#: builtin/merge.c:1061
+msgid "No default upstream defined for the current branch."
+msgstr ""
+
+#: builtin/merge.c:1066
+#, c-format
+msgid "No remote tracking branch for %s from %s"
+msgstr ""
+
+#: builtin/merge.c:1188
+msgid "There is no merge to abort (MERGE_HEAD missing)."
+msgstr ""
+
+#: builtin/merge.c:1204 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:1207 git-pull.sh:34
+msgid "You have not concluded your merge (MERGE_HEAD exists)."
+msgstr ""
+
+#: builtin/merge.c:1211
+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:1214
+msgid "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)."
+msgstr ""
+
+#: builtin/merge.c:1223
+msgid "You cannot combine --squash with --no-ff."
+msgstr ""
+
+#: builtin/merge.c:1228
+msgid "You cannot combine --no-ff with --ff-only."
+msgstr ""
+
+#: builtin/merge.c:1235
+msgid "No commit specified and merge.defaultToUpstream not set."
+msgstr ""
+
+#: builtin/merge.c:1266
+msgid "Can merge only exactly one commit into empty head"
+msgstr ""
+
+#: builtin/merge.c:1269
+msgid "Squash commit into empty head not supported yet"
+msgstr ""
+
+#: builtin/merge.c:1271
+msgid "Non-fast-forward commit does not make sense into an empty head"
+msgstr ""
+
+#: builtin/merge.c:1275 builtin/merge.c:1319
+#, c-format
+msgid "%s - not something we can merge"
+msgstr ""
+
+#: builtin/merge.c:1385
+#, c-format
+msgid "Updating %s..%s\n"
+msgstr ""
+
+#: builtin/merge.c:1423
+#, c-format
+msgid "Trying really trivial in-index merge...\n"
+msgstr ""
+
+#: builtin/merge.c:1430
+#, c-format
+msgid "Nope.\n"
+msgstr ""
+
+#: builtin/merge.c:1462
+msgid "Not possible to fast-forward, aborting."
+msgstr ""
+
+#: builtin/merge.c:1485 builtin/merge.c:1562
+#, c-format
+msgid "Rewinding the tree to pristine...\n"
+msgstr ""
+
+#: builtin/merge.c:1489
+#, c-format
+msgid "Trying merge strategy %s...\n"
+msgstr ""
+
+#: builtin/merge.c:1553
+#, c-format
+msgid "No merge strategy handled the merge.\n"
+msgstr ""
+
+#: builtin/merge.c:1555
+#, c-format
+msgid "Merge with strategy %s failed.\n"
+msgstr ""
+
+#: builtin/merge.c:1564
+#, c-format
+msgid "Using the %s to prepare resolving by hand.\n"
+msgstr ""
+
+#: builtin/merge.c:1575
+#, c-format
+msgid "Automatic merge went well; stopped before committing as requested\n"
+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
+#, c-format
+msgid "renaming '%s' failed"
+msgstr ""
+
+#: builtin/notes.c:139
+#, c-format
+msgid "unable to start 'show' for object '%s'"
+msgstr ""
+
+#: builtin/notes.c:145
+msgid "can't fdopen 'show' output fd"
+msgstr ""
+
+#: builtin/notes.c:155
+#, c-format
+msgid "failed to close pipe to 'show' for object '%s'"
+msgstr ""
+
+#: builtin/notes.c:158
+#, c-format
+msgid "failed to finish 'show' for object '%s'"
+msgstr ""
+
+#: builtin/notes.c:175 builtin/tag.c:343
+#, 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"
+msgstr ""
+
+#: builtin/notes.c:210 builtin/notes.c:973
+#, c-format
+msgid "Removing note for object %s\n"
+msgstr ""
+
+#: builtin/notes.c:215
+msgid "unable to write note object"
+msgstr ""
+
+#: builtin/notes.c:217
+#, c-format
+msgid "The note contents has been left in %s"
+msgstr ""
+
+#: builtin/notes.c:251 builtin/tag.c:521
+#, c-format
+msgid "cannot read '%s'"
+msgstr ""
+
+#: builtin/notes.c:253 builtin/tag.c:524
+#, c-format
+msgid "could not open or read '%s'"
+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:537
+#, c-format
+msgid "Failed to resolve '%s' as a valid ref."
+msgstr ""
+
+#: builtin/notes.c:275
+#, c-format
+msgid "Failed to read object '%s'."
+msgstr ""
+
+#: builtin/notes.c:299
+msgid "Cannot commit uninitialized/unreferenced notes tree"
+msgstr ""
+
+#: builtin/notes.c:340
+#, c-format
+msgid "Bad notes.rewriteMode value: '%s'"
+msgstr ""
+
+#: builtin/notes.c:350
+#, 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:377
+#, c-format
+msgid "Bad %s value: '%s'"
+msgstr ""
+
+#: builtin/notes.c:441
+#, c-format
+msgid "Malformed input line: '%s'."
+msgstr ""
+
+#: builtin/notes.c:456
+#, c-format
+msgid "Failed to copy notes from '%s' to '%s'"
+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"
+msgstr ""
+
+#: builtin/notes.c:513 builtin/notes.c:772
+#, c-format
+msgid "No note found for object %s."
+msgstr ""
+
+#: builtin/notes.c:580
+#, c-format
+msgid ""
+"Cannot add notes. Found existing notes for object %s. Use '-f' to overwrite "
+"existing notes"
+msgstr ""
+
+#: builtin/notes.c:585 builtin/notes.c:662
+#, c-format
+msgid "Overwriting existing notes for object %s\n"
+msgstr ""
+
+#: builtin/notes.c:635
+msgid "too few parameters"
+msgstr ""
+
+#: builtin/notes.c:656
+#, c-format
+msgid ""
+"Cannot copy notes. Found existing notes for object %s. Use '-f' to overwrite "
+"existing notes"
+msgstr ""
+
+#: builtin/notes.c:668
+#, c-format
+msgid "Missing notes on source object %s. Cannot copy."
+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"
+msgstr ""
+
+#: builtin/notes.c:971
+#, c-format
+msgid "Object %s has no note\n"
+msgstr ""
+
+#: builtin/notes.c:1103
+#, c-format
+msgid "Unknown subcommand: %s"
+msgstr ""
+
+#: builtin/pack-objects.c:2310
+#, c-format
+msgid "unsupported index version %s"
+msgstr ""
+
+#: builtin/pack-objects.c:2314
+#, c-format
+msgid "bad index version '%s'"
+msgstr ""
+
+#: builtin/pack-objects.c:2322
+#, c-format
+msgid "option %s does not accept negative form"
+msgstr ""
+
+#: builtin/pack-objects.c:2326
+#, c-format
+msgid "unable to parse value '%s' for option %s"
+msgstr ""
+
+#: builtin/push.c:44
+msgid "tag shorthand without <tag>"
+msgstr ""
+
+#: builtin/push.c:63
+msgid "--delete only accepts plain target ref names"
+msgstr ""
+
+#: builtin/push.c:73
+#, 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:80
+#, 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:88
+#, c-format
+msgid "The current branch %s has multiple upstream branches, refusing to push."
+msgstr ""
+
+#: builtin/push.c:111
+msgid ""
+"You didn't specify any refspecs to push, and push.default is \"nothing\"."
+msgstr ""
+
+#: builtin/push.c:131
+#, c-format
+msgid "Pushing to %s\n"
+msgstr ""
+
+#: builtin/push.c:135
+#, c-format
+msgid "failed to push some refs to '%s'"
+msgstr ""
+
+#: builtin/push.c:143
+#, c-format
+msgid ""
+"To prevent you from losing history, non-fast-forward updates were rejected\n"
+"Merge the remote changes (e.g. 'git pull') before pushing again. See the\n"
+"'Note about fast-forwards' section of 'git push --help' for details.\n"
+msgstr ""
+
+#: builtin/push.c:160
+#, c-format
+msgid "bad repository '%s'"
+msgstr ""
+
+#: builtin/push.c:161
+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:176
+msgid "--all and --tags are incompatible"
+msgstr ""
+
+#: builtin/push.c:177
+msgid "--all can't be combined with refspecs"
+msgstr ""
+
+#: builtin/push.c:182
+msgid "--mirror and --tags are incompatible"
+msgstr ""
+
+#: builtin/push.c:183
+msgid "--mirror can't be combined with refspecs"
+msgstr ""
+
+#: builtin/push.c:188
+msgid "--all and --mirror are incompatible"
+msgstr ""
+
+#: builtin/push.c:274
+msgid "--delete is incompatible with --all, --mirror and --tags"
+msgstr ""
+
+#: builtin/push.c:276
+msgid "--delete doesn't make sense without any refs"
+msgstr ""
+
+#: builtin/reset.c:33
+msgid "mixed"
+msgstr ""
+
+#: builtin/reset.c:33
+msgid "soft"
+msgstr ""
+
+#: builtin/reset.c:33
+msgid "hard"
+msgstr ""
+
+#: builtin/reset.c:33
+msgid "keep"
+msgstr ""
+
+#: builtin/reset.c:77
+msgid "You do not have a valid HEAD."
+msgstr ""
+
+#: builtin/reset.c:79
+msgid "Failed to find tree of HEAD."
+msgstr ""
+
+#: builtin/reset.c:85
+#, c-format
+msgid "Failed to find tree of %s."
+msgstr ""
+
+#: builtin/reset.c:96
+msgid "Could not write new index file."
+msgstr ""
+
+#: builtin/reset.c:106
+#, c-format
+msgid "HEAD is now at %s"
+msgstr ""
+
+#: 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 "Cannot do a %s reset in the middle of a merge."
+msgstr ""
+
+#: builtin/reset.c:297
+#, c-format
+msgid "Could not parse object '%s'."
+msgstr ""
+
+#: builtin/reset.c:302
+msgid "--patch is incompatible with --{hard,mixed,soft}"
+msgstr ""
+
+#: builtin/reset.c:311
+msgid "--mixed with paths is deprecated; use 'git reset -- <paths>' instead."
+msgstr ""
+
+#: builtin/reset.c:313
+#, c-format
+msgid "Cannot do %s reset with paths."
+msgstr ""
+
+#: builtin/reset.c:325
+#, c-format
+msgid "%s reset is not allowed in a bare repository"
+msgstr ""
+
+#: builtin/reset.c:341
+#, c-format
+msgid "Could not reset index file to revision '%s'."
+msgstr ""
+
+#: builtin/revert.c:70 builtin/revert.c:91
+#, c-format
+msgid "%s: %s cannot be used with %s"
+msgstr ""
+
+#: builtin/revert.c:126
+msgid "program error"
+msgstr ""
+
+#: builtin/revert.c:209
+msgid "revert failed"
+msgstr ""
+
+#: builtin/revert.c:224
+msgid "cherry-pick failed"
+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)"
+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)"
+msgstr ""
+
+#: builtin/rm.c:119
+#, c-format
+msgid ""
+"'%s' has local modifications\n"
+"(use --cached to keep the file, or -f to force removal)"
+msgstr ""
+
+#: builtin/rm.c:194
+#, c-format
+msgid "not removing '%s' recursively without -r"
+msgstr ""
+
+#: builtin/rm.c:230
+#, c-format
+msgid "git rm: unable to remove %s"
+msgstr ""
+
+#: builtin/shortlog.c:157
+#, c-format
+msgid "Missing author: %s"
+msgstr ""
+
+#: builtin/tag.c:58
+#, c-format
+msgid "malformed object at '%s'"
+msgstr ""
+
+#: builtin/tag.c:205
+#, c-format
+msgid "tag name too long: %.*s..."
+msgstr ""
+
+#: builtin/tag.c:210
+#, c-format
+msgid "tag '%s' not found."
+msgstr ""
+
+#: builtin/tag.c:225
+#, c-format
+msgid "Deleted tag '%s' (was %s)\n"
+msgstr ""
+
+#: builtin/tag.c:237
+#, c-format
+msgid "could not verify the tag '%s'"
+msgstr ""
+
+#: builtin/tag.c:247
+msgid ""
+"\n"
+"#\n"
+"# Write a tag message\n"
+"# Lines starting with '#' will be ignored.\n"
+"#\n"
+msgstr ""
+
+#: builtin/tag.c:254
+msgid ""
+"\n"
+"#\n"
+"# Write a tag message\n"
+"# Lines starting with '#' will be kept; you may remove them yourself if you "
+"want to.\n"
+"#\n"
+msgstr ""
+
+#: builtin/tag.c:294
+msgid "unable to sign the tag"
+msgstr ""
+
+#: builtin/tag.c:296
+msgid "unable to write tag file"
+msgstr ""
+
+#: builtin/tag.c:321
+msgid "bad object type."
+msgstr ""
+
+#: builtin/tag.c:334
+msgid "tag header too big."
+msgstr ""
+
+#: builtin/tag.c:366
+msgid "no tag message?"
+msgstr ""
+
+#: builtin/tag.c:372
+#, c-format
+msgid "The tag message has been left in %s\n"
+msgstr ""
+
+#: builtin/tag.c:421
+msgid "switch 'points-at' requires an object"
+msgstr ""
+
+#: builtin/tag.c:423
+#, c-format
+msgid "malformed object name '%s'"
+msgstr ""
+
+#: builtin/tag.c:502
+msgid "-n option is only allowed with -l."
+msgstr ""
+
+#: builtin/tag.c:504
+msgid "--contains option is only allowed with -l."
+msgstr ""
+
+#: builtin/tag.c:506
+msgid "--points-at option is only allowed with -l."
+msgstr ""
+
+#: builtin/tag.c:514
+msgid "only one -F or -m option is allowed."
+msgstr ""
+
+#: builtin/tag.c:534
+msgid "too many params"
+msgstr ""
+
+#: builtin/tag.c:540
+#, c-format
+msgid "'%s' is not a valid tag name."
+msgstr ""
+
+#: builtin/tag.c:545
+#, c-format
+msgid "tag '%s' already exists"
+msgstr ""
+
+#: builtin/tag.c:563
+#, c-format
+msgid "%s: cannot lock the ref"
+msgstr ""
+
+#: builtin/tag.c:565
+#, c-format
+msgid "%s: cannot update the ref"
+msgstr ""
+
+#: builtin/tag.c:567
+#, c-format
+msgid "Updated tag '%s' (was %s)\n"
+msgstr ""
+
+#: git-am.sh:49
+msgid "You need to set your committer info first"
+msgstr ""
+
+#: git-am.sh:136
+msgid "Repository lacks necessary blobs to fall back on 3-way merge."
+msgstr ""
+
+#: git-am.sh:147
+msgid ""
+"Did you hand edit your patch?\n"
+"It does not apply to blobs recorded in its index."
+msgstr ""
+
+#: git-am.sh:156
+msgid "Falling back to patching base and 3-way merge..."
+msgstr ""
+
+#: git-am.sh:268
+msgid "Only one StGIT patch series can be applied at once"
+msgstr ""
+
+#: git-am.sh:355
+#, sh-format
+msgid "Patch format $patch_format is not supported."
+msgstr ""
+
+#: git-am.sh:357
+msgid "Patch format detection failed."
+msgstr ""
+
+#: git-am.sh:411
+msgid "-d option is no longer supported. Do not use."
+msgstr ""
+
+#: git-am.sh:474
+#, sh-format
+msgid "previous rebase directory $dotest still exists but mbox given."
+msgstr ""
+
+#: git-am.sh:479
+msgid "Please make up your mind. --skip or --abort?"
+msgstr ""
+
+#: git-am.sh:506
+msgid "Resolve operation not in progress, we are not resuming."
+msgstr ""
+
+#: git-am.sh:572
+#, sh-format
+msgid "Dirty index: cannot apply patches (dirty: $files)"
+msgstr ""
+
+#: git-am.sh:748
+msgid "cannot be interactive without stdin connected to a terminal."
+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:759
+msgid "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all "
+msgstr ""
+
+#: git-am.sh:795
+#, sh-format
+msgid "Applying: $FIRSTLINE"
+msgstr ""
+
+#: git-am.sh:840
+msgid "No changes -- Patch already applied."
+msgstr ""
+
+#: git-am.sh:866
+msgid "applying to an empty history"
+msgstr ""
+
+#. TRANSLATORS: Make sure to include [Y] and [n] in your
+#. translation. The program will only accept English input
+#. at this point.
+#: git-bisect.sh:54
+msgid "Do you want me to do it for you [Y/n]? "
+msgstr ""
+
+#: git-bisect.sh:95
+#, sh-format
+msgid "unrecognised option: '$arg'"
+msgstr ""
+
+#: git-bisect.sh:99
+#, sh-format
+msgid "'$arg' does not appear to be a valid revision"
+msgstr ""
+
+#: git-bisect.sh:117
+msgid "Bad HEAD - I need a HEAD"
+msgstr ""
+
+#: git-bisect.sh:130
+#, sh-format
+msgid ""
+"Checking out '$start_head' failed. Try 'git bisect reset <validbranch>'."
+msgstr ""
+
+#: git-bisect.sh:140
+msgid "won't bisect on seeked tree"
+msgstr ""
+
+#: git-bisect.sh:144
+msgid "Bad HEAD - strange symbolic ref"
+msgstr ""
+
+#: git-bisect.sh:189
+#, sh-format
+msgid "Bad bisect_write argument: $state"
+msgstr ""
+
+#: git-bisect.sh:218
+#, sh-format
+msgid "Bad rev input: $arg"
+msgstr ""
+
+#: git-bisect.sh:232
+msgid "Please call 'bisect_state' with at least one argument."
+msgstr ""
+
+#: git-bisect.sh:244
+#, sh-format
+msgid "Bad rev input: $rev"
+msgstr ""
+
+#: git-bisect.sh:250
+msgid "'git bisect bad' can take only one argument."
+msgstr ""
+
+#. 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 ""
+
+#: git-bisect.sh:354
+#, sh-format
+msgid "'$invalid' is not a valid commit"
+msgstr ""
+
+#: git-bisect.sh:363
+#, sh-format
+msgid ""
+"Could not check out original HEAD '$branch'.\n"
+"Try 'git bisect reset <commit>'."
+msgstr ""
+
+#: git-bisect.sh:390
+msgid "No logfile given"
+msgstr ""
+
+#: git-bisect.sh:391
+#, sh-format
+msgid "cannot read $file for replaying"
+msgstr ""
+
+#: git-bisect.sh:408
+msgid "?? what are you talking about?"
+msgstr ""
+
+#: git-bisect.sh:474
+msgid "We are not bisecting."
+msgstr ""
+
+#: git-pull.sh:21
+msgid ""
+"Pull is not possible because you have unmerged files.\n"
+"Please, fix them up in the work tree, and then use 'git add/rm <file>'\n"
+"as appropriate to mark resolution, or use 'git commit -a'."
+msgstr ""
+
+#: git-pull.sh:25
+msgid "Pull is not possible because you have unmerged files."
+msgstr ""
+
+#: git-pull.sh:197
+msgid "updating an unborn branch with changes added to the index"
+msgstr ""
+
+#: git-pull.sh:253
+msgid "Cannot merge multiple branches into empty head"
+msgstr ""
+
+#: git-pull.sh:257
+msgid "Cannot rebase onto multiple branches"
+msgstr ""
+
+#: git-stash.sh:51
+msgid "git stash clear with parameters is unimplemented"
+msgstr ""
+
+#: git-stash.sh:74
+msgid "You do not have the initial commit yet"
+msgstr ""
+
+#: git-stash.sh:89
+msgid "Cannot save the current index state"
+msgstr ""
+
+#: git-stash.sh:123 git-stash.sh:136
+msgid "Cannot save the current worktree state"
+msgstr ""
+
+#: git-stash.sh:140
+msgid "No changes selected"
+msgstr ""
+
+#: git-stash.sh:143
+msgid "Cannot remove temporary index (can't happen)"
+msgstr ""
+
+#: git-stash.sh:156
+msgid "Cannot record working tree state"
+msgstr ""
+
+#: git-stash.sh:223
+msgid "No local changes to save"
+msgstr ""
+
+#: git-stash.sh:227
+msgid "Cannot initialize stash"
+msgstr ""
+
+#: git-stash.sh:235
+msgid "Cannot save the current status"
+msgstr ""
+
+#: git-stash.sh:253
+msgid "Cannot remove worktree changes"
+msgstr ""
+
+#: git-stash.sh:352
+msgid "No stash found."
+msgstr ""
+
+#: git-stash.sh:359
+#, sh-format
+msgid "Too many revisions specified: $REV"
+msgstr ""
+
+#: git-stash.sh:365
+#, sh-format
+msgid "$reference is not valid reference"
+msgstr ""
+
+#: git-stash.sh:393
+#, sh-format
+msgid "'$args' is not a stash-like commit"
+msgstr ""
+
+#: git-stash.sh:404
+#, sh-format
+msgid "'$args' is not a stash reference"
+msgstr ""
+
+#: git-stash.sh:412
+msgid "unable to refresh index"
+msgstr ""
+
+#: git-stash.sh:416
+msgid "Cannot apply a stash in the middle of a merge"
+msgstr ""
+
+#: git-stash.sh:424
+msgid "Conflicts in index. Try without --index."
+msgstr ""
+
+#: git-stash.sh:426
+msgid "Could not save index tree"
+msgstr ""
+
+#: git-stash.sh:460
+msgid "Cannot unstage modified files"
+msgstr ""
+
+#: git-stash.sh:491
+#, sh-format
+msgid "Dropped ${REV} ($s)"
+msgstr ""
+
+#: git-stash.sh:492
+#, sh-format
+msgid "${REV}: Could not drop stash entry"
+msgstr ""
+
+#: git-stash.sh:499
+msgid "No branch name specified"
+msgstr ""
+
+#: git-stash.sh:570
+msgid "(To restore them type \"git stash apply\")"
+msgstr ""
+
+#: git-submodule.sh:56
+#, sh-format
+msgid "cannot strip one component off url '$remoteurl'"
+msgstr ""
+
+#: git-submodule.sh:108
+#, sh-format
+msgid "No submodule mapping found in .gitmodules for path '$path'"
+msgstr ""
+
+#: git-submodule.sh:149
+#, sh-format
+msgid "Clone of '$url' into submodule path '$path' failed"
+msgstr ""
+
+#: git-submodule.sh:159
+#, sh-format
+msgid "Gitdir '$a' is part of the submodule path '$b' or vice versa"
+msgstr ""
+
+#: git-submodule.sh:247
+#, sh-format
+msgid "repo URL: '$repo' must be absolute or begin with ./|../"
+msgstr ""
+
+#: git-submodule.sh:264
+#, sh-format
+msgid "'$path' already exists in the index"
+msgstr ""
+
+#: git-submodule.sh:281
+#, sh-format
+msgid "'$path' already exists and is not a valid git repo"
+msgstr ""
+
+#: git-submodule.sh:295
+#, sh-format
+msgid "Unable to checkout submodule '$path'"
+msgstr ""
+
+#: git-submodule.sh:300
+#, sh-format
+msgid "Failed to add submodule '$path'"
+msgstr ""
+
+#: git-submodule.sh:305
+#, sh-format
+msgid "Failed to register submodule '$path'"
+msgstr ""
+
+#: git-submodule.sh:347
+#, sh-format
+msgid "Entering '$prefix$path'"
+msgstr ""
+
+#: git-submodule.sh:359
+#, sh-format
+msgid "Stopping at '$path'; script returned non-zero status."
+msgstr ""
+
+#: git-submodule.sh:401
+#, sh-format
+msgid "No url found for submodule path '$path' in .gitmodules"
+msgstr ""
+
+#: git-submodule.sh:410
+#, sh-format
+msgid "Failed to register url for submodule path '$path'"
+msgstr ""
+
+#: git-submodule.sh:418
+#, sh-format
+msgid "Failed to register update mode for submodule path '$path'"
+msgstr ""
+
+#: git-submodule.sh:420
+#, sh-format
+msgid "Submodule '$name' ($url) registered for path '$path'"
+msgstr ""
+
+#: git-submodule.sh:519
+#, sh-format
+msgid ""
+"Submodule path '$path' not initialized\n"
+"Maybe you want to use 'update --init'?"
+msgstr ""
+
+#: git-submodule.sh:532
+#, sh-format
+msgid "Unable to find current revision in submodule path '$path'"
+msgstr ""
+
+#: git-submodule.sh:551
+#, sh-format
+msgid "Unable to fetch in submodule path '$path'"
+msgstr ""
+
+#: git-submodule.sh:565
+#, sh-format
+msgid "Unable to rebase '$sha1' in submodule path '$path'"
+msgstr ""
+
+#: git-submodule.sh:566
+#, sh-format
+msgid "Submodule path '$path': rebased into '$sha1'"
+msgstr ""
+
+#: git-submodule.sh:571
+#, sh-format
+msgid "Unable to merge '$sha1' in submodule path '$path'"
+msgstr ""
+
+#: git-submodule.sh:572
+#, sh-format
+msgid "Submodule path '$path': merged in '$sha1'"
+msgstr ""
+
+#: git-submodule.sh:577
+#, sh-format
+msgid "Unable to checkout '$sha1' in submodule path '$path'"
+msgstr ""
+
+#: git-submodule.sh:578
+#, sh-format
+msgid "Submodule path '$path': checked out '$sha1'"
+msgstr ""
+
+#: git-submodule.sh:600 git-submodule.sh:923
+#, sh-format
+msgid "Failed to recurse into submodule path '$path'"
+msgstr ""
+
+#: git-submodule.sh:708
+msgid "--"
+msgstr ""
+
+#: git-submodule.sh:766
+#, sh-format
+msgid " Warn: $name doesn't contain commit $sha1_src"
+msgstr ""
+
+#: git-submodule.sh:769
+#, sh-format
+msgid " Warn: $name doesn't contain commit $sha1_dst"
+msgstr ""
+
+#: git-submodule.sh:772
+#, sh-format
+msgid " Warn: $name doesn't contain commits $sha1_src and $sha1_dst"
+msgstr ""
+
+#: git-submodule.sh:797
+msgid "blob"
+msgstr ""
+
+#: git-submodule.sh:798
+msgid "submodule"
+msgstr ""
+
+#: git-submodule.sh:969
+#, sh-format
+msgid "Synchronizing submodule url for '$name'"
+msgstr ""
diff --git a/po/de.po b/po/de.po
new file mode 100644
index 0000000000..591ba507d1
--- /dev/null
+++ b/po/de.po
@@ -0,0 +1,3809 @@
+# German translations for Git.
+# Copyright (C) 2012 Ralf Thielow <ralf.thielow@googlemail.com>
+# This file is distributed under the same license as the Git package.
+# Ralf Thielow <ralf.thielow@googlemail.com>, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: git 1.7.10\n"
+"Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
+"POT-Creation-Date: 2012-05-15 06:31+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"
+"Language: de\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: advice.c:40
+#, c-format
+msgid "hint: %.*s\n"
+msgstr "Hinweis: %.*s\n"
+
+#.
+#. * Message used both when 'git commit' fails and when
+#. * other commands doing a merge do.
+#.
+#: advice.c:70
+msgid ""
+"Fix them up in the work tree,\n"
+"and then use 'git add/rm <file>' as\n"
+"appropriate to mark resolution and make a commit,\n"
+"or use 'git commit -a'."
+msgstr ""
+"Korrigiere dies im Arbeitsbaum,\n"
+"und benutze dann 'git add/rm <Datei>'\n"
+"um die Auflösung entsprechend zu markieren und einzutragen,\n"
+"oder benutze 'git commit -a'."
+
+#: commit.c:47
+#, c-format
+msgid "could not parse %s"
+msgstr "konnte %s nicht parsen"
+
+#: commit.c:49
+#, c-format
+msgid "%s %s is not a commit!"
+msgstr "%s %s ist keine Version!"
+
+#: compat/obstack.c:406 compat/obstack.c:408
+msgid "memory exhausted"
+msgstr "Speicher verbraucht"
+
+#: connected.c:39
+msgid "Could not run 'git rev-list'"
+msgstr "Konnte 'git rev-list' nicht ausführen"
+
+#: connected.c:48
+#, c-format
+msgid "failed write to rev-list: %s"
+msgstr "Fehler beim Schreiben nach rev-list: %s"
+
+#: connected.c:56
+#, c-format
+msgid "failed to close rev-list's stdin: %s"
+msgstr "Fehler beim Schließen von rev-list's Standard-Eingabe: %s"
+
+#: diff.c:105
+#, c-format
+msgid " Failed to parse dirstat cut-off percentage '%.*s'\n"
+msgstr ""
+" Fehler beim Parsen des abgeschnittenen \"dirstat\" Prozentsatzes '%.*s'\n"
+
+#: diff.c:110
+#, c-format
+msgid " Unknown dirstat parameter '%.*s'\n"
+msgstr " Unbekannter \"dirstat\" Parameter '%.*s'\n"
+
+#: diff.c:210
+#, c-format
+msgid ""
+"Found errors in 'diff.dirstat' config variable:\n"
+"%s"
+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:1404
+#, 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
+#, c-format
+msgid ", %d insertion(+)"
+msgid_plural ", %d insertions(+)"
+msgstr[0] ", %d Zeile hinzugefügt(+)"
+msgstr[1] ", %d Zeilen hinzugefügt(+)"
+
+#: diff.c:1432
+#, c-format
+msgid ", %d deletion(-)"
+msgid_plural ", %d deletions(-)"
+msgstr[0] ", %d Zeile entfernt(-)"
+msgstr[1] ", %d Zeilen entfernt(-)"
+
+#: diff.c:3439
+#, c-format
+msgid ""
+"Failed to parse --dirstat/-X option parameter:\n"
+"%s"
+msgstr ""
+"Fehler beim Parsen des --dirstat/-X Optionsparameters:\n"
+"%s"
+
+#: gpg-interface.c:59
+msgid "could not run gpg."
+msgstr "konnte gpg nicht ausführen"
+
+#: gpg-interface.c:71
+msgid "gpg did not accept the data"
+msgstr "gpg hat die Daten nicht akzeptiert"
+
+#: gpg-interface.c:82
+msgid "gpg failed to sign the data"
+msgstr "gpg beim Signieren der Daten fehlgeschlagen"
+
+#: grep.c:1280
+#, c-format
+msgid "'%s': unable to read %s"
+msgstr "'%s': konnte nicht lesen %s"
+
+#: grep.c:1297
+#, c-format
+msgid "'%s': %s"
+msgstr "'%s': %s"
+
+#: grep.c:1308
+#, c-format
+msgid "'%s': short read %s"
+msgstr "'%s': read() zu kurz %s"
+
+#: help.c:287
+#, 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' scheint ein git-Kommando zu sein, konnte aber\n"
+"nicht ausgeführt werden. Vielleicht ist git-%s fehlerhaft?"
+
+#: remote.c:1607
+#, 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:1613
+#, 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] ""
+"Dein Zweig ist zu '%s' um %d Version hinterher, und kann vorgespult werden.\n"
+msgstr[1] ""
+"Dein Zweig ist zu '%s' um %d Versionen hinterher, und kann vorgespult "
+"werden.\n"
+
+#: remote.c:1621
+#, c-format
+msgid ""
+"Your branch and '%s' have diverged,\n"
+"and have %d and %d different commit each, respectively.\n"
+msgid_plural ""
+"Your branch and '%s' have diverged,\n"
+"and have %d and %d different commits each, respectively.\n"
+msgstr[0] ""
+"Dein Zweig und '%s' sind divergiert,\n"
+"und haben jeweils %d und %d unterschiedliche Versionen.\n"
+msgstr[1] ""
+"Dein Zweig und '%s' sind divergiert,\n"
+"und haben jeweils %d und %d unterschiedliche Versionen.\n"
+
+#: sequencer.c:120 builtin/merge.c:865 builtin/merge.c:978
+#: builtin/merge.c:1088 builtin/merge.c:1098
+#, c-format
+msgid "Could not open '%s' for writing"
+msgstr "Konnte '%s' nicht zum Schreiben öffnen."
+
+#: sequencer.c:122 builtin/merge.c:333 builtin/merge.c:868
+#: builtin/merge.c:1090 builtin/merge.c:1103
+#, c-format
+msgid "Could not write to '%s'"
+msgstr "Konnte nicht nach '%s' schreiben."
+
+#: sequencer.c:143
+msgid ""
+"after resolving the conflicts, mark the corrected paths\n"
+"with 'git add <paths>' or 'git rm <paths>'"
+msgstr ""
+"nach Auflösung der Konflikte, markiere die korrigierten Pfade\n"
+"mit 'git add <Pfade>' oder 'git rm <Pfade>'"
+
+#: sequencer.c:146
+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 ""
+"nach Auflösung der Konflikte, markiere die korrigierten Pfade\n"
+"mit 'git add <Pfade>' oder 'git rm <Pfade>'und trage das Ergebnis ein mit "
+"'git commit'"
+
+#: sequencer.c:159 sequencer.c:685 sequencer.c:768
+#, c-format
+msgid "Could not write to %s"
+msgstr "Konnte nicht nach %s schreiben"
+
+#: sequencer.c:162
+#, c-format
+msgid "Error wrapping up %s"
+msgstr "Fehler bei Nachbereitung von %s"
+
+#: sequencer.c:177
+msgid "Your local changes would be overwritten by cherry-pick."
+msgstr ""
+"Deine lokalen Änderungen würden von \"cherry-pick\" überschrieben werden."
+
+#: sequencer.c:179
+msgid "Your local changes would be overwritten by revert."
+msgstr "Deine lokalen Änderungen würden von \"revert\" überschrieben werden."
+
+#: sequencer.c:182
+msgid "Commit your changes or stash them to proceed."
+msgstr "Trage deine Änderungen ein oder benutze \"stash\" um fortzufahren."
+
+#. TRANSLATORS: %s will be "revert" or "cherry-pick"
+#: sequencer.c:232
+#, c-format
+msgid "%s: Unable to write new index file"
+msgstr "%s: Konnte neue Bereitstellungsdatei nicht schreiben"
+
+#: sequencer.c:298
+msgid "Your index file is unmerged."
+msgstr "Deine Bereitstellungsdatei ist nicht zusammengeführt."
+
+#: sequencer.c:301
+msgid "You do not have a valid HEAD"
+msgstr "Du hast keine gültige Zweigspitze (HEAD)"
+
+#: sequencer.c:316
+#, c-format
+msgid "Commit %s is a merge but no -m option was given."
+msgstr ""
+"Version %s ist eine Zusammenführung, aber die Option -m wurde nicht "
+"angegeben."
+
+#: sequencer.c:324
+#, c-format
+msgid "Commit %s does not have parent %d"
+msgstr "Version %s hat keinen Elternteil %d"
+
+#: sequencer.c:328
+#, c-format
+msgid "Mainline was specified but commit %s is not a merge."
+msgstr ""
+"Hauptlinie wurde spezifiziert, aber Version %s ist keine Zusammenführung."
+
+#. TRANSLATORS: The first %s will be "revert" or
+#. "cherry-pick", the second %s a SHA1
+#: sequencer.c:339
+#, c-format
+msgid "%s: cannot parse parent commit %s"
+msgstr "%s: kann Elternversion %s nicht parsen"
+
+#: sequencer.c:343
+#, c-format
+msgid "Cannot get commit message for %s"
+msgstr "Kann keine Versionsbeschreibung für %s bekommen"
+
+#: sequencer.c:427
+#, c-format
+msgid "could not revert %s... %s"
+msgstr "Konnte %s nicht zurücksetzen... %s"
+
+#: sequencer.c:428
+#, c-format
+msgid "could not apply %s... %s"
+msgstr "Konnte %s nicht anwenden... %s"
+
+#: sequencer.c:450 sequencer.c:909 builtin/log.c:288 builtin/log.c:713
+#: builtin/log.c:1329 builtin/log.c:1548 builtin/merge.c:347
+#: builtin/shortlog.c:181
+msgid "revision walk setup failed"
+msgstr "Einrichtung des Revisionsgangs fehlgeschlagen"
+
+#: sequencer.c:453
+msgid "empty commit set passed"
+msgstr "leere Menge von Versionen übergeben"
+
+#: sequencer.c:461
+#, c-format
+msgid "git %s: failed to read the index"
+msgstr "git %s: Fehler beim Lesen der Bereitstellung"
+
+#: sequencer.c:466
+#, c-format
+msgid "git %s: failed to refresh the index"
+msgstr "git %s: Fehler beim Aktualisieren der Bereitstellung"
+
+#: sequencer.c:551
+#, c-format
+msgid "Cannot %s during a %s"
+msgstr "Kann %s nicht während eines %s durchführen"
+
+#: sequencer.c:573
+#, c-format
+msgid "Could not parse line %d."
+msgstr "Konnte Zeile %d nicht parsen."
+
+#: sequencer.c:578
+msgid "No commits parsed."
+msgstr "Keine Versionen geparst."
+
+#: sequencer.c:591
+#, c-format
+msgid "Could not open %s"
+msgstr "Konnte %s nicht öffnen"
+
+#: sequencer.c:595
+#, c-format
+msgid "Could not read %s."
+msgstr "Konnte %s nicht lesen."
+
+#: sequencer.c:602
+#, c-format
+msgid "Unusable instruction sheet: %s"
+msgstr "Unbenutzbares Instruktionsblatt: %s"
+
+#: sequencer.c:630
+#, c-format
+msgid "Invalid key: %s"
+msgstr "Ungültiger Schlüssel: %s"
+
+#: sequencer.c:633
+#, c-format
+msgid "Invalid value for %s: %s"
+msgstr "Ungültiger Wert für %s: %s"
+
+#: sequencer.c:645
+#, c-format
+msgid "Malformed options sheet: %s"
+msgstr "Fehlerhaftes Optionsblatt: %s"
+
+#: sequencer.c:666
+msgid "a cherry-pick or revert is already in progress"
+msgstr "\"cherry-pick\" oder \"revert\" ist bereits im Gang"
+
+#: sequencer.c:667
+msgid "try \"git cherry-pick (--continue | --quit | --abort)\""
+msgstr "versuche \"git cherry-pick (--continue | --quit | --abort)\""
+
+#: sequencer.c:671
+#, c-format
+msgid "Could not create sequencer directory %s"
+msgstr "Konnte \"sequencer\"-Verzeichnis %s nicht erstellen"
+
+#: sequencer.c:687 sequencer.c:772
+#, c-format
+msgid "Error wrapping up %s."
+msgstr "Fehler beim Einpacken von %s."
+
+#: sequencer.c:706 sequencer.c:840
+msgid "no cherry-pick or revert in progress"
+msgstr "kein \"cherry-pick\" oder \"revert\" im Gang"
+
+#: sequencer.c:708
+msgid "cannot resolve HEAD"
+msgstr "kann Zweigspitze (HEAD) nicht auflösen"
+
+#: sequencer.c:710
+msgid "cannot abort from a branch yet to be born"
+msgstr "kann nicht abbrechen: bin auf einem Zweig, der noch geboren wird"
+
+#: sequencer.c:732
+#, c-format
+msgid "cannot open %s: %s"
+msgstr "Kann %s nicht öffnen: %s"
+
+#: sequencer.c:735
+#, c-format
+msgid "cannot read %s: %s"
+msgstr "Kann %s nicht lesen: %s"
+
+#: sequencer.c:736
+msgid "unexpected end of file"
+msgstr "Unerwartetes Dateiende"
+
+#: sequencer.c:742
+#, c-format
+msgid "stored pre-cherry-pick HEAD file '%s' is corrupt"
+msgstr ""
+"gespeicherte \"pre-cherry-pick\" Datei der Zweigspitze (HEAD) '%s' ist "
+"beschädigt"
+
+#: sequencer.c:765
+#, c-format
+msgid "Could not format %s."
+msgstr "Konnte %s nicht formatieren."
+
+#: sequencer.c:927
+msgid "Can't revert as initial commit"
+msgstr "Kann nicht zu initialer Version zurücksetzen."
+
+#: sequencer.c:928
+msgid "Can't cherry-pick into empty head"
+msgstr "Kann \"cherry-pick\" nicht in einen leeren Kopf ausführen."
+
+#: wt-status.c:134
+msgid "Unmerged paths:"
+msgstr "Nicht zusammengeführte Pfade:"
+
+#: wt-status.c:140 wt-status.c:157
+#, c-format
+msgid " (use \"git reset %s <file>...\" to unstage)"
+msgstr ""
+" (benutze \"git reset %s <Datei>...\" zum Herausnehmen aus der "
+"Bereitstellung)"
+
+#: wt-status.c:142 wt-status.c:159
+msgid " (use \"git rm --cached <file>...\" to unstage)"
+msgstr ""
+" (benutze \"git rm --cached <Datei>...\" zum Herausnehmen aus der "
+"Bereitstellung)"
+
+#: wt-status.c:143
+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:151
+msgid "Changes to be committed:"
+msgstr "zum Eintragen bereitgestellte Änderungen:"
+
+#: wt-status.c:169
+msgid "Changes not staged for commit:"
+msgstr "Änderungen, die nicht zum Eintragen bereitgestellt sind:"
+
+#: wt-status.c:173
+msgid " (use \"git add <file>...\" to update what will be committed)"
+msgstr " (benutze \"git add <Datei>...\" zum Bereitstellen)"
+
+#: wt-status.c:175
+msgid " (use \"git add/rm <file>...\" to update what will be committed)"
+msgstr " (benutze \"git add/rm <Datei>...\" zum Bereitstellen)"
+
+#: wt-status.c:176
+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:178
+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:187
+#, c-format
+msgid "%s files:"
+msgstr "%s Dateien:"
+
+#: wt-status.c:190
+#, 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:207
+msgid "bug"
+msgstr "Fehler"
+
+#: wt-status.c:212
+msgid "both deleted:"
+msgstr "beide gelöscht:"
+
+#: wt-status.c:213
+msgid "added by us:"
+msgstr "von uns hinzugefügt:"
+
+#: wt-status.c:214
+msgid "deleted by them:"
+msgstr "von denen gelöscht:"
+
+#: wt-status.c:215
+msgid "added by them:"
+msgstr "von denen hinzugefügt:"
+
+#: wt-status.c:216
+msgid "deleted by us:"
+msgstr "von uns gelöscht:"
+
+#: wt-status.c:217
+msgid "both added:"
+msgstr "von beiden hinzugefügt:"
+
+#: wt-status.c:218
+msgid "both modified:"
+msgstr "von beiden geändert:"
+
+#: wt-status.c:248
+msgid "new commits, "
+msgstr "neue Versionen, "
+
+#: wt-status.c:250
+msgid "modified content, "
+msgstr "geänderter Inhalt, "
+
+#: wt-status.c:252
+msgid "untracked content, "
+msgstr "unbeobachteter Inhalt, "
+
+#: wt-status.c:266
+#, c-format
+msgid "new file: %s"
+msgstr "neue Datei: %s"
+
+#: wt-status.c:269
+#, c-format
+msgid "copied: %s -> %s"
+msgstr "kopiert: %s -> %s"
+
+#: wt-status.c:272
+#, c-format
+msgid "deleted: %s"
+msgstr "gelöscht: %s"
+
+#: wt-status.c:275
+#, c-format
+msgid "modified: %s"
+msgstr "geändert: %s"
+
+#: wt-status.c:278
+#, c-format
+msgid "renamed: %s -> %s"
+msgstr "umbenannt: %s -> %s"
+
+#: wt-status.c:281
+#, c-format
+msgid "typechange: %s"
+msgstr "Typänderung: %s"
+
+#: wt-status.c:284
+#, c-format
+msgid "unknown: %s"
+msgstr "unbekannt: %s"
+
+#: wt-status.c:287
+#, c-format
+msgid "unmerged: %s"
+msgstr "nicht zusammengeführt: %s"
+
+#: wt-status.c:290
+#, c-format
+msgid "bug: unhandled diff status %c"
+msgstr "Fehler: unbehandelter Differenz-Status %c"
+
+#: wt-status.c:713
+msgid "On branch "
+msgstr "Auf Zweig "
+
+#: wt-status.c:720
+msgid "Not currently on any branch."
+msgstr "Im Moment auf keinem Zweig."
+
+#: wt-status.c:731
+msgid "Initial commit"
+msgstr "Initiale Version"
+
+#: wt-status.c:745
+msgid "Untracked"
+msgstr "Unbeobachtete"
+
+#: wt-status.c:747
+msgid "Ignored"
+msgstr "Ignorierte"
+
+#: wt-status.c:749
+#, c-format
+msgid "Untracked files not listed%s"
+msgstr "Unbeobachtete Dateien nicht aufgelistet%s"
+
+#: wt-status.c:751
+msgid " (use -u option to show untracked files)"
+msgstr " (benutze die Option -u um unbeobachteten Dateien anzuzeigen)"
+
+#: wt-status.c:757
+msgid "No changes"
+msgstr "Keine Änderungen"
+
+#: wt-status.c:761
+#, c-format
+msgid "no changes added to commit%s\n"
+msgstr "keine Änderungen zum Eintragen hinzugefügt%s\n"
+
+#: wt-status.c:763
+msgid " (use \"git add\" and/or \"git commit -a\")"
+msgstr " (benutze \"git add\" und/oder \"git commit -a\")"
+
+#: wt-status.c:765
+#, 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:767
+msgid " (use \"git add\" to track)"
+msgstr " (benutze \"git add\" zum Beobachten)"
+
+#: wt-status.c:769 wt-status.c:772 wt-status.c:775
+#, c-format
+msgid "nothing to commit%s\n"
+msgstr "nichts zum Eintragen%s\n"
+
+#: wt-status.c:770
+msgid " (create/copy files and use \"git add\" to track)"
+msgstr " (Erstelle/Kopiere Dateien und benutze \"git add\" zum Beobachten)"
+
+#: wt-status.c:773
+msgid " (use -u to show untracked files)"
+msgstr " (benutze die Option -u um unbeobachtete Dateien anzuzeigen)"
+
+#: wt-status.c:776
+msgid " (working directory clean)"
+msgstr " (Arbeitsverzeichnis sauber)"
+
+#: wt-status.c:884
+msgid "HEAD (no branch)"
+msgstr "HEAD (kein Zweig)"
+
+#: wt-status.c:890
+msgid "Initial commit on "
+msgstr "Initiale Version auf "
+
+#: wt-status.c:905
+msgid "behind "
+msgstr "hinterher "
+
+#: wt-status.c:908 wt-status.c:911
+msgid "ahead "
+msgstr "voraus "
+
+#: wt-status.c:913
+msgid ", behind "
+msgstr ", hinterher "
+
+#: builtin/add.c:62
+#, c-format
+msgid "unexpected diff status %c"
+msgstr "unerwarteter Differenz-Status %c"
+
+#: builtin/add.c:67 builtin/commit.c:298
+msgid "updating files failed"
+msgstr "Aktualisierung der Dateien fehlgeschlagen"
+
+#: builtin/add.c:77
+#, c-format
+msgid "remove '%s'\n"
+msgstr "entferne '%s'\n"
+
+#: builtin/add.c:176
+#, c-format
+msgid "Path '%s' is in submodule '%.*s'"
+msgstr "Pfad '%s' befindet sich in Unterprojekt '%.*s'"
+
+#: builtin/add.c:192
+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
+#, c-format
+msgid "pathspec '%s' did not match any files"
+msgstr "Pfadspezifikation '%s' stimmt mit keinen Dateien überein"
+
+#: builtin/add.c:209
+#, c-format
+msgid "'%s' is beyond a symbolic link"
+msgstr "'%s' ist über einer symbolischen Verknüpfung"
+
+#: builtin/add.c:276
+msgid "Could not read the index"
+msgstr "Konnte die Bereitstellung nicht lesen"
+
+#: builtin/add.c:286
+#, c-format
+msgid "Could not open '%s' for writing."
+msgstr "Konnte '%s' nicht zum Schreiben öffnen."
+
+#: builtin/add.c:290
+msgid "Could not write patch"
+msgstr "Konnte Patch nicht schreiben"
+
+#: builtin/add.c:295
+#, c-format
+msgid "Could not stat '%s'"
+msgstr "Konnte Verzeichnis '%s' nicht lesen"
+
+#: builtin/add.c:297
+msgid "Empty patch. Aborted."
+msgstr "Leerer Patch. Abgebrochen."
+
+#: builtin/add.c:303
+#, c-format
+msgid "Could not apply '%s'"
+msgstr "Konnte '%s' nicht anwenden."
+
+#: builtin/add.c:312
+msgid "The following paths are ignored by one of your .gitignore files:\n"
+msgstr ""
+"Die folgenden Pfade werden durch eine deiner \".gitignore\" Dateien "
+"ignoriert:\n"
+
+#: builtin/add.c:352
+#, c-format
+msgid "Use -f if you really want to add them.\n"
+msgstr "Verwende -f wenn du diese wirklich hinzufügen möchtest.\n"
+
+#: builtin/add.c:353
+msgid "no files added"
+msgstr "keine Dateien hinzugefügt"
+
+#: builtin/add.c:359
+msgid "adding files failed"
+msgstr "Hinzufügen von Dateien fehlgeschlagen"
+
+#: builtin/add.c:391
+msgid "-A and -u are mutually incompatible"
+msgstr "-A und -u sind zueinander inkompatibel"
+
+#: builtin/add.c:393
+msgid "Option --ignore-missing can only be used together with --dry-run"
+msgstr ""
+"Die Option --ignore-missing kann nur zusammen mit --dry-run benutzt werden."
+
+#: builtin/add.c:413
+#, c-format
+msgid "Nothing specified, nothing added.\n"
+msgstr "Nichts spezifiziert, nichts hinzugefügt.\n"
+
+#: builtin/add.c:414
+#, c-format
+msgid "Maybe you wanted to say 'git add .'?\n"
+msgstr "Wolltest du vielleicht 'git add .' sagen?\n"
+
+#: builtin/add.c:420 builtin/clean.c:95 builtin/commit.c:358 builtin/mv.c:82
+#: builtin/rm.c:162
+msgid "index file corrupt"
+msgstr "Bereitstellungsdatei beschädigt"
+
+#: builtin/add.c:476 builtin/mv.c:229 builtin/rm.c:260
+msgid "Unable to write new index file"
+msgstr "Konnte neue Bereitstellungsdatei nicht schreiben."
+
+#: builtin/archive.c:17
+#, c-format
+msgid "could not create archive file '%s'"
+msgstr "Konnte Archiv-Datei '%s' nicht erstellen."
+
+#: builtin/archive.c:20
+msgid "could not redirect output"
+msgstr "Konnte Ausgabe nicht umleiten."
+
+#: builtin/archive.c:37
+msgid "git archive: Remote with no URL"
+msgstr "git archive: Externes Archiv ohne URL"
+
+#: builtin/archive.c:58
+msgid "git archive: expected ACK/NAK, got EOF"
+msgstr "git archive: habe ACK/NAK erwartet, aber EOF bekommen"
+
+#: builtin/archive.c:63
+#, c-format
+msgid "git archive: NACK %s"
+msgstr "git archive: NACK %s"
+
+#: builtin/archive.c:65
+#, c-format
+msgid "remote error: %s"
+msgstr "Fehler am anderen Ende: %s"
+
+#: builtin/archive.c:66
+msgid "git archive: protocol error"
+msgstr "git archive: Protokollfehler"
+
+#: builtin/archive.c:71
+msgid "git archive: expected a flush"
+msgstr "git archive: erwartete eine Leerung (flush)"
+
+#: builtin/branch.c:137
+#, c-format
+msgid ""
+"deleting branch '%s' that has been merged to\n"
+" '%s', but not yet merged to HEAD."
+msgstr ""
+"entferne Zweig '%s', der zusammengeführt wurde mit\n"
+" '%s', aber noch nicht mit der Zweigspitze (HEAD) zusammengeführt "
+"wurde."
+
+#: builtin/branch.c:141
+#, c-format
+msgid ""
+"not deleting branch '%s' that is not yet merged to\n"
+" '%s', even though it is merged to HEAD."
+msgstr ""
+"entferne Zweig '%s' nicht, der noch nicht zusammengeführt wurde mit\n"
+" '%s', obwohl er mit der Zweigspitze (HEAD) zusammengeführt wurde."
+
+#. TRANSLATORS: This is "remote " in "remote branch '%s' not found"
+#: builtin/branch.c:163
+msgid "remote "
+msgstr "externer "
+
+#: builtin/branch.c:171
+msgid "cannot use -a with -d"
+msgstr "kann -a nicht mit -d benutzen"
+
+#: builtin/branch.c:177
+msgid "Couldn't look up commit object for HEAD"
+msgstr "Konnte Versionsobjekt für Zweigspitze (HEAD) nicht nachschlagen."
+
+#: builtin/branch.c:182
+#, c-format
+msgid "Cannot delete the branch '%s' which you are currently on."
+msgstr ""
+"Kann Zweig '%s' nicht entfernen, da du dich gerade auf diesem befindest."
+
+#: builtin/branch.c:192
+#, c-format
+msgid "%sbranch '%s' not found."
+msgstr "%sZweig '%s' nicht gefunden."
+
+#: builtin/branch.c:200
+#, c-format
+msgid "Couldn't look up commit object for '%s'"
+msgstr "Konnte Versionsobjekt für '%s' nicht nachschlagen."
+
+#: builtin/branch.c:206
+#, c-format
+msgid ""
+"The branch '%s' is not fully merged.\n"
+"If you are sure you want to delete it, run 'git branch -D %s'."
+msgstr ""
+"Der Zweig '%s' ist nicht vollständig zusammengeführt.\n"
+"Wenn du sicher bist diesen Zweig zu entfernen, führe 'git branch -D %s' aus."
+
+#: builtin/branch.c:214
+#, c-format
+msgid "Error deleting %sbranch '%s'"
+msgstr "Fehler beim Löschen von %sZweig '%s'"
+
+#: builtin/branch.c:219
+#, c-format
+msgid "Deleted %sbranch %s (was %s).\n"
+msgstr "Entferne %sZweig %s (war %s).\n"
+
+#: builtin/branch.c:224
+msgid "Update of config-file failed"
+msgstr "Aktualisierung der Konfigurationsdatei fehlgeschlagen."
+
+#: builtin/branch.c:322
+#, c-format
+msgid "branch '%s' does not point at a commit"
+msgstr "Zweig '%s' zeigt auf keine Version"
+
+#: builtin/branch.c:394
+#, c-format
+msgid "behind %d] "
+msgstr "%d hinterher] "
+
+#: builtin/branch.c:396
+#, c-format
+msgid "ahead %d] "
+msgstr "%d voraus] "
+
+#: builtin/branch.c:398
+#, c-format
+msgid "ahead %d, behind %d] "
+msgstr "%d voraus, %d hinterher] "
+
+#: builtin/branch.c:501
+msgid "(no branch)"
+msgstr "(kein Zweig)"
+
+#: builtin/branch.c:566
+msgid "some refs could not be read"
+msgstr "Konnte einige Referenzen nicht lesen"
+
+#: builtin/branch.c:579
+msgid "cannot rename the current branch while not on any."
+msgstr ""
+"Kann aktuellen Zweig nicht umbennen, solange du dich auf keinem befindest."
+
+#: builtin/branch.c:589
+#, c-format
+msgid "Invalid branch name: '%s'"
+msgstr "Ungültiger Zweig-Name: '%s'"
+
+#: builtin/branch.c:604
+msgid "Branch rename failed"
+msgstr "Umbenennung des Zweiges fehlgeschlagen"
+
+#: builtin/branch.c:608
+#, c-format
+msgid "Renamed a misnamed branch '%s' away"
+msgstr "falsch benannten Zweig '%s' umbenannt"
+
+#: builtin/branch.c:612
+#, c-format
+msgid "Branch renamed to %s, but HEAD is not updated!"
+msgstr "Zweig umbenannt zu %s, aber Zweigspitze (HEAD) ist nicht aktualisiert!"
+
+#: builtin/branch.c:619
+msgid "Branch is renamed, but update of config-file failed"
+msgstr ""
+"Zweig ist umbenannt, aber die Aktualisierung der Konfigurationsdatei ist "
+"fehlgeschlagen."
+
+#: builtin/branch.c:634
+#, c-format
+msgid "malformed object name %s"
+msgstr "Missgebildeter Objektname %s"
+
+#: builtin/branch.c:658
+#, c-format
+msgid "could not write branch description template: %s\n"
+msgstr "Konnte Beschreibungsvorlage für Zweig nicht schreiben: %s\n"
+
+#: builtin/branch.c:746
+msgid "Failed to resolve HEAD as a valid ref."
+msgstr "Konnte Zweigspitze (HEAD) nicht als gültige Referenz auflösen."
+
+#: builtin/branch.c:751 builtin/clone.c:558
+msgid "HEAD not found below refs/heads!"
+msgstr "Zweigspitze (HEAD) wurde nicht unter \"refs/heads\" gefunden!"
+
+#: builtin/branch.c:809
+msgid "-a and -r options to 'git branch' do not make sense with a branch name"
+msgstr ""
+"Die Optionen -a und -r bei 'git branch' machen mit einem Zweignamen keinen "
+"Sinn."
+
+#: builtin/bundle.c:47
+#, c-format
+msgid "%s is okay\n"
+msgstr "%s ist in Ordnung\n"
+
+#: builtin/bundle.c:56
+msgid "Need a repository to create a bundle."
+msgstr "Um ein Paket zu erstellen wird ein Projektarchiv benötigt."
+
+#: builtin/bundle.c:60
+msgid "Need a repository to unbundle."
+msgstr "Zum Entpacken wird ein Projektarchiv benötigt."
+
+#: builtin/checkout.c:113 builtin/checkout.c:146
+#, 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
+#, c-format
+msgid "path '%s' does not have their version"
+msgstr "Pfad '%s' hat nicht deren Version."
+
+#: builtin/checkout.c:131
+#, c-format
+msgid "path '%s' does not have all necessary versions"
+msgstr "Pfad '%s' hat nicht alle notwendigen Versionen."
+
+#: builtin/checkout.c:175
+#, c-format
+msgid "path '%s' does not have necessary versions"
+msgstr "Pfad '%s' hat nicht die notwendigen Versionen."
+
+#: builtin/checkout.c:192
+#, c-format
+msgid "path '%s': cannot merge"
+msgstr "Pfad '%s': kann nicht zusammenführen"
+
+#: builtin/checkout.c:209
+#, c-format
+msgid "Unable to add merge result for '%s'"
+msgstr "Konnte Ergebnis der Zusammenführung von '%s' nicht hinzufügen."
+
+#: builtin/checkout.c:212 builtin/reset.c:158
+#, c-format
+msgid "make_cache_entry failed for path '%s'"
+msgstr "make_cache_entry für Pfad '%s' fehlgeschlagen"
+
+#: builtin/checkout.c:234 builtin/checkout.c:392
+msgid "corrupt index file"
+msgstr "beschädigte Bereitstellungsdatei"
+
+#: builtin/checkout.c:264 builtin/checkout.c:271
+#, 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
+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."
+
+#: builtin/checkout.c:533
+#, c-format
+msgid "Can not do reflog for '%s'\n"
+msgstr "Konnte \"reflog\" für '%s' nicht durchführen\n"
+
+#: builtin/checkout.c:565
+msgid "HEAD is now at"
+msgstr "Zweigspitze (HEAD) ist jetzt bei"
+
+#: builtin/checkout.c:572
+#, c-format
+msgid "Reset branch '%s'\n"
+msgstr "Setze Zweig '%s' zurück\n"
+
+#: builtin/checkout.c:575
+#, c-format
+msgid "Already on '%s'\n"
+msgstr "Bereits auf '%s'\n"
+
+#: builtin/checkout.c:579
+#, c-format
+msgid "Switched to and reset branch '%s'\n"
+msgstr "Gewechselt zu zurückgesetztem Zweig '%s'\n"
+
+#: builtin/checkout.c:581
+#, c-format
+msgid "Switched to a new branch '%s'\n"
+msgstr "Gewechselt zu einem neuen Zweig '%s'\n"
+
+#: builtin/checkout.c:583
+#, c-format
+msgid "Switched to branch '%s'\n"
+msgstr "Gewechselt zu Zweig '%s'\n"
+
+#: builtin/checkout.c:639
+#, c-format
+msgid " ... and %d more.\n"
+msgstr " ... und %d weitere.\n"
+
+#. The singular version
+#: builtin/checkout.c:645
+#, 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"
+"\n"
+"%s\n"
+msgstr[0] ""
+"Warnung: Du bist um %d Version hinterher, nicht verbunden zu\n"
+"einem deiner Zweige:\n"
+"\n"
+"%s\n"
+msgstr[1] ""
+"Warnung: Du bist um %d Versionen hinterher, nicht verbunden zu\n"
+"einem deiner Zweige:\n"
+"\n"
+"%s\n"
+
+#: builtin/checkout.c:663
+#, 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"
+msgstr ""
+"Wenn du diese durch einen neuen Zweig behalten möchtest, dann könnte jetzt\n"
+"ein guter Zeitpunkt sein dies zu tun mit:\n"
+"\n"
+" git branch neuer_zweig_name %s\n"
+"\n"
+
+#: builtin/checkout.c:693
+msgid "internal error in revision walk"
+msgstr "interner Fehler im Revisionsgang"
+
+#: builtin/checkout.c:697
+msgid "Previous HEAD position was"
+msgstr "Vorherige Position der Zweigspitze (HEAD) war"
+
+#: builtin/checkout.c:723
+msgid "You are on a branch yet to be born"
+msgstr "du bist auf einem Zweig, der noch geboren wird"
+
+#. case (1)
+#: builtin/checkout.c:854
+#, c-format
+msgid "invalid reference: %s"
+msgstr "Ungültige Referenz: %s"
+
+#. case (1): want a tree
+#: builtin/checkout.c:893
+#, c-format
+msgid "reference is not a tree: %s"
+msgstr "Referenz ist kein Baum: %s"
+
+#: builtin/checkout.c:973
+msgid "-B cannot be used with -b"
+msgstr "-B kann nicht mit -b benutzt werden"
+
+#: builtin/checkout.c:982
+msgid "--patch is incompatible with all other options"
+msgstr "--patch ist inkompatibel mit allen anderen Optionen"
+
+#: builtin/checkout.c:985
+msgid "--detach cannot be used with -b/-B/--orphan"
+msgstr "--detach kann nicht mit -b/-B/--orphan benutzt werden"
+
+#: builtin/checkout.c:987
+msgid "--detach cannot be used with -t"
+msgstr "--detach kann nicht mit -t benutzt werden"
+
+#: builtin/checkout.c:993
+msgid "--track needs a branch name"
+msgstr "--track benötigt einen Zweignamen"
+
+#: builtin/checkout.c:1000
+msgid "Missing branch name; try -b"
+msgstr "Vermisse Zweignamen; versuche -b"
+
+#: builtin/checkout.c:1006
+msgid "--orphan and -b|-B are mutually exclusive"
+msgstr "--orphan und -b|-B sind gegenseitig exklusiv"
+
+#: builtin/checkout.c:1008
+msgid "--orphan cannot be used with -t"
+msgstr "--orphan kann nicht mit -t benutzt werden"
+
+#: builtin/checkout.c:1018
+msgid "git checkout: -f and -m are incompatible"
+msgstr "git checkout: -f und -m sind inkompatibel"
+
+#: builtin/checkout.c:1052
+msgid "invalid path specification"
+msgstr "ungültige Pfadspezifikation"
+
+#: builtin/checkout.c:1060
+#, 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?"
+msgstr ""
+"git checkout: Die Aktualisierung von Pfaden ist inkompatibel mit dem Wechsel "
+"von Zweigen.\n"
+"Hast du beabsichtigt '%s' auszuchecken, welcher nicht als Version aufgelöst "
+"werden kann?"
+
+#: builtin/checkout.c:1062
+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:1067
+msgid "git checkout: --detach does not take a path argument"
+msgstr "git checkout: --detach nimmt kein Pfad-Argument"
+
+#: builtin/checkout.c:1070
+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"
+"du aus der Bereitstellung auscheckst."
+
+#: builtin/checkout.c:1089
+msgid "Cannot switch branch to a non-commit."
+msgstr "Kann Zweig nur zu einer Version wechseln."
+
+#: builtin/checkout.c:1092
+msgid "--ours/--theirs is incompatible with switching branches."
+msgstr "--ours/--theirs ist inkompatibel mit den Wechseln von Zweigen."
+
+#: builtin/clean.c:78
+msgid "-x and -X cannot be used together"
+msgstr "-x und -X können nicht zusammen benutzt werden"
+
+#: builtin/clean.c:82
+msgid ""
+"clean.requireForce set to true and neither -n nor -f given; refusing to clean"
+msgstr ""
+"clean.requireForce auf \"true\" gesetzt und weder -n noch -f gegeben; "
+"Säuberung verweigert"
+
+#: builtin/clean.c:85
+msgid ""
+"clean.requireForce defaults to true and neither -n nor -f given; refusing to "
+"clean"
+msgstr ""
+"clean.requireForce standardmäßig auf \"true\" gesetzt und weder -n noch -f "
+"gegeben; Säuberung verweigert"
+
+#: builtin/clean.c:155 builtin/clean.c:176
+#, c-format
+msgid "Would remove %s\n"
+msgstr "Würde %s entfernen\n"
+
+#: builtin/clean.c:159 builtin/clean.c:179
+#, c-format
+msgid "Removing %s\n"
+msgstr "Entferne %s\n"
+
+#: builtin/clean.c:162 builtin/clean.c:182
+#, c-format
+msgid "failed to remove %s"
+msgstr "Fehler beim Entfernen von %s"
+
+#: builtin/clean.c:166
+#, c-format
+msgid "Would not remove %s\n"
+msgstr "Würde %s nicht entfernen\n"
+
+#: builtin/clean.c:168
+#, c-format
+msgid "Not removing %s\n"
+msgstr "Entferne %s nicht\n"
+
+#: builtin/clone.c:243
+#, c-format
+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
+#, c-format
+msgid "failed to stat '%s'"
+msgstr "Konnte '%s' nicht lesen"
+
+#: builtin/clone.c:310
+#, c-format
+msgid "%s exists and is not a directory"
+msgstr "%s existiert und ist kein Verzeichnis"
+
+#: builtin/clone.c:324
+#, c-format
+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'"
+msgstr "Konnte Verknüpfung '%s' nicht erstellen"
+
+#: builtin/clone.c:350
+#, c-format
+msgid "failed to copy file to '%s'"
+msgstr "Konnte Datei nicht nach '%s' kopieren"
+
+#: builtin/clone.c:373
+#, c-format
+msgid "done.\n"
+msgstr "Fertig.\n"
+
+#: builtin/clone.c:440
+#, c-format
+msgid "Could not find remote branch %s to clone."
+msgstr "Konnte zu klonenden externer Zweig %s nicht finden."
+
+#: builtin/clone.c:549
+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
+msgid "Too many arguments."
+msgstr "Zu viele Argumente."
+
+#: builtin/clone.c:643
+msgid "You must specify a repository to clone."
+msgstr "Du musst ein Projektarchiv zum Klonen angeben."
+
+#: builtin/clone.c:654
+#, c-format
+msgid "--bare and --origin %s options are incompatible."
+msgstr "--bare und --origin %s Optionen sind inkompatibel."
+
+#: builtin/clone.c:668
+#, c-format
+msgid "repository '%s' does not exist"
+msgstr "Projektarchiv '%s' existiert nicht."
+
+#: builtin/clone.c:673
+msgid "--depth is ignored in local clones; use file:// instead."
+msgstr "--depth wird in lokalen Klonen ignoriert; benutze stattdessen file://."
+
+#: builtin/clone.c:683
+#, 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
+#, c-format
+msgid "working tree '%s' already exists."
+msgstr "Arbeitsbaum '%s' existiert bereits."
+
+#: builtin/clone.c:706 builtin/clone.c:720
+#, c-format
+msgid "could not create leading directories of '%s'"
+msgstr "Konnte führende Verzeichnisse von '%s' nicht erstellen."
+
+#: builtin/clone.c:709
+#, c-format
+msgid "could not create work tree dir '%s'."
+msgstr "Konnte Arbeitsverzeichnis '%s' nicht erstellen."
+
+#: builtin/clone.c:728
+#, c-format
+msgid "Cloning into bare repository '%s'...\n"
+msgstr "Klone in bloßes Projektarchiv '%s'...\n"
+
+#: builtin/clone.c:730
+#, c-format
+msgid "Cloning into '%s'...\n"
+msgstr "Klone nach '%s'...\n"
+
+#: builtin/clone.c:786
+#, c-format
+msgid "Don't know how to clone %s"
+msgstr "Weiß nicht wie %s zu klonen ist."
+
+#: builtin/clone.c:835
+#, 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
+msgid "You appear to have cloned an empty repository."
+msgstr "Du scheinst ein leeres Projektarchiv geklont zu haben."
+
+#: builtin/commit.c:42
+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 ""
+"Dein Name und E-Mail Adresse wurden automatisch auf Basis\n"
+"deines Benutzer- und Rechnernamens konfiguriert. Bitte prüfe, dass diese\n"
+"zutreffend sind. Du kannst diese Meldung unterdrücken, indem du diese\n"
+"explizit setzt:\n"
+"\n"
+" git config --global user.name \"Dein Name\"\n"
+" git config --global user.email deine@emailadresse.de\n"
+"\n"
+"Nachdem du das getan hast, kannst du deine Identität für diese Version "
+"ändern mit:\n"
+"\n"
+" git commit --amend --reset-author\n"
+
+#: builtin/commit.c:54
+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 ""
+"Du fragtest die jüngste Version nachzubessern, aber das würde diese leer\n"
+"machen. Du kannst Dein Kommando mit --allow-empty wiederholen, oder die\n"
+"Version mit \"git reset HEAD^\" vollständig entfernen.\n"
+
+#: builtin/commit.c:59
+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 ""
+"Der letzte \"cherry-pick\" ist jetzt leer, möglicherweise durch eine "
+"Konfliktauflösung.\n"
+"Wenn du dies trotzdem eintragen willst, benutze:\n"
+"\n"
+" git commit --allow-empty\n"
+"\n"
+"Andernfalls benutze bitte 'git reset'\n"
+
+#: builtin/commit.c:205 builtin/reset.c:33
+msgid "merge"
+msgstr "zusammenführen"
+
+#: builtin/commit.c:208
+msgid "cherry-pick"
+msgstr "cherry-pick"
+
+#: builtin/commit.c:325
+msgid "failed to unpack HEAD tree object"
+msgstr "Fehler beim Entpacken des Baum-Objektes der Zweigspitze (HEAD)."
+
+#: builtin/commit.c:367
+msgid "unable to create temporary index"
+msgstr "Konnte temporäre Bereitstellung nicht erstellen."
+
+#: builtin/commit.c:373
+msgid "interactive add failed"
+msgstr "interaktives Hinzufügen fehlgeschlagen"
+
+#: builtin/commit.c:406 builtin/commit.c:427 builtin/commit.c:473
+msgid "unable to write new_index file"
+msgstr "Konnte new_index Datei nicht schreiben"
+
+#: builtin/commit.c:457
+#, c-format
+msgid "cannot do a partial commit during a %s."
+msgstr "Kann keine partielle Eintragung durchführen, während %s im Gange ist."
+
+#: builtin/commit.c:466
+msgid "cannot read the index"
+msgstr "Kann Bereitstellung nicht lesen"
+
+#: builtin/commit.c:486
+msgid "unable to write temporary index file"
+msgstr "Konnte temporäre Bereitstellungsdatei nicht schreiben."
+
+#: builtin/commit.c:561 builtin/commit.c:567
+#, c-format
+msgid "invalid commit: %s"
+msgstr "Ungültige Version: %s"
+
+#: builtin/commit.c:590
+msgid "malformed --author parameter"
+msgstr "Fehlerhafter --author Parameter"
+
+#: builtin/commit.c:651
+#, c-format
+msgid "Malformed ident string: '%s'"
+msgstr "Fehlerhafter Identifikations-String: '%s'"
+
+#: builtin/commit.c:689 builtin/commit.c:722 builtin/commit.c:1033
+#, c-format
+msgid "could not lookup commit %s"
+msgstr "Konnte Version %s nicht nachschlagen"
+
+#: builtin/commit.c:701 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:703
+msgid "could not read log from standard input"
+msgstr "Konnte Log nicht von Standard-Eingabe lesen."
+
+#: builtin/commit.c:707
+#, c-format
+msgid "could not read log file '%s'"
+msgstr "Konnte Log-Datei '%s' nicht lesen"
+
+#: builtin/commit.c:713
+msgid "commit has empty message"
+msgstr "Version hat eine leere Beschreibung"
+
+#: builtin/commit.c:729
+msgid "could not read MERGE_MSG"
+msgstr "Konnte MERGE_MSG nicht lesen"
+
+#: builtin/commit.c:733
+msgid "could not read SQUASH_MSG"
+msgstr "Konnte SQUASH_MSG nicht lesen"
+
+#: builtin/commit.c:737
+#, c-format
+msgid "could not read '%s'"
+msgstr "Konnte '%s' nicht lesen"
+
+#: builtin/commit.c:765
+#, c-format
+msgid "could not open '%s'"
+msgstr "Konnte '%s' nicht öffnen"
+
+#: builtin/commit.c:789
+msgid "could not write commit template"
+msgstr "Konnte Versionsvorlage nicht schreiben"
+
+#: builtin/commit.c:799
+#, c-format
+msgid ""
+"\n"
+"It looks like you may be committing a %s.\n"
+"If this is not correct, please remove the file\n"
+"\t%s\n"
+"and try again.\n"
+msgstr ""
+"\n"
+"Es sieht so aus, als trägst du ein '%s' ein.\n"
+"Falls das nicht korrekt ist, entferne bitte die Datei\n"
+"\t%s\n"
+"und versuche es erneut.\n"
+
+#: builtin/commit.c:812
+msgid "Please enter the commit message for your changes."
+msgstr "Bitte gebe die Versionsbeschreibung für deine Änderungen ein."
+
+#: builtin/commit.c:815
+msgid ""
+" Lines starting\n"
+"with '#' will be ignored, and an empty message aborts the commit.\n"
+msgstr ""
+" Zeilen, die mit '#'\n"
+"beginnen, werden ignoriert, und eine leere Versionsbeschreibung bricht die "
+"Eintragung ab.\n"
+
+#: builtin/commit.c:820
+msgid ""
+" 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 ""
+" Zeilen, die mit '#'\n"
+"beginnen, werden beibehalten; wenn du möchtest, kannst du diese entfernen.\n"
+"Eine leere Versionsbeschreibung bricht die Eintragung ab.\n"
+
+#: builtin/commit.c:832
+#, c-format
+msgid "%sAuthor: %s"
+msgstr "%sAutor: %s"
+
+#: builtin/commit.c:839
+#, c-format
+msgid "%sCommitter: %s"
+msgstr "%sEintragender: %s"
+
+#: builtin/commit.c:859
+msgid "Cannot read index"
+msgstr "Kann Bereitstellung nicht lesen"
+
+#: builtin/commit.c:896
+msgid "Error building trees"
+msgstr "Fehler beim Erzeugen der Zweige"
+
+#: builtin/commit.c:911 builtin/tag.c:357
+#, c-format
+msgid "Please supply the message using either -m or -F option.\n"
+msgstr "Bitte liefere die Beschreibung entweder mit der Option -m oder -F.\n"
+
+#: builtin/commit.c:1008
+#, c-format
+msgid "No existing author found with '%s'"
+msgstr "Kein existierender Autor mit '%s' gefunden."
+
+#: builtin/commit.c:1023 builtin/commit.c:1217
+#, c-format
+msgid "Invalid untracked files mode '%s'"
+msgstr "Ungültiger Modus '%s' für unbeobachtete Dateien"
+
+#: builtin/commit.c:1063
+msgid "Using both --reset-author and --author does not make sense"
+msgstr "Verwendung von --reset-author und --author macht keinen Sinn."
+
+#: builtin/commit.c:1074
+msgid "You have nothing to amend."
+msgstr "Du hast nichts zum nachbessern."
+
+#: builtin/commit.c:1076
+#, c-format
+msgid "You are in the middle of a %s -- cannot amend."
+msgstr "%s ist im Gange -- kann nicht nachbessern."
+
+#: builtin/commit.c:1078
+msgid "Options --squash and --fixup cannot be used together"
+msgstr ""
+"Die Optionen --squash und --fixup können nicht gemeinsam benutzt werden."
+
+#: builtin/commit.c:1088
+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:1090
+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:1098
+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:1115
+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:1117
+msgid "No paths with --include/--only does not make sense."
+msgstr "--include/--only machen ohne Pfade keinen Sinn."
+
+#: builtin/commit.c:1119
+msgid "Clever... amending the last one with dirty index."
+msgstr ""
+"Klug... die letzte Version mit einer unsauberen Bereitstellung nachbessern."
+
+#: builtin/commit.c:1121
+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:1131 builtin/tag.c:556
+#, c-format
+msgid "Invalid cleanup mode %s"
+msgstr "Ungültiger \"cleanup\" Modus %s"
+
+#: builtin/commit.c:1136
+msgid "Paths with -a does not make sense."
+msgstr "Pfade mit -a machen keinen Sinn."
+
+#: builtin/commit.c:1315
+msgid "couldn't look up newly created commit"
+msgstr "Konnte neu erstellte Version nicht nachschlagen."
+
+#: builtin/commit.c:1317
+msgid "could not parse newly created commit"
+msgstr "Konnte neu erstellte Version nicht analysieren."
+
+#: builtin/commit.c:1358
+msgid "detached HEAD"
+msgstr "losgelöste Zweigspitze (HEAD)"
+
+#: builtin/commit.c:1360
+msgid " (root-commit)"
+msgstr " (Basis-Version)"
+
+#: builtin/commit.c:1450
+msgid "could not parse HEAD commit"
+msgstr "Konnte Version der Zweigspitze (HEAD) nicht analysieren."
+
+#: builtin/commit.c:1487 builtin/merge.c:509
+#, c-format
+msgid "could not open '%s' for reading"
+msgstr "Konnte '%s' nicht zum Lesen öffnen."
+
+#: builtin/commit.c:1494
+#, c-format
+msgid "Corrupt MERGE_HEAD file (%s)"
+msgstr "Beschädigte MERGE_HEAD-Datei (%s)"
+
+#: builtin/commit.c:1501
+msgid "could not read MERGE_MODE"
+msgstr "Konnte MERGE_MODE nicht lesen"
+
+#: builtin/commit.c:1520
+#, c-format
+msgid "could not read commit message: %s"
+msgstr "Konnte Versionsbeschreibung nicht lesen: %s"
+
+#: 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:1539
+#, c-format
+msgid "Aborting commit due to empty commit message.\n"
+msgstr "Eintragung aufgrund leerer Versionsbeschreibung abgebrochen.\n"
+
+#: builtin/commit.c:1554 builtin/merge.c:936 builtin/merge.c:961
+msgid "failed to write commit object"
+msgstr "Fehler beim Schreiben des Versionsobjektes."
+
+#: builtin/commit.c:1575
+msgid "cannot lock HEAD ref"
+msgstr "Kann Referenz der Zweigspitze (HEAD) nicht sperren."
+
+#: builtin/commit.c:1579
+msgid "cannot update HEAD ref"
+msgstr "Kann Referenz der Zweigspitze (HEAD) nicht aktualisieren."
+
+#: 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"
+"voll und dein Kontingent nicht aufgebraucht ist und führe\n"
+"anschließend \"git reset HEAD\" zu Wiederherstellung aus."
+
+#: builtin/describe.c:234
+#, c-format
+msgid "annotated tag %s not available"
+msgstr "annotierte Markierung %s ist nicht verfügbar"
+
+#: builtin/describe.c:238
+#, c-format
+msgid "annotated tag %s has no embedded name"
+msgstr "annotierte Markierung %s hat keinen eingebetteten Namen"
+
+#: builtin/describe.c:240
+#, c-format
+msgid "tag '%s' is really '%s' here"
+msgstr "Markierung '%s' ist eigentlich '%s' hier"
+
+#: builtin/describe.c:267
+#, c-format
+msgid "Not a valid object name %s"
+msgstr "%s ist kein gültiger Objekt-Name"
+
+#: builtin/describe.c:270
+#, c-format
+msgid "%s is not a valid '%s' object"
+msgstr "%s ist kein gültiges '%s' Objekt"
+
+#: builtin/describe.c:287
+#, c-format
+msgid "no tag exactly matches '%s'"
+msgstr "kein Markierung entspricht exakt '%s'"
+
+#: builtin/describe.c:289
+#, c-format
+msgid "searching to describe %s\n"
+msgstr "suche zur Beschreibung von %s\n"
+
+#: builtin/describe.c:329
+#, c-format
+msgid "finished search at %s\n"
+msgstr "beendete Suche bei %s\n"
+
+#: builtin/describe.c:353
+#, c-format
+msgid ""
+"No annotated tags can describe '%s'.\n"
+"However, there were unannotated tags: try --tags."
+msgstr ""
+"Keine annotierten Markierungen können '%s' beschreiben.\n"
+"Jedoch gab es nicht annotierte Markierungen: versuche --tags."
+
+#: builtin/describe.c:357
+#, c-format
+msgid ""
+"No tags can describe '%s'.\n"
+"Try --always, or create some tags."
+msgstr ""
+"Keine Markierungen können '%s' beschreiben.\n"
+"Versuche --always oder erstelle einige Markierungen."
+
+#: builtin/describe.c:378
+#, c-format
+msgid "traversed %lu commits\n"
+msgstr "%lu Versionen durchlaufen\n"
+
+#: builtin/describe.c:381
+#, c-format
+msgid ""
+"more than %i tags found; listed %i most recent\n"
+"gave up search at %s\n"
+msgstr ""
+"mehr als %i Markierungen gefunden; Führe die ersten %i auf\n"
+"Suche bei %s aufgegeben\n"
+
+#: builtin/describe.c:436
+msgid "--long is incompatible with --abbrev=0"
+msgstr "--long ist inkompatibel mit --abbrev=0"
+
+#: builtin/describe.c:462
+msgid "No names found, cannot describe anything."
+msgstr "Keine Namen gefunden, kann nichts beschreiben."
+
+#: builtin/describe.c:482
+msgid "--dirty is incompatible with committishes"
+msgstr "--dirty ist inkompatibel mit Versionen"
+
+#: builtin/diff.c:77
+#, c-format
+msgid "'%s': not a regular file or symlink"
+msgstr "'%s': keine reguläre Datei oder symbolische Verknüpfung"
+
+#: builtin/diff.c:220
+#, c-format
+msgid "invalid option: %s"
+msgstr "Ungültige Option: %s"
+
+#: builtin/diff.c:297
+msgid "Not a git repository"
+msgstr "Kein Git-Projektarchiv"
+
+#: builtin/diff.c:347
+#, c-format
+msgid "invalid object '%s' given."
+msgstr "Objekt '%s' ist ungültig."
+
+#: builtin/diff.c:352
+#, c-format
+msgid "more than %d trees given: '%s'"
+msgstr "Mehr als %d Zweige angegeben: '%s'"
+
+#: builtin/diff.c:362
+#, c-format
+msgid "more than two blobs given: '%s'"
+msgstr "Mehr als zwei Blobs angegeben: '%s'"
+
+#: builtin/diff.c:370
+#, c-format
+msgid "unhandled object '%s' given."
+msgstr "unbehandeltes Objekt '%s' angegeben"
+
+#: builtin/fetch.c:200
+msgid "Couldn't find remote ref HEAD"
+msgstr "Konnte externe Referenz der Zweigspitze (HEAD) nicht finden."
+
+#: builtin/fetch.c:253
+#, c-format
+msgid "object %s not found"
+msgstr "Objekt %s nicht gefunden"
+
+#: builtin/fetch.c:259
+msgid "[up to date]"
+msgstr "[aktuell]"
+
+#: builtin/fetch.c:273
+#, c-format
+msgid "! %-*s %-*s -> %s (can't fetch in current branch)"
+msgstr "! %-*s %-*s -> %s (kann nicht im aktuellen Zweig anfordern)"
+
+#: builtin/fetch.c:274 builtin/fetch.c:360
+msgid "[rejected]"
+msgstr "[zurückgewiesen]"
+
+#: builtin/fetch.c:285
+msgid "[tag update]"
+msgstr "[Markierungsaktualisierung]"
+
+#: builtin/fetch.c:287 builtin/fetch.c:322 builtin/fetch.c:340
+msgid " (unable to update local ref)"
+msgstr " (kann lokale Referenz nicht aktualisieren)"
+
+#: builtin/fetch.c:305
+msgid "[new tag]"
+msgstr "[neue Markierung]"
+
+#: builtin/fetch.c:308
+msgid "[new branch]"
+msgstr "[neuer Zweig]"
+
+#: builtin/fetch.c:311
+msgid "[new ref]"
+msgstr "[neue Referenz]"
+
+#: builtin/fetch.c:356
+msgid "unable to update local ref"
+msgstr "kann lokale Referenz nicht aktualisieren"
+
+#: builtin/fetch.c:356
+msgid "forced update"
+msgstr "Aktualisierung erzwungen"
+
+#: builtin/fetch.c:362
+msgid "(non-fast-forward)"
+msgstr "(kein Vorspulen)"
+
+#: builtin/fetch.c:393 builtin/fetch.c:685
+#, c-format
+msgid "cannot open %s: %s\n"
+msgstr "kann %s nicht öffnen: %s\n"
+
+#: builtin/fetch.c:402
+#, c-format
+msgid "%s did not send all necessary objects\n"
+msgstr "%s hat nicht alle erforderlichen Objekte gesendet\n"
+
+#: builtin/fetch.c:488
+#, c-format
+msgid "From %.*s\n"
+msgstr "Von %.*s\n"
+
+#: builtin/fetch.c:499
+#, c-format
+msgid ""
+"some local refs could not be updated; try running\n"
+" 'git remote prune %s' to remove any old, conflicting branches"
+msgstr ""
+"Einige lokale Referenzen konnten nicht aktualisiert werden; versuche\n"
+"'git remote prune %s' um jeden älteren, widersprüchlichen Zweig zu entfernen."
+
+#: builtin/fetch.c:549
+#, c-format
+msgid " (%s will become dangling)\n"
+msgstr " (%s wird unreferenziert)\n"
+
+#: builtin/fetch.c:550
+#, c-format
+msgid " (%s has become dangling)\n"
+msgstr " (%s wurde unreferenziert)\n"
+
+#: builtin/fetch.c:557
+msgid "[deleted]"
+msgstr "[gelöscht]"
+
+#: builtin/fetch.c:558
+msgid "(none)"
+msgstr "(nichts)"
+
+#: builtin/fetch.c:675
+#, c-format
+msgid "Refusing to fetch into current branch %s of non-bare repository"
+msgstr ""
+"Das Anfordern in den aktuellen Zweig %s von einem nicht-bloßen"
+"\"Projektarchiv wurde verweigert."
+
+#: builtin/fetch.c:709
+#, c-format
+msgid "Don't know how to fetch from %s"
+msgstr "Weiß nicht wie von %s angefordert wird."
+
+#: builtin/fetch.c:786
+#, c-format
+msgid "Option \"%s\" value \"%s\" is not valid for %s"
+msgstr "Option \"%s\" Wert \"%s\" ist nicht gültig für %s"
+
+#: builtin/fetch.c:789
+#, c-format
+msgid "Option \"%s\" is ignored for %s\n"
+msgstr "Option \"%s\" wird ignoriert für %s\n"
+
+#: builtin/fetch.c:888
+#, c-format
+msgid "Fetching %s\n"
+msgstr "Fordere an von %s\n"
+
+#: builtin/fetch.c:890
+#, c-format
+msgid "Could not fetch %s"
+msgstr "Konnte nicht von %s anfordern"
+
+#: 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."
+msgstr ""
+"Kein externes Projektarchiv angegeben. Bitte gebe entweder eine URL\n"
+"oder den Namen des externen Archivs an, von welchem neue\n"
+"Versionen angefordert werden sollen."
+
+#: builtin/fetch.c:927
+msgid "You need to specify a tag name."
+msgstr "Du musst den Namen der Markierung angeben."
+
+#: builtin/fetch.c:979
+msgid "fetch --all does not take a repository argument"
+msgstr "fetch --all akzeptiert kein Projektarchiv als Argument"
+
+#: builtin/fetch.c:981
+msgid "fetch --all does not make sense with refspecs"
+msgstr "fetch --all macht keinen Sinn mit Referenzspezifikationen"
+
+#: builtin/fetch.c:992
+#, c-format
+msgid "No such remote or remote group: %s"
+msgstr "Kein externes Archiv (einzeln oder Gruppe): %s"
+
+#: builtin/fetch.c:1000
+msgid "Fetching a group and specifying refspecs does not make sense"
+msgstr ""
+"Abholen einer Gruppe und Spezifizieren von Referenzspezifikationen macht "
+"keinen Sinn."
+
+#: builtin/gc.c:63
+#, c-format
+msgid "Invalid %s: '%s'"
+msgstr "Ungültiger %s: '%s'"
+
+#: builtin/gc.c:90
+#, c-format
+msgid "insanely long object directory %.*s"
+msgstr "zu langes Objekt-Verzeichnis %.*s"
+
+#: builtin/gc.c:221
+#, c-format
+msgid "Auto packing the repository for optimum performance.\n"
+msgstr ""
+"Die Datenbank des Projektarchivs wird für eine optimale Performance "
+"komprimiert.\n"
+
+#: builtin/gc.c:224
+#, 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 ""
+"Die Datenbank des Projektarchivs wird für eine optimale Performance\n"
+"komprimiert. Du kannst auch \"git gc\" manuell ausführen. Siehe \"git help gc"
+"\" für weitere Informationen.\n"
+
+#: builtin/gc.c:251
+msgid ""
+"There are too many unreachable loose objects; run 'git prune' to remove them."
+msgstr ""
+"Es gibt zu viele unerreichbare lose Objekte; führe 'git prune' aus, um diese "
+"zu entfernen."
+
+#: builtin/grep.c:216
+#, c-format
+msgid "grep: failed to create thread: %s"
+msgstr "grep: Fehler beim Erzeugen eines Thread: %s"
+
+#: builtin/grep.c:402
+#, c-format
+msgid "Failed to chdir: %s"
+msgstr "Fehler beim Verzeichniswechsel: %s"
+
+#: builtin/grep.c:478 builtin/grep.c:512
+#, c-format
+msgid "unable to read tree (%s)"
+msgstr "konnte Zweig (%s) nicht lesen"
+
+#: builtin/grep.c:526
+#, 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
+#, c-format
+msgid "switch `%c' expects a numerical value"
+msgstr "Schalter '%c' erwartet einen numerischen Wert"
+
+#: builtin/grep.c:601
+#, c-format
+msgid "cannot open '%s'"
+msgstr "kann '%s' nicht öffnen"
+
+#: builtin/grep.c:888
+msgid "no pattern given."
+msgstr "keine Muster gegeben"
+
+#: builtin/grep.c:902
+#, c-format
+msgid "bad object %s"
+msgstr "ungültiges Objekt %s"
+
+#: builtin/grep.c:943
+msgid "--open-files-in-pager only works on the worktree"
+msgstr "--open-files-in-pager arbeitet nur auf dem Arbeitsbaum"
+
+#: builtin/grep.c:966
+msgid "--cached or --untracked cannot be used with --no-index."
+msgstr "--cached oder --untracked kann nicht mit --no-index benutzt werden"
+
+#: builtin/grep.c:971
+msgid "--no-index or --untracked cannot be used with revs."
+msgstr "--no-index oder --untracked kann nicht mit Revisionen benutzt werden"
+
+#: builtin/grep.c:974
+msgid "--[no-]exclude-standard cannot be used for tracked contents."
+msgstr ""
+"--[no-]exlude-standard kann nicht mit beobachteten Inhalten benutzt werden"
+
+#: builtin/grep.c:982
+msgid "both --cached and trees are given."
+msgstr "sowohl --cached als auch Zweige gegeben"
+
+#: builtin/init-db.c:35
+#, c-format
+msgid "Could not make %s writable by group"
+msgstr "Konnte %s nicht schreibbar für Gruppen machen"
+
+#: builtin/init-db.c:62
+#, c-format
+msgid "insanely long template name %s"
+msgstr "zu langer Vorlagen-Name %s"
+
+#: builtin/init-db.c:67
+#, c-format
+msgid "cannot stat '%s'"
+msgstr "Kann '%s' nicht lesen"
+
+#: builtin/init-db.c:73
+#, c-format
+msgid "cannot stat template '%s'"
+msgstr "kann Vorlage '%s' nicht lesen"
+
+#: builtin/init-db.c:80
+#, c-format
+msgid "cannot opendir '%s'"
+msgstr "kann Verzeichnis '%s' nicht öffnen"
+
+#: builtin/init-db.c:97
+#, c-format
+msgid "cannot readlink '%s'"
+msgstr "kann Verknüfpung '%s' nicht lesen"
+
+#: builtin/init-db.c:99
+#, c-format
+msgid "insanely long symlink %s"
+msgstr "zu lange symbolische Verknüpfung %s"
+
+#: builtin/init-db.c:102
+#, c-format
+msgid "cannot symlink '%s' '%s'"
+msgstr "kann '%s' nicht mit '%s' symbolisch verknüpfen"
+
+#: builtin/init-db.c:106
+#, c-format
+msgid "cannot copy '%s' to '%s'"
+msgstr "kann '%s' nicht nach '%s' kopieren"
+
+#: builtin/init-db.c:110
+#, c-format
+msgid "ignoring template %s"
+msgstr "ignoriere Vorlage %s"
+
+#: builtin/init-db.c:133
+#, c-format
+msgid "insanely long template path %s"
+msgstr "zu langer Vorlagen-Pfad %s"
+
+#: builtin/init-db.c:141
+#, c-format
+msgid "templates not found %s"
+msgstr "keine Vorlagen in '%s' gefunden"
+
+#: builtin/init-db.c:154
+#, c-format
+msgid "not copying templates of a wrong format version %d from '%s'"
+msgstr "kopiere keine Vorlagen mit einer falschen Formatversion %d von '%s'"
+
+#: builtin/init-db.c:192
+#, c-format
+msgid "insane git directory %s"
+msgstr "ungültiges git Verzeichnis %s"
+
+#: builtin/init-db.c:322 builtin/init-db.c:325
+#, c-format
+msgid "%s already exists"
+msgstr "%s existiert bereits"
+
+#: builtin/init-db.c:354
+#, c-format
+msgid "unable to handle file type %d"
+msgstr "kann nicht mit Dateityp %d umgehen"
+
+#: builtin/init-db.c:357
+#, c-format
+msgid "unable to move %s to %s"
+msgstr "Konnte %s nicht nach %s verschieben"
+
+#: builtin/init-db.c:362
+#, c-format
+msgid "Could not create git link %s"
+msgstr "Konnte git-Verknüfung %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
+#, 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
+msgid "Reinitialized existing"
+msgstr "Reinitialisierte existierendes"
+
+#: builtin/init-db.c:420
+msgid "Initialized empty"
+msgstr "Initialisierte leeres"
+
+#: builtin/init-db.c:421
+msgid " shared"
+msgstr " geteiltes"
+
+#: builtin/init-db.c:440
+msgid "cannot tell cwd"
+msgstr "kann aktuelles Verzeichnis nicht bestimmen"
+
+#: builtin/init-db.c:521 builtin/init-db.c:528
+#, c-format
+msgid "cannot mkdir %s"
+msgstr "kann Verzeichnis %s nicht erstellen"
+
+#: builtin/init-db.c:532
+#, c-format
+msgid "cannot chdir to %s"
+msgstr "kann nicht in Verzeichnis %s wechseln"
+
+#: builtin/init-db.c:554
+#, c-format
+msgid ""
+"%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-"
+"dir=<directory>)"
+msgstr ""
+"%s (oder --work-tree=<Verzeichnis>) nicht erlaubt ohne Spezifizierung von %s "
+"(oder --git-dir=<Verzeichnis>)"
+
+#: builtin/init-db.c:578
+msgid "Cannot access current working directory"
+msgstr "Kann nicht auf aktuelles Arbeitsverzeichnis zugreifen."
+
+#: builtin/init-db.c:585
+#, c-format
+msgid "Cannot access work tree '%s'"
+msgstr "Kann nicht auf Arbeitsbaum '%s' zugreifen."
+
+#: builtin/log.c:187
+#, c-format
+msgid "Final output: %d %s\n"
+msgstr "letzte Ausgabe: %d %s\n"
+
+#: builtin/log.c:395 builtin/log.c:483
+#, c-format
+msgid "Could not read object %s"
+msgstr "Kann Objekt %s nicht lesen."
+
+#: builtin/log.c:507
+#, c-format
+msgid "Unknown type: %d"
+msgstr "Unbekannter Typ: %d"
+
+#: builtin/log.c:596
+msgid "format.headers without value"
+msgstr "format.headers ohne Wert"
+
+#: builtin/log.c:669
+msgid "name of output directory is too long"
+msgstr "Name des Ausgabeverzeichnisses ist zu lang."
+
+#: builtin/log.c:680
+#, c-format
+msgid "Cannot open patch file %s"
+msgstr "Kann Patch-Datei %s nicht öffnen"
+
+#: builtin/log.c:694
+msgid "Need exactly one range."
+msgstr "Brauche genau einen Versionsbereich."
+
+#: builtin/log.c:702
+msgid "Not a range."
+msgstr "Kein Versionsbereich."
+
+#: builtin/log.c:739
+msgid "Could not extract email from committer identity."
+msgstr "Konnte E-Mail-Adresse des Einreichers nicht extrahieren."
+
+#: builtin/log.c:785
+msgid "Cover letter needs email format"
+msgstr "Deckblatt benötigt E-Mail-Format"
+
+#: builtin/log.c:879
+#, c-format
+msgid "insane in-reply-to: %s"
+msgstr "ungültiges in-reply-to: %s"
+
+#: builtin/log.c:952
+msgid "Two output directories?"
+msgstr "Zwei Ausgabeverzeichnisse?"
+
+#: builtin/log.c:1173
+#, c-format
+msgid "bogus committer info %s"
+msgstr "unechte Einreicher-Information %s"
+
+#: builtin/log.c:1218
+msgid "-n and -k are mutually exclusive."
+msgstr "-n und -k schliessen sich gegenseitig aus"
+
+#: builtin/log.c:1220
+msgid "--subject-prefix and -k are mutually exclusive."
+msgstr "--subject-prefix und -k schliessen sich gegenseitig aus"
+
+#: builtin/log.c:1225 builtin/shortlog.c:284
+#, c-format
+msgid "unrecognized argument: %s"
+msgstr "nicht erkanntes Argument: %s"
+
+#: builtin/log.c:1228
+msgid "--name-only does not make sense"
+msgstr "--name-only macht keinen Sinn"
+
+#: builtin/log.c:1230
+msgid "--name-status does not make sense"
+msgstr "--name-status macht keinen Sinn"
+
+#: builtin/log.c:1232
+msgid "--check does not make sense"
+msgstr "--check macht keinen Sinn"
+
+#: builtin/log.c:1255
+msgid "standard output, or directory, which one?"
+msgstr "Standard-Ausgabe oder Verzeichnis, welches von beidem?"
+
+#: builtin/log.c:1257
+#, c-format
+msgid "Could not create directory '%s'"
+msgstr "Konnte Verzeichnis '%s' nicht erstellen."
+
+#: builtin/log.c:1410
+msgid "Failed to create output files"
+msgstr "Fehler beim Erstellen der Ausgabedateien."
+
+#: builtin/log.c:1514
+#, c-format
+msgid ""
+"Could not find a tracked remote branch, please specify <upstream> manually.\n"
+msgstr ""
+"Konnte gefolgten, externen Zweig nicht finden, bitte gebe <upstream> manuell "
+"an.\n"
+
+#: builtin/log.c:1530 builtin/log.c:1532 builtin/log.c:1544
+#, c-format
+msgid "Unknown commit %s"
+msgstr "Unbekannte Version %s"
+
+#: builtin/merge.c:90
+msgid "switch `m' requires a value"
+msgstr "Schalter 'm' erfordert einen Wert."
+
+#: builtin/merge.c:127
+#, c-format
+msgid "Could not find merge strategy '%s'.\n"
+msgstr "Konnte Zusammenführungsstrategie '%s' nicht finden.\n"
+
+#: builtin/merge.c:128
+#, c-format
+msgid "Available strategies are:"
+msgstr "Verfügbare Strategien sind:"
+
+#: builtin/merge.c:133
+#, c-format
+msgid "Available custom strategies are:"
+msgstr "Verfügbare benutzerdefinierte Strategien sind:"
+
+#: builtin/merge.c:240
+msgid "could not run stash."
+msgstr "Konnte \"stash\" nicht ausführen."
+
+#: builtin/merge.c:245
+msgid "stash failed"
+msgstr "\"stash\" fehlgeschlagen"
+
+#: builtin/merge.c:250
+#, c-format
+msgid "not a valid object: %s"
+msgstr "kein gültiges Objekt: %s"
+
+#: builtin/merge.c:269 builtin/merge.c:286
+msgid "read-tree failed"
+msgstr "read-tree fehlgeschlagen"
+
+#: builtin/merge.c:316
+msgid " (nothing to squash)"
+msgstr " (nichts zu quetschen)"
+
+#: builtin/merge.c:329
+#, c-format
+msgid "Squash commit -- not updating HEAD\n"
+msgstr "Quetsche Version -- Zweigspitze (HEAD) wird nicht aktualisiert\n"
+
+#: builtin/merge.c:361
+msgid "Writing SQUASH_MSG"
+msgstr "Schreibe SQUASH_MSG"
+
+#: builtin/merge.c:363
+msgid "Finishing SQUASH_MSG"
+msgstr "Schließe SQUASH_MSG ab"
+
+#: builtin/merge.c:386
+#, c-format
+msgid "No merge message -- not updating HEAD\n"
+msgstr ""
+"Keine Zusammenführungsbeschreibung -- Zweigspitze (HEAD) wird nicht "
+"aktualisiert\n"
+
+#: builtin/merge.c:437
+#, c-format
+msgid "'%s' does not point to a commit"
+msgstr "'%s' zeigt auf keine Version"
+
+#: builtin/merge.c:536
+#, c-format
+msgid "Bad branch.%s.mergeoptions string: %s"
+msgstr "Ungültiger branch.%s.mergeoptions String: %s"
+
+#: builtin/merge.c:629
+msgid "git write-tree failed to write a tree"
+msgstr "\"git write-tree\" schlug beim Schreiben eines Baumes fehl"
+
+#: builtin/merge.c:679
+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
+msgid "Not handling anything other than two heads merge."
+msgstr "Es wird nur die Zusammenführung von zwei Zweigen behandelt."
+
+#: builtin/merge.c:724
+#, c-format
+msgid "Unknown option for merge-recursive: -X%s"
+msgstr "Unbekannte Option für merge-recursive: -X%s"
+
+#: builtin/merge.c:738
+#, c-format
+msgid "unable to write %s"
+msgstr "konnte %s nicht schreiben"
+
+#: builtin/merge.c:877
+#, c-format
+msgid "Could not read from '%s'"
+msgstr "konnte nicht von '%s' lesen"
+
+#: builtin/merge.c:886
+#, 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
+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 ""
+"Bitte gebe eine Versionsbeschreibung ein um zu erklären, warum diese "
+"Zusammenführung erforderlich ist,\n"
+"insbesondere wenn es einen aktualisierten, externen Zweig mit einem Thema-"
+"Zweig zusammenführt.\n"
+"\n"
+"Zeilen beginnend mit '#' werden ignoriert, und eine leere Beschreibung "
+"bricht die Eintragung ab.\n"
+
+#: builtin/merge.c:916
+msgid "Empty commit message."
+msgstr "Leere Versionsbeschreibung."
+
+#: builtin/merge.c:928
+#, c-format
+msgid "Wonderful.\n"
+msgstr "Wunderbar.\n"
+
+#: builtin/merge.c:993
+#, 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
+#, c-format
+msgid "'%s' is not a commit"
+msgstr "'%s' ist keine Version"
+
+#: builtin/merge.c:1050
+msgid "No current branch."
+msgstr "Du befindest dich auf keinem Zweig."
+
+#: builtin/merge.c:1052
+msgid "No remote for the current branch."
+msgstr "Kein externes Archiv für den aktuellen Zweig."
+
+#: builtin/merge.c:1054
+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
+#, 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
+#, c-format
+msgid "%s - not something we can merge"
+msgstr "%s - nichts was wir zusammenführen können"
+
+#: builtin/merge.c:1214
+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
+msgid ""
+"You have not concluded your merge (MERGE_HEAD exists).\n"
+"Please, commit your changes before you can merge."
+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
+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
+msgid ""
+"You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
+"Please, commit your changes before you can merge."
+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
+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
+msgid "You cannot combine --squash with --no-ff."
+msgstr "Du kannst --squash nicht mit --no-ff kombinieren."
+
+#: builtin/merge.c:1254
+msgid "You cannot combine --no-ff with --ff-only."
+msgstr "Du kannst --no-ff nicht mit --ff--only kombinieren."
+
+#: builtin/merge.c:1261
+msgid "No commit specified and merge.defaultToUpstream not set."
+msgstr "Keine Version angegeben und merge.defaultToUpstream ist nicht gesetzt."
+
+#: builtin/merge.c:1293
+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
+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
+msgid "Non-fast-forward commit does not make sense into an empty head"
+msgstr "Bin auf einem Zweig, der noch geboren wird; --no-ff macht keinen Sinn."
+
+#: builtin/merge.c:1413
+#, c-format
+msgid "Updating %s..%s\n"
+msgstr "Aktualisiere %s..%s\n"
+
+#: builtin/merge.c:1451
+#, c-format
+msgid "Trying really trivial in-index merge...\n"
+msgstr "Probiere wirklich triviale \"in-index\"-Zusammenführung...\n"
+
+#: builtin/merge.c:1458
+#, c-format
+msgid "Nope.\n"
+msgstr "Nein.\n"
+
+#: builtin/merge.c:1490
+msgid "Not possible to fast-forward, aborting."
+msgstr "Vorspulen nicht möglich, breche ab."
+
+#: builtin/merge.c:1513 builtin/merge.c:1592
+#, c-format
+msgid "Rewinding the tree to pristine...\n"
+msgstr "Rücklauf des Zweiges bis zum Ursprung...\n"
+
+#: builtin/merge.c:1517
+#, c-format
+msgid "Trying merge strategy %s...\n"
+msgstr "Probiere Zusammenführungsstrategie %s...\n"
+
+#: builtin/merge.c:1583
+#, c-format
+msgid "No merge strategy handled the merge.\n"
+msgstr "Keine Zusammenführungsstrategie behandelt diese Zusammenführung.\n"
+
+#: builtin/merge.c:1585
+#, c-format
+msgid "Merge with strategy %s failed.\n"
+msgstr "Zusammenführung mit Strategie %s fehlgeschlagen.\n"
+
+#: builtin/merge.c:1594
+#, 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
+#, c-format
+msgid "Automatic merge went well; stopped before committing as requested\n"
+msgstr ""
+"Automatische Zusammenführung abgeschlossen; halte, wie gewünscht, vor der "
+"Eintragung an\n"
+
+#: builtin/mv.c:108
+#, c-format
+msgid "Checking rename of '%s' to '%s'\n"
+msgstr "Prüfe Umbenennung von '%s' nach '%s'\n"
+
+#: builtin/mv.c:112
+msgid "bad source"
+msgstr "ungültige Quelle"
+
+#: builtin/mv.c:115
+msgid "can not move directory into itself"
+msgstr "kann Verzeichnis nicht in sich selbst verschieben"
+
+#: builtin/mv.c:118
+msgid "cannot move directory over file"
+msgstr "kann Verzeichnis nicht über Datei verschieben"
+
+#: builtin/mv.c:128
+#, c-format
+msgid "Huh? %.*s is in index?"
+msgstr "Huh? %.*s ist bereitgestellt?"
+
+#: builtin/mv.c:140
+msgid "source directory is empty"
+msgstr "Quellverzeichnis ist leer"
+
+#: builtin/mv.c:171
+msgid "not under version control"
+msgstr "nicht unter Versionskontrolle"
+
+#: builtin/mv.c:173
+msgid "destination exists"
+msgstr "Ziel existiert bereits"
+
+#: builtin/mv.c:181
+#, c-format
+msgid "overwriting '%s'"
+msgstr "überschreibe '%s'"
+
+#: builtin/mv.c:184
+msgid "Cannot overwrite"
+msgstr "Kann nicht überschreiben"
+
+#: builtin/mv.c:187
+msgid "multiple sources for the same target"
+msgstr "mehrere Quellen für das selbe Ziel"
+
+#: builtin/mv.c:202
+#, c-format
+msgid "%s, source=%s, destination=%s"
+msgstr "%s, Quelle=%s, Ziel=%s"
+
+#: builtin/mv.c:212
+#, c-format
+msgid "Renaming %s to %s\n"
+msgstr "Benenne %s nach %s um\n"
+
+#: builtin/mv.c:215
+#, c-format
+msgid "renaming '%s' failed"
+msgstr "Umbenennung von '%s' fehlgeschlagen"
+
+#: builtin/notes.c:139
+#, c-format
+msgid "unable to start 'show' for object '%s'"
+msgstr "konnte 'show' für Objekt '%s' nicht starten"
+
+#: builtin/notes.c:145
+msgid "can't fdopen 'show' output fd"
+msgstr "konnte Datei-Deskriptor für Ausgabe von 'show' nicht öffnen"
+
+#: builtin/notes.c:155
+#, c-format
+msgid "failed to close pipe to 'show' for object '%s'"
+msgstr "Schließen der Verbindung zu 'show' ist für Objekt '%s' fehlgeschlagen."
+
+#: builtin/notes.c:158
+#, c-format
+msgid "failed to finish 'show' for object '%s'"
+msgstr "konnte 'show' für Objekt '%s' nicht abschließen"
+
+#: builtin/notes.c:175 builtin/tag.c:343
+#, c-format
+msgid "could not create file '%s'"
+msgstr "konnte Datei '%s' nicht erstellen"
+
+#: builtin/notes.c:189
+msgid "Please supply the note contents using either -m or -F option"
+msgstr "Bitte liefere den Notiz-Inhalt unter Verwendung der Option -m oder -F."
+
+#: builtin/notes.c:210 builtin/notes.c:973
+#, c-format
+msgid "Removing note for object %s\n"
+msgstr "Entferne Notiz für Objekt %s\n"
+
+#: builtin/notes.c:215
+msgid "unable to write note object"
+msgstr "Konnte Notiz-Objekt nicht schreiben"
+
+#: builtin/notes.c:217
+#, c-format
+msgid "The note contents has been left in %s"
+msgstr "Die Notiz-Inhalte wurden in %s belassen"
+
+#: builtin/notes.c:251 builtin/tag.c:521
+#, c-format
+msgid "cannot read '%s'"
+msgstr "kann '%s' nicht lesen"
+
+#: builtin/notes.c:253 builtin/tag.c:524
+#, c-format
+msgid "could not open or read '%s'"
+msgstr "konnte '%s' nicht öffnen oder lesen"
+
+#: builtin/notes.c:272 builtin/notes.c:445 builtin/notes.c:447
+#: builtin/notes.c:507 builtin/notes.c:561 builtin/notes.c:644
+#: builtin/notes.c:649 builtin/notes.c:724 builtin/notes.c:766
+#: builtin/notes.c:968 builtin/reset.c:293 builtin/tag.c:537
+#, c-format
+msgid "Failed to resolve '%s' as a valid ref."
+msgstr "Konnte '%s' nicht als gültige Referenz auflösen."
+
+#: builtin/notes.c:275
+#, c-format
+msgid "Failed to read object '%s'."
+msgstr "Fehler beim Lesen des Objektes '%s'."
+
+#: builtin/notes.c:299
+msgid "Cannot commit uninitialized/unreferenced notes tree"
+msgstr "Kann uninitialisierten/unreferenzierten Notiz-Baum nicht eintragen."
+
+#: builtin/notes.c:340
+#, c-format
+msgid "Bad notes.rewriteMode value: '%s'"
+msgstr "Ungültiger notes.rewriteMode Wert: '%s'"
+
+#: builtin/notes.c:350
+#, c-format
+msgid "Refusing to rewrite notes in %s (outside of refs/notes/)"
+msgstr ""
+"Neuschreiben der Notizen in %s zurückgewiesen (außerhalb von refs/notes/)"
+
+#. 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'"
+msgstr "Ungültiger %s Wert: '%s'"
+
+#: builtin/notes.c:441
+#, c-format
+msgid "Malformed input line: '%s'."
+msgstr "Fehlerhafte Eingabezeile: '%s'."
+
+#: builtin/notes.c:456
+#, c-format
+msgid "Failed to copy notes from '%s' to '%s'"
+msgstr "Fehler beim Kopieren der Notizen von '%s' nach '%s'"
+
+#: builtin/notes.c:500 builtin/notes.c:554 builtin/notes.c:627
+#: builtin/notes.c:639 builtin/notes.c:712 builtin/notes.c:759
+#: builtin/notes.c:1033
+msgid "too many parameters"
+msgstr "zu viele Parameter"
+
+#: builtin/notes.c:513 builtin/notes.c:772
+#, c-format
+msgid "No note found for object %s."
+msgstr "Kein Notiz für Objekt %s gefunden."
+
+#: builtin/notes.c:580
+#, c-format
+msgid ""
+"Cannot add notes. Found existing notes for object %s. Use '-f' to overwrite "
+"existing notes"
+msgstr ""
+"Konnte Notizen nicht hinzufügen. Existierende Notizen für Objekt %s "
+"gefunden. Verwende '-f' um die existierenden Notizen zu überschreiben."
+
+#: builtin/notes.c:585 builtin/notes.c:662
+#, c-format
+msgid "Overwriting existing notes for object %s\n"
+msgstr "Überschreibe existierende Notizen für Objekt %s\n"
+
+#: builtin/notes.c:635
+msgid "too few parameters"
+msgstr "zu wenig Parameter"
+
+#: builtin/notes.c:656
+#, c-format
+msgid ""
+"Cannot copy notes. Found existing notes for object %s. Use '-f' to overwrite "
+"existing notes"
+msgstr ""
+"Kann Notizen nicht kopieren. Existierende Notizen für Objekt %s gefunden. "
+"Verwende '-f' um die existierenden Notizen zu überschreiben."
+
+#: builtin/notes.c:668
+#, c-format
+msgid "Missing notes on source object %s. Cannot copy."
+msgstr "Keine Notizen für Quell-Objekt %s. Kopie nicht möglich."
+
+#: builtin/notes.c:717
+#, 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 ""
+"Die Optionen -m/-F/-c/-C sind für das Unterkommando 'edit' veraltet.\n"
+"Bitte benutze stattdessen 'git notes add -f -m/-F/-c/-C'.\n"
+
+#: builtin/notes.c:971
+#, c-format
+msgid "Object %s has no note\n"
+msgstr "Objekt %s hat keine Notiz\n"
+
+#: builtin/notes.c:1103
+#, c-format
+msgid "Unknown subcommand: %s"
+msgstr "Unbekanntes Unterkommando: %s"
+
+#: builtin/pack-objects.c:2315
+#, c-format
+msgid "unsupported index version %s"
+msgstr "Nicht unterstützte Bereitstellungsversion %s"
+
+#: builtin/pack-objects.c:2319
+#, c-format
+msgid "bad index version '%s'"
+msgstr "Ungültige Bereitstellungsversion '%s'"
+
+#: builtin/pack-objects.c:2342
+#, c-format
+msgid "option %s does not accept negative form"
+msgstr "Option %s akzeptiert keine negative Form"
+
+#: builtin/pack-objects.c:2346
+#, c-format
+msgid "unable to parse value '%s' for option %s"
+msgstr "konnte Wert '%s' für Option %s nicht parsen"
+
+#: builtin/push.c:45
+msgid "tag shorthand without <tag>"
+msgstr "Kurzschrift für Markierung ohne <Markierung>"
+
+#: builtin/push.c:64
+msgid "--delete only accepts plain target ref names"
+msgstr "--delete akzeptiert nur reine Referenz-Namen als Ziel"
+
+#: builtin/push.c:84
+#, 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 ""
+"Du befindest dich sich im Moment auf keinem Zweig.\n"
+"Um die Historie, führend zum aktuellen (freistehende Zweigspitze (HEAD))\n"
+"Status zu versenden, benutze\n"
+"\n"
+" git push %s HEAD:<Name-des-externen-Zweiges>\n"
+
+#: builtin/push.c:91
+#, 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 ""
+"Der aktuelle Zweig %s hat keinen Zweig im externen Projektarchiv.\n"
+"Um den aktuellen Zweig zu versenden und das Fernarchiv als externes\n"
+"Projektarchiv zu verwenden, benutze\n"
+"\n"
+" git push --set-upstream %s %s\n"
+
+#: builtin/push.c:99
+#, c-format
+msgid "The current branch %s has multiple upstream branches, refusing to push."
+msgstr "Der aktuelle Zweig %s hat mehrere externe Zweige, Versand verweigert."
+
+#: builtin/push.c:102
+#, 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 ""
+"Du versendest nach '%s', welches kein externes Projektarchiv deines\n"
+"aktuellen Zweiges '%s' ist, ohne mir mitzuteilen, was ich versenden\n"
+"soll, um welchen externen Zweig zu aktualisieren."
+
+#: builtin/push.c:131
+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:138
+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 ""
+"Aktualisierungen wurden zurückgewiesen, weil die Spitze deines aktuellen\n"
+"Zweiges hinter seinem externen Gegenstück zurückgefallen ist. Führe die\n"
+"externen Änderungen zusammen (z.B. 'git pull') bevor du erneut versendest.\n"
+"Siehe auch die Sektion 'Note about fast-forwards' in 'git push --help' für\n"
+"weitere Details."
+
+#: builtin/push.c:144
+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."
+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"
+"oder 'upstream' setzen, um nur den aktuellen Zweig zu versenden."
+
+#: builtin/push.c:150
+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 ""
+"Aktualisierungen wurden zurückgewiesen, weil die Spitze eines versendeten\n"
+"Zweiges hinter seinem externen Gegenstück zurückgefallen ist. Checke diesen\n"
+"Zweig aus und führe die externen Änderungen zusammen (z.B. 'git pull')\n"
+"bevor du erneut versendest.\n"
+"Siehe auch die Sektion 'Note about fast-forwards' in 'git push --help'\n"
+"für weitere Details."
+
+#: builtin/push.c:190
+#, c-format
+msgid "Pushing to %s\n"
+msgstr "Versende nach %s\n"
+
+#: builtin/push.c:194
+#, c-format
+msgid "failed to push some refs to '%s'"
+msgstr "Fehler beim Versenden einiger Referenzen nach '%s'"
+
+#: builtin/push.c:226
+#, c-format
+msgid "bad repository '%s'"
+msgstr "ungültiges Projektarchiv '%s'"
+
+#: builtin/push.c:227
+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 ""
+"Kein Ziel zum Versenden konfiguriert.\n"
+"Entweder spezifizierst du die URL von der Kommandozeile oder konfigurierst "
+"ein externes Projektarchiv unter Benutzung von\n"
+"\n"
+" git remote add <Name> <URL>\n"
+"\n"
+"und versendest dann unter Benutzung dieses Namens\n"
+"\n"
+" git push <Name>\n"
+
+#: builtin/push.c:242
+msgid "--all and --tags are incompatible"
+msgstr "--all und --tags sind inkompatibel"
+
+#: builtin/push.c:243
+msgid "--all can't be combined with refspecs"
+msgstr "--all kann nicht mit Referenzspezifikationen kombiniert werden"
+
+#: builtin/push.c:248
+msgid "--mirror and --tags are incompatible"
+msgstr "--mirror und --tags sind inkompatibel"
+
+#: builtin/push.c:249
+msgid "--mirror can't be combined with refspecs"
+msgstr "--mirror kann nicht mit Referenzspezifikationen kombiniert werden"
+
+#: builtin/push.c:254
+msgid "--all and --mirror are incompatible"
+msgstr "--all und --mirror sind inkompatibel"
+
+#: builtin/push.c:334
+msgid "--delete is incompatible with --all, --mirror and --tags"
+msgstr "--delete ist inkompatibel mit --all, --mirror und --tags"
+
+#: builtin/push.c:336
+msgid "--delete doesn't make sense without any refs"
+msgstr "--delete macht ohne irgendeine Referenz keinen Sinn"
+
+#: builtin/reset.c:33
+msgid "mixed"
+msgstr "mixed"
+
+#: builtin/reset.c:33
+msgid "soft"
+msgstr "soft"
+
+#: builtin/reset.c:33
+msgid "hard"
+msgstr "hard"
+
+#: builtin/reset.c:33
+msgid "keep"
+msgstr "keep"
+
+#: builtin/reset.c:77
+msgid "You do not have a valid HEAD."
+msgstr "Du hast keine gültige Zweigspitze (HEAD)."
+
+#: builtin/reset.c:79
+msgid "Failed to find tree of HEAD."
+msgstr "Fehler beim Finden des Baumes der Zweigspitze (HEAD)."
+
+#: builtin/reset.c:85
+#, c-format
+msgid "Failed to find tree of %s."
+msgstr "Fehler beim Finden des Baumes von %s."
+
+#: builtin/reset.c:96
+msgid "Could not write new index file."
+msgstr "Konnte neue Bereitstellungsdatei nicht schreiben."
+
+#: builtin/reset.c:106
+#, c-format
+msgid "HEAD is now at %s"
+msgstr "Zweigspitze (HEAD) ist jetzt bei %s"
+
+#: builtin/reset.c:130
+msgid "Could not read index"
+msgstr "Konnte Bereitstellung nicht lesen"
+
+#: builtin/reset.c:133
+msgid "Unstaged changes after reset:"
+msgstr "Nicht bereitgestellte Änderungen nach Zurücksetzung:"
+
+#: builtin/reset.c:223
+#, c-format
+msgid "Cannot do a %s reset in the middle of a merge."
+msgstr ""
+"Kann keine '%s' Zurücksetzung durchführen, während eine Zusammenführung im "
+"Gange ist."
+
+#: builtin/reset.c:297
+#, c-format
+msgid "Could not parse object '%s'."
+msgstr "Konnte Objekt '%s' nicht parsen."
+
+#: builtin/reset.c:302
+msgid "--patch is incompatible with --{hard,mixed,soft}"
+msgstr "--patch ist inkompatibel mit --{hard,mixed,soft}"
+
+#: builtin/reset.c:311
+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
+#, c-format
+msgid "Cannot do %s reset with paths."
+msgstr "Eine '%s' Zurücksetzung mit Pfaden ist nicht möglich."
+
+#: builtin/reset.c:325
+#, 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
+#, c-format
+msgid "Could not reset index file to revision '%s'."
+msgstr "Konnte Bereitstellungsdatei nicht zu Version '%s' zurücksetzen."
+
+#: builtin/revert.c:70 builtin/revert.c:92
+#, c-format
+msgid "%s: %s cannot be used with %s"
+msgstr "%s: %s kann nicht mit %s benutzt werden"
+
+#: builtin/revert.c:127
+msgid "program error"
+msgstr "Programmfehler"
+
+#: builtin/revert.c:213
+msgid "revert failed"
+msgstr "\"revert\" fehlgeschlagen"
+
+#: builtin/revert.c:228
+msgid "cherry-pick failed"
+msgstr "\"cherry-pick\" fehlgeschlagen"
+
+#: 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' hat bereitgestellten Inhalt unterschiedlich zu der Datei und der\n"
+"Zweigspitze (HEAD) (benutze -f um die Entfernung zu erzwingen)"
+
+#: 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' hat Änderungen in der Bereitstellung\n"
+"(benutze --cached um die Datei zu behalten, oder -f um die Entfernung zu "
+"erzwingen)"
+
+#: 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' hat lokale Modifikationen\n"
+"(benutze --cached um die Datei zu behalten, oder -f um die Entfernung zu "
+"erzwingen)"
+
+#: builtin/rm.c:194
+#, c-format
+msgid "not removing '%s' recursively without -r"
+msgstr "'%s' wird nicht ohne -r rekursiv entfernt"
+
+#: builtin/rm.c:230
+#, c-format
+msgid "git rm: unable to remove %s"
+msgstr "git rm: konnte %s nicht entfernen"
+
+#: builtin/shortlog.c:157
+#, c-format
+msgid "Missing author: %s"
+msgstr "fehlender Autor: %s"
+
+#: builtin/tag.c:58
+#, c-format
+msgid "malformed object at '%s'"
+msgstr "fehlerhaftes Objekt bei '%s'"
+
+#: builtin/tag.c:205
+#, c-format
+msgid "tag name too long: %.*s..."
+msgstr "Markierungsname zu lang: %.*s..."
+
+#: builtin/tag.c:210
+#, c-format
+msgid "tag '%s' not found."
+msgstr "Markierung '%s' nicht gefunden."
+
+#: builtin/tag.c:225
+#, c-format
+msgid "Deleted tag '%s' (was %s)\n"
+msgstr "Gelöschte Markierung '%s' (war %s)\n"
+
+#: builtin/tag.c:237
+#, c-format
+msgid "could not verify the tag '%s'"
+msgstr "Konnte Markierung '%s' nicht verifizieren"
+
+#: builtin/tag.c:247
+msgid ""
+"\n"
+"#\n"
+"# Write a tag message\n"
+"# Lines starting with '#' will be ignored.\n"
+"#\n"
+msgstr ""
+"\n"
+"#\n"
+"# Gebe eine Markierungsbeschreibung ein\n"
+"# Zeilen, die mit '#' beginnen, werden ignoriert.\n"
+"#\n"
+
+#: builtin/tag.c:254
+msgid ""
+"\n"
+"#\n"
+"# Write a tag message\n"
+"# Lines starting with '#' will be kept; you may remove them yourself if you "
+"want to.\n"
+"#\n"
+msgstr ""
+"\n"
+"#\n"
+"# Gebe eine Markierungsbeschreibung ein\n"
+"# Zeilen, die mit '#' beginnen, werden behalten; du darfst diese\n"
+"# selbst entfernen wenn du möchtest.\n"
+"#\n"
+
+#: builtin/tag.c:294
+msgid "unable to sign the tag"
+msgstr "konnte Markierung nicht signieren"
+
+#: builtin/tag.c:296
+msgid "unable to write tag file"
+msgstr "konnte Markierungsdatei nicht schreiben"
+
+#: builtin/tag.c:321
+msgid "bad object type."
+msgstr "ungültiger Objekt-Typ"
+
+#: builtin/tag.c:334
+msgid "tag header too big."
+msgstr "Markierungskopf zu groß."
+
+#: builtin/tag.c:366
+msgid "no tag message?"
+msgstr "keine Markierungsbeschreibung?"
+
+#: builtin/tag.c:372
+#, c-format
+msgid "The tag message has been left in %s\n"
+msgstr "Die Markierungsbeschreibung wurde in %s gelassen\n"
+
+#: builtin/tag.c:421
+msgid "switch 'points-at' requires an object"
+msgstr "Option 'points-at' erfordert ein Objekt"
+
+#: builtin/tag.c:423
+#, c-format
+msgid "malformed object name '%s'"
+msgstr "fehlerhafter Objekt-Name '%s'"
+
+#: builtin/tag.c:502
+msgid "-n option is only allowed with -l."
+msgstr "-n Option ist nur erlaubt mit -l."
+
+#: builtin/tag.c:504
+msgid "--contains option is only allowed with -l."
+msgstr "--contains Option ist nur erlaubt mit -l."
+
+#: builtin/tag.c:506
+msgid "--points-at option is only allowed with -l."
+msgstr "--points-at Option ist nur erlaubt mit -l."
+
+#: builtin/tag.c:514
+msgid "only one -F or -m option is allowed."
+msgstr "nur eine -F oder -m Option ist erlaubt."
+
+#: builtin/tag.c:534
+msgid "too many params"
+msgstr "zu viele Parameter"
+
+#: builtin/tag.c:540
+#, c-format
+msgid "'%s' is not a valid tag name."
+msgstr "'%s' ist kein gültiger Markierungsname."
+
+#: builtin/tag.c:545
+#, c-format
+msgid "tag '%s' already exists"
+msgstr "Markierung '%s' existiert bereits"
+
+#: builtin/tag.c:563
+#, c-format
+msgid "%s: cannot lock the ref"
+msgstr "%s: kann Referenz nicht sperren"
+
+#: builtin/tag.c:565
+#, c-format
+msgid "%s: cannot update the ref"
+msgstr "%s: kann Referenz nicht aktualisieren"
+
+#: builtin/tag.c:567
+#, c-format
+msgid "Updated tag '%s' (was %s)\n"
+msgstr "Aktualisierte Markierung '%s' (war %s)\n"
+
+#: git-am.sh:49
+msgid "You need to set your committer info first"
+msgstr "Du musst zuerst die Informationen des Eintragenden setzen."
+
+#: git-am.sh:136
+msgid "Repository lacks necessary blobs to fall back on 3-way merge."
+msgstr ""
+"Dem Projektarchiv fehlen notwendige Blobs um auf eine 3-Wege-Zusammenführung "
+"zurückzufallen."
+
+#: git-am.sh:147
+msgid ""
+"Did you hand edit your patch?\n"
+"It does not apply to blobs recorded in its index."
+msgstr ""
+"Hast du den Patch per Hand editiert?\n"
+"Er kann nicht auf die Blobs in seiner 'index' Zeile angewendet werden."
+
+#: git-am.sh:156
+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:268
+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:355
+#, sh-format
+msgid "Patch format $patch_format is not supported."
+msgstr "Patch-Format $patch_format wird nicht unterstützt."
+
+#: git-am.sh:357
+msgid "Patch format detection failed."
+msgstr "Patch-Formaterkennung fehlgeschlagen."
+
+#: git-am.sh:411
+msgid "-d option is no longer supported. Do not use."
+msgstr "-d Option wird nicht länger unterstützt. Nicht benutzen."
+
+#: git-am.sh:474
+#, 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:479
+msgid "Please make up your mind. --skip or --abort?"
+msgstr "Bitte werde dir klar. --skip oder --abort?"
+
+#: git-am.sh:506
+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:572
+#, sh-format
+msgid "Dirty index: cannot apply patches (dirty: $files)"
+msgstr ""
+"Unsaubere Bereitstellung: kann Patches nicht anwenden (unsauber: $files)"
+
+#: git-am.sh:748
+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."
+
+#. 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:759
+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:795
+#, sh-format
+msgid "Applying: $FIRSTLINE"
+msgstr "Wende an: $FIRSTLINE"
+
+#: git-am.sh:840
+msgid "No changes -- Patch already applied."
+msgstr "Keine Änderungen -- Patches bereits angewendet."
+
+#: git-am.sh:866
+msgid "applying to an empty history"
+msgstr "wende zu leerer Historie an"
+
+#. TRANSLATORS: Make sure to include [Y] and [n] in your
+#. translation. The program will only accept English input
+#. at this point.
+#: git-bisect.sh:54
+msgid "Do you want me to do it for you [Y/n]? "
+msgstr "Willst du, dass ich es für dich mache [Y/n]? "
+
+#: git-bisect.sh:95
+#, sh-format
+msgid "unrecognised option: '$arg'"
+msgstr "nicht erkannte Option: '$arg'"
+
+#: git-bisect.sh:99
+#, sh-format
+msgid "'$arg' does not appear to be a valid revision"
+msgstr "'$arg' scheint keine gültige Version zu sein"
+
+#: git-bisect.sh:117
+msgid "Bad HEAD - I need a HEAD"
+msgstr "Ungültige Zweigspitze (HEAD) - Zweigspitze (HEAD) wird benötigt"
+
+#: git-bisect.sh:130
+#, sh-format
+msgid ""
+"Checking out '$start_head' failed. Try 'git bisect reset <validbranch>'."
+msgstr ""
+"Auschecken von '$start_head' fehlgeschlagen. Versuche 'git bisect reset "
+"<gueltigerzweig>'."
+
+#: git-bisect.sh:140
+msgid "won't bisect on seeked tree"
+msgstr "\"bisect\" auf gesuchtem Zweig nicht möglich"
+
+#: git-bisect.sh:144
+msgid "Bad HEAD - strange symbolic ref"
+msgstr "Ungültige Zweigspitze (HEAD) - merkwürdige symbolische Referenz"
+
+#: git-bisect.sh:189
+#, sh-format
+msgid "Bad bisect_write argument: $state"
+msgstr "Ungültiges \"bisect_write\" Argument: $state"
+
+#: git-bisect.sh:218
+#, sh-format
+msgid "Bad rev input: $arg"
+msgstr "Ungültige Referenz-Eingabe: $arg"
+
+#: git-bisect.sh:232
+msgid "Please call 'bisect_state' with at least one argument."
+msgstr "Bitte rufe 'bisect_state' mit mindestens einem Argument auf."
+
+#: git-bisect.sh:244
+#, sh-format
+msgid "Bad rev input: $rev"
+msgstr "Ungültige Referenz-Eingabe: $rev"
+
+#: git-bisect.sh:250
+msgid "'git bisect bad' can take only one argument."
+msgstr "'git bisect bad' kann nur ein Argument entgegennehmen."
+
+#. 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 "Bist du sicher [Y/n]? "
+
+#: git-bisect.sh:354
+#, sh-format
+msgid "'$invalid' is not a valid commit"
+msgstr "'$invalid' ist keine gültige Version"
+
+#: git-bisect.sh:363
+#, sh-format
+msgid ""
+"Could not check out original HEAD '$branch'.\n"
+"Try 'git bisect reset <commit>'."
+msgstr ""
+"Konnte die ursprüngliche Zweigspitze (HEAD) '$branch' nicht auschecken.\n"
+"Versuche 'git bisect reset <Version>'."
+
+#: git-bisect.sh:390
+msgid "No logfile given"
+msgstr "Keine Log-Datei gegeben"
+
+#: git-bisect.sh:391
+#, sh-format
+msgid "cannot read $file for replaying"
+msgstr "kann $file nicht zum neu abspielen lesen"
+
+#: git-bisect.sh:408
+msgid "?? what are you talking about?"
+msgstr "?? Was redest du da?"
+
+#: git-bisect.sh:474
+msgid "We are not bisecting."
+msgstr "Wir sind nicht beim Halbieren."
+
+#: git-pull.sh:21
+msgid ""
+"Pull is not possible because you have unmerged files.\n"
+"Please, fix them up in the work tree, and then use 'git add/rm <file>'\n"
+"as appropriate to mark resolution, or use 'git commit -a'."
+msgstr ""
+"\"pull\" ist nicht möglich, weil du nicht zusammengeführte Dateien hast.\n"
+"Bitte korrigiere dies im Arbeitsbaum und benutze dann 'git add/rm <Datei>'\n"
+"um die Auflösung entsprechend zu markieren, oder benutze 'git commit -a'."
+
+#: git-pull.sh:25
+msgid "Pull is not possible because you have unmerged files."
+msgstr ""
+"\"pull\" ist nicht möglich, weil du nicht zusammengeführte Dateien hast."
+
+#: git-pull.sh:197
+msgid "updating an unborn branch with changes added to the index"
+msgstr ""
+"Aktualisiere eine ungeborenen Zweig mit Änderungen, die zur Bereitstellung "
+"hinzugefügt wurden"
+
+#: git-pull.sh:253
+msgid "Cannot merge multiple branches into empty head"
+msgstr "Kann nicht mehrere Zweige in einen ungeborenen Zweig zusammenführen"
+
+#: git-pull.sh:257
+msgid "Cannot rebase onto multiple branches"
+msgstr "kann nicht auf mehrere Zweige neu aufbauen"
+
+#: git-stash.sh:51
+msgid "git stash clear with parameters is unimplemented"
+msgstr "git stash clear mit Parametern ist nicht implementiert"
+
+#: git-stash.sh:74
+msgid "You do not have the initial commit yet"
+msgstr "Du hast bisher noch keine initiale Version"
+
+#: git-stash.sh:89
+msgid "Cannot save the current index state"
+msgstr "Kann den aktuellen Zustand der Bereitstellung nicht speichern"
+
+#: git-stash.sh:123 git-stash.sh:136
+msgid "Cannot save the current worktree state"
+msgstr "Kann den aktuellen Zustand des Arbeitsbaumes nicht speichern"
+
+#: git-stash.sh:140
+msgid "No changes selected"
+msgstr "Keine Änderungen ausgewählt"
+
+#: git-stash.sh:143
+msgid "Cannot remove temporary index (can't happen)"
+msgstr "Kann temporäre Bereitstellung nicht entfernen (kann nicht passieren)"
+
+#: git-stash.sh:156
+msgid "Cannot record working tree state"
+msgstr "Kann Zustand des Arbeitsbaumes nicht aufzeichnen"
+
+#: git-stash.sh:223
+msgid "No local changes to save"
+msgstr "Keine lokalen Änderungen zum Speichern"
+
+#: git-stash.sh:227
+msgid "Cannot initialize stash"
+msgstr "Kann \"stash\" nicht initialisieren"
+
+#: git-stash.sh:235
+msgid "Cannot save the current status"
+msgstr "Kann den aktuellen Status nicht speichern"
+
+#: git-stash.sh:253
+msgid "Cannot remove worktree changes"
+msgstr "Kann Änderungen am Arbeitsbaum nicht entfernen"
+
+#: git-stash.sh:352
+msgid "No stash found."
+msgstr "Kein \"stash\" gefunden."
+
+#: git-stash.sh:359
+#, sh-format
+msgid "Too many revisions specified: $REV"
+msgstr "Zu viele Revisionen angegeben: $REV"
+
+#: git-stash.sh:365
+#, sh-format
+msgid "$reference is not valid reference"
+msgstr "$reference ist keine gültige Referenz"
+
+#: git-stash.sh:393
+#, sh-format
+msgid "'$args' is not a stash-like commit"
+msgstr "'$args' ist keine \"stash\"-artige Version"
+
+#: git-stash.sh:404
+#, sh-format
+msgid "'$args' is not a stash reference"
+msgstr "'$args' ist keine \"stash\"-Referenz"
+
+#: git-stash.sh:412
+msgid "unable to refresh index"
+msgstr "Konnte die Bereitstellung nicht aktualisieren"
+
+#: git-stash.sh:416
+msgid "Cannot apply a stash in the middle of a merge"
+msgstr ""
+"Kann \"stash\" nicht anwenden, solang eine Zusammenführung im Gange ist"
+
+#: git-stash.sh:424
+msgid "Conflicts in index. Try without --index."
+msgstr "Konflikte in der Bereitstellung. Versuche es ohne --index."
+
+#: git-stash.sh:426
+msgid "Could not save index tree"
+msgstr "Konnte Bereitstellungsbaum nicht speichern"
+
+#: git-stash.sh:460
+msgid "Cannot unstage modified files"
+msgstr "Kann geänderte Dateien nicht aus der Bereitstellung herausnehmen"
+
+#: git-stash.sh:491
+#, sh-format
+msgid "Dropped ${REV} ($s)"
+msgstr "Gelöscht ${REV} ($s)"
+
+#: git-stash.sh:492
+#, sh-format
+msgid "${REV}: Could not drop stash entry"
+msgstr "${REV}: Konnte \"stash\"-Eintrag nicht löschen"
+
+#: git-stash.sh:499
+msgid "No branch name specified"
+msgstr "Kein Zweigname spezifiziert"
+
+#: git-stash.sh:570
+msgid "(To restore them type \"git stash apply\")"
+msgstr "(Zur Wiederherstellung gebe \"git stash apply\" ein)"
+
+#: git-submodule.sh:56
+#, sh-format
+msgid "cannot strip one component off url '$remoteurl'"
+msgstr "Kann eine Komponente von URL '$remoteurl' nicht extrahieren"
+
+#: git-submodule.sh:108
+#, sh-format
+msgid "No submodule mapping found in .gitmodules for path '$path'"
+msgstr "Keine Unterprojekt-Zuordnung in .gitmodules für Pfad '$path' gefunden"
+
+#: git-submodule.sh:149
+#, sh-format
+msgid "Clone of '$url' into submodule path '$path' failed"
+msgstr "Klonen von '$url' in Unterprojekt-Pfad '$path' fehlgeschlagen"
+
+#: git-submodule.sh:159
+#, 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:248
+#, 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:265
+#, sh-format
+msgid "'$path' already exists in the index"
+msgstr "'$path' existiert bereits in der Bereitstellung"
+
+#: git-submodule.sh:282
+#, sh-format
+msgid "'$path' already exists and is not a valid git repo"
+msgstr "'$path' existiert bereits und ist kein gültiges Git-Projektarchiv"
+
+#: git-submodule.sh:296
+#, sh-format
+msgid "Unable to checkout submodule '$path'"
+msgstr "Unfähig Unterprojekt '$path' auszuchecken"
+
+#: git-submodule.sh:301
+#, sh-format
+msgid "Failed to add submodule '$path'"
+msgstr "Hinzufügen von Unterprojekt '$path' fehlgeschlagen"
+
+#: git-submodule.sh:306
+#, sh-format
+msgid "Failed to register submodule '$path'"
+msgstr "Registrierung von Unterprojekt '$path' fehlgeschlagen"
+
+#: git-submodule.sh:348
+#, sh-format
+msgid "Entering '$prefix$path'"
+msgstr "Betrete '$prefix$path'"
+
+#: git-submodule.sh:360
+#, sh-format
+msgid "Stopping at '$path'; script returned non-zero status."
+msgstr "Stoppe bei '$path'; Skript gab nicht-Null Status zurück."
+
+#: git-submodule.sh:402
+#, sh-format
+msgid "No url found for submodule path '$path' in .gitmodules"
+msgstr "Keine URL für Unterprojekt-Pfad '$path' in .gitmodules gefunden"
+
+#: git-submodule.sh:411
+#, sh-format
+msgid "Failed to register url for submodule path '$path'"
+msgstr "Registrierung der URL für Unterprojekt-Pfad '$path' fehlgeschlagen"
+
+#: git-submodule.sh:419
+#, sh-format
+msgid "Failed to register update mode for submodule path '$path'"
+msgstr ""
+"Registrierung des Aktualisierungsmodus für Unterprojekt-Pfad '$path' "
+"fehlgeschlagen"
+
+#: git-submodule.sh:421
+#, sh-format
+msgid "Submodule '$name' ($url) registered for path '$path'"
+msgstr "Unterprojekt '$name' ($url) ist für Pfad '$path' registriert"
+
+#: git-submodule.sh:520
+#, sh-format
+msgid ""
+"Submodule path '$path' not initialized\n"
+"Maybe you want to use 'update --init'?"
+msgstr ""
+"Unterprojekt-Pfad '$path' ist nicht initialisiert\n"
+"Vielleicht möchtest du 'update --init' benutzen?"
+
+#: git-submodule.sh:533
+#, sh-format
+msgid "Unable to find current revision in submodule path '$path'"
+msgstr "Konnte aktuelle Version in Unterprojekt-Pfad '$path' nicht finden"
+
+#: git-submodule.sh:552
+#, sh-format
+msgid "Unable to fetch in submodule path '$path'"
+msgstr "Konnte Unterprojekt-Pfad '$path' nicht anfordern"
+
+#: git-submodule.sh:566
+#, sh-format
+msgid "Unable to rebase '$sha1' in submodule path '$path'"
+msgstr "Neuaufbau von '$sha1' in Unterprojekt-Pfad '$path' nicht möglich"
+
+#: git-submodule.sh:567
+#, sh-format
+msgid "Submodule path '$path': rebased into '$sha1'"
+msgstr "Unterprojekt-Pfad '$path': neu aufgebaut in '$sha1'"
+
+#: git-submodule.sh:572
+#, sh-format
+msgid "Unable to merge '$sha1' in submodule path '$path'"
+msgstr ""
+"Zusammenführung von '$sha1' in Unterprojekt-Pfad '$path' fehlgeschlagen"
+
+#: git-submodule.sh:573
+#, sh-format
+msgid "Submodule path '$path': merged in '$sha1'"
+msgstr "Unterprojekt-Pfad '$path': zusammengeführt in '$sha1'"
+
+#: git-submodule.sh:578
+#, sh-format
+msgid "Unable to checkout '$sha1' in submodule path '$path'"
+msgstr "Konnte '$sha1' in Unterprojekt-Pfad '$path' nicht auschecken."
+
+#: git-submodule.sh:579
+#, sh-format
+msgid "Submodule path '$path': checked out '$sha1'"
+msgstr "Unterprojekt-Pfad: '$path': '$sha1' ausgecheckt"
+
+#: git-submodule.sh:601 git-submodule.sh:924
+#, sh-format
+msgid "Failed to recurse into submodule path '$path'"
+msgstr "Fehler bei Rekursion in Unterprojekt-Pfad '$path'"
+
+#: git-submodule.sh:709
+msgid "--"
+msgstr "--"
+
+#: git-submodule.sh:767
+#, sh-format
+msgid " Warn: $name doesn't contain commit $sha1_src"
+msgstr " Warnung: $name beinhaltet nicht Version $sha1_src"
+
+#: git-submodule.sh:770
+#, sh-format
+msgid " Warn: $name doesn't contain commit $sha1_dst"
+msgstr " Warnung: $name beinhaltet nicht Version $sha1_dst"
+
+#: git-submodule.sh:773
+#, 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:798
+msgid "blob"
+msgstr "Blob"
+
+#: git-submodule.sh:799
+msgid "submodule"
+msgstr "Unterprojekt"
+
+#: git-submodule.sh:970
+#, sh-format
+msgid "Synchronizing submodule url for '$name'"
+msgstr "Synchronisiere Unterprojekt-URL für '$name'"
+
+#~ msgid "Too many options specified"
+#~ msgstr "Zu viele Optionen angegeben"
diff --git a/po/git.pot b/po/git.pot
new file mode 100644
index 0000000000..35b6b2a727
--- /dev/null
+++ b/po/git.pot
@@ -0,0 +1,3534 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
+"POT-Creation-Date: 2012-05-15 06:31+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"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
+
+#: advice.c:40
+#, c-format
+msgid "hint: %.*s\n"
+msgstr ""
+
+#.
+#. * Message used both when 'git commit' fails and when
+#. * other commands doing a merge do.
+#.
+#: advice.c:70
+msgid ""
+"Fix them up in the work tree,\n"
+"and then use 'git add/rm <file>' as\n"
+"appropriate to mark resolution and make a commit,\n"
+"or use 'git commit -a'."
+msgstr ""
+
+#: commit.c:47
+#, c-format
+msgid "could not parse %s"
+msgstr ""
+
+#: commit.c:49
+#, c-format
+msgid "%s %s is not a commit!"
+msgstr ""
+
+#: compat/obstack.c:406 compat/obstack.c:408
+msgid "memory exhausted"
+msgstr ""
+
+#: connected.c:39
+msgid "Could not run 'git rev-list'"
+msgstr ""
+
+#: connected.c:48
+#, c-format
+msgid "failed write to rev-list: %s"
+msgstr ""
+
+#: connected.c:56
+#, c-format
+msgid "failed to close rev-list's stdin: %s"
+msgstr ""
+
+#: diff.c:105
+#, c-format
+msgid " Failed to parse dirstat cut-off percentage '%.*s'\n"
+msgstr ""
+
+#: diff.c:110
+#, c-format
+msgid " Unknown dirstat parameter '%.*s'\n"
+msgstr ""
+
+#: diff.c:210
+#, c-format
+msgid ""
+"Found errors in 'diff.dirstat' config variable:\n"
+"%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:3439
+#, c-format
+msgid ""
+"Failed to parse --dirstat/-X option parameter:\n"
+"%s"
+msgstr ""
+
+#: gpg-interface.c:59
+msgid "could not run gpg."
+msgstr ""
+
+#: gpg-interface.c:71
+msgid "gpg did not accept the data"
+msgstr ""
+
+#: gpg-interface.c:82
+msgid "gpg failed to sign the data"
+msgstr ""
+
+#: grep.c:1280
+#, c-format
+msgid "'%s': unable to read %s"
+msgstr ""
+
+#: grep.c:1297
+#, c-format
+msgid "'%s': %s"
+msgstr ""
+
+#: grep.c:1308
+#, c-format
+msgid "'%s': short read %s"
+msgstr ""
+
+#: help.c:287
+#, 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 ""
+
+#: remote.c:1607
+#, 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:1613
+#, 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] ""
+msgstr[1] ""
+
+#: remote.c:1621
+#, c-format
+msgid ""
+"Your branch and '%s' have diverged,\n"
+"and have %d and %d different commit each, respectively.\n"
+msgid_plural ""
+"Your branch and '%s' have diverged,\n"
+"and have %d and %d different commits each, respectively.\n"
+msgstr[0] ""
+msgstr[1] ""
+
+#: sequencer.c:120 builtin/merge.c:865 builtin/merge.c:978
+#: builtin/merge.c:1088 builtin/merge.c:1098
+#, c-format
+msgid "Could not open '%s' for writing"
+msgstr ""
+
+#: sequencer.c:122 builtin/merge.c:333 builtin/merge.c:868
+#: builtin/merge.c:1090 builtin/merge.c:1103
+#, c-format
+msgid "Could not write to '%s'"
+msgstr ""
+
+#: sequencer.c:143
+msgid ""
+"after resolving the conflicts, mark the corrected paths\n"
+"with 'git add <paths>' or 'git rm <paths>'"
+msgstr ""
+
+#: sequencer.c:146
+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:159 sequencer.c:685 sequencer.c:768
+#, c-format
+msgid "Could not write to %s"
+msgstr ""
+
+#: sequencer.c:162
+#, c-format
+msgid "Error wrapping up %s"
+msgstr ""
+
+#: sequencer.c:177
+msgid "Your local changes would be overwritten by cherry-pick."
+msgstr ""
+
+#: sequencer.c:179
+msgid "Your local changes would be overwritten by revert."
+msgstr ""
+
+#: sequencer.c:182
+msgid "Commit your changes or stash them to proceed."
+msgstr ""
+
+#. TRANSLATORS: %s will be "revert" or "cherry-pick"
+#: sequencer.c:232
+#, c-format
+msgid "%s: Unable to write new index file"
+msgstr ""
+
+#: sequencer.c:298
+msgid "Your index file is unmerged."
+msgstr ""
+
+#: sequencer.c:301
+msgid "You do not have a valid HEAD"
+msgstr ""
+
+#: sequencer.c:316
+#, c-format
+msgid "Commit %s is a merge but no -m option was given."
+msgstr ""
+
+#: sequencer.c:324
+#, c-format
+msgid "Commit %s does not have parent %d"
+msgstr ""
+
+#: sequencer.c:328
+#, 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:339
+#, c-format
+msgid "%s: cannot parse parent commit %s"
+msgstr ""
+
+#: sequencer.c:343
+#, c-format
+msgid "Cannot get commit message for %s"
+msgstr ""
+
+#: sequencer.c:427
+#, c-format
+msgid "could not revert %s... %s"
+msgstr ""
+
+#: sequencer.c:428
+#, c-format
+msgid "could not apply %s... %s"
+msgstr ""
+
+#: sequencer.c:450 sequencer.c:909 builtin/log.c:288 builtin/log.c:713
+#: builtin/log.c:1329 builtin/log.c:1548 builtin/merge.c:347
+#: builtin/shortlog.c:181
+msgid "revision walk setup failed"
+msgstr ""
+
+#: sequencer.c:453
+msgid "empty commit set passed"
+msgstr ""
+
+#: sequencer.c:461
+#, c-format
+msgid "git %s: failed to read the index"
+msgstr ""
+
+#: sequencer.c:466
+#, c-format
+msgid "git %s: failed to refresh the index"
+msgstr ""
+
+#: sequencer.c:551
+#, c-format
+msgid "Cannot %s during a %s"
+msgstr ""
+
+#: sequencer.c:573
+#, c-format
+msgid "Could not parse line %d."
+msgstr ""
+
+#: sequencer.c:578
+msgid "No commits parsed."
+msgstr ""
+
+#: sequencer.c:591
+#, c-format
+msgid "Could not open %s"
+msgstr ""
+
+#: sequencer.c:595
+#, c-format
+msgid "Could not read %s."
+msgstr ""
+
+#: sequencer.c:602
+#, c-format
+msgid "Unusable instruction sheet: %s"
+msgstr ""
+
+#: sequencer.c:630
+#, c-format
+msgid "Invalid key: %s"
+msgstr ""
+
+#: sequencer.c:633
+#, c-format
+msgid "Invalid value for %s: %s"
+msgstr ""
+
+#: sequencer.c:645
+#, c-format
+msgid "Malformed options sheet: %s"
+msgstr ""
+
+#: sequencer.c:666
+msgid "a cherry-pick or revert is already in progress"
+msgstr ""
+
+#: sequencer.c:667
+msgid "try \"git cherry-pick (--continue | --quit | --abort)\""
+msgstr ""
+
+#: sequencer.c:671
+#, c-format
+msgid "Could not create sequencer directory %s"
+msgstr ""
+
+#: sequencer.c:687 sequencer.c:772
+#, c-format
+msgid "Error wrapping up %s."
+msgstr ""
+
+#: sequencer.c:706 sequencer.c:840
+msgid "no cherry-pick or revert in progress"
+msgstr ""
+
+#: sequencer.c:708
+msgid "cannot resolve HEAD"
+msgstr ""
+
+#: sequencer.c:710
+msgid "cannot abort from a branch yet to be born"
+msgstr ""
+
+#: sequencer.c:732
+#, c-format
+msgid "cannot open %s: %s"
+msgstr ""
+
+#: sequencer.c:735
+#, c-format
+msgid "cannot read %s: %s"
+msgstr ""
+
+#: sequencer.c:736
+msgid "unexpected end of file"
+msgstr ""
+
+#: sequencer.c:742
+#, c-format
+msgid "stored pre-cherry-pick HEAD file '%s' is corrupt"
+msgstr ""
+
+#: sequencer.c:765
+#, c-format
+msgid "Could not format %s."
+msgstr ""
+
+#: sequencer.c:927
+msgid "Can't revert as initial commit"
+msgstr ""
+
+#: sequencer.c:928
+msgid "Can't cherry-pick into empty head"
+msgstr ""
+
+#: wt-status.c:134
+msgid "Unmerged paths:"
+msgstr ""
+
+#: wt-status.c:140 wt-status.c:157
+#, c-format
+msgid " (use \"git reset %s <file>...\" to unstage)"
+msgstr ""
+
+#: wt-status.c:142 wt-status.c:159
+msgid " (use \"git rm --cached <file>...\" to unstage)"
+msgstr ""
+
+#: wt-status.c:143
+msgid " (use \"git add/rm <file>...\" as appropriate to mark resolution)"
+msgstr ""
+
+#: wt-status.c:151
+msgid "Changes to be committed:"
+msgstr ""
+
+#: wt-status.c:169
+msgid "Changes not staged for commit:"
+msgstr ""
+
+#: wt-status.c:173
+msgid " (use \"git add <file>...\" to update what will be committed)"
+msgstr ""
+
+#: wt-status.c:175
+msgid " (use \"git add/rm <file>...\" to update what will be committed)"
+msgstr ""
+
+#: wt-status.c:176
+msgid ""
+" (use \"git checkout -- <file>...\" to discard changes in working directory)"
+msgstr ""
+
+#: wt-status.c:178
+msgid " (commit or discard the untracked or modified content in submodules)"
+msgstr ""
+
+#: wt-status.c:187
+#, c-format
+msgid "%s files:"
+msgstr ""
+
+#: wt-status.c:190
+#, c-format
+msgid " (use \"git %s <file>...\" to include in what will be committed)"
+msgstr ""
+
+#: wt-status.c:207
+msgid "bug"
+msgstr ""
+
+#: wt-status.c:212
+msgid "both deleted:"
+msgstr ""
+
+#: wt-status.c:213
+msgid "added by us:"
+msgstr ""
+
+#: wt-status.c:214
+msgid "deleted by them:"
+msgstr ""
+
+#: wt-status.c:215
+msgid "added by them:"
+msgstr ""
+
+#: wt-status.c:216
+msgid "deleted by us:"
+msgstr ""
+
+#: wt-status.c:217
+msgid "both added:"
+msgstr ""
+
+#: wt-status.c:218
+msgid "both modified:"
+msgstr ""
+
+#: wt-status.c:248
+msgid "new commits, "
+msgstr ""
+
+#: wt-status.c:250
+msgid "modified content, "
+msgstr ""
+
+#: wt-status.c:252
+msgid "untracked content, "
+msgstr ""
+
+#: wt-status.c:266
+#, c-format
+msgid "new file: %s"
+msgstr ""
+
+#: wt-status.c:269
+#, c-format
+msgid "copied: %s -> %s"
+msgstr ""
+
+#: wt-status.c:272
+#, c-format
+msgid "deleted: %s"
+msgstr ""
+
+#: wt-status.c:275
+#, c-format
+msgid "modified: %s"
+msgstr ""
+
+#: wt-status.c:278
+#, c-format
+msgid "renamed: %s -> %s"
+msgstr ""
+
+#: wt-status.c:281
+#, c-format
+msgid "typechange: %s"
+msgstr ""
+
+#: wt-status.c:284
+#, c-format
+msgid "unknown: %s"
+msgstr ""
+
+#: wt-status.c:287
+#, c-format
+msgid "unmerged: %s"
+msgstr ""
+
+#: wt-status.c:290
+#, c-format
+msgid "bug: unhandled diff status %c"
+msgstr ""
+
+#: wt-status.c:713
+msgid "On branch "
+msgstr ""
+
+#: wt-status.c:720
+msgid "Not currently on any branch."
+msgstr ""
+
+#: wt-status.c:731
+msgid "Initial commit"
+msgstr ""
+
+#: wt-status.c:745
+msgid "Untracked"
+msgstr ""
+
+#: wt-status.c:747
+msgid "Ignored"
+msgstr ""
+
+#: wt-status.c:749
+#, c-format
+msgid "Untracked files not listed%s"
+msgstr ""
+
+#: wt-status.c:751
+msgid " (use -u option to show untracked files)"
+msgstr ""
+
+#: wt-status.c:757
+msgid "No changes"
+msgstr ""
+
+#: wt-status.c:761
+#, c-format
+msgid "no changes added to commit%s\n"
+msgstr ""
+
+#: wt-status.c:763
+msgid " (use \"git add\" and/or \"git commit -a\")"
+msgstr ""
+
+#: wt-status.c:765
+#, c-format
+msgid "nothing added to commit but untracked files present%s\n"
+msgstr ""
+
+#: wt-status.c:767
+msgid " (use \"git add\" to track)"
+msgstr ""
+
+#: wt-status.c:769 wt-status.c:772 wt-status.c:775
+#, c-format
+msgid "nothing to commit%s\n"
+msgstr ""
+
+#: wt-status.c:770
+msgid " (create/copy files and use \"git add\" to track)"
+msgstr ""
+
+#: wt-status.c:773
+msgid " (use -u to show untracked files)"
+msgstr ""
+
+#: wt-status.c:776
+msgid " (working directory clean)"
+msgstr ""
+
+#: wt-status.c:884
+msgid "HEAD (no branch)"
+msgstr ""
+
+#: wt-status.c:890
+msgid "Initial commit on "
+msgstr ""
+
+#: wt-status.c:905
+msgid "behind "
+msgstr ""
+
+#: wt-status.c:908 wt-status.c:911
+msgid "ahead "
+msgstr ""
+
+#: wt-status.c:913
+msgid ", behind "
+msgstr ""
+
+#: builtin/add.c:62
+#, c-format
+msgid "unexpected diff status %c"
+msgstr ""
+
+#: builtin/add.c:67 builtin/commit.c:298
+msgid "updating files failed"
+msgstr ""
+
+#: builtin/add.c:77
+#, c-format
+msgid "remove '%s'\n"
+msgstr ""
+
+#: builtin/add.c:176
+#, c-format
+msgid "Path '%s' is in submodule '%.*s'"
+msgstr ""
+
+#: builtin/add.c:192
+msgid "Unstaged changes after refreshing the index:"
+msgstr ""
+
+#: builtin/add.c:195 builtin/add.c:456 builtin/rm.c:186
+#, c-format
+msgid "pathspec '%s' did not match any files"
+msgstr ""
+
+#: builtin/add.c:209
+#, c-format
+msgid "'%s' is beyond a symbolic link"
+msgstr ""
+
+#: builtin/add.c:276
+msgid "Could not read the index"
+msgstr ""
+
+#: builtin/add.c:286
+#, c-format
+msgid "Could not open '%s' for writing."
+msgstr ""
+
+#: builtin/add.c:290
+msgid "Could not write patch"
+msgstr ""
+
+#: builtin/add.c:295
+#, c-format
+msgid "Could not stat '%s'"
+msgstr ""
+
+#: builtin/add.c:297
+msgid "Empty patch. Aborted."
+msgstr ""
+
+#: builtin/add.c:303
+#, c-format
+msgid "Could not apply '%s'"
+msgstr ""
+
+#: builtin/add.c:312
+msgid "The following paths are ignored by one of your .gitignore files:\n"
+msgstr ""
+
+#: builtin/add.c:352
+#, c-format
+msgid "Use -f if you really want to add them.\n"
+msgstr ""
+
+#: builtin/add.c:353
+msgid "no files added"
+msgstr ""
+
+#: builtin/add.c:359
+msgid "adding files failed"
+msgstr ""
+
+#: builtin/add.c:391
+msgid "-A and -u are mutually incompatible"
+msgstr ""
+
+#: builtin/add.c:393
+msgid "Option --ignore-missing can only be used together with --dry-run"
+msgstr ""
+
+#: builtin/add.c:413
+#, c-format
+msgid "Nothing specified, nothing added.\n"
+msgstr ""
+
+#: builtin/add.c:414
+#, c-format
+msgid "Maybe you wanted to say 'git add .'?\n"
+msgstr ""
+
+#: builtin/add.c:420 builtin/clean.c:95 builtin/commit.c:358 builtin/mv.c:82
+#: builtin/rm.c:162
+msgid "index file corrupt"
+msgstr ""
+
+#: builtin/add.c:476 builtin/mv.c:229 builtin/rm.c:260
+msgid "Unable to write new index file"
+msgstr ""
+
+#: builtin/archive.c:17
+#, c-format
+msgid "could not create archive file '%s'"
+msgstr ""
+
+#: builtin/archive.c:20
+msgid "could not redirect output"
+msgstr ""
+
+#: builtin/archive.c:37
+msgid "git archive: Remote with no URL"
+msgstr ""
+
+#: builtin/archive.c:58
+msgid "git archive: expected ACK/NAK, got EOF"
+msgstr ""
+
+#: builtin/archive.c:63
+#, c-format
+msgid "git archive: NACK %s"
+msgstr ""
+
+#: builtin/archive.c:65
+#, c-format
+msgid "remote error: %s"
+msgstr ""
+
+#: builtin/archive.c:66
+msgid "git archive: protocol error"
+msgstr ""
+
+#: builtin/archive.c:71
+msgid "git archive: expected a flush"
+msgstr ""
+
+#: builtin/branch.c:137
+#, c-format
+msgid ""
+"deleting branch '%s' that has been merged to\n"
+" '%s', but not yet merged to HEAD."
+msgstr ""
+
+#: builtin/branch.c:141
+#, c-format
+msgid ""
+"not deleting branch '%s' that is not yet merged to\n"
+" '%s', even though it is merged to HEAD."
+msgstr ""
+
+#. TRANSLATORS: This is "remote " in "remote branch '%s' not found"
+#: builtin/branch.c:163
+msgid "remote "
+msgstr ""
+
+#: builtin/branch.c:171
+msgid "cannot use -a with -d"
+msgstr ""
+
+#: builtin/branch.c:177
+msgid "Couldn't look up commit object for HEAD"
+msgstr ""
+
+#: builtin/branch.c:182
+#, c-format
+msgid "Cannot delete the branch '%s' which you are currently on."
+msgstr ""
+
+#: builtin/branch.c:192
+#, c-format
+msgid "%sbranch '%s' not found."
+msgstr ""
+
+#: builtin/branch.c:200
+#, c-format
+msgid "Couldn't look up commit object for '%s'"
+msgstr ""
+
+#: builtin/branch.c:206
+#, 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:214
+#, c-format
+msgid "Error deleting %sbranch '%s'"
+msgstr ""
+
+#: builtin/branch.c:219
+#, c-format
+msgid "Deleted %sbranch %s (was %s).\n"
+msgstr ""
+
+#: builtin/branch.c:224
+msgid "Update of config-file failed"
+msgstr ""
+
+#: builtin/branch.c:322
+#, c-format
+msgid "branch '%s' does not point at a commit"
+msgstr ""
+
+#: builtin/branch.c:394
+#, c-format
+msgid "behind %d] "
+msgstr ""
+
+#: builtin/branch.c:396
+#, c-format
+msgid "ahead %d] "
+msgstr ""
+
+#: builtin/branch.c:398
+#, c-format
+msgid "ahead %d, behind %d] "
+msgstr ""
+
+#: builtin/branch.c:501
+msgid "(no branch)"
+msgstr ""
+
+#: builtin/branch.c:566
+msgid "some refs could not be read"
+msgstr ""
+
+#: builtin/branch.c:579
+msgid "cannot rename the current branch while not on any."
+msgstr ""
+
+#: builtin/branch.c:589
+#, c-format
+msgid "Invalid branch name: '%s'"
+msgstr ""
+
+#: builtin/branch.c:604
+msgid "Branch rename failed"
+msgstr ""
+
+#: builtin/branch.c:608
+#, c-format
+msgid "Renamed a misnamed branch '%s' away"
+msgstr ""
+
+#: builtin/branch.c:612
+#, c-format
+msgid "Branch renamed to %s, but HEAD is not updated!"
+msgstr ""
+
+#: builtin/branch.c:619
+msgid "Branch is renamed, but update of config-file failed"
+msgstr ""
+
+#: builtin/branch.c:634
+#, c-format
+msgid "malformed object name %s"
+msgstr ""
+
+#: builtin/branch.c:658
+#, c-format
+msgid "could not write branch description template: %s\n"
+msgstr ""
+
+#: builtin/branch.c:746
+msgid "Failed to resolve HEAD as a valid ref."
+msgstr ""
+
+#: builtin/branch.c:751 builtin/clone.c:558
+msgid "HEAD not found below refs/heads!"
+msgstr ""
+
+#: builtin/branch.c:809
+msgid "-a and -r options to 'git branch' do not make sense with a branch name"
+msgstr ""
+
+#: builtin/bundle.c:47
+#, c-format
+msgid "%s is okay\n"
+msgstr ""
+
+#: builtin/bundle.c:56
+msgid "Need a repository to create a bundle."
+msgstr ""
+
+#: builtin/bundle.c:60
+msgid "Need a repository to unbundle."
+msgstr ""
+
+#: builtin/checkout.c:113 builtin/checkout.c:146
+#, c-format
+msgid "path '%s' does not have our version"
+msgstr ""
+
+#: builtin/checkout.c:115 builtin/checkout.c:148
+#, c-format
+msgid "path '%s' does not have their version"
+msgstr ""
+
+#: builtin/checkout.c:131
+#, c-format
+msgid "path '%s' does not have all necessary versions"
+msgstr ""
+
+#: builtin/checkout.c:175
+#, c-format
+msgid "path '%s' does not have necessary versions"
+msgstr ""
+
+#: builtin/checkout.c:192
+#, c-format
+msgid "path '%s': cannot merge"
+msgstr ""
+
+#: builtin/checkout.c:209
+#, c-format
+msgid "Unable to add merge result for '%s'"
+msgstr ""
+
+#: builtin/checkout.c:212 builtin/reset.c:158
+#, c-format
+msgid "make_cache_entry failed for path '%s'"
+msgstr ""
+
+#: builtin/checkout.c:234 builtin/checkout.c:392
+msgid "corrupt index file"
+msgstr ""
+
+#: builtin/checkout.c:264 builtin/checkout.c:271
+#, c-format
+msgid "path '%s' is unmerged"
+msgstr ""
+
+#: builtin/checkout.c:302 builtin/checkout.c:498 builtin/clone.c:583
+#: builtin/merge.c:812
+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 ""
+
+#: builtin/checkout.c:414
+msgid "you need to resolve your current index first"
+msgstr ""
+
+#: builtin/checkout.c:533
+#, c-format
+msgid "Can not do reflog for '%s'\n"
+msgstr ""
+
+#: builtin/checkout.c:565
+msgid "HEAD is now at"
+msgstr ""
+
+#: builtin/checkout.c:572
+#, c-format
+msgid "Reset branch '%s'\n"
+msgstr ""
+
+#: builtin/checkout.c:575
+#, c-format
+msgid "Already on '%s'\n"
+msgstr ""
+
+#: builtin/checkout.c:579
+#, c-format
+msgid "Switched to and reset branch '%s'\n"
+msgstr ""
+
+#: builtin/checkout.c:581
+#, c-format
+msgid "Switched to a new branch '%s'\n"
+msgstr ""
+
+#: builtin/checkout.c:583
+#, c-format
+msgid "Switched to branch '%s'\n"
+msgstr ""
+
+#: builtin/checkout.c:639
+#, c-format
+msgid " ... and %d more.\n"
+msgstr ""
+
+#. The singular version
+#: builtin/checkout.c:645
+#, 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"
+"\n"
+"%s\n"
+msgstr[0] ""
+msgstr[1] ""
+
+#: builtin/checkout.c:663
+#, 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"
+msgstr ""
+
+#: builtin/checkout.c:693
+msgid "internal error in revision walk"
+msgstr ""
+
+#: builtin/checkout.c:697
+msgid "Previous HEAD position was"
+msgstr ""
+
+#: builtin/checkout.c:723
+msgid "You are on a branch yet to be born"
+msgstr ""
+
+#. case (1)
+#: builtin/checkout.c:854
+#, c-format
+msgid "invalid reference: %s"
+msgstr ""
+
+#. case (1): want a tree
+#: builtin/checkout.c:893
+#, c-format
+msgid "reference is not a tree: %s"
+msgstr ""
+
+#: builtin/checkout.c:973
+msgid "-B cannot be used with -b"
+msgstr ""
+
+#: builtin/checkout.c:982
+msgid "--patch is incompatible with all other options"
+msgstr ""
+
+#: builtin/checkout.c:985
+msgid "--detach cannot be used with -b/-B/--orphan"
+msgstr ""
+
+#: builtin/checkout.c:987
+msgid "--detach cannot be used with -t"
+msgstr ""
+
+#: builtin/checkout.c:993
+msgid "--track needs a branch name"
+msgstr ""
+
+#: builtin/checkout.c:1000
+msgid "Missing branch name; try -b"
+msgstr ""
+
+#: builtin/checkout.c:1006
+msgid "--orphan and -b|-B are mutually exclusive"
+msgstr ""
+
+#: builtin/checkout.c:1008
+msgid "--orphan cannot be used with -t"
+msgstr ""
+
+#: builtin/checkout.c:1018
+msgid "git checkout: -f and -m are incompatible"
+msgstr ""
+
+#: builtin/checkout.c:1052
+msgid "invalid path specification"
+msgstr ""
+
+#: builtin/checkout.c:1060
+#, 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?"
+msgstr ""
+
+#: builtin/checkout.c:1062
+msgid "git checkout: updating paths is incompatible with switching branches."
+msgstr ""
+
+#: builtin/checkout.c:1067
+msgid "git checkout: --detach does not take a path argument"
+msgstr ""
+
+#: builtin/checkout.c:1070
+msgid ""
+"git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
+"checking out of the index."
+msgstr ""
+
+#: builtin/checkout.c:1089
+msgid "Cannot switch branch to a non-commit."
+msgstr ""
+
+#: builtin/checkout.c:1092
+msgid "--ours/--theirs is incompatible with switching branches."
+msgstr ""
+
+#: builtin/clean.c:78
+msgid "-x and -X cannot be used together"
+msgstr ""
+
+#: builtin/clean.c:82
+msgid ""
+"clean.requireForce set to true and neither -n nor -f given; refusing to clean"
+msgstr ""
+
+#: builtin/clean.c:85
+msgid ""
+"clean.requireForce defaults to true and neither -n nor -f given; refusing to "
+"clean"
+msgstr ""
+
+#: builtin/clean.c:155 builtin/clean.c:176
+#, c-format
+msgid "Would remove %s\n"
+msgstr ""
+
+#: builtin/clean.c:159 builtin/clean.c:179
+#, c-format
+msgid "Removing %s\n"
+msgstr ""
+
+#: builtin/clean.c:162 builtin/clean.c:182
+#, c-format
+msgid "failed to remove %s"
+msgstr ""
+
+#: builtin/clean.c:166
+#, c-format
+msgid "Would not remove %s\n"
+msgstr ""
+
+#: builtin/clean.c:168
+#, c-format
+msgid "Not removing %s\n"
+msgstr ""
+
+#: builtin/clone.c:243
+#, c-format
+msgid "reference repository '%s' is not a local directory."
+msgstr ""
+
+#: builtin/clone.c:302
+#, c-format
+msgid "failed to open '%s'"
+msgstr ""
+
+#: builtin/clone.c:306
+#, c-format
+msgid "failed to create directory '%s'"
+msgstr ""
+
+#: builtin/clone.c:308 builtin/diff.c:75
+#, c-format
+msgid "failed to stat '%s'"
+msgstr ""
+
+#: builtin/clone.c:310
+#, c-format
+msgid "%s exists and is not a directory"
+msgstr ""
+
+#: builtin/clone.c:324
+#, c-format
+msgid "failed to stat %s\n"
+msgstr ""
+
+#: builtin/clone.c:341
+#, c-format
+msgid "failed to unlink '%s'"
+msgstr ""
+
+#: builtin/clone.c:346
+#, c-format
+msgid "failed to create link '%s'"
+msgstr ""
+
+#: builtin/clone.c:350
+#, c-format
+msgid "failed to copy file to '%s'"
+msgstr ""
+
+#: builtin/clone.c:373
+#, c-format
+msgid "done.\n"
+msgstr ""
+
+#: builtin/clone.c:440
+#, c-format
+msgid "Could not find remote branch %s to clone."
+msgstr ""
+
+#: builtin/clone.c:549
+msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n"
+msgstr ""
+
+#: builtin/clone.c:639
+msgid "Too many arguments."
+msgstr ""
+
+#: builtin/clone.c:643
+msgid "You must specify a repository to clone."
+msgstr ""
+
+#: builtin/clone.c:654
+#, c-format
+msgid "--bare and --origin %s options are incompatible."
+msgstr ""
+
+#: builtin/clone.c:668
+#, c-format
+msgid "repository '%s' does not exist"
+msgstr ""
+
+#: builtin/clone.c:673
+msgid "--depth is ignored in local clones; use file:// instead."
+msgstr ""
+
+#: builtin/clone.c:683
+#, c-format
+msgid "destination path '%s' already exists and is not an empty directory."
+msgstr ""
+
+#: builtin/clone.c:693
+#, c-format
+msgid "working tree '%s' already exists."
+msgstr ""
+
+#: builtin/clone.c:706 builtin/clone.c:720
+#, c-format
+msgid "could not create leading directories of '%s'"
+msgstr ""
+
+#: builtin/clone.c:709
+#, c-format
+msgid "could not create work tree dir '%s'."
+msgstr ""
+
+#: builtin/clone.c:728
+#, c-format
+msgid "Cloning into bare repository '%s'...\n"
+msgstr ""
+
+#: builtin/clone.c:730
+#, c-format
+msgid "Cloning into '%s'...\n"
+msgstr ""
+
+#: builtin/clone.c:786
+#, c-format
+msgid "Don't know how to clone %s"
+msgstr ""
+
+#: builtin/clone.c:835
+#, 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/commit.c:42
+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/commit.c:54
+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 ""
+
+#: builtin/commit.c:59
+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/commit.c:205 builtin/reset.c:33
+msgid "merge"
+msgstr ""
+
+#: builtin/commit.c:208
+msgid "cherry-pick"
+msgstr ""
+
+#: builtin/commit.c:325
+msgid "failed to unpack HEAD tree object"
+msgstr ""
+
+#: builtin/commit.c:367
+msgid "unable to create temporary index"
+msgstr ""
+
+#: builtin/commit.c:373
+msgid "interactive add failed"
+msgstr ""
+
+#: builtin/commit.c:406 builtin/commit.c:427 builtin/commit.c:473
+msgid "unable to write new_index file"
+msgstr ""
+
+#: builtin/commit.c:457
+#, c-format
+msgid "cannot do a partial commit during a %s."
+msgstr ""
+
+#: builtin/commit.c:466
+msgid "cannot read the index"
+msgstr ""
+
+#: builtin/commit.c:486
+msgid "unable to write temporary index file"
+msgstr ""
+
+#: builtin/commit.c:561 builtin/commit.c:567
+#, c-format
+msgid "invalid commit: %s"
+msgstr ""
+
+#: builtin/commit.c:590
+msgid "malformed --author parameter"
+msgstr ""
+
+#: builtin/commit.c:651
+#, c-format
+msgid "Malformed ident string: '%s'"
+msgstr ""
+
+#: builtin/commit.c:689 builtin/commit.c:722 builtin/commit.c:1033
+#, c-format
+msgid "could not lookup commit %s"
+msgstr ""
+
+#: builtin/commit.c:701 builtin/shortlog.c:296
+#, c-format
+msgid "(reading log message from standard input)\n"
+msgstr ""
+
+#: builtin/commit.c:703
+msgid "could not read log from standard input"
+msgstr ""
+
+#: builtin/commit.c:707
+#, c-format
+msgid "could not read log file '%s'"
+msgstr ""
+
+#: builtin/commit.c:713
+msgid "commit has empty message"
+msgstr ""
+
+#: builtin/commit.c:729
+msgid "could not read MERGE_MSG"
+msgstr ""
+
+#: builtin/commit.c:733
+msgid "could not read SQUASH_MSG"
+msgstr ""
+
+#: builtin/commit.c:737
+#, c-format
+msgid "could not read '%s'"
+msgstr ""
+
+#: builtin/commit.c:765
+#, c-format
+msgid "could not open '%s'"
+msgstr ""
+
+#: builtin/commit.c:789
+msgid "could not write commit template"
+msgstr ""
+
+#: builtin/commit.c:799
+#, c-format
+msgid ""
+"\n"
+"It looks like you may be committing a %s.\n"
+"If this is not correct, please remove the file\n"
+"\t%s\n"
+"and try again.\n"
+msgstr ""
+
+#: builtin/commit.c:812
+msgid "Please enter the commit message for your changes."
+msgstr ""
+
+#: builtin/commit.c:815
+msgid ""
+" Lines starting\n"
+"with '#' will be ignored, and an empty message aborts the commit.\n"
+msgstr ""
+
+#: builtin/commit.c:820
+msgid ""
+" Lines starting\n"
+"with '#' will be kept; you may remove them yourself if you want to.\n"
+"An empty message aborts the commit.\n"
+msgstr ""
+
+#: builtin/commit.c:832
+#, c-format
+msgid "%sAuthor: %s"
+msgstr ""
+
+#: builtin/commit.c:839
+#, c-format
+msgid "%sCommitter: %s"
+msgstr ""
+
+#: builtin/commit.c:859
+msgid "Cannot read index"
+msgstr ""
+
+#: builtin/commit.c:896
+msgid "Error building trees"
+msgstr ""
+
+#: builtin/commit.c:911 builtin/tag.c:357
+#, c-format
+msgid "Please supply the message using either -m or -F option.\n"
+msgstr ""
+
+#: builtin/commit.c:1008
+#, c-format
+msgid "No existing author found with '%s'"
+msgstr ""
+
+#: builtin/commit.c:1023 builtin/commit.c:1217
+#, c-format
+msgid "Invalid untracked files mode '%s'"
+msgstr ""
+
+#: builtin/commit.c:1063
+msgid "Using both --reset-author and --author does not make sense"
+msgstr ""
+
+#: builtin/commit.c:1074
+msgid "You have nothing to amend."
+msgstr ""
+
+#: builtin/commit.c:1076
+#, c-format
+msgid "You are in the middle of a %s -- cannot amend."
+msgstr ""
+
+#: builtin/commit.c:1078
+msgid "Options --squash and --fixup cannot be used together"
+msgstr ""
+
+#: builtin/commit.c:1088
+msgid "Only one of -c/-C/-F/--fixup can be used."
+msgstr ""
+
+#: builtin/commit.c:1090
+msgid "Option -m cannot be combined with -c/-C/-F/--fixup."
+msgstr ""
+
+#: builtin/commit.c:1098
+msgid "--reset-author can be used only with -C, -c or --amend."
+msgstr ""
+
+#: builtin/commit.c:1115
+msgid "Only one of --include/--only/--all/--interactive/--patch can be used."
+msgstr ""
+
+#: builtin/commit.c:1117
+msgid "No paths with --include/--only does not make sense."
+msgstr ""
+
+#: builtin/commit.c:1119
+msgid "Clever... amending the last one with dirty index."
+msgstr ""
+
+#: builtin/commit.c:1121
+msgid "Explicit paths specified without -i nor -o; assuming --only paths..."
+msgstr ""
+
+#: builtin/commit.c:1131 builtin/tag.c:556
+#, c-format
+msgid "Invalid cleanup mode %s"
+msgstr ""
+
+#: builtin/commit.c:1136
+msgid "Paths with -a does not make sense."
+msgstr ""
+
+#: builtin/commit.c:1315
+msgid "couldn't look up newly created commit"
+msgstr ""
+
+#: builtin/commit.c:1317
+msgid "could not parse newly created commit"
+msgstr ""
+
+#: builtin/commit.c:1358
+msgid "detached HEAD"
+msgstr ""
+
+#: builtin/commit.c:1360
+msgid " (root-commit)"
+msgstr ""
+
+#: builtin/commit.c:1450
+msgid "could not parse HEAD commit"
+msgstr ""
+
+#: builtin/commit.c:1487 builtin/merge.c:509
+#, c-format
+msgid "could not open '%s' for reading"
+msgstr ""
+
+#: builtin/commit.c:1494
+#, c-format
+msgid "Corrupt MERGE_HEAD file (%s)"
+msgstr ""
+
+#: builtin/commit.c:1501
+msgid "could not read MERGE_MODE"
+msgstr ""
+
+#: builtin/commit.c:1520
+#, c-format
+msgid "could not read commit message: %s"
+msgstr ""
+
+#: builtin/commit.c:1534
+#, c-format
+msgid "Aborting commit; you did not edit the message.\n"
+msgstr ""
+
+#: builtin/commit.c:1539
+#, c-format
+msgid "Aborting commit due to empty commit message.\n"
+msgstr ""
+
+#: builtin/commit.c:1554 builtin/merge.c:936 builtin/merge.c:961
+msgid "failed to write commit object"
+msgstr ""
+
+#: builtin/commit.c:1575
+msgid "cannot lock HEAD ref"
+msgstr ""
+
+#: builtin/commit.c:1579
+msgid "cannot update HEAD ref"
+msgstr ""
+
+#: 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 ""
+
+#: builtin/describe.c:234
+#, c-format
+msgid "annotated tag %s not available"
+msgstr ""
+
+#: builtin/describe.c:238
+#, c-format
+msgid "annotated tag %s has no embedded name"
+msgstr ""
+
+#: builtin/describe.c:240
+#, c-format
+msgid "tag '%s' is really '%s' here"
+msgstr ""
+
+#: builtin/describe.c:267
+#, c-format
+msgid "Not a valid object name %s"
+msgstr ""
+
+#: builtin/describe.c:270
+#, c-format
+msgid "%s is not a valid '%s' object"
+msgstr ""
+
+#: builtin/describe.c:287
+#, c-format
+msgid "no tag exactly matches '%s'"
+msgstr ""
+
+#: builtin/describe.c:289
+#, c-format
+msgid "searching to describe %s\n"
+msgstr ""
+
+#: builtin/describe.c:329
+#, c-format
+msgid "finished search at %s\n"
+msgstr ""
+
+#: builtin/describe.c:353
+#, c-format
+msgid ""
+"No annotated tags can describe '%s'.\n"
+"However, there were unannotated tags: try --tags."
+msgstr ""
+
+#: builtin/describe.c:357
+#, c-format
+msgid ""
+"No tags can describe '%s'.\n"
+"Try --always, or create some tags."
+msgstr ""
+
+#: builtin/describe.c:378
+#, c-format
+msgid "traversed %lu commits\n"
+msgstr ""
+
+#: builtin/describe.c:381
+#, c-format
+msgid ""
+"more than %i tags found; listed %i most recent\n"
+"gave up search at %s\n"
+msgstr ""
+
+#: builtin/describe.c:436
+msgid "--long is incompatible with --abbrev=0"
+msgstr ""
+
+#: builtin/describe.c:462
+msgid "No names found, cannot describe anything."
+msgstr ""
+
+#: builtin/describe.c:482
+msgid "--dirty is incompatible with committishes"
+msgstr ""
+
+#: builtin/diff.c:77
+#, c-format
+msgid "'%s': not a regular file or symlink"
+msgstr ""
+
+#: builtin/diff.c:220
+#, c-format
+msgid "invalid option: %s"
+msgstr ""
+
+#: builtin/diff.c:297
+msgid "Not a git repository"
+msgstr ""
+
+#: builtin/diff.c:347
+#, c-format
+msgid "invalid object '%s' given."
+msgstr ""
+
+#: builtin/diff.c:352
+#, c-format
+msgid "more than %d trees given: '%s'"
+msgstr ""
+
+#: builtin/diff.c:362
+#, c-format
+msgid "more than two blobs given: '%s'"
+msgstr ""
+
+#: builtin/diff.c:370
+#, c-format
+msgid "unhandled object '%s' given."
+msgstr ""
+
+#: builtin/fetch.c:200
+msgid "Couldn't find remote ref HEAD"
+msgstr ""
+
+#: builtin/fetch.c:253
+#, c-format
+msgid "object %s not found"
+msgstr ""
+
+#: builtin/fetch.c:259
+msgid "[up to date]"
+msgstr ""
+
+#: builtin/fetch.c:273
+#, c-format
+msgid "! %-*s %-*s -> %s (can't fetch in current branch)"
+msgstr ""
+
+#: builtin/fetch.c:274 builtin/fetch.c:360
+msgid "[rejected]"
+msgstr ""
+
+#: builtin/fetch.c:285
+msgid "[tag update]"
+msgstr ""
+
+#: builtin/fetch.c:287 builtin/fetch.c:322 builtin/fetch.c:340
+msgid " (unable to update local ref)"
+msgstr ""
+
+#: builtin/fetch.c:305
+msgid "[new tag]"
+msgstr ""
+
+#: builtin/fetch.c:308
+msgid "[new branch]"
+msgstr ""
+
+#: builtin/fetch.c:311
+msgid "[new ref]"
+msgstr ""
+
+#: builtin/fetch.c:356
+msgid "unable to update local ref"
+msgstr ""
+
+#: builtin/fetch.c:356
+msgid "forced update"
+msgstr ""
+
+#: builtin/fetch.c:362
+msgid "(non-fast-forward)"
+msgstr ""
+
+#: builtin/fetch.c:393 builtin/fetch.c:685
+#, c-format
+msgid "cannot open %s: %s\n"
+msgstr ""
+
+#: builtin/fetch.c:402
+#, c-format
+msgid "%s did not send all necessary objects\n"
+msgstr ""
+
+#: builtin/fetch.c:488
+#, c-format
+msgid "From %.*s\n"
+msgstr ""
+
+#: builtin/fetch.c:499
+#, c-format
+msgid ""
+"some local refs could not be updated; try running\n"
+" 'git remote prune %s' to remove any old, conflicting branches"
+msgstr ""
+
+#: builtin/fetch.c:549
+#, c-format
+msgid " (%s will become dangling)\n"
+msgstr ""
+
+#: builtin/fetch.c:550
+#, c-format
+msgid " (%s has become dangling)\n"
+msgstr ""
+
+#: builtin/fetch.c:557
+msgid "[deleted]"
+msgstr ""
+
+#: builtin/fetch.c:558
+msgid "(none)"
+msgstr ""
+
+#: builtin/fetch.c:675
+#, c-format
+msgid "Refusing to fetch into current branch %s of non-bare repository"
+msgstr ""
+
+#: builtin/fetch.c:709
+#, c-format
+msgid "Don't know how to fetch from %s"
+msgstr ""
+
+#: builtin/fetch.c:786
+#, c-format
+msgid "Option \"%s\" value \"%s\" is not valid for %s"
+msgstr ""
+
+#: builtin/fetch.c:789
+#, c-format
+msgid "Option \"%s\" is ignored for %s\n"
+msgstr ""
+
+#: builtin/fetch.c:888
+#, c-format
+msgid "Fetching %s\n"
+msgstr ""
+
+#: builtin/fetch.c:890
+#, c-format
+msgid "Could not fetch %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."
+msgstr ""
+
+#: builtin/fetch.c:927
+msgid "You need to specify a tag name."
+msgstr ""
+
+#: builtin/fetch.c:979
+msgid "fetch --all does not take a repository argument"
+msgstr ""
+
+#: builtin/fetch.c:981
+msgid "fetch --all does not make sense with refspecs"
+msgstr ""
+
+#: builtin/fetch.c:992
+#, c-format
+msgid "No such remote or remote group: %s"
+msgstr ""
+
+#: builtin/fetch.c:1000
+msgid "Fetching a group and specifying refspecs does not make sense"
+msgstr ""
+
+#: builtin/gc.c:63
+#, c-format
+msgid "Invalid %s: '%s'"
+msgstr ""
+
+#: builtin/gc.c:90
+#, c-format
+msgid "insanely long object directory %.*s"
+msgstr ""
+
+#: builtin/gc.c:221
+#, c-format
+msgid "Auto packing the repository for optimum performance.\n"
+msgstr ""
+
+#: builtin/gc.c:224
+#, 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/gc.c:251
+msgid ""
+"There are too many unreachable loose objects; run 'git prune' to remove them."
+msgstr ""
+
+#: builtin/grep.c:216
+#, c-format
+msgid "grep: failed to create thread: %s"
+msgstr ""
+
+#: builtin/grep.c:402
+#, c-format
+msgid "Failed to chdir: %s"
+msgstr ""
+
+#: builtin/grep.c:478 builtin/grep.c:512
+#, c-format
+msgid "unable to read tree (%s)"
+msgstr ""
+
+#: builtin/grep.c:526
+#, c-format
+msgid "unable to grep from object of type %s"
+msgstr ""
+
+#: builtin/grep.c:584
+#, c-format
+msgid "switch `%c' expects a numerical value"
+msgstr ""
+
+#: builtin/grep.c:601
+#, c-format
+msgid "cannot open '%s'"
+msgstr ""
+
+#: builtin/grep.c:888
+msgid "no pattern given."
+msgstr ""
+
+#: builtin/grep.c:902
+#, c-format
+msgid "bad object %s"
+msgstr ""
+
+#: builtin/grep.c:943
+msgid "--open-files-in-pager only works on the worktree"
+msgstr ""
+
+#: builtin/grep.c:966
+msgid "--cached or --untracked cannot be used with --no-index."
+msgstr ""
+
+#: builtin/grep.c:971
+msgid "--no-index or --untracked cannot be used with revs."
+msgstr ""
+
+#: builtin/grep.c:974
+msgid "--[no-]exclude-standard cannot be used for tracked contents."
+msgstr ""
+
+#: builtin/grep.c:982
+msgid "both --cached and trees are 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:322 builtin/init-db.c:325
+#, c-format
+msgid "%s already exists"
+msgstr ""
+
+#: builtin/init-db.c:354
+#, c-format
+msgid "unable to handle file type %d"
+msgstr ""
+
+#: builtin/init-db.c:357
+#, c-format
+msgid "unable to move %s to %s"
+msgstr ""
+
+#: builtin/init-db.c:362
+#, 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:419
+#, c-format
+msgid "%s%s Git repository in %s%s\n"
+msgstr ""
+
+#: builtin/init-db.c:420
+msgid "Reinitialized existing"
+msgstr ""
+
+#: builtin/init-db.c:420
+msgid "Initialized empty"
+msgstr ""
+
+#: builtin/init-db.c:421
+msgid " shared"
+msgstr ""
+
+#: builtin/init-db.c:440
+msgid "cannot tell cwd"
+msgstr ""
+
+#: builtin/init-db.c:521 builtin/init-db.c:528
+#, c-format
+msgid "cannot mkdir %s"
+msgstr ""
+
+#: builtin/init-db.c:532
+#, c-format
+msgid "cannot chdir to %s"
+msgstr ""
+
+#: builtin/init-db.c:554
+#, c-format
+msgid ""
+"%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-"
+"dir=<directory>)"
+msgstr ""
+
+#: builtin/init-db.c:578
+msgid "Cannot access current working directory"
+msgstr ""
+
+#: builtin/init-db.c:585
+#, c-format
+msgid "Cannot access work tree '%s'"
+msgstr ""
+
+#: builtin/log.c:187
+#, c-format
+msgid "Final output: %d %s\n"
+msgstr ""
+
+#: builtin/log.c:395 builtin/log.c:483
+#, c-format
+msgid "Could not read object %s"
+msgstr ""
+
+#: builtin/log.c:507
+#, c-format
+msgid "Unknown type: %d"
+msgstr ""
+
+#: builtin/log.c:596
+msgid "format.headers without value"
+msgstr ""
+
+#: builtin/log.c:669
+msgid "name of output directory is too long"
+msgstr ""
+
+#: builtin/log.c:680
+#, c-format
+msgid "Cannot open patch file %s"
+msgstr ""
+
+#: builtin/log.c:694
+msgid "Need exactly one range."
+msgstr ""
+
+#: builtin/log.c:702
+msgid "Not a range."
+msgstr ""
+
+#: builtin/log.c:739
+msgid "Could not extract email from committer identity."
+msgstr ""
+
+#: builtin/log.c:785
+msgid "Cover letter needs email format"
+msgstr ""
+
+#: builtin/log.c:879
+#, c-format
+msgid "insane in-reply-to: %s"
+msgstr ""
+
+#: builtin/log.c:952
+msgid "Two output directories?"
+msgstr ""
+
+#: builtin/log.c:1173
+#, c-format
+msgid "bogus committer info %s"
+msgstr ""
+
+#: builtin/log.c:1218
+msgid "-n and -k are mutually exclusive."
+msgstr ""
+
+#: builtin/log.c:1220
+msgid "--subject-prefix and -k are mutually exclusive."
+msgstr ""
+
+#: builtin/log.c:1225 builtin/shortlog.c:284
+#, c-format
+msgid "unrecognized argument: %s"
+msgstr ""
+
+#: builtin/log.c:1228
+msgid "--name-only does not make sense"
+msgstr ""
+
+#: builtin/log.c:1230
+msgid "--name-status does not make sense"
+msgstr ""
+
+#: builtin/log.c:1232
+msgid "--check does not make sense"
+msgstr ""
+
+#: builtin/log.c:1255
+msgid "standard output, or directory, which one?"
+msgstr ""
+
+#: builtin/log.c:1257
+#, c-format
+msgid "Could not create directory '%s'"
+msgstr ""
+
+#: builtin/log.c:1410
+msgid "Failed to create output files"
+msgstr ""
+
+#: builtin/log.c:1514
+#, c-format
+msgid ""
+"Could not find a tracked remote branch, please specify <upstream> manually.\n"
+msgstr ""
+
+#: builtin/log.c:1530 builtin/log.c:1532 builtin/log.c:1544
+#, c-format
+msgid "Unknown commit %s"
+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: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:437
+#, c-format
+msgid "'%s' does not point to a commit"
+msgstr ""
+
+#: builtin/merge.c:536
+#, c-format
+msgid "Bad branch.%s.mergeoptions string: %s"
+msgstr ""
+
+#: builtin/merge.c:629
+msgid "git write-tree failed to write a tree"
+msgstr ""
+
+#: builtin/merge.c:679
+msgid "failed to read the cache"
+msgstr ""
+
+#: builtin/merge.c:697
+msgid "Unable to write index."
+msgstr ""
+
+#: builtin/merge.c:710
+msgid "Not handling anything other than two heads merge."
+msgstr ""
+
+#: builtin/merge.c:724
+#, c-format
+msgid "Unknown option for merge-recursive: -X%s"
+msgstr ""
+
+#: builtin/merge.c:738
+#, c-format
+msgid "unable to write %s"
+msgstr ""
+
+#: builtin/merge.c:877
+#, c-format
+msgid "Could not read from '%s'"
+msgstr ""
+
+#: builtin/merge.c:886
+#, c-format
+msgid "Not committing merge; use 'git commit' to complete the merge.\n"
+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"
+msgstr ""
+
+#: builtin/merge.c:916
+msgid "Empty commit message."
+msgstr ""
+
+#: builtin/merge.c:928
+#, c-format
+msgid "Wonderful.\n"
+msgstr ""
+
+#: builtin/merge.c:993
+#, c-format
+msgid "Automatic merge failed; fix conflicts and then commit the result.\n"
+msgstr ""
+
+#: builtin/merge.c:1009
+#, c-format
+msgid "'%s' is not a commit"
+msgstr ""
+
+#: builtin/merge.c:1050
+msgid "No current branch."
+msgstr ""
+
+#: builtin/merge.c:1052
+msgid "No remote for the current branch."
+msgstr ""
+
+#: builtin/merge.c:1054
+msgid "No default upstream defined for the current branch."
+msgstr ""
+
+#: builtin/merge.c:1059
+#, c-format
+msgid "No remote tracking branch for %s from %s"
+msgstr ""
+
+#: builtin/merge.c:1146 builtin/merge.c:1303
+#, c-format
+msgid "%s - not something we can merge"
+msgstr ""
+
+#: builtin/merge.c:1214
+msgid "There is no merge to abort (MERGE_HEAD missing)."
+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."
+msgstr ""
+
+#: builtin/merge.c:1233 git-pull.sh:34
+msgid "You have not concluded your merge (MERGE_HEAD exists)."
+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."
+msgstr ""
+
+#: builtin/merge.c:1240
+msgid "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)."
+msgstr ""
+
+#: builtin/merge.c:1249
+msgid "You cannot combine --squash with --no-ff."
+msgstr ""
+
+#: builtin/merge.c:1254
+msgid "You cannot combine --no-ff with --ff-only."
+msgstr ""
+
+#: builtin/merge.c:1261
+msgid "No commit specified and merge.defaultToUpstream not set."
+msgstr ""
+
+#: builtin/merge.c:1293
+msgid "Can merge only exactly one commit into empty head"
+msgstr ""
+
+#: builtin/merge.c:1296
+msgid "Squash commit into empty head not supported yet"
+msgstr ""
+
+#: builtin/merge.c:1298
+msgid "Non-fast-forward commit does not make sense into an empty head"
+msgstr ""
+
+#: builtin/merge.c:1413
+#, c-format
+msgid "Updating %s..%s\n"
+msgstr ""
+
+#: builtin/merge.c:1451
+#, c-format
+msgid "Trying really trivial in-index merge...\n"
+msgstr ""
+
+#: builtin/merge.c:1458
+#, c-format
+msgid "Nope.\n"
+msgstr ""
+
+#: builtin/merge.c:1490
+msgid "Not possible to fast-forward, aborting."
+msgstr ""
+
+#: builtin/merge.c:1513 builtin/merge.c:1592
+#, c-format
+msgid "Rewinding the tree to pristine...\n"
+msgstr ""
+
+#: builtin/merge.c:1517
+#, c-format
+msgid "Trying merge strategy %s...\n"
+msgstr ""
+
+#: builtin/merge.c:1583
+#, c-format
+msgid "No merge strategy handled the merge.\n"
+msgstr ""
+
+#: builtin/merge.c:1585
+#, c-format
+msgid "Merge with strategy %s failed.\n"
+msgstr ""
+
+#: builtin/merge.c:1594
+#, c-format
+msgid "Using the %s to prepare resolving by hand.\n"
+msgstr ""
+
+#: builtin/merge.c:1606
+#, c-format
+msgid "Automatic merge went well; stopped before committing as requested\n"
+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
+#, c-format
+msgid "renaming '%s' failed"
+msgstr ""
+
+#: builtin/notes.c:139
+#, c-format
+msgid "unable to start 'show' for object '%s'"
+msgstr ""
+
+#: builtin/notes.c:145
+msgid "can't fdopen 'show' output fd"
+msgstr ""
+
+#: builtin/notes.c:155
+#, c-format
+msgid "failed to close pipe to 'show' for object '%s'"
+msgstr ""
+
+#: builtin/notes.c:158
+#, c-format
+msgid "failed to finish 'show' for object '%s'"
+msgstr ""
+
+#: builtin/notes.c:175 builtin/tag.c:343
+#, 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"
+msgstr ""
+
+#: builtin/notes.c:210 builtin/notes.c:973
+#, c-format
+msgid "Removing note for object %s\n"
+msgstr ""
+
+#: builtin/notes.c:215
+msgid "unable to write note object"
+msgstr ""
+
+#: builtin/notes.c:217
+#, c-format
+msgid "The note contents has been left in %s"
+msgstr ""
+
+#: builtin/notes.c:251 builtin/tag.c:521
+#, c-format
+msgid "cannot read '%s'"
+msgstr ""
+
+#: builtin/notes.c:253 builtin/tag.c:524
+#, c-format
+msgid "could not open or read '%s'"
+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:537
+#, c-format
+msgid "Failed to resolve '%s' as a valid ref."
+msgstr ""
+
+#: builtin/notes.c:275
+#, c-format
+msgid "Failed to read object '%s'."
+msgstr ""
+
+#: builtin/notes.c:299
+msgid "Cannot commit uninitialized/unreferenced notes tree"
+msgstr ""
+
+#: builtin/notes.c:340
+#, c-format
+msgid "Bad notes.rewriteMode value: '%s'"
+msgstr ""
+
+#: builtin/notes.c:350
+#, 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:377
+#, c-format
+msgid "Bad %s value: '%s'"
+msgstr ""
+
+#: builtin/notes.c:441
+#, c-format
+msgid "Malformed input line: '%s'."
+msgstr ""
+
+#: builtin/notes.c:456
+#, c-format
+msgid "Failed to copy notes from '%s' to '%s'"
+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"
+msgstr ""
+
+#: builtin/notes.c:513 builtin/notes.c:772
+#, c-format
+msgid "No note found for object %s."
+msgstr ""
+
+#: builtin/notes.c:580
+#, c-format
+msgid ""
+"Cannot add notes. Found existing notes for object %s. Use '-f' to overwrite "
+"existing notes"
+msgstr ""
+
+#: builtin/notes.c:585 builtin/notes.c:662
+#, c-format
+msgid "Overwriting existing notes for object %s\n"
+msgstr ""
+
+#: builtin/notes.c:635
+msgid "too few parameters"
+msgstr ""
+
+#: builtin/notes.c:656
+#, c-format
+msgid ""
+"Cannot copy notes. Found existing notes for object %s. Use '-f' to overwrite "
+"existing notes"
+msgstr ""
+
+#: builtin/notes.c:668
+#, c-format
+msgid "Missing notes on source object %s. Cannot copy."
+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"
+msgstr ""
+
+#: builtin/notes.c:971
+#, c-format
+msgid "Object %s has no note\n"
+msgstr ""
+
+#: builtin/notes.c:1103
+#, c-format
+msgid "Unknown subcommand: %s"
+msgstr ""
+
+#: builtin/pack-objects.c:2315
+#, c-format
+msgid "unsupported index version %s"
+msgstr ""
+
+#: builtin/pack-objects.c:2319
+#, c-format
+msgid "bad index version '%s'"
+msgstr ""
+
+#: builtin/pack-objects.c:2342
+#, c-format
+msgid "option %s does not accept negative form"
+msgstr ""
+
+#: builtin/pack-objects.c:2346
+#, c-format
+msgid "unable to parse value '%s' for option %s"
+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:84
+#, 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:91
+#, 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:99
+#, c-format
+msgid "The current branch %s has multiple upstream branches, refusing to push."
+msgstr ""
+
+#: builtin/push.c:102
+#, 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:131
+msgid ""
+"You didn't specify any refspecs to push, and push.default is \"nothing\"."
+msgstr ""
+
+#: builtin/push.c:138
+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:144
+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."
+msgstr ""
+
+#: builtin/push.c:150
+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:190
+#, c-format
+msgid "Pushing to %s\n"
+msgstr ""
+
+#: builtin/push.c:194
+#, c-format
+msgid "failed to push some refs to '%s'"
+msgstr ""
+
+#: builtin/push.c:226
+#, c-format
+msgid "bad repository '%s'"
+msgstr ""
+
+#: builtin/push.c:227
+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:242
+msgid "--all and --tags are incompatible"
+msgstr ""
+
+#: builtin/push.c:243
+msgid "--all can't be combined with refspecs"
+msgstr ""
+
+#: builtin/push.c:248
+msgid "--mirror and --tags are incompatible"
+msgstr ""
+
+#: builtin/push.c:249
+msgid "--mirror can't be combined with refspecs"
+msgstr ""
+
+#: builtin/push.c:254
+msgid "--all and --mirror are incompatible"
+msgstr ""
+
+#: builtin/push.c:334
+msgid "--delete is incompatible with --all, --mirror and --tags"
+msgstr ""
+
+#: builtin/push.c:336
+msgid "--delete doesn't make sense without any refs"
+msgstr ""
+
+#: builtin/reset.c:33
+msgid "mixed"
+msgstr ""
+
+#: builtin/reset.c:33
+msgid "soft"
+msgstr ""
+
+#: builtin/reset.c:33
+msgid "hard"
+msgstr ""
+
+#: builtin/reset.c:33
+msgid "keep"
+msgstr ""
+
+#: builtin/reset.c:77
+msgid "You do not have a valid HEAD."
+msgstr ""
+
+#: builtin/reset.c:79
+msgid "Failed to find tree of HEAD."
+msgstr ""
+
+#: builtin/reset.c:85
+#, c-format
+msgid "Failed to find tree of %s."
+msgstr ""
+
+#: builtin/reset.c:96
+msgid "Could not write new index file."
+msgstr ""
+
+#: builtin/reset.c:106
+#, c-format
+msgid "HEAD is now at %s"
+msgstr ""
+
+#: 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 "Cannot do a %s reset in the middle of a merge."
+msgstr ""
+
+#: builtin/reset.c:297
+#, c-format
+msgid "Could not parse object '%s'."
+msgstr ""
+
+#: builtin/reset.c:302
+msgid "--patch is incompatible with --{hard,mixed,soft}"
+msgstr ""
+
+#: builtin/reset.c:311
+msgid "--mixed with paths is deprecated; use 'git reset -- <paths>' instead."
+msgstr ""
+
+#: builtin/reset.c:313
+#, c-format
+msgid "Cannot do %s reset with paths."
+msgstr ""
+
+#: builtin/reset.c:325
+#, c-format
+msgid "%s reset is not allowed in a bare repository"
+msgstr ""
+
+#: builtin/reset.c:341
+#, c-format
+msgid "Could not reset index file to revision '%s'."
+msgstr ""
+
+#: builtin/revert.c:70 builtin/revert.c:92
+#, c-format
+msgid "%s: %s cannot be used with %s"
+msgstr ""
+
+#: builtin/revert.c:127
+msgid "program error"
+msgstr ""
+
+#: builtin/revert.c:213
+msgid "revert failed"
+msgstr ""
+
+#: builtin/revert.c:228
+msgid "cherry-pick failed"
+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)"
+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)"
+msgstr ""
+
+#: builtin/rm.c:119
+#, c-format
+msgid ""
+"'%s' has local modifications\n"
+"(use --cached to keep the file, or -f to force removal)"
+msgstr ""
+
+#: builtin/rm.c:194
+#, c-format
+msgid "not removing '%s' recursively without -r"
+msgstr ""
+
+#: builtin/rm.c:230
+#, c-format
+msgid "git rm: unable to remove %s"
+msgstr ""
+
+#: builtin/shortlog.c:157
+#, c-format
+msgid "Missing author: %s"
+msgstr ""
+
+#: builtin/tag.c:58
+#, c-format
+msgid "malformed object at '%s'"
+msgstr ""
+
+#: builtin/tag.c:205
+#, c-format
+msgid "tag name too long: %.*s..."
+msgstr ""
+
+#: builtin/tag.c:210
+#, c-format
+msgid "tag '%s' not found."
+msgstr ""
+
+#: builtin/tag.c:225
+#, c-format
+msgid "Deleted tag '%s' (was %s)\n"
+msgstr ""
+
+#: builtin/tag.c:237
+#, c-format
+msgid "could not verify the tag '%s'"
+msgstr ""
+
+#: builtin/tag.c:247
+msgid ""
+"\n"
+"#\n"
+"# Write a tag message\n"
+"# Lines starting with '#' will be ignored.\n"
+"#\n"
+msgstr ""
+
+#: builtin/tag.c:254
+msgid ""
+"\n"
+"#\n"
+"# Write a tag message\n"
+"# Lines starting with '#' will be kept; you may remove them yourself if you "
+"want to.\n"
+"#\n"
+msgstr ""
+
+#: builtin/tag.c:294
+msgid "unable to sign the tag"
+msgstr ""
+
+#: builtin/tag.c:296
+msgid "unable to write tag file"
+msgstr ""
+
+#: builtin/tag.c:321
+msgid "bad object type."
+msgstr ""
+
+#: builtin/tag.c:334
+msgid "tag header too big."
+msgstr ""
+
+#: builtin/tag.c:366
+msgid "no tag message?"
+msgstr ""
+
+#: builtin/tag.c:372
+#, c-format
+msgid "The tag message has been left in %s\n"
+msgstr ""
+
+#: builtin/tag.c:421
+msgid "switch 'points-at' requires an object"
+msgstr ""
+
+#: builtin/tag.c:423
+#, c-format
+msgid "malformed object name '%s'"
+msgstr ""
+
+#: builtin/tag.c:502
+msgid "-n option is only allowed with -l."
+msgstr ""
+
+#: builtin/tag.c:504
+msgid "--contains option is only allowed with -l."
+msgstr ""
+
+#: builtin/tag.c:506
+msgid "--points-at option is only allowed with -l."
+msgstr ""
+
+#: builtin/tag.c:514
+msgid "only one -F or -m option is allowed."
+msgstr ""
+
+#: builtin/tag.c:534
+msgid "too many params"
+msgstr ""
+
+#: builtin/tag.c:540
+#, c-format
+msgid "'%s' is not a valid tag name."
+msgstr ""
+
+#: builtin/tag.c:545
+#, c-format
+msgid "tag '%s' already exists"
+msgstr ""
+
+#: builtin/tag.c:563
+#, c-format
+msgid "%s: cannot lock the ref"
+msgstr ""
+
+#: builtin/tag.c:565
+#, c-format
+msgid "%s: cannot update the ref"
+msgstr ""
+
+#: builtin/tag.c:567
+#, c-format
+msgid "Updated tag '%s' (was %s)\n"
+msgstr ""
+
+#: git-am.sh:49
+msgid "You need to set your committer info first"
+msgstr ""
+
+#: git-am.sh:136
+msgid "Repository lacks necessary blobs to fall back on 3-way merge."
+msgstr ""
+
+#: git-am.sh:147
+msgid ""
+"Did you hand edit your patch?\n"
+"It does not apply to blobs recorded in its index."
+msgstr ""
+
+#: git-am.sh:156
+msgid "Falling back to patching base and 3-way merge..."
+msgstr ""
+
+#: git-am.sh:268
+msgid "Only one StGIT patch series can be applied at once"
+msgstr ""
+
+#: git-am.sh:355
+#, sh-format
+msgid "Patch format $patch_format is not supported."
+msgstr ""
+
+#: git-am.sh:357
+msgid "Patch format detection failed."
+msgstr ""
+
+#: git-am.sh:411
+msgid "-d option is no longer supported. Do not use."
+msgstr ""
+
+#: git-am.sh:474
+#, sh-format
+msgid "previous rebase directory $dotest still exists but mbox given."
+msgstr ""
+
+#: git-am.sh:479
+msgid "Please make up your mind. --skip or --abort?"
+msgstr ""
+
+#: git-am.sh:506
+msgid "Resolve operation not in progress, we are not resuming."
+msgstr ""
+
+#: git-am.sh:572
+#, sh-format
+msgid "Dirty index: cannot apply patches (dirty: $files)"
+msgstr ""
+
+#: git-am.sh:748
+msgid "cannot be interactive without stdin connected to a terminal."
+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:759
+msgid "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all "
+msgstr ""
+
+#: git-am.sh:795
+#, sh-format
+msgid "Applying: $FIRSTLINE"
+msgstr ""
+
+#: git-am.sh:840
+msgid "No changes -- Patch already applied."
+msgstr ""
+
+#: git-am.sh:866
+msgid "applying to an empty history"
+msgstr ""
+
+#. TRANSLATORS: Make sure to include [Y] and [n] in your
+#. translation. The program will only accept English input
+#. at this point.
+#: git-bisect.sh:54
+msgid "Do you want me to do it for you [Y/n]? "
+msgstr ""
+
+#: git-bisect.sh:95
+#, sh-format
+msgid "unrecognised option: '$arg'"
+msgstr ""
+
+#: git-bisect.sh:99
+#, sh-format
+msgid "'$arg' does not appear to be a valid revision"
+msgstr ""
+
+#: git-bisect.sh:117
+msgid "Bad HEAD - I need a HEAD"
+msgstr ""
+
+#: git-bisect.sh:130
+#, sh-format
+msgid ""
+"Checking out '$start_head' failed. Try 'git bisect reset <validbranch>'."
+msgstr ""
+
+#: git-bisect.sh:140
+msgid "won't bisect on seeked tree"
+msgstr ""
+
+#: git-bisect.sh:144
+msgid "Bad HEAD - strange symbolic ref"
+msgstr ""
+
+#: git-bisect.sh:189
+#, sh-format
+msgid "Bad bisect_write argument: $state"
+msgstr ""
+
+#: git-bisect.sh:218
+#, sh-format
+msgid "Bad rev input: $arg"
+msgstr ""
+
+#: git-bisect.sh:232
+msgid "Please call 'bisect_state' with at least one argument."
+msgstr ""
+
+#: git-bisect.sh:244
+#, sh-format
+msgid "Bad rev input: $rev"
+msgstr ""
+
+#: git-bisect.sh:250
+msgid "'git bisect bad' can take only one argument."
+msgstr ""
+
+#. 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 ""
+
+#: git-bisect.sh:354
+#, sh-format
+msgid "'$invalid' is not a valid commit"
+msgstr ""
+
+#: git-bisect.sh:363
+#, sh-format
+msgid ""
+"Could not check out original HEAD '$branch'.\n"
+"Try 'git bisect reset <commit>'."
+msgstr ""
+
+#: git-bisect.sh:390
+msgid "No logfile given"
+msgstr ""
+
+#: git-bisect.sh:391
+#, sh-format
+msgid "cannot read $file for replaying"
+msgstr ""
+
+#: git-bisect.sh:408
+msgid "?? what are you talking about?"
+msgstr ""
+
+#: git-bisect.sh:474
+msgid "We are not bisecting."
+msgstr ""
+
+#: git-pull.sh:21
+msgid ""
+"Pull is not possible because you have unmerged files.\n"
+"Please, fix them up in the work tree, and then use 'git add/rm <file>'\n"
+"as appropriate to mark resolution, or use 'git commit -a'."
+msgstr ""
+
+#: git-pull.sh:25
+msgid "Pull is not possible because you have unmerged files."
+msgstr ""
+
+#: git-pull.sh:197
+msgid "updating an unborn branch with changes added to the index"
+msgstr ""
+
+#: git-pull.sh:253
+msgid "Cannot merge multiple branches into empty head"
+msgstr ""
+
+#: git-pull.sh:257
+msgid "Cannot rebase onto multiple branches"
+msgstr ""
+
+#: git-stash.sh:51
+msgid "git stash clear with parameters is unimplemented"
+msgstr ""
+
+#: git-stash.sh:74
+msgid "You do not have the initial commit yet"
+msgstr ""
+
+#: git-stash.sh:89
+msgid "Cannot save the current index state"
+msgstr ""
+
+#: git-stash.sh:123 git-stash.sh:136
+msgid "Cannot save the current worktree state"
+msgstr ""
+
+#: git-stash.sh:140
+msgid "No changes selected"
+msgstr ""
+
+#: git-stash.sh:143
+msgid "Cannot remove temporary index (can't happen)"
+msgstr ""
+
+#: git-stash.sh:156
+msgid "Cannot record working tree state"
+msgstr ""
+
+#: git-stash.sh:223
+msgid "No local changes to save"
+msgstr ""
+
+#: git-stash.sh:227
+msgid "Cannot initialize stash"
+msgstr ""
+
+#: git-stash.sh:235
+msgid "Cannot save the current status"
+msgstr ""
+
+#: git-stash.sh:253
+msgid "Cannot remove worktree changes"
+msgstr ""
+
+#: git-stash.sh:352
+msgid "No stash found."
+msgstr ""
+
+#: git-stash.sh:359
+#, sh-format
+msgid "Too many revisions specified: $REV"
+msgstr ""
+
+#: git-stash.sh:365
+#, sh-format
+msgid "$reference is not valid reference"
+msgstr ""
+
+#: git-stash.sh:393
+#, sh-format
+msgid "'$args' is not a stash-like commit"
+msgstr ""
+
+#: git-stash.sh:404
+#, sh-format
+msgid "'$args' is not a stash reference"
+msgstr ""
+
+#: git-stash.sh:412
+msgid "unable to refresh index"
+msgstr ""
+
+#: git-stash.sh:416
+msgid "Cannot apply a stash in the middle of a merge"
+msgstr ""
+
+#: git-stash.sh:424
+msgid "Conflicts in index. Try without --index."
+msgstr ""
+
+#: git-stash.sh:426
+msgid "Could not save index tree"
+msgstr ""
+
+#: git-stash.sh:460
+msgid "Cannot unstage modified files"
+msgstr ""
+
+#: git-stash.sh:491
+#, sh-format
+msgid "Dropped ${REV} ($s)"
+msgstr ""
+
+#: git-stash.sh:492
+#, sh-format
+msgid "${REV}: Could not drop stash entry"
+msgstr ""
+
+#: git-stash.sh:499
+msgid "No branch name specified"
+msgstr ""
+
+#: git-stash.sh:570
+msgid "(To restore them type \"git stash apply\")"
+msgstr ""
+
+#: git-submodule.sh:56
+#, sh-format
+msgid "cannot strip one component off url '$remoteurl'"
+msgstr ""
+
+#: git-submodule.sh:108
+#, sh-format
+msgid "No submodule mapping found in .gitmodules for path '$path'"
+msgstr ""
+
+#: git-submodule.sh:149
+#, sh-format
+msgid "Clone of '$url' into submodule path '$path' failed"
+msgstr ""
+
+#: git-submodule.sh:159
+#, sh-format
+msgid "Gitdir '$a' is part of the submodule path '$b' or vice versa"
+msgstr ""
+
+#: git-submodule.sh:248
+#, sh-format
+msgid "repo URL: '$repo' must be absolute or begin with ./|../"
+msgstr ""
+
+#: git-submodule.sh:265
+#, sh-format
+msgid "'$path' already exists in the index"
+msgstr ""
+
+#: git-submodule.sh:282
+#, sh-format
+msgid "'$path' already exists and is not a valid git repo"
+msgstr ""
+
+#: git-submodule.sh:296
+#, sh-format
+msgid "Unable to checkout submodule '$path'"
+msgstr ""
+
+#: git-submodule.sh:301
+#, sh-format
+msgid "Failed to add submodule '$path'"
+msgstr ""
+
+#: git-submodule.sh:306
+#, sh-format
+msgid "Failed to register submodule '$path'"
+msgstr ""
+
+#: git-submodule.sh:348
+#, sh-format
+msgid "Entering '$prefix$path'"
+msgstr ""
+
+#: git-submodule.sh:360
+#, sh-format
+msgid "Stopping at '$path'; script returned non-zero status."
+msgstr ""
+
+#: git-submodule.sh:402
+#, sh-format
+msgid "No url found for submodule path '$path' in .gitmodules"
+msgstr ""
+
+#: git-submodule.sh:411
+#, sh-format
+msgid "Failed to register url for submodule path '$path'"
+msgstr ""
+
+#: git-submodule.sh:419
+#, sh-format
+msgid "Failed to register update mode for submodule path '$path'"
+msgstr ""
+
+#: git-submodule.sh:421
+#, sh-format
+msgid "Submodule '$name' ($url) registered for path '$path'"
+msgstr ""
+
+#: git-submodule.sh:520
+#, sh-format
+msgid ""
+"Submodule path '$path' not initialized\n"
+"Maybe you want to use 'update --init'?"
+msgstr ""
+
+#: git-submodule.sh:533
+#, sh-format
+msgid "Unable to find current revision in submodule path '$path'"
+msgstr ""
+
+#: git-submodule.sh:552
+#, sh-format
+msgid "Unable to fetch in submodule path '$path'"
+msgstr ""
+
+#: git-submodule.sh:566
+#, sh-format
+msgid "Unable to rebase '$sha1' in submodule path '$path'"
+msgstr ""
+
+#: git-submodule.sh:567
+#, sh-format
+msgid "Submodule path '$path': rebased into '$sha1'"
+msgstr ""
+
+#: git-submodule.sh:572
+#, sh-format
+msgid "Unable to merge '$sha1' in submodule path '$path'"
+msgstr ""
+
+#: git-submodule.sh:573
+#, sh-format
+msgid "Submodule path '$path': merged in '$sha1'"
+msgstr ""
+
+#: git-submodule.sh:578
+#, sh-format
+msgid "Unable to checkout '$sha1' in submodule path '$path'"
+msgstr ""
+
+#: git-submodule.sh:579
+#, sh-format
+msgid "Submodule path '$path': checked out '$sha1'"
+msgstr ""
+
+#: git-submodule.sh:601 git-submodule.sh:924
+#, sh-format
+msgid "Failed to recurse into submodule path '$path'"
+msgstr ""
+
+#: git-submodule.sh:709
+msgid "--"
+msgstr ""
+
+#: git-submodule.sh:767
+#, sh-format
+msgid " Warn: $name doesn't contain commit $sha1_src"
+msgstr ""
+
+#: git-submodule.sh:770
+#, sh-format
+msgid " Warn: $name doesn't contain commit $sha1_dst"
+msgstr ""
+
+#: git-submodule.sh:773
+#, sh-format
+msgid " Warn: $name doesn't contain commits $sha1_src and $sha1_dst"
+msgstr ""
+
+#: git-submodule.sh:798
+msgid "blob"
+msgstr ""
+
+#: git-submodule.sh:799
+msgid "submodule"
+msgstr ""
+
+#: git-submodule.sh:970
+#, sh-format
+msgid "Synchronizing submodule url for '$name'"
+msgstr ""
diff --git a/po/nl.po b/po/nl.po
new file mode 100644
index 0000000000..e1399e2b6d
--- /dev/null
+++ b/po/nl.po
@@ -0,0 +1,3493 @@
+# Dutch translations for Git.
+# Copyright (C) 2012 Vincent van Ravesteijn <vfr@lyx.org>
+# This file is distributed under the same license as the Git package.
+# Vincent van Ravesteijn <vfr@lyx.org>, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Git\n"
+"Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
+"POT-Creation-Date: 2012-02-28 09:17+0800\n"
+"PO-Revision-Date: 2012-03-07 12:02+0100\n"
+"Last-Translator: Vincent van Ravesteijn <vfr@lyx.org>\n"
+"Language-Team: Dutch\n"
+"Language: nl\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ASCII\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: advice.c:34
+#, c-format
+msgid "hint: %.*s\n"
+msgstr ""
+
+#.
+#. * Message used both when 'git commit' fails and when
+#. * other commands doing a merge do.
+#.
+#: advice.c:64
+msgid ""
+"Fix them up in the work tree,\n"
+"and then use 'git add/rm <file>' as\n"
+"appropriate to mark resolution and make a commit,\n"
+"or use 'git commit -a'."
+msgstr ""
+
+#: commit.c:47
+#, c-format
+msgid "could not parse %s"
+msgstr ""
+
+#: commit.c:49
+#, c-format
+msgid "%s %s is not a commit!"
+msgstr ""
+
+#: compat/obstack.c:406 compat/obstack.c:408
+msgid "memory exhausted"
+msgstr ""
+
+#: connected.c:39
+msgid "Could not run 'git rev-list'"
+msgstr ""
+
+#: connected.c:48
+#, c-format
+msgid "failed write to rev-list: %s"
+msgstr ""
+
+#: connected.c:56
+#, c-format
+msgid "failed to close rev-list's stdin: %s"
+msgstr ""
+
+#: diff.c:104
+#, c-format
+msgid " Failed to parse dirstat cut-off percentage '%.*s'\n"
+msgstr ""
+
+#: diff.c:109
+#, c-format
+msgid " Unknown dirstat parameter '%.*s'\n"
+msgstr ""
+
+#: diff.c:205
+#, c-format
+msgid ""
+"Found errors in 'diff.dirstat' config variable:\n"
+"%s"
+msgstr ""
+
+#: diff.c:1331
+msgid " 0 files changed\n"
+msgstr ""
+
+#: diff.c:1335
+#, c-format
+msgid " %d file changed"
+msgid_plural " %d files changed"
+msgstr[0] ""
+msgstr[1] ""
+
+#: diff.c:1352
+#, c-format
+msgid ", %d insertion(+)"
+msgid_plural ", %d insertions(+)"
+msgstr[0] ""
+msgstr[1] ""
+
+#: diff.c:1363
+#, c-format
+msgid ", %d deletion(-)"
+msgid_plural ", %d deletions(-)"
+msgstr[0] ""
+msgstr[1] ""
+
+#: diff.c:3364
+#, c-format
+msgid ""
+"Failed to parse --dirstat/-X option parameter:\n"
+"%s"
+msgstr ""
+
+#: gpg-interface.c:59
+msgid "could not run gpg."
+msgstr ""
+
+#: gpg-interface.c:71
+msgid "gpg did not accept the data"
+msgstr ""
+
+#: gpg-interface.c:82
+msgid "gpg failed to sign the data"
+msgstr ""
+
+#: grep.c:1285
+#, c-format
+msgid "'%s': unable to read %s"
+msgstr ""
+
+#: grep.c:1302
+#, c-format
+msgid "'%s': %s"
+msgstr ""
+
+#: grep.c:1313
+#, c-format
+msgid "'%s': short read %s"
+msgstr ""
+
+#: help.c:287
+#, 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 ""
+
+#: remote.c:1607
+#, 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:1613
+#, 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] ""
+msgstr[1] ""
+
+#: remote.c:1621
+#, c-format
+msgid ""
+"Your branch and '%s' have diverged,\n"
+"and have %d and %d different commit each, respectively.\n"
+msgid_plural ""
+"Your branch and '%s' have diverged,\n"
+"and have %d and %d different commits each, respectively.\n"
+msgstr[0] ""
+msgstr[1] ""
+
+#: sequencer.c:120 builtin/merge.c:862 builtin/merge.c:983
+#: builtin/merge.c:1093 builtin/merge.c:1103
+#, c-format
+msgid "Could not open '%s' for writing"
+msgstr ""
+
+#: sequencer.c:122 builtin/merge.c:334 builtin/merge.c:865
+#: builtin/merge.c:1095 builtin/merge.c:1108
+#, c-format
+msgid "Could not write to '%s'"
+msgstr ""
+
+#: sequencer.c:142
+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:154 sequencer.c:680 sequencer.c:763
+#, c-format
+msgid "Could not write to %s"
+msgstr ""
+
+#: sequencer.c:157
+#, c-format
+msgid "Error wrapping up %s"
+msgstr ""
+
+#: sequencer.c:172
+msgid "Your local changes would be overwritten by cherry-pick."
+msgstr ""
+
+#: sequencer.c:174
+msgid "Your local changes would be overwritten by revert."
+msgstr ""
+
+#: sequencer.c:177
+msgid "Commit your changes or stash them to proceed."
+msgstr ""
+
+#. TRANSLATORS: %s will be "revert" or "cherry-pick"
+#: sequencer.c:227
+#, c-format
+msgid "%s: Unable to write new index file"
+msgstr ""
+
+#: sequencer.c:293
+msgid "Your index file is unmerged."
+msgstr ""
+
+#: sequencer.c:296
+msgid "You do not have a valid HEAD"
+msgstr ""
+
+#: sequencer.c:311
+#, c-format
+msgid "Commit %s is a merge but no -m option was given."
+msgstr ""
+
+#: sequencer.c:319
+#, c-format
+msgid "Commit %s does not have parent %d"
+msgstr ""
+
+#: sequencer.c:323
+#, 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:334
+#, c-format
+msgid "%s: cannot parse parent commit %s"
+msgstr ""
+
+#: sequencer.c:338
+#, c-format
+msgid "Cannot get commit message for %s"
+msgstr ""
+
+#: sequencer.c:422
+#, c-format
+msgid "could not revert %s... %s"
+msgstr ""
+
+#: sequencer.c:423
+#, c-format
+msgid "could not apply %s... %s"
+msgstr ""
+
+#: sequencer.c:445 sequencer.c:904 builtin/log.c:286 builtin/log.c:709
+#: builtin/log.c:1325 builtin/log.c:1544 builtin/merge.c:348
+#: builtin/shortlog.c:181
+msgid "revision walk setup failed"
+msgstr ""
+
+#: sequencer.c:448
+msgid "empty commit set passed"
+msgstr ""
+
+#: sequencer.c:456
+#, c-format
+msgid "git %s: failed to read the index"
+msgstr ""
+
+#: sequencer.c:461
+#, c-format
+msgid "git %s: failed to refresh the index"
+msgstr ""
+
+#: sequencer.c:546
+#, c-format
+msgid "Cannot %s during a %s"
+msgstr ""
+
+#: sequencer.c:568
+#, c-format
+msgid "Could not parse line %d."
+msgstr ""
+
+#: sequencer.c:573
+msgid "No commits parsed."
+msgstr ""
+
+#: sequencer.c:586
+#, c-format
+msgid "Could not open %s"
+msgstr ""
+
+#: sequencer.c:590
+#, c-format
+msgid "Could not read %s."
+msgstr ""
+
+#: sequencer.c:597
+#, c-format
+msgid "Unusable instruction sheet: %s"
+msgstr ""
+
+#: sequencer.c:625
+#, c-format
+msgid "Invalid key: %s"
+msgstr ""
+
+#: sequencer.c:628
+#, c-format
+msgid "Invalid value for %s: %s"
+msgstr ""
+
+#: sequencer.c:640
+#, c-format
+msgid "Malformed options sheet: %s"
+msgstr ""
+
+#: sequencer.c:661
+msgid "a cherry-pick or revert is already in progress"
+msgstr ""
+
+#: sequencer.c:662
+msgid "try \"git cherry-pick (--continue | --quit | --abort)\""
+msgstr ""
+
+#: sequencer.c:666
+#, c-format
+msgid "Could not create sequencer directory %s"
+msgstr ""
+
+#: sequencer.c:682 sequencer.c:767
+#, c-format
+msgid "Error wrapping up %s."
+msgstr ""
+
+#: sequencer.c:701 sequencer.c:835
+msgid "no cherry-pick or revert in progress"
+msgstr ""
+
+#: sequencer.c:703
+msgid "cannot resolve HEAD"
+msgstr ""
+
+#: sequencer.c:705
+msgid "cannot abort from a branch yet to be born"
+msgstr ""
+
+#: sequencer.c:727
+#, c-format
+msgid "cannot open %s: %s"
+msgstr ""
+
+#: sequencer.c:730
+#, c-format
+msgid "cannot read %s: %s"
+msgstr ""
+
+#: sequencer.c:731
+msgid "unexpected end of file"
+msgstr ""
+
+#: sequencer.c:737
+#, c-format
+msgid "stored pre-cherry-pick HEAD file '%s' is corrupt"
+msgstr ""
+
+#: sequencer.c:760
+#, c-format
+msgid "Could not format %s."
+msgstr ""
+
+#: sequencer.c:922
+msgid "Can't revert as initial commit"
+msgstr ""
+
+#: sequencer.c:923
+msgid "Can't cherry-pick into empty head"
+msgstr ""
+
+#: wt-status.c:134
+msgid "Unmerged paths:"
+msgstr ""
+
+#: wt-status.c:140 wt-status.c:157
+#, c-format
+msgid " (use \"git reset %s <file>...\" to unstage)"
+msgstr ""
+
+#: wt-status.c:142 wt-status.c:159
+msgid " (use \"git rm --cached <file>...\" to unstage)"
+msgstr ""
+
+#: wt-status.c:143
+msgid " (use \"git add/rm <file>...\" as appropriate to mark resolution)"
+msgstr ""
+
+#: wt-status.c:151
+msgid "Changes to be committed:"
+msgstr ""
+
+#: wt-status.c:169
+msgid "Changes not staged for commit:"
+msgstr ""
+
+#: wt-status.c:173
+msgid " (use \"git add <file>...\" to update what will be committed)"
+msgstr ""
+
+#: wt-status.c:175
+msgid " (use \"git add/rm <file>...\" to update what will be committed)"
+msgstr ""
+
+#: wt-status.c:176
+msgid ""
+" (use \"git checkout -- <file>...\" to discard changes in working directory)"
+msgstr ""
+
+#: wt-status.c:178
+msgid " (commit or discard the untracked or modified content in submodules)"
+msgstr ""
+
+#: wt-status.c:187
+#, c-format
+msgid "%s files:"
+msgstr ""
+
+#: wt-status.c:190
+#, c-format
+msgid " (use \"git %s <file>...\" to include in what will be committed)"
+msgstr ""
+
+#: wt-status.c:207
+msgid "bug"
+msgstr ""
+
+#: wt-status.c:212
+msgid "both deleted:"
+msgstr ""
+
+#: wt-status.c:213
+msgid "added by us:"
+msgstr ""
+
+#: wt-status.c:214
+msgid "deleted by them:"
+msgstr ""
+
+#: wt-status.c:215
+msgid "added by them:"
+msgstr ""
+
+#: wt-status.c:216
+msgid "deleted by us:"
+msgstr ""
+
+#: wt-status.c:217
+msgid "both added:"
+msgstr ""
+
+#: wt-status.c:218
+msgid "both modified:"
+msgstr ""
+
+#: wt-status.c:248
+msgid "new commits, "
+msgstr ""
+
+#: wt-status.c:250
+msgid "modified content, "
+msgstr ""
+
+#: wt-status.c:252
+msgid "untracked content, "
+msgstr ""
+
+#: wt-status.c:266
+#, c-format
+msgid "new file: %s"
+msgstr ""
+
+#: wt-status.c:269
+#, c-format
+msgid "copied: %s -> %s"
+msgstr ""
+
+#: wt-status.c:272
+#, c-format
+msgid "deleted: %s"
+msgstr ""
+
+#: wt-status.c:275
+#, c-format
+msgid "modified: %s"
+msgstr ""
+
+#: wt-status.c:278
+#, c-format
+msgid "renamed: %s -> %s"
+msgstr ""
+
+#: wt-status.c:281
+#, c-format
+msgid "typechange: %s"
+msgstr ""
+
+#: wt-status.c:284
+#, c-format
+msgid "unknown: %s"
+msgstr ""
+
+#: wt-status.c:287
+#, c-format
+msgid "unmerged: %s"
+msgstr ""
+
+#: wt-status.c:290
+#, c-format
+msgid "bug: unhandled diff status %c"
+msgstr ""
+
+#: wt-status.c:713
+msgid "On branch "
+msgstr ""
+
+#: wt-status.c:720
+msgid "Not currently on any branch."
+msgstr ""
+
+#: wt-status.c:731
+msgid "Initial commit"
+msgstr ""
+
+#: wt-status.c:745
+msgid "Untracked"
+msgstr ""
+
+#: wt-status.c:747
+msgid "Ignored"
+msgstr ""
+
+#: wt-status.c:749
+#, c-format
+msgid "Untracked files not listed%s"
+msgstr ""
+
+#: wt-status.c:751
+msgid " (use -u option to show untracked files)"
+msgstr ""
+
+#: wt-status.c:757
+msgid "No changes"
+msgstr ""
+
+#: wt-status.c:761
+#, c-format
+msgid "no changes added to commit%s\n"
+msgstr ""
+
+#: wt-status.c:763
+msgid " (use \"git add\" and/or \"git commit -a\")"
+msgstr ""
+
+#: wt-status.c:765
+#, c-format
+msgid "nothing added to commit but untracked files present%s\n"
+msgstr ""
+
+#: wt-status.c:767
+msgid " (use \"git add\" to track)"
+msgstr ""
+
+#: wt-status.c:769 wt-status.c:772 wt-status.c:775
+#, c-format
+msgid "nothing to commit%s\n"
+msgstr ""
+
+#: wt-status.c:770
+msgid " (create/copy files and use \"git add\" to track)"
+msgstr ""
+
+#: wt-status.c:773
+msgid " (use -u to show untracked files)"
+msgstr ""
+
+#: wt-status.c:776
+msgid " (working directory clean)"
+msgstr ""
+
+#: wt-status.c:884
+msgid "HEAD (no branch)"
+msgstr ""
+
+#: wt-status.c:890
+msgid "Initial commit on "
+msgstr ""
+
+#: wt-status.c:905
+msgid "behind "
+msgstr ""
+
+#: wt-status.c:908 wt-status.c:911
+msgid "ahead "
+msgstr ""
+
+#: wt-status.c:913
+msgid ", behind "
+msgstr ""
+
+#: builtin/add.c:62
+#, c-format
+msgid "unexpected diff status %c"
+msgstr ""
+
+#: builtin/add.c:67 builtin/commit.c:298
+msgid "updating files failed"
+msgstr ""
+
+#: builtin/add.c:77
+#, c-format
+msgid "remove '%s'\n"
+msgstr ""
+
+#: builtin/add.c:176
+#, c-format
+msgid "Path '%s' is in submodule '%.*s'"
+msgstr ""
+
+#: builtin/add.c:192
+msgid "Unstaged changes after refreshing the index:"
+msgstr ""
+
+#: builtin/add.c:195 builtin/add.c:456 builtin/rm.c:186
+#, c-format
+msgid "pathspec '%s' did not match any files"
+msgstr ""
+
+#: builtin/add.c:209
+#, c-format
+msgid "'%s' is beyond a symbolic link"
+msgstr ""
+
+#: builtin/add.c:276
+msgid "Could not read the index"
+msgstr ""
+
+#: builtin/add.c:286
+#, c-format
+msgid "Could not open '%s' for writing."
+msgstr ""
+
+#: builtin/add.c:290
+msgid "Could not write patch"
+msgstr ""
+
+#: builtin/add.c:295
+#, c-format
+msgid "Could not stat '%s'"
+msgstr ""
+
+#: builtin/add.c:297
+msgid "Empty patch. Aborted."
+msgstr ""
+
+#: builtin/add.c:303
+#, c-format
+msgid "Could not apply '%s'"
+msgstr ""
+
+#: builtin/add.c:312
+msgid "The following paths are ignored by one of your .gitignore files:\n"
+msgstr ""
+
+#: builtin/add.c:352
+#, c-format
+msgid "Use -f if you really want to add them.\n"
+msgstr ""
+
+#: builtin/add.c:353
+msgid "no files added"
+msgstr ""
+
+#: builtin/add.c:359
+msgid "adding files failed"
+msgstr ""
+
+#: builtin/add.c:391
+msgid "-A and -u are mutually incompatible"
+msgstr ""
+
+#: builtin/add.c:393
+msgid "Option --ignore-missing can only be used together with --dry-run"
+msgstr ""
+
+#: builtin/add.c:413
+#, c-format
+msgid "Nothing specified, nothing added.\n"
+msgstr ""
+
+#: builtin/add.c:414
+#, c-format
+msgid "Maybe you wanted to say 'git add .'?\n"
+msgstr ""
+
+#: builtin/add.c:420 builtin/clean.c:95 builtin/commit.c:358 builtin/mv.c:82
+#: builtin/rm.c:162
+msgid "index file corrupt"
+msgstr ""
+
+#: builtin/add.c:476 builtin/mv.c:229 builtin/rm.c:260
+msgid "Unable to write new index file"
+msgstr ""
+
+#: builtin/archive.c:17
+#, c-format
+msgid "could not create archive file '%s'"
+msgstr ""
+
+#: builtin/archive.c:20
+msgid "could not redirect output"
+msgstr ""
+
+#: builtin/archive.c:37
+msgid "git archive: Remote with no URL"
+msgstr ""
+
+#: builtin/archive.c:58
+msgid "git archive: expected ACK/NAK, got EOF"
+msgstr ""
+
+#: builtin/archive.c:63
+#, c-format
+msgid "git archive: NACK %s"
+msgstr ""
+
+#: builtin/archive.c:65
+#, c-format
+msgid "remote error: %s"
+msgstr ""
+
+#: builtin/archive.c:66
+msgid "git archive: protocol error"
+msgstr ""
+
+#: builtin/archive.c:71
+msgid "git archive: expected a flush"
+msgstr ""
+
+#: builtin/branch.c:137
+#, c-format
+msgid ""
+"deleting branch '%s' that has been merged to\n"
+" '%s', but not yet merged to HEAD."
+msgstr ""
+
+#: builtin/branch.c:141
+#, c-format
+msgid ""
+"not deleting branch '%s' that is not yet merged to\n"
+" '%s', even though it is merged to HEAD."
+msgstr ""
+
+#. TRANSLATORS: This is "remote " in "remote branch '%s' not found"
+#: builtin/branch.c:163
+msgid "remote "
+msgstr ""
+
+#: builtin/branch.c:171
+msgid "cannot use -a with -d"
+msgstr ""
+
+#: builtin/branch.c:177
+msgid "Couldn't look up commit object for HEAD"
+msgstr ""
+
+#: builtin/branch.c:182
+#, c-format
+msgid "Cannot delete the branch '%s' which you are currently on."
+msgstr ""
+
+#: builtin/branch.c:192
+#, c-format
+msgid "%sbranch '%s' not found."
+msgstr ""
+
+#: builtin/branch.c:200
+#, c-format
+msgid "Couldn't look up commit object for '%s'"
+msgstr ""
+
+#: builtin/branch.c:206
+#, 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:214
+#, c-format
+msgid "Error deleting %sbranch '%s'"
+msgstr ""
+
+#: builtin/branch.c:219
+#, c-format
+msgid "Deleted %sbranch %s (was %s).\n"
+msgstr ""
+
+#: builtin/branch.c:224
+msgid "Update of config-file failed"
+msgstr ""
+
+#: builtin/branch.c:322
+#, c-format
+msgid "branch '%s' does not point at a commit"
+msgstr ""
+
+#: builtin/branch.c:394
+#, c-format
+msgid "behind %d] "
+msgstr ""
+
+#: builtin/branch.c:396
+#, c-format
+msgid "ahead %d] "
+msgstr ""
+
+#: builtin/branch.c:398
+#, c-format
+msgid "ahead %d, behind %d] "
+msgstr ""
+
+#: builtin/branch.c:501
+msgid "(no branch)"
+msgstr ""
+
+#: builtin/branch.c:562
+msgid "some refs could not be read"
+msgstr ""
+
+#: builtin/branch.c:575
+msgid "cannot rename the current branch while not on any."
+msgstr ""
+
+#: builtin/branch.c:585
+#, c-format
+msgid "Invalid branch name: '%s'"
+msgstr ""
+
+#: builtin/branch.c:600
+msgid "Branch rename failed"
+msgstr ""
+
+#: builtin/branch.c:604
+#, c-format
+msgid "Renamed a misnamed branch '%s' away"
+msgstr ""
+
+#: builtin/branch.c:608
+#, c-format
+msgid "Branch renamed to %s, but HEAD is not updated!"
+msgstr ""
+
+#: builtin/branch.c:615
+msgid "Branch is renamed, but update of config-file failed"
+msgstr ""
+
+#: builtin/branch.c:630
+#, c-format
+msgid "malformed object name %s"
+msgstr ""
+
+#: builtin/branch.c:654
+#, c-format
+msgid "could not write branch description template: %s\n"
+msgstr ""
+
+#: builtin/branch.c:742
+msgid "Failed to resolve HEAD as a valid ref."
+msgstr ""
+
+#: builtin/branch.c:747 builtin/clone.c:558
+msgid "HEAD not found below refs/heads!"
+msgstr ""
+
+#: builtin/branch.c:805
+msgid "-a and -r options to 'git branch' do not make sense with a branch name"
+msgstr ""
+
+#: builtin/bundle.c:47
+#, c-format
+msgid "%s is okay\n"
+msgstr ""
+
+#: builtin/bundle.c:56
+msgid "Need a repository to create a bundle."
+msgstr ""
+
+#: builtin/bundle.c:60
+msgid "Need a repository to unbundle."
+msgstr ""
+
+#: builtin/checkout.c:113 builtin/checkout.c:146
+#, c-format
+msgid "path '%s' does not have our version"
+msgstr ""
+
+#: builtin/checkout.c:115 builtin/checkout.c:148
+#, c-format
+msgid "path '%s' does not have their version"
+msgstr ""
+
+#: builtin/checkout.c:131
+#, c-format
+msgid "path '%s' does not have all necessary versions"
+msgstr ""
+
+#: builtin/checkout.c:175
+#, c-format
+msgid "path '%s' does not have necessary versions"
+msgstr ""
+
+#: builtin/checkout.c:192
+#, c-format
+msgid "path '%s': cannot merge"
+msgstr ""
+
+#: builtin/checkout.c:209
+#, c-format
+msgid "Unable to add merge result for '%s'"
+msgstr ""
+
+#: builtin/checkout.c:212 builtin/reset.c:158
+#, c-format
+msgid "make_cache_entry failed for path '%s'"
+msgstr ""
+
+#: builtin/checkout.c:234 builtin/checkout.c:392
+msgid "corrupt index file"
+msgstr ""
+
+#: builtin/checkout.c:264 builtin/checkout.c:271
+#, c-format
+msgid "path '%s' is unmerged"
+msgstr ""
+
+#: builtin/checkout.c:302 builtin/checkout.c:498 builtin/clone.c:583
+#: builtin/merge.c:809
+msgid "unable to write new index file"
+msgstr ""
+
+#: builtin/checkout.c:319 builtin/diff.c:298 builtin/merge.c:406
+msgid "diff_setup_done failed"
+msgstr ""
+
+#: builtin/checkout.c:414
+msgid "you need to resolve your current index first"
+msgstr ""
+
+#: builtin/checkout.c:533
+#, c-format
+msgid "Can not do reflog for '%s'\n"
+msgstr ""
+
+#: builtin/checkout.c:565
+msgid "HEAD is now at"
+msgstr ""
+
+#: builtin/checkout.c:572
+#, c-format
+msgid "Reset branch '%s'\n"
+msgstr ""
+
+#: builtin/checkout.c:575
+#, c-format
+msgid "Already on '%s'\n"
+msgstr ""
+
+#: builtin/checkout.c:579
+#, c-format
+msgid "Switched to and reset branch '%s'\n"
+msgstr ""
+
+#: builtin/checkout.c:581
+#, c-format
+msgid "Switched to a new branch '%s'\n"
+msgstr ""
+
+#: builtin/checkout.c:583
+#, c-format
+msgid "Switched to branch '%s'\n"
+msgstr ""
+
+#: builtin/checkout.c:639
+#, c-format
+msgid " ... and %d more.\n"
+msgstr ""
+
+#. The singular version
+#: builtin/checkout.c:645
+#, 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"
+"\n"
+"%s\n"
+msgstr[0] ""
+msgstr[1] ""
+
+#: builtin/checkout.c:663
+#, 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"
+msgstr ""
+
+#: builtin/checkout.c:692
+msgid "internal error in revision walk"
+msgstr ""
+
+#: builtin/checkout.c:696
+msgid "Previous HEAD position was"
+msgstr ""
+
+#: builtin/checkout.c:722
+msgid "You are on a branch yet to be born"
+msgstr ""
+
+#. case (1)
+#: builtin/checkout.c:853
+#, c-format
+msgid "invalid reference: %s"
+msgstr ""
+
+#. case (1): want a tree
+#: builtin/checkout.c:892
+#, c-format
+msgid "reference is not a tree: %s"
+msgstr ""
+
+#: builtin/checkout.c:972
+msgid "-B cannot be used with -b"
+msgstr ""
+
+#: builtin/checkout.c:981
+msgid "--patch is incompatible with all other options"
+msgstr ""
+
+#: builtin/checkout.c:984
+msgid "--detach cannot be used with -b/-B/--orphan"
+msgstr ""
+
+#: builtin/checkout.c:986
+msgid "--detach cannot be used with -t"
+msgstr ""
+
+#: builtin/checkout.c:992
+msgid "--track needs a branch name"
+msgstr ""
+
+#: builtin/checkout.c:999
+msgid "Missing branch name; try -b"
+msgstr ""
+
+#: builtin/checkout.c:1005
+msgid "--orphan and -b|-B are mutually exclusive"
+msgstr ""
+
+#: builtin/checkout.c:1007
+msgid "--orphan cannot be used with -t"
+msgstr ""
+
+#: builtin/checkout.c:1017
+msgid "git checkout: -f and -m are incompatible"
+msgstr ""
+
+#: builtin/checkout.c:1051
+msgid "invalid path specification"
+msgstr ""
+
+#: builtin/checkout.c:1059
+#, 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?"
+msgstr ""
+
+#: builtin/checkout.c:1061
+msgid "git checkout: updating paths is incompatible with switching branches."
+msgstr ""
+
+#: builtin/checkout.c:1066
+msgid "git checkout: --detach does not take a path argument"
+msgstr ""
+
+#: builtin/checkout.c:1069
+msgid ""
+"git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
+"checking out of the index."
+msgstr ""
+
+#: builtin/checkout.c:1088
+msgid "Cannot switch branch to a non-commit."
+msgstr ""
+
+#: builtin/checkout.c:1091
+msgid "--ours/--theirs is incompatible with switching branches."
+msgstr ""
+
+#: builtin/clean.c:78
+msgid "-x and -X cannot be used together"
+msgstr ""
+
+#: builtin/clean.c:82
+msgid ""
+"clean.requireForce set to true and neither -n nor -f given; refusing to clean"
+msgstr ""
+
+#: builtin/clean.c:85
+msgid ""
+"clean.requireForce defaults to true and neither -n nor -f given; refusing to "
+"clean"
+msgstr ""
+
+#: builtin/clean.c:155 builtin/clean.c:176
+#, c-format
+msgid "Would remove %s\n"
+msgstr ""
+
+#: builtin/clean.c:159 builtin/clean.c:179
+#, c-format
+msgid "Removing %s\n"
+msgstr ""
+
+#: builtin/clean.c:162 builtin/clean.c:182
+#, c-format
+msgid "failed to remove %s"
+msgstr ""
+
+#: builtin/clean.c:166
+#, c-format
+msgid "Would not remove %s\n"
+msgstr ""
+
+#: builtin/clean.c:168
+#, c-format
+msgid "Not removing %s\n"
+msgstr ""
+
+#: builtin/clone.c:243
+#, c-format
+msgid "reference repository '%s' is not a local directory."
+msgstr ""
+
+#: builtin/clone.c:302
+#, c-format
+msgid "failed to open '%s'"
+msgstr ""
+
+#: builtin/clone.c:306
+#, c-format
+msgid "failed to create directory '%s'"
+msgstr ""
+
+#: builtin/clone.c:308 builtin/diff.c:75
+#, c-format
+msgid "failed to stat '%s'"
+msgstr ""
+
+#: builtin/clone.c:310
+#, c-format
+msgid "%s exists and is not a directory"
+msgstr ""
+
+#: builtin/clone.c:324
+#, c-format
+msgid "failed to stat %s\n"
+msgstr ""
+
+#: builtin/clone.c:341
+#, c-format
+msgid "failed to unlink '%s'"
+msgstr ""
+
+#: builtin/clone.c:346
+#, c-format
+msgid "failed to create link '%s'"
+msgstr ""
+
+#: builtin/clone.c:350
+#, c-format
+msgid "failed to copy file to '%s'"
+msgstr ""
+
+#: builtin/clone.c:373
+#, c-format
+msgid "done.\n"
+msgstr ""
+
+#: builtin/clone.c:440
+#, c-format
+msgid "Could not find remote branch %s to clone."
+msgstr ""
+
+#: builtin/clone.c:549
+msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n"
+msgstr ""
+
+#: builtin/clone.c:639
+msgid "Too many arguments."
+msgstr ""
+
+#: builtin/clone.c:643
+msgid "You must specify a repository to clone."
+msgstr ""
+
+#: builtin/clone.c:654
+#, c-format
+msgid "--bare and --origin %s options are incompatible."
+msgstr ""
+
+#: builtin/clone.c:668
+#, c-format
+msgid "repository '%s' does not exist"
+msgstr ""
+
+#: builtin/clone.c:673
+msgid "--depth is ignored in local clones; use file:// instead."
+msgstr ""
+
+#: builtin/clone.c:683
+#, c-format
+msgid "destination path '%s' already exists and is not an empty directory."
+msgstr ""
+
+#: builtin/clone.c:693
+#, c-format
+msgid "working tree '%s' already exists."
+msgstr ""
+
+#: builtin/clone.c:706 builtin/clone.c:720
+#, c-format
+msgid "could not create leading directories of '%s'"
+msgstr ""
+
+#: builtin/clone.c:709
+#, c-format
+msgid "could not create work tree dir '%s'."
+msgstr ""
+
+#: builtin/clone.c:728
+#, c-format
+msgid "Cloning into bare repository '%s'...\n"
+msgstr ""
+
+#: builtin/clone.c:730
+#, c-format
+msgid "Cloning into '%s'...\n"
+msgstr ""
+
+#: builtin/clone.c:786
+#, c-format
+msgid "Don't know how to clone %s"
+msgstr ""
+
+#: builtin/clone.c:835
+#, 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/commit.c:42
+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/commit.c:54
+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 ""
+
+#: builtin/commit.c:59
+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/commit.c:205 builtin/reset.c:33
+msgid "merge"
+msgstr ""
+
+#: builtin/commit.c:208
+msgid "cherry-pick"
+msgstr ""
+
+#: builtin/commit.c:325
+msgid "failed to unpack HEAD tree object"
+msgstr ""
+
+#: builtin/commit.c:367
+msgid "unable to create temporary index"
+msgstr ""
+
+#: builtin/commit.c:373
+msgid "interactive add failed"
+msgstr ""
+
+#: builtin/commit.c:406 builtin/commit.c:427 builtin/commit.c:473
+msgid "unable to write new_index file"
+msgstr ""
+
+#: builtin/commit.c:457
+#, c-format
+msgid "cannot do a partial commit during a %s."
+msgstr ""
+
+#: builtin/commit.c:466
+msgid "cannot read the index"
+msgstr ""
+
+#: builtin/commit.c:486
+msgid "unable to write temporary index file"
+msgstr ""
+
+#: builtin/commit.c:550 builtin/commit.c:556
+#, c-format
+msgid "invalid commit: %s"
+msgstr ""
+
+#: builtin/commit.c:579
+msgid "malformed --author parameter"
+msgstr ""
+
+#: builtin/commit.c:635
+#, c-format
+msgid "Malformed ident string: '%s'"
+msgstr ""
+
+#: builtin/commit.c:670 builtin/commit.c:703 builtin/commit.c:1000
+#, c-format
+msgid "could not lookup commit %s"
+msgstr ""
+
+#: builtin/commit.c:682 builtin/shortlog.c:296
+#, c-format
+msgid "(reading log message from standard input)\n"
+msgstr ""
+
+#: builtin/commit.c:684
+msgid "could not read log from standard input"
+msgstr ""
+
+#: builtin/commit.c:688
+#, c-format
+msgid "could not read log file '%s'"
+msgstr ""
+
+#: builtin/commit.c:694
+msgid "commit has empty message"
+msgstr ""
+
+#: builtin/commit.c:710
+msgid "could not read MERGE_MSG"
+msgstr ""
+
+#: builtin/commit.c:714
+msgid "could not read SQUASH_MSG"
+msgstr ""
+
+#: builtin/commit.c:718
+#, c-format
+msgid "could not read '%s'"
+msgstr ""
+
+#: builtin/commit.c:746
+#, c-format
+msgid "could not open '%s'"
+msgstr ""
+
+#: builtin/commit.c:770
+msgid "could not write commit template"
+msgstr ""
+
+#: builtin/commit.c:783
+#, c-format
+msgid ""
+"\n"
+"It looks like you may be committing a %s.\n"
+"If this is not correct, please remove the file\n"
+"\t%s\n"
+"and try again.\n"
+msgstr ""
+
+#: builtin/commit.c:796
+msgid "Please enter the commit message for your changes."
+msgstr ""
+
+#: builtin/commit.c:799
+msgid ""
+" Lines starting\n"
+"with '#' will be ignored, and an empty message aborts the commit.\n"
+msgstr ""
+
+#: builtin/commit.c:804
+msgid ""
+" Lines starting\n"
+"with '#' will be kept; you may remove them yourself if you want to.\n"
+"An empty message aborts the commit.\n"
+msgstr ""
+
+#: builtin/commit.c:816
+#, c-format
+msgid "%sAuthor: %s"
+msgstr ""
+
+#: builtin/commit.c:823
+#, c-format
+msgid "%sCommitter: %s"
+msgstr ""
+
+#: builtin/commit.c:843
+msgid "Cannot read index"
+msgstr ""
+
+#: builtin/commit.c:880
+msgid "Error building trees"
+msgstr ""
+
+#: builtin/commit.c:895 builtin/tag.c:357
+#, c-format
+msgid "Please supply the message using either -m or -F option.\n"
+msgstr ""
+
+#: builtin/commit.c:975
+#, c-format
+msgid "No existing author found with '%s'"
+msgstr ""
+
+#: builtin/commit.c:990 builtin/commit.c:1182
+#, c-format
+msgid "Invalid untracked files mode '%s'"
+msgstr ""
+
+#: builtin/commit.c:1030
+msgid "Using both --reset-author and --author does not make sense"
+msgstr ""
+
+#: builtin/commit.c:1041
+msgid "You have nothing to amend."
+msgstr ""
+
+#: builtin/commit.c:1043
+#, c-format
+msgid "You are in the middle of a %s -- cannot amend."
+msgstr ""
+
+#: builtin/commit.c:1045
+msgid "Options --squash and --fixup cannot be used together"
+msgstr ""
+
+#: builtin/commit.c:1055
+msgid "Only one of -c/-C/-F/--fixup can be used."
+msgstr ""
+
+#: builtin/commit.c:1057
+msgid "Option -m cannot be combined with -c/-C/-F/--fixup."
+msgstr ""
+
+#: builtin/commit.c:1063
+msgid "--reset-author can be used only with -C, -c or --amend."
+msgstr ""
+
+#: builtin/commit.c:1080
+msgid "Only one of --include/--only/--all/--interactive/--patch can be used."
+msgstr ""
+
+#: builtin/commit.c:1082
+msgid "No paths with --include/--only does not make sense."
+msgstr ""
+
+#: builtin/commit.c:1084
+msgid "Clever... amending the last one with dirty index."
+msgstr ""
+
+#: builtin/commit.c:1086
+msgid "Explicit paths specified without -i nor -o; assuming --only paths..."
+msgstr ""
+
+#: builtin/commit.c:1096 builtin/tag.c:556
+#, c-format
+msgid "Invalid cleanup mode %s"
+msgstr ""
+
+#: builtin/commit.c:1101
+msgid "Paths with -a does not make sense."
+msgstr ""
+
+#: builtin/commit.c:1280
+msgid "couldn't look up newly created commit"
+msgstr ""
+
+#: builtin/commit.c:1282
+msgid "could not parse newly created commit"
+msgstr ""
+
+#: builtin/commit.c:1323
+msgid "detached HEAD"
+msgstr ""
+
+#: builtin/commit.c:1325
+msgid " (root-commit)"
+msgstr ""
+
+#: builtin/commit.c:1415
+msgid "could not parse HEAD commit"
+msgstr ""
+
+#: builtin/commit.c:1452 builtin/merge.c:507
+#, c-format
+msgid "could not open '%s' for reading"
+msgstr ""
+
+#: builtin/commit.c:1459
+#, c-format
+msgid "Corrupt MERGE_HEAD file (%s)"
+msgstr ""
+
+#: builtin/commit.c:1466
+msgid "could not read MERGE_MODE"
+msgstr ""
+
+#: builtin/commit.c:1485
+#, c-format
+msgid "could not read commit message: %s"
+msgstr ""
+
+#: builtin/commit.c:1499
+#, c-format
+msgid "Aborting commit due to empty commit message.\n"
+msgstr ""
+
+#: builtin/commit.c:1514 builtin/merge.c:933 builtin/merge.c:966
+msgid "failed to write commit object"
+msgstr ""
+
+#: builtin/commit.c:1535
+msgid "cannot lock HEAD ref"
+msgstr ""
+
+#: builtin/commit.c:1539
+msgid "cannot update HEAD ref"
+msgstr ""
+
+#: builtin/commit.c:1550
+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/describe.c:234
+#, c-format
+msgid "annotated tag %s not available"
+msgstr ""
+
+#: builtin/describe.c:238
+#, c-format
+msgid "annotated tag %s has no embedded name"
+msgstr ""
+
+#: builtin/describe.c:240
+#, c-format
+msgid "tag '%s' is really '%s' here"
+msgstr ""
+
+#: builtin/describe.c:267
+#, c-format
+msgid "Not a valid object name %s"
+msgstr ""
+
+#: builtin/describe.c:270
+#, c-format
+msgid "%s is not a valid '%s' object"
+msgstr ""
+
+#: builtin/describe.c:287
+#, c-format
+msgid "no tag exactly matches '%s'"
+msgstr ""
+
+#: builtin/describe.c:289
+#, c-format
+msgid "searching to describe %s\n"
+msgstr ""
+
+#: builtin/describe.c:329
+#, c-format
+msgid "finished search at %s\n"
+msgstr ""
+
+#: builtin/describe.c:353
+#, c-format
+msgid ""
+"No annotated tags can describe '%s'.\n"
+"However, there were unannotated tags: try --tags."
+msgstr ""
+
+#: builtin/describe.c:357
+#, c-format
+msgid ""
+"No tags can describe '%s'.\n"
+"Try --always, or create some tags."
+msgstr ""
+
+#: builtin/describe.c:378
+#, c-format
+msgid "traversed %lu commits\n"
+msgstr ""
+
+#: builtin/describe.c:381
+#, c-format
+msgid ""
+"more than %i tags found; listed %i most recent\n"
+"gave up search at %s\n"
+msgstr ""
+
+#: builtin/describe.c:436
+msgid "--long is incompatible with --abbrev=0"
+msgstr ""
+
+#: builtin/describe.c:462
+msgid "No names found, cannot describe anything."
+msgstr ""
+
+#: builtin/describe.c:482
+msgid "--dirty is incompatible with committishes"
+msgstr ""
+
+#: builtin/diff.c:77
+#, c-format
+msgid "'%s': not a regular file or symlink"
+msgstr ""
+
+#: builtin/diff.c:220
+#, c-format
+msgid "invalid option: %s"
+msgstr ""
+
+#: builtin/diff.c:293
+msgid "Not a git repository"
+msgstr ""
+
+#: builtin/diff.c:343
+#, c-format
+msgid "invalid object '%s' given."
+msgstr ""
+
+#: builtin/diff.c:348
+#, c-format
+msgid "more than %d trees given: '%s'"
+msgstr ""
+
+#: builtin/diff.c:358
+#, c-format
+msgid "more than two blobs given: '%s'"
+msgstr ""
+
+#: builtin/diff.c:366
+#, c-format
+msgid "unhandled object '%s' given."
+msgstr ""
+
+#: builtin/fetch.c:200
+msgid "Couldn't find remote ref HEAD"
+msgstr ""
+
+#: builtin/fetch.c:252
+#, c-format
+msgid "object %s not found"
+msgstr ""
+
+#: builtin/fetch.c:258
+msgid "[up to date]"
+msgstr ""
+
+#: builtin/fetch.c:272
+#, c-format
+msgid "! %-*s %-*s -> %s (can't fetch in current branch)"
+msgstr ""
+
+#: builtin/fetch.c:273 builtin/fetch.c:351
+msgid "[rejected]"
+msgstr ""
+
+#: builtin/fetch.c:284
+msgid "[tag update]"
+msgstr ""
+
+#: builtin/fetch.c:286 builtin/fetch.c:313 builtin/fetch.c:331
+msgid " (unable to update local ref)"
+msgstr ""
+
+#: builtin/fetch.c:298
+msgid "[new tag]"
+msgstr ""
+
+#: builtin/fetch.c:302
+msgid "[new branch]"
+msgstr ""
+
+#: builtin/fetch.c:347
+msgid "unable to update local ref"
+msgstr ""
+
+#: builtin/fetch.c:347
+msgid "forced update"
+msgstr ""
+
+#: builtin/fetch.c:353
+msgid "(non-fast-forward)"
+msgstr ""
+
+#: builtin/fetch.c:384 builtin/fetch.c:676
+#, c-format
+msgid "cannot open %s: %s\n"
+msgstr ""
+
+#: builtin/fetch.c:393
+#, c-format
+msgid "%s did not send all necessary objects\n"
+msgstr ""
+
+#: builtin/fetch.c:479
+#, c-format
+msgid "From %.*s\n"
+msgstr ""
+
+#: builtin/fetch.c:490
+#, c-format
+msgid ""
+"some local refs could not be updated; try running\n"
+" 'git remote prune %s' to remove any old, conflicting branches"
+msgstr ""
+
+#: builtin/fetch.c:540
+#, c-format
+msgid " (%s will become dangling)\n"
+msgstr ""
+
+#: builtin/fetch.c:541
+#, c-format
+msgid " (%s has become dangling)\n"
+msgstr ""
+
+#: builtin/fetch.c:548
+msgid "[deleted]"
+msgstr ""
+
+#: builtin/fetch.c:549
+msgid "(none)"
+msgstr ""
+
+#: builtin/fetch.c:666
+#, c-format
+msgid "Refusing to fetch into current branch %s of non-bare repository"
+msgstr ""
+
+#: builtin/fetch.c:700
+#, c-format
+msgid "Don't know how to fetch from %s"
+msgstr ""
+
+#: builtin/fetch.c:777
+#, c-format
+msgid "Option \"%s\" value \"%s\" is not valid for %s"
+msgstr ""
+
+#: builtin/fetch.c:780
+#, c-format
+msgid "Option \"%s\" is ignored for %s\n"
+msgstr ""
+
+#: builtin/fetch.c:879
+#, c-format
+msgid "Fetching %s\n"
+msgstr ""
+
+#: builtin/fetch.c:881
+#, c-format
+msgid "Could not fetch %s"
+msgstr ""
+
+#: builtin/fetch.c:898
+msgid ""
+"No remote repository specified. Please, specify either a URL or a\n"
+"remote name from which new revisions should be fetched."
+msgstr ""
+
+#: builtin/fetch.c:918
+msgid "You need to specify a tag name."
+msgstr ""
+
+#: builtin/fetch.c:970
+msgid "fetch --all does not take a repository argument"
+msgstr ""
+
+#: builtin/fetch.c:972
+msgid "fetch --all does not make sense with refspecs"
+msgstr ""
+
+#: builtin/fetch.c:983
+#, c-format
+msgid "No such remote or remote group: %s"
+msgstr ""
+
+#: builtin/fetch.c:991
+msgid "Fetching a group and specifying refspecs does not make sense"
+msgstr ""
+
+#: builtin/gc.c:63
+#, c-format
+msgid "Invalid %s: '%s'"
+msgstr ""
+
+#: builtin/gc.c:78
+msgid "Too many options specified"
+msgstr ""
+
+#: builtin/gc.c:103
+#, c-format
+msgid "insanely long object directory %.*s"
+msgstr ""
+
+#: builtin/gc.c:223
+#, c-format
+msgid "Auto packing the repository for optimum performance.\n"
+msgstr ""
+
+#: builtin/gc.c:226
+#, 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/gc.c:256
+msgid ""
+"There are too many unreachable loose objects; run 'git prune' to remove them."
+msgstr ""
+
+#: builtin/grep.c:216
+#, c-format
+msgid "grep: failed to create thread: %s"
+msgstr ""
+
+#: builtin/grep.c:402
+#, c-format
+msgid "Failed to chdir: %s"
+msgstr ""
+
+#: builtin/grep.c:478 builtin/grep.c:512
+#, c-format
+msgid "unable to read tree (%s)"
+msgstr ""
+
+#: builtin/grep.c:526
+#, c-format
+msgid "unable to grep from object of type %s"
+msgstr ""
+
+#: builtin/grep.c:584
+#, c-format
+msgid "switch `%c' expects a numerical value"
+msgstr ""
+
+#: builtin/grep.c:601
+#, c-format
+msgid "cannot open '%s'"
+msgstr ""
+
+#: builtin/grep.c:889
+msgid "no pattern given."
+msgstr ""
+
+#: builtin/grep.c:903
+#, c-format
+msgid "bad object %s"
+msgstr ""
+
+#: builtin/grep.c:944
+msgid "--open-files-in-pager only works on the worktree"
+msgstr ""
+
+#: builtin/grep.c:967
+msgid "--cached or --untracked cannot be used with --no-index."
+msgstr ""
+
+#: builtin/grep.c:972
+msgid "--no-index or --untracked cannot be used with revs."
+msgstr ""
+
+#: builtin/grep.c:975
+msgid "--[no-]exclude-standard cannot be used for tracked contents."
+msgstr ""
+
+#: builtin/grep.c:983
+msgid "both --cached and trees are 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:322 builtin/init-db.c:325
+#, c-format
+msgid "%s already exists"
+msgstr ""
+
+#: builtin/init-db.c:354
+#, c-format
+msgid "unable to handle file type %d"
+msgstr ""
+
+#: builtin/init-db.c:357
+#, c-format
+msgid "unable to move %s to %s"
+msgstr ""
+
+#: builtin/init-db.c:362
+#, 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:419
+#, c-format
+msgid "%s%s Git repository in %s%s\n"
+msgstr ""
+
+#: builtin/init-db.c:420
+msgid "Reinitialized existing"
+msgstr ""
+
+#: builtin/init-db.c:420
+msgid "Initialized empty"
+msgstr ""
+
+#: builtin/init-db.c:421
+msgid " shared"
+msgstr ""
+
+#: builtin/init-db.c:440
+msgid "cannot tell cwd"
+msgstr ""
+
+#: builtin/init-db.c:521 builtin/init-db.c:528
+#, c-format
+msgid "cannot mkdir %s"
+msgstr ""
+
+#: builtin/init-db.c:532
+#, c-format
+msgid "cannot chdir to %s"
+msgstr ""
+
+#: builtin/init-db.c:554
+#, c-format
+msgid ""
+"%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-"
+"dir=<directory>)"
+msgstr ""
+
+#: builtin/init-db.c:578
+msgid "Cannot access current working directory"
+msgstr ""
+
+#: builtin/init-db.c:585
+#, c-format
+msgid "Cannot access work tree '%s'"
+msgstr ""
+
+#: builtin/log.c:185
+#, c-format
+msgid "Final output: %d %s\n"
+msgstr ""
+
+#: builtin/log.c:393 builtin/log.c:479
+#, c-format
+msgid "Could not read object %s"
+msgstr ""
+
+#: builtin/log.c:503
+#, c-format
+msgid "Unknown type: %d"
+msgstr ""
+
+#: builtin/log.c:592
+msgid "format.headers without value"
+msgstr ""
+
+#: builtin/log.c:665
+msgid "name of output directory is too long"
+msgstr ""
+
+#: builtin/log.c:676
+#, c-format
+msgid "Cannot open patch file %s"
+msgstr ""
+
+#: builtin/log.c:690
+msgid "Need exactly one range."
+msgstr ""
+
+#: builtin/log.c:698
+msgid "Not a range."
+msgstr ""
+
+#: builtin/log.c:735
+msgid "Could not extract email from committer identity."
+msgstr ""
+
+#: builtin/log.c:781
+msgid "Cover letter needs email format"
+msgstr ""
+
+#: builtin/log.c:875
+#, c-format
+msgid "insane in-reply-to: %s"
+msgstr ""
+
+#: builtin/log.c:948
+msgid "Two output directories?"
+msgstr ""
+
+#: builtin/log.c:1169
+#, c-format
+msgid "bogus committer info %s"
+msgstr ""
+
+#: builtin/log.c:1214
+msgid "-n and -k are mutually exclusive."
+msgstr ""
+
+#: builtin/log.c:1216
+msgid "--subject-prefix and -k are mutually exclusive."
+msgstr ""
+
+#: builtin/log.c:1221 builtin/shortlog.c:284
+#, c-format
+msgid "unrecognized argument: %s"
+msgstr ""
+
+#: builtin/log.c:1224
+msgid "--name-only does not make sense"
+msgstr ""
+
+#: builtin/log.c:1226
+msgid "--name-status does not make sense"
+msgstr ""
+
+#: builtin/log.c:1228
+msgid "--check does not make sense"
+msgstr ""
+
+#: builtin/log.c:1251
+msgid "standard output, or directory, which one?"
+msgstr ""
+
+#: builtin/log.c:1253
+#, c-format
+msgid "Could not create directory '%s'"
+msgstr ""
+
+#: builtin/log.c:1406
+msgid "Failed to create output files"
+msgstr ""
+
+#: builtin/log.c:1510
+#, c-format
+msgid ""
+"Could not find a tracked remote branch, please specify <upstream> manually.\n"
+msgstr ""
+
+#: builtin/log.c:1526 builtin/log.c:1528 builtin/log.c:1540
+#, c-format
+msgid "Unknown commit %s"
+msgstr ""
+
+#: builtin/merge.c:91
+msgid "switch `m' requires a value"
+msgstr ""
+
+#: builtin/merge.c:128
+#, c-format
+msgid "Could not find merge strategy '%s'.\n"
+msgstr ""
+
+#: builtin/merge.c:129
+#, c-format
+msgid "Available strategies are:"
+msgstr ""
+
+#: builtin/merge.c:134
+#, c-format
+msgid "Available custom strategies are:"
+msgstr ""
+
+#: builtin/merge.c:241
+msgid "could not run stash."
+msgstr ""
+
+#: builtin/merge.c:246
+msgid "stash failed"
+msgstr ""
+
+#: builtin/merge.c:251
+#, c-format
+msgid "not a valid object: %s"
+msgstr ""
+
+#: builtin/merge.c:270 builtin/merge.c:287
+msgid "read-tree failed"
+msgstr ""
+
+#: builtin/merge.c:317
+msgid " (nothing to squash)"
+msgstr ""
+
+#: builtin/merge.c:330
+#, c-format
+msgid "Squash commit -- not updating HEAD\n"
+msgstr ""
+
+#: builtin/merge.c:362
+msgid "Writing SQUASH_MSG"
+msgstr ""
+
+#: builtin/merge.c:364
+msgid "Finishing SQUASH_MSG"
+msgstr ""
+
+#: builtin/merge.c:386
+#, c-format
+msgid "No merge message -- not updating HEAD\n"
+msgstr ""
+
+#: builtin/merge.c:435
+#, c-format
+msgid "'%s' does not point to a commit"
+msgstr ""
+
+#: builtin/merge.c:534
+#, c-format
+msgid "Bad branch.%s.mergeoptions string: %s"
+msgstr ""
+
+#: builtin/merge.c:627
+msgid "git write-tree failed to write a tree"
+msgstr ""
+
+#: builtin/merge.c:677
+msgid "failed to read the cache"
+msgstr ""
+
+#: builtin/merge.c:694
+msgid "Unable to write index."
+msgstr ""
+
+#: builtin/merge.c:707
+msgid "Not handling anything other than two heads merge."
+msgstr ""
+
+#: builtin/merge.c:721
+#, c-format
+msgid "Unknown option for merge-recursive: -X%s"
+msgstr ""
+
+#: builtin/merge.c:735
+#, c-format
+msgid "unable to write %s"
+msgstr ""
+
+#: builtin/merge.c:874
+#, c-format
+msgid "Could not read from '%s'"
+msgstr ""
+
+#: builtin/merge.c:883
+#, c-format
+msgid "Not committing merge; use 'git commit' to complete the merge.\n"
+msgstr ""
+
+#: builtin/merge.c:889
+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:913
+msgid "Empty commit message."
+msgstr ""
+
+#: builtin/merge.c:925
+#, c-format
+msgid "Wonderful.\n"
+msgstr ""
+
+#: builtin/merge.c:998
+#, c-format
+msgid "Automatic merge failed; fix conflicts and then commit the result.\n"
+msgstr ""
+
+#: builtin/merge.c:1014
+#, c-format
+msgid "'%s' is not a commit"
+msgstr ""
+
+#: builtin/merge.c:1055
+msgid "No current branch."
+msgstr ""
+
+#: builtin/merge.c:1057
+msgid "No remote for the current branch."
+msgstr ""
+
+#: builtin/merge.c:1059
+msgid "No default upstream defined for the current branch."
+msgstr ""
+
+#: builtin/merge.c:1064
+#, c-format
+msgid "No remote tracking branch for %s from %s"
+msgstr ""
+
+#: builtin/merge.c:1186
+msgid "There is no merge to abort (MERGE_HEAD missing)."
+msgstr ""
+
+#: builtin/merge.c:1202 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:1205 git-pull.sh:34
+msgid "You have not concluded your merge (MERGE_HEAD exists)."
+msgstr ""
+
+#: builtin/merge.c:1209
+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:1212
+msgid "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)."
+msgstr ""
+
+#: builtin/merge.c:1221
+msgid "You cannot combine --squash with --no-ff."
+msgstr ""
+
+#: builtin/merge.c:1226
+msgid "You cannot combine --no-ff with --ff-only."
+msgstr ""
+
+#: builtin/merge.c:1233
+msgid "No commit specified and merge.defaultToUpstream not set."
+msgstr ""
+
+#: builtin/merge.c:1264
+msgid "Can merge only exactly one commit into empty head"
+msgstr ""
+
+#: builtin/merge.c:1267
+msgid "Squash commit into empty head not supported yet"
+msgstr ""
+
+#: builtin/merge.c:1269
+msgid "Non-fast-forward commit does not make sense into an empty head"
+msgstr ""
+
+#: builtin/merge.c:1273 builtin/merge.c:1317
+#, c-format
+msgid "%s - not something we can merge"
+msgstr ""
+
+#: builtin/merge.c:1383
+#, c-format
+msgid "Updating %s..%s\n"
+msgstr ""
+
+#: builtin/merge.c:1421
+#, c-format
+msgid "Trying really trivial in-index merge...\n"
+msgstr ""
+
+#: builtin/merge.c:1428
+#, c-format
+msgid "Nope.\n"
+msgstr ""
+
+#: builtin/merge.c:1460
+msgid "Not possible to fast-forward, aborting."
+msgstr ""
+
+#: builtin/merge.c:1483 builtin/merge.c:1560
+#, c-format
+msgid "Rewinding the tree to pristine...\n"
+msgstr ""
+
+#: builtin/merge.c:1487
+#, c-format
+msgid "Trying merge strategy %s...\n"
+msgstr ""
+
+#: builtin/merge.c:1551
+#, c-format
+msgid "No merge strategy handled the merge.\n"
+msgstr ""
+
+#: builtin/merge.c:1553
+#, c-format
+msgid "Merge with strategy %s failed.\n"
+msgstr ""
+
+#: builtin/merge.c:1562
+#, c-format
+msgid "Using the %s to prepare resolving by hand.\n"
+msgstr ""
+
+#: builtin/merge.c:1573
+#, c-format
+msgid "Automatic merge went well; stopped before committing as requested\n"
+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
+#, c-format
+msgid "renaming '%s' failed"
+msgstr ""
+
+#: builtin/notes.c:139
+#, c-format
+msgid "unable to start 'show' for object '%s'"
+msgstr ""
+
+#: builtin/notes.c:145
+msgid "can't fdopen 'show' output fd"
+msgstr ""
+
+#: builtin/notes.c:155
+#, c-format
+msgid "failed to close pipe to 'show' for object '%s'"
+msgstr ""
+
+#: builtin/notes.c:158
+#, c-format
+msgid "failed to finish 'show' for object '%s'"
+msgstr ""
+
+#: builtin/notes.c:175 builtin/tag.c:343
+#, 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"
+msgstr ""
+
+#: builtin/notes.c:210 builtin/notes.c:973
+#, c-format
+msgid "Removing note for object %s\n"
+msgstr ""
+
+#: builtin/notes.c:215
+msgid "unable to write note object"
+msgstr ""
+
+#: builtin/notes.c:217
+#, c-format
+msgid "The note contents has been left in %s"
+msgstr ""
+
+#: builtin/notes.c:251 builtin/tag.c:521
+#, c-format
+msgid "cannot read '%s'"
+msgstr ""
+
+#: builtin/notes.c:253 builtin/tag.c:524
+#, c-format
+msgid "could not open or read '%s'"
+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:537
+#, c-format
+msgid "Failed to resolve '%s' as a valid ref."
+msgstr ""
+
+#: builtin/notes.c:275
+#, c-format
+msgid "Failed to read object '%s'."
+msgstr ""
+
+#: builtin/notes.c:299
+msgid "Cannot commit uninitialized/unreferenced notes tree"
+msgstr ""
+
+#: builtin/notes.c:340
+#, c-format
+msgid "Bad notes.rewriteMode value: '%s'"
+msgstr ""
+
+#: builtin/notes.c:350
+#, 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:377
+#, c-format
+msgid "Bad %s value: '%s'"
+msgstr ""
+
+#: builtin/notes.c:441
+#, c-format
+msgid "Malformed input line: '%s'."
+msgstr ""
+
+#: builtin/notes.c:456
+#, c-format
+msgid "Failed to copy notes from '%s' to '%s'"
+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"
+msgstr ""
+
+#: builtin/notes.c:513 builtin/notes.c:772
+#, c-format
+msgid "No note found for object %s."
+msgstr ""
+
+#: builtin/notes.c:580
+#, c-format
+msgid ""
+"Cannot add notes. Found existing notes for object %s. Use '-f' to overwrite "
+"existing notes"
+msgstr ""
+
+#: builtin/notes.c:585 builtin/notes.c:662
+#, c-format
+msgid "Overwriting existing notes for object %s\n"
+msgstr ""
+
+#: builtin/notes.c:635
+msgid "too few parameters"
+msgstr ""
+
+#: builtin/notes.c:656
+#, c-format
+msgid ""
+"Cannot copy notes. Found existing notes for object %s. Use '-f' to overwrite "
+"existing notes"
+msgstr ""
+
+#: builtin/notes.c:668
+#, c-format
+msgid "Missing notes on source object %s. Cannot copy."
+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"
+msgstr ""
+
+#: builtin/notes.c:971
+#, c-format
+msgid "Object %s has no note\n"
+msgstr ""
+
+#: builtin/notes.c:1103
+#, c-format
+msgid "Unknown subcommand: %s"
+msgstr ""
+
+#: builtin/pack-objects.c:2310
+#, c-format
+msgid "unsupported index version %s"
+msgstr ""
+
+#: builtin/pack-objects.c:2314
+#, c-format
+msgid "bad index version '%s'"
+msgstr ""
+
+#: builtin/pack-objects.c:2322
+#, c-format
+msgid "option %s does not accept negative form"
+msgstr ""
+
+#: builtin/pack-objects.c:2326
+#, c-format
+msgid "unable to parse value '%s' for option %s"
+msgstr ""
+
+#: builtin/push.c:44
+msgid "tag shorthand without <tag>"
+msgstr ""
+
+#: builtin/push.c:63
+msgid "--delete only accepts plain target ref names"
+msgstr ""
+
+#: builtin/push.c:73
+#, 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:80
+#, 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:88
+#, c-format
+msgid "The current branch %s has multiple upstream branches, refusing to push."
+msgstr ""
+
+#: builtin/push.c:111
+msgid ""
+"You didn't specify any refspecs to push, and push.default is \"nothing\"."
+msgstr ""
+
+#: builtin/push.c:131
+#, c-format
+msgid "Pushing to %s\n"
+msgstr ""
+
+#: builtin/push.c:135
+#, c-format
+msgid "failed to push some refs to '%s'"
+msgstr ""
+
+#: builtin/push.c:143
+#, c-format
+msgid ""
+"To prevent you from losing history, non-fast-forward updates were rejected\n"
+"Merge the remote changes (e.g. 'git pull') before pushing again. See the\n"
+"'Note about fast-forwards' section of 'git push --help' for details.\n"
+msgstr ""
+
+#: builtin/push.c:160
+#, c-format
+msgid "bad repository '%s'"
+msgstr ""
+
+#: builtin/push.c:161
+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:176
+msgid "--all and --tags are incompatible"
+msgstr ""
+
+#: builtin/push.c:177
+msgid "--all can't be combined with refspecs"
+msgstr ""
+
+#: builtin/push.c:182
+msgid "--mirror and --tags are incompatible"
+msgstr ""
+
+#: builtin/push.c:183
+msgid "--mirror can't be combined with refspecs"
+msgstr ""
+
+#: builtin/push.c:188
+msgid "--all and --mirror are incompatible"
+msgstr ""
+
+#: builtin/push.c:274
+msgid "--delete is incompatible with --all, --mirror and --tags"
+msgstr ""
+
+#: builtin/push.c:276
+msgid "--delete doesn't make sense without any refs"
+msgstr ""
+
+#: builtin/reset.c:33
+msgid "mixed"
+msgstr ""
+
+#: builtin/reset.c:33
+msgid "soft"
+msgstr ""
+
+#: builtin/reset.c:33
+msgid "hard"
+msgstr ""
+
+#: builtin/reset.c:33
+msgid "keep"
+msgstr ""
+
+#: builtin/reset.c:77
+msgid "You do not have a valid HEAD."
+msgstr ""
+
+#: builtin/reset.c:79
+msgid "Failed to find tree of HEAD."
+msgstr ""
+
+#: builtin/reset.c:85
+#, c-format
+msgid "Failed to find tree of %s."
+msgstr ""
+
+#: builtin/reset.c:96
+msgid "Could not write new index file."
+msgstr ""
+
+#: builtin/reset.c:106
+#, c-format
+msgid "HEAD is now at %s"
+msgstr ""
+
+#: 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 "Cannot do a %s reset in the middle of a merge."
+msgstr ""
+
+#: builtin/reset.c:297
+#, c-format
+msgid "Could not parse object '%s'."
+msgstr ""
+
+#: builtin/reset.c:302
+msgid "--patch is incompatible with --{hard,mixed,soft}"
+msgstr ""
+
+#: builtin/reset.c:311
+msgid "--mixed with paths is deprecated; use 'git reset -- <paths>' instead."
+msgstr ""
+
+#: builtin/reset.c:313
+#, c-format
+msgid "Cannot do %s reset with paths."
+msgstr ""
+
+#: builtin/reset.c:325
+#, c-format
+msgid "%s reset is not allowed in a bare repository"
+msgstr ""
+
+#: builtin/reset.c:341
+#, c-format
+msgid "Could not reset index file to revision '%s'."
+msgstr ""
+
+#: builtin/revert.c:70 builtin/revert.c:91
+#, c-format
+msgid "%s: %s cannot be used with %s"
+msgstr ""
+
+#: builtin/revert.c:126
+msgid "program error"
+msgstr ""
+
+#: builtin/revert.c:209
+msgid "revert failed"
+msgstr ""
+
+#: builtin/revert.c:224
+msgid "cherry-pick failed"
+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)"
+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)"
+msgstr ""
+
+#: builtin/rm.c:119
+#, c-format
+msgid ""
+"'%s' has local modifications\n"
+"(use --cached to keep the file, or -f to force removal)"
+msgstr ""
+
+#: builtin/rm.c:194
+#, c-format
+msgid "not removing '%s' recursively without -r"
+msgstr ""
+
+#: builtin/rm.c:230
+#, c-format
+msgid "git rm: unable to remove %s"
+msgstr ""
+
+#: builtin/shortlog.c:157
+#, c-format
+msgid "Missing author: %s"
+msgstr ""
+
+#: builtin/tag.c:58
+#, c-format
+msgid "malformed object at '%s'"
+msgstr ""
+
+#: builtin/tag.c:205
+#, c-format
+msgid "tag name too long: %.*s..."
+msgstr ""
+
+#: builtin/tag.c:210
+#, c-format
+msgid "tag '%s' not found."
+msgstr ""
+
+#: builtin/tag.c:225
+#, c-format
+msgid "Deleted tag '%s' (was %s)\n"
+msgstr ""
+
+#: builtin/tag.c:237
+#, c-format
+msgid "could not verify the tag '%s'"
+msgstr ""
+
+#: builtin/tag.c:247
+msgid ""
+"\n"
+"#\n"
+"# Write a tag message\n"
+"# Lines starting with '#' will be ignored.\n"
+"#\n"
+msgstr ""
+
+#: builtin/tag.c:254
+msgid ""
+"\n"
+"#\n"
+"# Write a tag message\n"
+"# Lines starting with '#' will be kept; you may remove them yourself if you "
+"want to.\n"
+"#\n"
+msgstr ""
+
+#: builtin/tag.c:294
+msgid "unable to sign the tag"
+msgstr ""
+
+#: builtin/tag.c:296
+msgid "unable to write tag file"
+msgstr ""
+
+#: builtin/tag.c:321
+msgid "bad object type."
+msgstr ""
+
+#: builtin/tag.c:334
+msgid "tag header too big."
+msgstr ""
+
+#: builtin/tag.c:366
+msgid "no tag message?"
+msgstr ""
+
+#: builtin/tag.c:372
+#, c-format
+msgid "The tag message has been left in %s\n"
+msgstr ""
+
+#: builtin/tag.c:421
+msgid "switch 'points-at' requires an object"
+msgstr ""
+
+#: builtin/tag.c:423
+#, c-format
+msgid "malformed object name '%s'"
+msgstr ""
+
+#: builtin/tag.c:502
+msgid "-n option is only allowed with -l."
+msgstr ""
+
+#: builtin/tag.c:504
+msgid "--contains option is only allowed with -l."
+msgstr ""
+
+#: builtin/tag.c:506
+msgid "--points-at option is only allowed with -l."
+msgstr ""
+
+#: builtin/tag.c:514
+msgid "only one -F or -m option is allowed."
+msgstr ""
+
+#: builtin/tag.c:534
+msgid "too many params"
+msgstr ""
+
+#: builtin/tag.c:540
+#, c-format
+msgid "'%s' is not a valid tag name."
+msgstr ""
+
+#: builtin/tag.c:545
+#, c-format
+msgid "tag '%s' already exists"
+msgstr ""
+
+#: builtin/tag.c:563
+#, c-format
+msgid "%s: cannot lock the ref"
+msgstr ""
+
+#: builtin/tag.c:565
+#, c-format
+msgid "%s: cannot update the ref"
+msgstr ""
+
+#: builtin/tag.c:567
+#, c-format
+msgid "Updated tag '%s' (was %s)\n"
+msgstr ""
+
+#: git-am.sh:49
+msgid "You need to set your committer info first"
+msgstr ""
+
+#: git-am.sh:135
+msgid "Repository lacks necessary blobs to fall back on 3-way merge."
+msgstr ""
+
+#: git-am.sh:144
+msgid ""
+"Did you hand edit your patch?\n"
+"It does not apply to blobs recorded in its index."
+msgstr ""
+
+#: git-am.sh:153
+msgid "Falling back to patching base and 3-way merge..."
+msgstr ""
+
+#: git-am.sh:265
+msgid "Only one StGIT patch series can be applied at once"
+msgstr ""
+
+#: git-am.sh:352
+#, sh-format
+msgid "Patch format $patch_format is not supported."
+msgstr ""
+
+#: git-am.sh:354
+msgid "Patch format detection failed."
+msgstr ""
+
+#: git-am.sh:406
+msgid "-d option is no longer supported. Do not use."
+msgstr ""
+
+#: git-am.sh:469
+#, sh-format
+msgid "previous rebase directory $dotest still exists but mbox given."
+msgstr ""
+
+#: git-am.sh:474
+msgid "Please make up your mind. --skip or --abort?"
+msgstr ""
+
+#: git-am.sh:501
+msgid "Resolve operation not in progress, we are not resuming."
+msgstr ""
+
+#: git-am.sh:567
+#, sh-format
+msgid "Dirty index: cannot apply patches (dirty: $files)"
+msgstr ""
+
+#: git-am.sh:743
+msgid "cannot be interactive without stdin connected to a terminal."
+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:754
+msgid "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all "
+msgstr ""
+
+#: git-am.sh:790
+#, sh-format
+msgid "Applying: $FIRSTLINE"
+msgstr ""
+
+#: git-am.sh:835
+msgid "No changes -- Patch already applied."
+msgstr ""
+
+#: git-am.sh:861
+msgid "applying to an empty history"
+msgstr ""
+
+#. TRANSLATORS: Make sure to include [Y] and [n] in your
+#. translation. The program will only accept English input
+#. at this point.
+#: git-bisect.sh:54
+msgid "Do you want me to do it for you [Y/n]? "
+msgstr ""
+
+#: git-bisect.sh:95
+#, sh-format
+msgid "unrecognised option: '$arg'"
+msgstr ""
+
+#: git-bisect.sh:99
+#, sh-format
+msgid "'$arg' does not appear to be a valid revision"
+msgstr ""
+
+#: git-bisect.sh:117
+msgid "Bad HEAD - I need a HEAD"
+msgstr ""
+
+#: git-bisect.sh:130
+#, sh-format
+msgid ""
+"Checking out '$start_head' failed. Try 'git bisect reset <validbranch>'."
+msgstr ""
+
+#: git-bisect.sh:140
+msgid "won't bisect on seeked tree"
+msgstr ""
+
+#: git-bisect.sh:144
+msgid "Bad HEAD - strange symbolic ref"
+msgstr ""
+
+#: git-bisect.sh:189
+#, sh-format
+msgid "Bad bisect_write argument: $state"
+msgstr ""
+
+#: git-bisect.sh:218
+#, sh-format
+msgid "Bad rev input: $arg"
+msgstr ""
+
+#: git-bisect.sh:232
+msgid "Please call 'bisect_state' with at least one argument."
+msgstr ""
+
+#: git-bisect.sh:244
+#, sh-format
+msgid "Bad rev input: $rev"
+msgstr ""
+
+#: git-bisect.sh:250
+msgid "'git bisect bad' can take only one argument."
+msgstr ""
+
+#. 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 ""
+
+#: git-bisect.sh:354
+#, sh-format
+msgid "'$invalid' is not a valid commit"
+msgstr ""
+
+#: git-bisect.sh:363
+#, sh-format
+msgid ""
+"Could not check out original HEAD '$branch'.\n"
+"Try 'git bisect reset <commit>'."
+msgstr ""
+
+#: git-bisect.sh:390
+msgid "No logfile given"
+msgstr ""
+
+#: git-bisect.sh:391
+#, sh-format
+msgid "cannot read $file for replaying"
+msgstr ""
+
+#: git-bisect.sh:408
+msgid "?? what are you talking about?"
+msgstr ""
+
+#: git-bisect.sh:474
+msgid "We are not bisecting."
+msgstr ""
+
+#: git-pull.sh:21
+msgid ""
+"Pull is not possible because you have unmerged files.\n"
+"Please, fix them up in the work tree, and then use 'git add/rm <file>'\n"
+"as appropriate to mark resolution, or use 'git commit -a'."
+msgstr ""
+
+#: git-pull.sh:25
+msgid "Pull is not possible because you have unmerged files."
+msgstr ""
+
+#: git-pull.sh:197
+msgid "updating an unborn branch with changes added to the index"
+msgstr ""
+
+#: git-pull.sh:253
+msgid "Cannot merge multiple branches into empty head"
+msgstr ""
+
+#: git-pull.sh:257
+msgid "Cannot rebase onto multiple branches"
+msgstr ""
+
+#: git-stash.sh:51
+msgid "git stash clear with parameters is unimplemented"
+msgstr ""
+
+#: git-stash.sh:74
+msgid "You do not have the initial commit yet"
+msgstr ""
+
+#: git-stash.sh:89
+msgid "Cannot save the current index state"
+msgstr ""
+
+#: git-stash.sh:123 git-stash.sh:136
+msgid "Cannot save the current worktree state"
+msgstr ""
+
+#: git-stash.sh:140
+msgid "No changes selected"
+msgstr ""
+
+#: git-stash.sh:143
+msgid "Cannot remove temporary index (can't happen)"
+msgstr ""
+
+#: git-stash.sh:156
+msgid "Cannot record working tree state"
+msgstr ""
+
+#: git-stash.sh:223
+msgid "No local changes to save"
+msgstr ""
+
+#: git-stash.sh:227
+msgid "Cannot initialize stash"
+msgstr ""
+
+#: git-stash.sh:235
+msgid "Cannot save the current status"
+msgstr ""
+
+#: git-stash.sh:253
+msgid "Cannot remove worktree changes"
+msgstr ""
+
+#: git-stash.sh:352
+msgid "No stash found."
+msgstr ""
+
+#: git-stash.sh:359
+#, sh-format
+msgid "Too many revisions specified: $REV"
+msgstr ""
+
+#: git-stash.sh:365
+#, sh-format
+msgid "$reference is not valid reference"
+msgstr ""
+
+#: git-stash.sh:393
+#, sh-format
+msgid "'$args' is not a stash-like commit"
+msgstr ""
+
+#: git-stash.sh:404
+#, sh-format
+msgid "'$args' is not a stash reference"
+msgstr ""
+
+#: git-stash.sh:412
+msgid "unable to refresh index"
+msgstr ""
+
+#: git-stash.sh:416
+msgid "Cannot apply a stash in the middle of a merge"
+msgstr ""
+
+#: git-stash.sh:424
+msgid "Conflicts in index. Try without --index."
+msgstr ""
+
+#: git-stash.sh:426
+msgid "Could not save index tree"
+msgstr ""
+
+#: git-stash.sh:460
+msgid "Cannot unstage modified files"
+msgstr ""
+
+#: git-stash.sh:491
+#, sh-format
+msgid "Dropped ${REV} ($s)"
+msgstr ""
+
+#: git-stash.sh:492
+#, sh-format
+msgid "${REV}: Could not drop stash entry"
+msgstr ""
+
+#: git-stash.sh:499
+msgid "No branch name specified"
+msgstr ""
+
+#: git-stash.sh:570
+msgid "(To restore them type \"git stash apply\")"
+msgstr ""
+
+#: git-submodule.sh:56
+#, sh-format
+msgid "cannot strip one component off url '$remoteurl'"
+msgstr ""
+
+#: git-submodule.sh:108
+#, sh-format
+msgid "No submodule mapping found in .gitmodules for path '$path'"
+msgstr ""
+
+#: git-submodule.sh:173
+#, sh-format
+msgid "Clone of '$url' into submodule path '$path' failed"
+msgstr ""
+
+#: git-submodule.sh:247
+#, sh-format
+msgid "repo URL: '$repo' must be absolute or begin with ./|../"
+msgstr ""
+
+#: git-submodule.sh:264
+#, sh-format
+msgid "'$path' already exists in the index"
+msgstr ""
+
+#: git-submodule.sh:281
+#, sh-format
+msgid "'$path' already exists and is not a valid git repo"
+msgstr ""
+
+#: git-submodule.sh:295
+#, sh-format
+msgid "Unable to checkout submodule '$path'"
+msgstr ""
+
+#: git-submodule.sh:300
+#, sh-format
+msgid "Failed to add submodule '$path'"
+msgstr ""
+
+#: git-submodule.sh:305
+#, sh-format
+msgid "Failed to register submodule '$path'"
+msgstr ""
+
+#: git-submodule.sh:347
+#, sh-format
+msgid "Entering '$prefix$path'"
+msgstr ""
+
+#: git-submodule.sh:359
+#, sh-format
+msgid "Stopping at '$path'; script returned non-zero status."
+msgstr ""
+
+#: git-submodule.sh:401
+#, sh-format
+msgid "No url found for submodule path '$path' in .gitmodules"
+msgstr ""
+
+#: git-submodule.sh:410
+#, sh-format
+msgid "Failed to register url for submodule path '$path'"
+msgstr ""
+
+#: git-submodule.sh:418
+#, sh-format
+msgid "Failed to register update mode for submodule path '$path'"
+msgstr ""
+
+#: git-submodule.sh:420
+#, sh-format
+msgid "Submodule '$name' ($url) registered for path '$path'"
+msgstr ""
+
+#: git-submodule.sh:519
+#, sh-format
+msgid ""
+"Submodule path '$path' not initialized\n"
+"Maybe you want to use 'update --init'?"
+msgstr ""
+
+#: git-submodule.sh:532
+#, sh-format
+msgid "Unable to find current revision in submodule path '$path'"
+msgstr ""
+
+#: git-submodule.sh:551
+#, sh-format
+msgid "Unable to fetch in submodule path '$path'"
+msgstr ""
+
+#: git-submodule.sh:565
+#, sh-format
+msgid "Unable to rebase '$sha1' in submodule path '$path'"
+msgstr ""
+
+#: git-submodule.sh:566
+#, sh-format
+msgid "Submodule path '$path': rebased into '$sha1'"
+msgstr ""
+
+#: git-submodule.sh:571
+#, sh-format
+msgid "Unable to merge '$sha1' in submodule path '$path'"
+msgstr ""
+
+#: git-submodule.sh:572
+#, sh-format
+msgid "Submodule path '$path': merged in '$sha1'"
+msgstr ""
+
+#: git-submodule.sh:577
+#, sh-format
+msgid "Unable to checkout '$sha1' in submodule path '$path'"
+msgstr ""
+
+#: git-submodule.sh:578
+#, sh-format
+msgid "Submodule path '$path': checked out '$sha1'"
+msgstr ""
+
+#: git-submodule.sh:600 git-submodule.sh:923
+#, sh-format
+msgid "Failed to recurse into submodule path '$path'"
+msgstr ""
+
+#: git-submodule.sh:708
+msgid "--"
+msgstr ""
+
+#: git-submodule.sh:766
+#, sh-format
+msgid " Warn: $name doesn't contain commit $sha1_src"
+msgstr ""
+
+#: git-submodule.sh:769
+#, sh-format
+msgid " Warn: $name doesn't contain commit $sha1_dst"
+msgstr ""
+
+#: git-submodule.sh:772
+#, sh-format
+msgid " Warn: $name doesn't contain commits $sha1_src and $sha1_dst"
+msgstr ""
+
+#: git-submodule.sh:797
+msgid "blob"
+msgstr ""
+
+#: git-submodule.sh:798
+msgid "submodule"
+msgstr ""
+
+#: git-submodule.sh:969
+#, sh-format
+msgid "Synchronizing submodule url for '$name'"
+msgstr ""
diff --git a/po/pt_PT.po b/po/pt_PT.po
new file mode 100644
index 0000000000..d28c568c73
--- /dev/null
+++ b/po/pt_PT.po
@@ -0,0 +1,3595 @@
+# Portuguese translations for Git package.
+# Copyright (C) 2012 Marco Sousa <marcomsousa AT gmail.com>
+# This file is distributed under the same license as the Git package.
+# Contributers:
+# - Marco Sousa <marcomsousa AT gmail.com>
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Git\n"
+"Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
+"POT-Creation-Date: 2012-03-16 20:18+0800\n"
+"PO-Revision-Date: 2012-04-05 20:48+0100\n"
+"Last-Translator: Marco Sousa <marcomsousa AT gmail.com>\n"
+"Language-Team: Portuguese\n"
+"Language: pt\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: advice.c:34
+#, c-format
+msgid "hint: %.*s\n"
+msgstr "dica: %.*s\n"
+
+#.
+#. * Message used both when 'git commit' fails and when
+#. * other commands doing a merge do.
+#.
+#: advice.c:64
+msgid ""
+"Fix them up in the work tree,\n"
+"and then use 'git add/rm <file>' as\n"
+"appropriate to mark resolution and make a commit,\n"
+"or use 'git commit -a'."
+msgstr ""
+
+#: commit.c:47
+#, c-format
+msgid "could not parse %s"
+msgstr "não consigo parsear %s"
+
+#: commit.c:49
+#, c-format
+msgid "%s %s is not a commit!"
+msgstr "%s %s não é um commit!"
+
+#: compat/obstack.c:406
+#: compat/obstack.c:408
+msgid "memory exhausted"
+msgstr "memória esgotada"
+
+#: connected.c:39
+msgid "Could not run 'git rev-list'"
+msgstr "Não foi possível executar 'git rev-list'"
+
+#: connected.c:48
+#, c-format
+msgid "failed write to rev-list: %s"
+msgstr ""
+
+#: connected.c:56
+#, c-format
+msgid "failed to close rev-list's stdin: %s"
+msgstr ""
+
+#: diff.c:105
+#, c-format
+msgid " Failed to parse dirstat cut-off percentage '%.*s'\n"
+msgstr ""
+
+#: diff.c:110
+#, c-format
+msgid " Unknown dirstat parameter '%.*s'\n"
+msgstr ""
+
+#: diff.c:210
+#, c-format
+msgid ""
+"Found errors in 'diff.dirstat' config variable:\n"
+"%s"
+msgstr ""
+
+#: diff.c:1336
+msgid " 0 files changed\n"
+msgstr " 0 ficheros modificados\n"
+
+#: diff.c:1340
+#, c-format
+msgid " %d file changed"
+msgid_plural " %d files changed"
+msgstr[0] " %d ficheiro modificado"
+msgstr[1] " %d ficheiros modificados"
+
+#: diff.c:1357
+#, c-format
+msgid ", %d insertion(+)"
+msgid_plural ", %d insertions(+)"
+msgstr[0] ", %d adição(+)"
+msgstr[1] ", %d adições(+)"
+
+#: diff.c:1368
+#, c-format
+msgid ", %d deletion(-)"
+msgid_plural ", %d deletions(-)"
+msgstr[0] ", %d eliminado(-)"
+msgstr[1] ", %d eliminados(-)"
+
+#: diff.c:3424
+#, c-format
+msgid ""
+"Failed to parse --dirstat/-X option parameter:\n"
+"%s"
+msgstr ""
+
+#: gpg-interface.c:59
+msgid "could not run gpg."
+msgstr "não consegue ejecutar gpg."
+
+#: gpg-interface.c:71
+msgid "gpg did not accept the data"
+msgstr ""
+
+#: gpg-interface.c:82
+msgid "gpg failed to sign the data"
+msgstr ""
+
+#: grep.c:1280
+#, c-format
+msgid "'%s': unable to read %s"
+msgstr ""
+
+#: grep.c:1297
+#, c-format
+msgid "'%s': %s"
+msgstr "'%s': %s"
+
+#: grep.c:1308
+#, c-format
+msgid "'%s': short read %s"
+msgstr ""
+
+#: help.c:287
+#, 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 ""
+
+#: remote.c:1607
+#, 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] "A sua rama está à frente de '%s' pelo commit %d.\n"
+msgstr[1] "A sua rama está à frente de '%s' pelos commites %d.\n"
+
+#: remote.c:1613
+#, 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] ""
+msgstr[1] ""
+
+#: remote.c:1621
+#, c-format
+msgid ""
+"Your branch and '%s' have diverged,\n"
+"and have %d and %d different commit each, respectively.\n"
+msgid_plural ""
+"Your branch and '%s' have diverged,\n"
+"and have %d and %d different commits each, respectively.\n"
+msgstr[0] ""
+msgstr[1] ""
+
+#: sequencer.c:120
+#: builtin/merge.c:864
+#: builtin/merge.c:985
+#: builtin/merge.c:1095
+#: builtin/merge.c:1105
+#, c-format
+msgid "Could not open '%s' for writing"
+msgstr ""
+
+#: sequencer.c:122
+#: builtin/merge.c:334
+#: builtin/merge.c:867
+#: builtin/merge.c:1097
+#: builtin/merge.c:1110
+#, c-format
+msgid "Could not write to '%s'"
+msgstr "Não foi possível escrever para '%s'"
+
+#: sequencer.c:143
+msgid ""
+"after resolving the conflicts, mark the corrected paths\n"
+"with 'git add <paths>' or 'git rm <paths>'"
+msgstr ""
+
+#: sequencer.c:146
+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:159
+#: sequencer.c:685
+#: sequencer.c:768
+#, c-format
+msgid "Could not write to %s"
+msgstr "Não foi possível gravar para %s"
+
+#: sequencer.c:162
+#, c-format
+msgid "Error wrapping up %s"
+msgstr ""
+
+#: sequencer.c:177
+msgid "Your local changes would be overwritten by cherry-pick."
+msgstr ""
+
+#: sequencer.c:179
+msgid "Your local changes would be overwritten by revert."
+msgstr ""
+
+#: sequencer.c:182
+msgid "Commit your changes or stash them to proceed."
+msgstr ""
+
+#. TRANSLATORS: %s will be "revert" or "cherry-pick"
+#: sequencer.c:232
+#, c-format
+msgid "%s: Unable to write new index file"
+msgstr ""
+
+#: sequencer.c:298
+msgid "Your index file is unmerged."
+msgstr "O seu ficheiro de índice é não fundido."
+
+#: sequencer.c:301
+msgid "You do not have a valid HEAD"
+msgstr "Você não tem uma HEAD válida"
+
+#: sequencer.c:316
+#, c-format
+msgid "Commit %s is a merge but no -m option was given."
+msgstr ""
+
+#: sequencer.c:324
+#, c-format
+msgid "Commit %s does not have parent %d"
+msgstr ""
+
+#: sequencer.c:328
+#, 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:339
+#, c-format
+msgid "%s: cannot parse parent commit %s"
+msgstr ""
+
+#: sequencer.c:343
+#, c-format
+msgid "Cannot get commit message for %s"
+msgstr "Não é possível obter mensagem commit para %s"
+
+#: sequencer.c:427
+#, c-format
+msgid "could not revert %s... %s"
+msgstr ""
+
+#: sequencer.c:428
+#, c-format
+msgid "could not apply %s... %s"
+msgstr ""
+
+#: sequencer.c:450
+#: sequencer.c:909
+#: builtin/log.c:288
+#: builtin/log.c:713
+#: builtin/log.c:1329
+#: builtin/log.c:1548
+#: builtin/merge.c:348
+#: builtin/shortlog.c:181
+msgid "revision walk setup failed"
+msgstr ""
+
+#: sequencer.c:453
+msgid "empty commit set passed"
+msgstr "passado commit com o set vazio"
+
+#: sequencer.c:461
+#, c-format
+msgid "git %s: failed to read the index"
+msgstr ""
+
+#: sequencer.c:466
+#, c-format
+msgid "git %s: failed to refresh the index"
+msgstr ""
+
+#: sequencer.c:551
+#, c-format
+msgid "Cannot %s during a %s"
+msgstr "Não foi possível abrir %s durante um %s"
+
+#: sequencer.c:573
+#, c-format
+msgid "Could not parse line %d."
+msgstr "Não foi possível parsear linha %d."
+
+#: sequencer.c:578
+msgid "No commits parsed."
+msgstr "Nenhum commit parseado."
+
+#: sequencer.c:591
+#, c-format
+msgid "Could not open %s"
+msgstr "Não foi possível abrir %s"
+
+#: sequencer.c:595
+#, c-format
+msgid "Could not read %s."
+msgstr "Não foi possível ler %s."
+
+#: sequencer.c:602
+#, c-format
+msgid "Unusable instruction sheet: %s"
+msgstr ""
+
+#: sequencer.c:630
+#, c-format
+msgid "Invalid key: %s"
+msgstr ""
+
+#: sequencer.c:633
+#, c-format
+msgid "Invalid value for %s: %s"
+msgstr "Valor inválido para %s: %s"
+
+#: sequencer.c:645
+#, c-format
+msgid "Malformed options sheet: %s"
+msgstr ""
+
+#: sequencer.c:666
+msgid "a cherry-pick or revert is already in progress"
+msgstr ""
+
+#: sequencer.c:667
+msgid "try \"git cherry-pick (--continue | --quit | --abort)\""
+msgstr ""
+
+#: sequencer.c:671
+#, c-format
+msgid "Could not create sequencer directory %s"
+msgstr ""
+
+#: sequencer.c:687
+#: sequencer.c:772
+#, c-format
+msgid "Error wrapping up %s."
+msgstr ""
+
+#: sequencer.c:706
+#: sequencer.c:840
+msgid "no cherry-pick or revert in progress"
+msgstr ""
+
+#: sequencer.c:708
+msgid "cannot resolve HEAD"
+msgstr ""
+
+#: sequencer.c:710
+msgid "cannot abort from a branch yet to be born"
+msgstr ""
+
+#: sequencer.c:732
+#, c-format
+msgid "cannot open %s: %s"
+msgstr "não foi possível abrir %s: %s"
+
+#: sequencer.c:735
+#, c-format
+msgid "cannot read %s: %s"
+msgstr "não foi possível ler %s: %s"
+
+#: sequencer.c:736
+msgid "unexpected end of file"
+msgstr ""
+
+#: sequencer.c:742
+#, c-format
+msgid "stored pre-cherry-pick HEAD file '%s' is corrupt"
+msgstr ""
+
+#: sequencer.c:765
+#, c-format
+msgid "Could not format %s."
+msgstr "Não foi possível formatear %s."
+
+#: sequencer.c:927
+msgid "Can't revert as initial commit"
+msgstr ""
+
+#: sequencer.c:928
+msgid "Can't cherry-pick into empty head"
+msgstr ""
+
+#: wt-status.c:134
+msgid "Unmerged paths:"
+msgstr "caminhos não fundidos:"
+
+#: wt-status.c:140
+#: wt-status.c:157
+#, c-format
+msgid " (use \"git reset %s <file>...\" to unstage)"
+msgstr ""
+
+#: wt-status.c:142
+#: wt-status.c:159
+msgid " (use \"git rm --cached <file>...\" to unstage)"
+msgstr ""
+
+#: wt-status.c:143
+msgid " (use \"git add/rm <file>...\" as appropriate to mark resolution)"
+msgstr " (usa \"git add/rm <ficheiro>...\" para marcar como resolvido)"
+
+#: wt-status.c:151
+msgid "Changes to be committed:"
+msgstr "Mudanças a serem commitadas"
+
+#: wt-status.c:169
+msgid "Changes not staged for commit:"
+msgstr ""
+
+#: wt-status.c:173
+msgid " (use \"git add <file>...\" to update what will be committed)"
+msgstr " (usa \"git add <ficheiro>...\" para actualizar o que vai ser commitado)"
+
+#: wt-status.c:175
+msgid " (use \"git add/rm <file>...\" to update what will be committed)"
+msgstr " (usa \"git add/rm <ficheiro>...\" para actualizar o que vai ser commitado)"
+
+#: wt-status.c:176
+msgid " (use \"git checkout -- <file>...\" to discard changes in working directory)"
+msgstr ""
+
+#: wt-status.c:178
+msgid " (commit or discard the untracked or modified content in submodules)"
+msgstr ""
+
+#: wt-status.c:187
+#, c-format
+msgid "%s files:"
+msgstr "%s ficheros:"
+
+#: wt-status.c:190
+#, c-format
+msgid " (use \"git %s <file>...\" to include in what will be committed)"
+msgstr ""
+
+#: wt-status.c:207
+msgid "bug"
+msgstr "erro"
+
+#: wt-status.c:212
+msgid "both deleted:"
+msgstr "eliminados em ambos:"
+
+#: wt-status.c:213
+msgid "added by us:"
+msgstr "adicionado por nós:"
+
+#: wt-status.c:214
+msgid "deleted by them:"
+msgstr "eliminados por eles:"
+
+#: wt-status.c:215
+msgid "added by them:"
+msgstr "adicionados por eles:"
+
+#: wt-status.c:216
+msgid "deleted by us:"
+msgstr "eliminados por nós:"
+
+#: wt-status.c:217
+msgid "both added:"
+msgstr "adicionados em ambos:"
+
+#: wt-status.c:218
+msgid "both modified:"
+msgstr "modificados em ambos:"
+
+#: wt-status.c:248
+msgid "new commits, "
+msgstr "novos commits, "
+
+#: wt-status.c:250
+msgid "modified content, "
+msgstr "conteúdo modificado, "
+
+#: wt-status.c:252
+msgid "untracked content, "
+msgstr "conteúdo não seguido"
+
+#: wt-status.c:266
+#, c-format
+msgid "new file: %s"
+msgstr "novo ficheiro: %s"
+
+#: wt-status.c:269
+#, c-format
+msgid "copied: %s -> %s"
+msgstr "copiado: %s -> %s"
+
+#: wt-status.c:272
+#, c-format
+msgid "deleted: %s"
+msgstr "eliminado: %s"
+
+#: wt-status.c:275
+#, c-format
+msgid "modified: %s"
+msgstr "modificado: %s"
+
+#: wt-status.c:278
+#, c-format
+msgid "renamed: %s -> %s"
+msgstr "mudado de nome: %s -> %s"
+
+#: wt-status.c:281
+#, c-format
+msgid "typechange: %s"
+msgstr ""
+
+#: wt-status.c:284
+#, c-format
+msgid "unknown: %s"
+msgstr "desconhecido: %s"
+
+#: wt-status.c:287
+#, c-format
+msgid "unmerged: %s"
+msgstr "não fundidos: %s"
+
+#: wt-status.c:290
+#, c-format
+msgid "bug: unhandled diff status %c"
+msgstr ""
+
+#: wt-status.c:713
+msgid "On branch "
+msgstr "Na rama"
+
+#: wt-status.c:720
+msgid "Not currently on any branch."
+msgstr "Não está em nenhuma rama."
+
+#: wt-status.c:731
+msgid "Initial commit"
+msgstr "Commit inicial"
+
+#: wt-status.c:745
+msgid "Untracked"
+msgstr "Não seguido"
+
+#: wt-status.c:747
+msgid "Ignored"
+msgstr "Ignorado"
+
+#: wt-status.c:749
+#, c-format
+msgid "Untracked files not listed%s"
+msgstr ""
+
+#: wt-status.c:751
+msgid " (use -u option to show untracked files)"
+msgstr ""
+
+#: wt-status.c:757
+msgid "No changes"
+msgstr "Sem mudanças"
+
+#: wt-status.c:761
+#, c-format
+msgid "no changes added to commit%s\n"
+msgstr "nenhuma alteração adicionado ao commit%s\n"
+
+#: wt-status.c:763
+msgid " (use \"git add\" and/or \"git commit -a\")"
+msgstr " (usa \"git add\" e/ou \"git commit -a\")"
+
+#: wt-status.c:765
+#, c-format
+msgid "nothing added to commit but untracked files present%s\n"
+msgstr ""
+
+#: wt-status.c:767
+msgid " (use \"git add\" to track)"
+msgstr " (usa \"git add\" para seguir)"
+
+#: wt-status.c:769
+#: wt-status.c:772
+#: wt-status.c:775
+#, c-format
+msgid "nothing to commit%s\n"
+msgstr "nada para fazer commit%s\n"
+
+#: wt-status.c:770
+msgid " (create/copy files and use \"git add\" to track)"
+msgstr ""
+
+#: wt-status.c:773
+msgid " (use -u to show untracked files)"
+msgstr ""
+
+#: wt-status.c:776
+msgid " (working directory clean)"
+msgstr " (directório de trabalho vacio)"
+
+#: wt-status.c:884
+msgid "HEAD (no branch)"
+msgstr "HEAD (Não é rama)"
+
+#: wt-status.c:890
+msgid "Initial commit on "
+msgstr "Commit inicial em "
+
+#: wt-status.c:905
+msgid "behind "
+msgstr "atrás "
+
+#: wt-status.c:908
+#: wt-status.c:911
+msgid "ahead "
+msgstr "a frente "
+
+#: wt-status.c:913
+msgid ", behind "
+msgstr ", atrás "
+
+#: builtin/add.c:62
+#, c-format
+msgid "unexpected diff status %c"
+msgstr ""
+
+#: builtin/add.c:67
+#: builtin/commit.c:298
+msgid "updating files failed"
+msgstr "Falou a atualização dos ficheiros"
+
+#: builtin/add.c:77
+#, c-format
+msgid "remove '%s'\n"
+msgstr "eliminar '%s'\n"
+
+#: builtin/add.c:176
+#, c-format
+msgid "Path '%s' is in submodule '%.*s'"
+msgstr ""
+
+#: builtin/add.c:192
+msgid "Unstaged changes after refreshing the index:"
+msgstr ""
+
+#: builtin/add.c:195
+#: builtin/add.c:456
+#: builtin/rm.c:186
+#, c-format
+msgid "pathspec '%s' did not match any files"
+msgstr ""
+
+#: builtin/add.c:209
+#, c-format
+msgid "'%s' is beyond a symbolic link"
+msgstr ""
+
+#: builtin/add.c:276
+msgid "Could not read the index"
+msgstr "Não foi possível ler o indíce"
+
+#: builtin/add.c:286
+#, c-format
+msgid "Could not open '%s' for writing."
+msgstr "Não foi possível abrir '%s' para escrever."
+
+#: builtin/add.c:290
+msgid "Could not write patch"
+msgstr "Não consegue escrever patch"
+
+#: builtin/add.c:295
+#, c-format
+msgid "Could not stat '%s'"
+msgstr ""
+
+#: builtin/add.c:297
+msgid "Empty patch. Aborted."
+msgstr "Patch vazio. Aborted."
+
+#: builtin/add.c:303
+#, c-format
+msgid "Could not apply '%s'"
+msgstr "Não foi possível aplicar o '%s'"
+
+#: builtin/add.c:312
+msgid "The following paths are ignored by one of your .gitignore files:\n"
+msgstr ""
+
+#: builtin/add.c:352
+#, c-format
+msgid "Use -f if you really want to add them.\n"
+msgstr ""
+
+#: builtin/add.c:353
+msgid "no files added"
+msgstr "nenhum ficheiros adicionado"
+
+#: builtin/add.c:359
+msgid "adding files failed"
+msgstr "falhou a adicionar ficheiros"
+
+#: builtin/add.c:391
+msgid "-A and -u are mutually incompatible"
+msgstr ""
+
+#: builtin/add.c:393
+msgid "Option --ignore-missing can only be used together with --dry-run"
+msgstr ""
+
+#: builtin/add.c:413
+#, c-format
+msgid "Nothing specified, nothing added.\n"
+msgstr ""
+
+#: builtin/add.c:414
+#, c-format
+msgid "Maybe you wanted to say 'git add .'?\n"
+msgstr ""
+
+#: builtin/add.c:420
+#: builtin/clean.c:95
+#: builtin/commit.c:358
+#: builtin/mv.c:82
+#: builtin/rm.c:162
+msgid "index file corrupt"
+msgstr "ficheiro index corrupto"
+
+#: builtin/add.c:476
+#: builtin/mv.c:229
+#: builtin/rm.c:260
+msgid "Unable to write new index file"
+msgstr ""
+
+#: builtin/archive.c:17
+#, c-format
+msgid "could not create archive file '%s'"
+msgstr ""
+
+#: builtin/archive.c:20
+msgid "could not redirect output"
+msgstr ""
+
+#: builtin/archive.c:37
+msgid "git archive: Remote with no URL"
+msgstr ""
+
+#: builtin/archive.c:58
+msgid "git archive: expected ACK/NAK, got EOF"
+msgstr ""
+
+#: builtin/archive.c:63
+#, c-format
+msgid "git archive: NACK %s"
+msgstr ""
+
+#: builtin/archive.c:65
+#, c-format
+msgid "remote error: %s"
+msgstr "erro remoto: %s"
+
+#: builtin/archive.c:66
+msgid "git archive: protocol error"
+msgstr ""
+
+#: builtin/archive.c:71
+msgid "git archive: expected a flush"
+msgstr ""
+
+#: builtin/branch.c:137
+#, c-format
+msgid ""
+"deleting branch '%s' that has been merged to\n"
+" '%s', but not yet merged to HEAD."
+msgstr ""
+
+#: builtin/branch.c:141
+#, c-format
+msgid ""
+"not deleting branch '%s' that is not yet merged to\n"
+" '%s', even though it is merged to HEAD."
+msgstr ""
+
+#. TRANSLATORS: This is "remote " in "remote branch '%s' not found"
+#: builtin/branch.c:163
+msgid "remote "
+msgstr "remota"
+
+#: builtin/branch.c:171
+msgid "cannot use -a with -d"
+msgstr "Não é possível usar -a com um -d"
+
+#: builtin/branch.c:177
+msgid "Couldn't look up commit object for HEAD"
+msgstr ""
+
+#: builtin/branch.c:182
+#, c-format
+msgid "Cannot delete the branch '%s' which you are currently on."
+msgstr ""
+
+#: builtin/branch.c:192
+#, c-format
+msgid "%sbranch '%s' not found."
+msgstr "%sbranch '%s' não encontrado."
+
+#: builtin/branch.c:200
+#, c-format
+msgid "Couldn't look up commit object for '%s'"
+msgstr ""
+
+#: builtin/branch.c:206
+#, 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:214
+#, c-format
+msgid "Error deleting %sbranch '%s'"
+msgstr ""
+
+#: builtin/branch.c:219
+#, c-format
+msgid "Deleted %sbranch %s (was %s).\n"
+msgstr ""
+
+#: builtin/branch.c:224
+msgid "Update of config-file failed"
+msgstr ""
+
+#: builtin/branch.c:322
+#, c-format
+msgid "branch '%s' does not point at a commit"
+msgstr ""
+
+#: builtin/branch.c:394
+#, c-format
+msgid "behind %d] "
+msgstr "atrás %d] "
+
+#: builtin/branch.c:396
+#, c-format
+msgid "ahead %d] "
+msgstr "a frente %d] "
+
+#: builtin/branch.c:398
+#, c-format
+msgid "ahead %d, behind %d] "
+msgstr "a frente %d, atrás %d] "
+
+#: builtin/branch.c:501
+msgid "(no branch)"
+msgstr "(não é rama)"
+
+#: builtin/branch.c:566
+msgid "some refs could not be read"
+msgstr ""
+
+#: builtin/branch.c:579
+msgid "cannot rename the current branch while not on any."
+msgstr ""
+
+#: builtin/branch.c:589
+#, c-format
+msgid "Invalid branch name: '%s'"
+msgstr "Nome da rama inválida: '%s'"
+
+#: builtin/branch.c:604
+msgid "Branch rename failed"
+msgstr "Falhou renomeação da rama"
+
+#: builtin/branch.c:608
+#, c-format
+msgid "Renamed a misnamed branch '%s' away"
+msgstr "Renomeado uma rama erronea '%s'"
+
+#: builtin/branch.c:612
+#, c-format
+msgid "Branch renamed to %s, but HEAD is not updated!"
+msgstr ""
+
+#: builtin/branch.c:619
+msgid "Branch is renamed, but update of config-file failed"
+msgstr ""
+
+#: builtin/branch.c:634
+#, c-format
+msgid "malformed object name %s"
+msgstr ""
+
+#: builtin/branch.c:658
+#, c-format
+msgid "could not write branch description template: %s\n"
+msgstr ""
+
+#: builtin/branch.c:746
+msgid "Failed to resolve HEAD as a valid ref."
+msgstr ""
+
+#: builtin/branch.c:751
+#: builtin/clone.c:558
+msgid "HEAD not found below refs/heads!"
+msgstr ""
+
+#: builtin/branch.c:809
+msgid "-a and -r options to 'git branch' do not make sense with a branch name"
+msgstr ""
+
+#: builtin/bundle.c:47
+#, c-format
+msgid "%s is okay\n"
+msgstr "%s está bem\n"
+
+#: builtin/bundle.c:56
+msgid "Need a repository to create a bundle."
+msgstr ""
+
+#: builtin/bundle.c:60
+msgid "Need a repository to unbundle."
+msgstr ""
+
+#: builtin/checkout.c:113
+#: builtin/checkout.c:146
+#, c-format
+msgid "path '%s' does not have our version"
+msgstr ""
+
+#: builtin/checkout.c:115
+#: builtin/checkout.c:148
+#, c-format
+msgid "path '%s' does not have their version"
+msgstr ""
+
+#: builtin/checkout.c:131
+#, c-format
+msgid "path '%s' does not have all necessary versions"
+msgstr ""
+
+#: builtin/checkout.c:175
+#, c-format
+msgid "path '%s' does not have necessary versions"
+msgstr ""
+
+#: builtin/checkout.c:192
+#, c-format
+msgid "path '%s': cannot merge"
+msgstr ""
+
+#: builtin/checkout.c:209
+#, c-format
+msgid "Unable to add merge result for '%s'"
+msgstr ""
+
+#: builtin/checkout.c:212
+#: builtin/reset.c:158
+#, c-format
+msgid "make_cache_entry failed for path '%s'"
+msgstr ""
+
+#: builtin/checkout.c:234
+#: builtin/checkout.c:392
+msgid "corrupt index file"
+msgstr "ficheiro index corrupto"
+
+#: builtin/checkout.c:264
+#: builtin/checkout.c:271
+#, c-format
+msgid "path '%s' is unmerged"
+msgstr ""
+
+#: builtin/checkout.c:302
+#: builtin/checkout.c:498
+#: builtin/clone.c:583
+#: 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 ""
+
+#: builtin/checkout.c:414
+msgid "you need to resolve your current index first"
+msgstr ""
+
+#: builtin/checkout.c:533
+#, c-format
+msgid "Can not do reflog for '%s'\n"
+msgstr ""
+
+#: builtin/checkout.c:565
+msgid "HEAD is now at"
+msgstr "HEAD é agora em "
+
+#: builtin/checkout.c:572
+#, c-format
+msgid "Reset branch '%s'\n"
+msgstr "Reset rama '%s'\n"
+
+#: builtin/checkout.c:575
+#, c-format
+msgid "Already on '%s'\n"
+msgstr "Já em '%s'\n"
+
+#: builtin/checkout.c:579
+#, c-format
+msgid "Switched to and reset branch '%s'\n"
+msgstr ""
+
+#: builtin/checkout.c:581
+#, c-format
+msgid "Switched to a new branch '%s'\n"
+msgstr "Mudado para a nova rama '%s'\n"
+
+#: builtin/checkout.c:583
+#, c-format
+msgid "Switched to branch '%s'\n"
+msgstr "Mudado para a rama '%s'\n"
+
+#: builtin/checkout.c:639
+#, c-format
+msgid " ... and %d more.\n"
+msgstr " ... e %d mais.\n"
+
+#. The singular version
+#: builtin/checkout.c:645
+#, 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"
+"\n"
+"%s\n"
+msgstr[0] ""
+msgstr[1] ""
+
+#: builtin/checkout.c:663
+#, 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"
+msgstr ""
+
+#: builtin/checkout.c:692
+msgid "internal error in revision walk"
+msgstr ""
+
+#: builtin/checkout.c:696
+msgid "Previous HEAD position was"
+msgstr ""
+
+#: builtin/checkout.c:722
+msgid "You are on a branch yet to be born"
+msgstr ""
+
+#. case (1)
+#: builtin/checkout.c:853
+#, c-format
+msgid "invalid reference: %s"
+msgstr ""
+
+#. case (1): want a tree
+#: builtin/checkout.c:892
+#, c-format
+msgid "reference is not a tree: %s"
+msgstr ""
+
+#: builtin/checkout.c:972
+msgid "-B cannot be used with -b"
+msgstr ""
+
+#: builtin/checkout.c:981
+msgid "--patch is incompatible with all other options"
+msgstr ""
+
+#: builtin/checkout.c:984
+msgid "--detach cannot be used with -b/-B/--orphan"
+msgstr ""
+
+#: builtin/checkout.c:986
+msgid "--detach cannot be used with -t"
+msgstr ""
+
+#: builtin/checkout.c:992
+msgid "--track needs a branch name"
+msgstr ""
+
+#: builtin/checkout.c:999
+msgid "Missing branch name; try -b"
+msgstr ""
+
+#: builtin/checkout.c:1005
+msgid "--orphan and -b|-B are mutually exclusive"
+msgstr ""
+
+#: builtin/checkout.c:1007
+msgid "--orphan cannot be used with -t"
+msgstr ""
+
+#: builtin/checkout.c:1017
+msgid "git checkout: -f and -m are incompatible"
+msgstr ""
+
+#: builtin/checkout.c:1051
+msgid "invalid path specification"
+msgstr ""
+
+#: builtin/checkout.c:1059
+#, 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?"
+msgstr ""
+
+#: builtin/checkout.c:1061
+msgid "git checkout: updating paths is incompatible with switching branches."
+msgstr ""
+
+#: builtin/checkout.c:1066
+msgid "git checkout: --detach does not take a path argument"
+msgstr ""
+
+#: builtin/checkout.c:1069
+msgid ""
+"git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
+"checking out of the index."
+msgstr ""
+
+#: builtin/checkout.c:1088
+msgid "Cannot switch branch to a non-commit."
+msgstr ""
+
+#: builtin/checkout.c:1091
+msgid "--ours/--theirs is incompatible with switching branches."
+msgstr ""
+
+#: builtin/clean.c:78
+msgid "-x and -X cannot be used together"
+msgstr ""
+
+#: builtin/clean.c:82
+msgid "clean.requireForce set to true and neither -n nor -f given; refusing to clean"
+msgstr ""
+
+#: builtin/clean.c:85
+msgid "clean.requireForce defaults to true and neither -n nor -f given; refusing to clean"
+msgstr ""
+
+#: builtin/clean.c:155
+#: builtin/clean.c:176
+#, c-format
+msgid "Would remove %s\n"
+msgstr ""
+
+#: builtin/clean.c:159
+#: builtin/clean.c:179
+#, c-format
+msgid "Removing %s\n"
+msgstr "Eliminando %s\n"
+
+#: builtin/clean.c:162
+#: builtin/clean.c:182
+#, c-format
+msgid "failed to remove %s"
+msgstr ""
+
+#: builtin/clean.c:166
+#, c-format
+msgid "Would not remove %s\n"
+msgstr ""
+
+#: builtin/clean.c:168
+#, c-format
+msgid "Not removing %s\n"
+msgstr ""
+
+#: builtin/clone.c:243
+#, c-format
+msgid "reference repository '%s' is not a local directory."
+msgstr ""
+
+#: builtin/clone.c:302
+#, c-format
+msgid "failed to open '%s'"
+msgstr ""
+
+#: builtin/clone.c:306
+#, c-format
+msgid "failed to create directory '%s'"
+msgstr ""
+
+#: builtin/clone.c:308
+#: builtin/diff.c:75
+#, c-format
+msgid "failed to stat '%s'"
+msgstr ""
+
+#: builtin/clone.c:310
+#, c-format
+msgid "%s exists and is not a directory"
+msgstr ""
+
+#: builtin/clone.c:324
+#, c-format
+msgid "failed to stat %s\n"
+msgstr ""
+
+#: builtin/clone.c:341
+#, c-format
+msgid "failed to unlink '%s'"
+msgstr ""
+
+#: builtin/clone.c:346
+#, c-format
+msgid "failed to create link '%s'"
+msgstr ""
+
+#: builtin/clone.c:350
+#, c-format
+msgid "failed to copy file to '%s'"
+msgstr ""
+
+#: builtin/clone.c:373
+#, c-format
+msgid "done.\n"
+msgstr "terminado.\n"
+
+#: builtin/clone.c:440
+#, c-format
+msgid "Could not find remote branch %s to clone."
+msgstr ""
+
+#: builtin/clone.c:549
+msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n"
+msgstr ""
+
+#: builtin/clone.c:639
+msgid "Too many arguments."
+msgstr "Demasiados parametros."
+
+#: builtin/clone.c:643
+msgid "You must specify a repository to clone."
+msgstr ""
+
+#: builtin/clone.c:654
+#, c-format
+msgid "--bare and --origin %s options are incompatible."
+msgstr ""
+
+#: builtin/clone.c:668
+#, c-format
+msgid "repository '%s' does not exist"
+msgstr ""
+
+#: builtin/clone.c:673
+msgid "--depth is ignored in local clones; use file:// instead."
+msgstr ""
+
+#: builtin/clone.c:683
+#, c-format
+msgid "destination path '%s' already exists and is not an empty directory."
+msgstr ""
+
+#: builtin/clone.c:693
+#, c-format
+msgid "working tree '%s' already exists."
+msgstr ""
+
+#: builtin/clone.c:706
+#: builtin/clone.c:720
+#, c-format
+msgid "could not create leading directories of '%s'"
+msgstr ""
+
+#: builtin/clone.c:709
+#, c-format
+msgid "could not create work tree dir '%s'."
+msgstr ""
+
+#: builtin/clone.c:728
+#, c-format
+msgid "Cloning into bare repository '%s'...\n"
+msgstr "Clonando em um repositorio nu (bare) '%s'...\n"
+
+#: builtin/clone.c:730
+#, c-format
+msgid "Cloning into '%s'...\n"
+msgstr "Clonar em '%s'...\n"
+
+#: builtin/clone.c:786
+#, c-format
+msgid "Don't know how to clone %s"
+msgstr "Não sei como clonar %s"
+
+#: builtin/clone.c:835
+#, 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/commit.c:42
+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 ""
+"O seu nome e endereço de e-mail foram configurados automaticamente com base\n"
+"no o seu usuario e nome da maquina. Por favor, verifique se eles são precisos.\n"
+"Você pode suprimir esta mensagem, configurando-los explicitamente:\n"
+"\n"
+" git config --global user.name \"O teu Nome\"\n"
+" git config --global user.email tu@examplo.com\n"
+"\n"
+"Após fazer isso, você pode corregir a identidade usada em este commit com:\n"
+"\n"
+" git commit --amend --reset-author\n"
+
+#: builtin/commit.c:54
+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 ""
+
+#: builtin/commit.c:59
+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/commit.c:205
+#: builtin/reset.c:33
+msgid "merge"
+msgstr "juntar"
+
+#: builtin/commit.c:208
+msgid "cherry-pick"
+msgstr "cherry-pick"
+
+#: builtin/commit.c:325
+msgid "failed to unpack HEAD tree object"
+msgstr ""
+
+#: builtin/commit.c:367
+msgid "unable to create temporary index"
+msgstr ""
+
+#: builtin/commit.c:373
+msgid "interactive add failed"
+msgstr "falhou adicionar interativo"
+
+#: builtin/commit.c:406
+#: builtin/commit.c:427
+#: builtin/commit.c:473
+msgid "unable to write new_index file"
+msgstr ""
+
+#: builtin/commit.c:457
+#, c-format
+msgid "cannot do a partial commit during a %s."
+msgstr ""
+
+#: builtin/commit.c:466
+msgid "cannot read the index"
+msgstr "não foi possível ler o indíce"
+
+#: builtin/commit.c:486
+msgid "unable to write temporary index file"
+msgstr ""
+
+#: builtin/commit.c:550
+#: builtin/commit.c:556
+#, c-format
+msgid "invalid commit: %s"
+msgstr "commit inválido: %s"
+
+#: builtin/commit.c:579
+msgid "malformed --author parameter"
+msgstr ""
+
+#: builtin/commit.c:635
+#, c-format
+msgid "Malformed ident string: '%s'"
+msgstr ""
+
+#: builtin/commit.c:670
+#: builtin/commit.c:703
+#: builtin/commit.c:1000
+#, c-format
+msgid "could not lookup commit %s"
+msgstr ""
+
+#: builtin/commit.c:682
+#: builtin/shortlog.c:296
+#, c-format
+msgid "(reading log message from standard input)\n"
+msgstr ""
+
+#: builtin/commit.c:684
+msgid "could not read log from standard input"
+msgstr ""
+
+#: builtin/commit.c:688
+#, c-format
+msgid "could not read log file '%s'"
+msgstr "não é possivel ler o ficheiro de log '%s'"
+
+#: builtin/commit.c:694
+msgid "commit has empty message"
+msgstr "a mensagem do commit está vazia"
+
+#: builtin/commit.c:710
+msgid "could not read MERGE_MSG"
+msgstr "não é possivel ler MERGE_MSG"
+
+#: builtin/commit.c:714
+msgid "could not read SQUASH_MSG"
+msgstr "não é possivel ler SQUASH_MSG"
+
+#: builtin/commit.c:718
+#, c-format
+msgid "could not read '%s'"
+msgstr "não é possivel ler '%s'"
+
+#: builtin/commit.c:746
+#, c-format
+msgid "could not open '%s'"
+msgstr "não é possivel abrir '%s'"
+
+#: builtin/commit.c:770
+msgid "could not write commit template"
+msgstr ""
+
+#: builtin/commit.c:783
+#, c-format
+msgid ""
+"\n"
+"It looks like you may be committing a %s.\n"
+"If this is not correct, please remove the file\n"
+"\t%s\n"
+"and try again.\n"
+msgstr ""
+
+#: builtin/commit.c:796
+msgid "Please enter the commit message for your changes."
+msgstr "Por favor insira a mensagem de commit das suas alterações."
+
+#: builtin/commit.c:799
+msgid ""
+" Lines starting\n"
+"with '#' will be ignored, and an empty message aborts the commit.\n"
+msgstr ""
+
+#: builtin/commit.c:804
+msgid ""
+" Lines starting\n"
+"with '#' will be kept; you may remove them yourself if you want to.\n"
+"An empty message aborts the commit.\n"
+msgstr ""
+
+#: builtin/commit.c:816
+#, c-format
+msgid "%sAuthor: %s"
+msgstr "%sAutor: %s"
+
+#: builtin/commit.c:823
+#, c-format
+msgid "%sCommitter: %s"
+msgstr "%sCommitador: %s"
+
+#: builtin/commit.c:843
+msgid "Cannot read index"
+msgstr ""
+
+#: builtin/commit.c:880
+msgid "Error building trees"
+msgstr ""
+
+#: builtin/commit.c:895
+#: builtin/tag.c:357
+#, c-format
+msgid "Please supply the message using either -m or -F option.\n"
+msgstr ""
+
+#: builtin/commit.c:975
+#, c-format
+msgid "No existing author found with '%s'"
+msgstr ""
+
+#: builtin/commit.c:990
+#: builtin/commit.c:1182
+#, c-format
+msgid "Invalid untracked files mode '%s'"
+msgstr ""
+
+#: builtin/commit.c:1030
+msgid "Using both --reset-author and --author does not make sense"
+msgstr ""
+
+#: builtin/commit.c:1041
+msgid "You have nothing to amend."
+msgstr "Você não tem nada a corregir."
+
+#: builtin/commit.c:1043
+#, c-format
+msgid "You are in the middle of a %s -- cannot amend."
+msgstr ""
+
+#: builtin/commit.c:1045
+msgid "Options --squash and --fixup cannot be used together"
+msgstr ""
+
+#: builtin/commit.c:1055
+msgid "Only one of -c/-C/-F/--fixup can be used."
+msgstr ""
+
+#: builtin/commit.c:1057
+msgid "Option -m cannot be combined with -c/-C/-F/--fixup."
+msgstr ""
+
+#: builtin/commit.c:1063
+msgid "--reset-author can be used only with -C, -c or --amend."
+msgstr ""
+
+#: builtin/commit.c:1080
+msgid "Only one of --include/--only/--all/--interactive/--patch can be used."
+msgstr ""
+
+#: builtin/commit.c:1082
+msgid "No paths with --include/--only does not make sense."
+msgstr ""
+
+#: builtin/commit.c:1084
+msgid "Clever... amending the last one with dirty index."
+msgstr ""
+
+#: builtin/commit.c:1086
+msgid "Explicit paths specified without -i nor -o; assuming --only paths..."
+msgstr ""
+
+#: builtin/commit.c:1096
+#: builtin/tag.c:556
+#, c-format
+msgid "Invalid cleanup mode %s"
+msgstr ""
+
+#: builtin/commit.c:1101
+msgid "Paths with -a does not make sense."
+msgstr ""
+
+#: builtin/commit.c:1280
+msgid "couldn't look up newly created commit"
+msgstr ""
+
+#: builtin/commit.c:1282
+msgid "could not parse newly created commit"
+msgstr ""
+
+#: builtin/commit.c:1323
+msgid "detached HEAD"
+msgstr ""
+
+#: builtin/commit.c:1325
+msgid " (root-commit)"
+msgstr " (root-commit)"
+
+#: builtin/commit.c:1415
+msgid "could not parse HEAD commit"
+msgstr ""
+
+#: builtin/commit.c:1452
+#: builtin/merge.c:509
+#, c-format
+msgid "could not open '%s' for reading"
+msgstr ""
+
+#: builtin/commit.c:1459
+#, c-format
+msgid "Corrupt MERGE_HEAD file (%s)"
+msgstr ""
+
+#: builtin/commit.c:1466
+msgid "could not read MERGE_MODE"
+msgstr ""
+
+#: builtin/commit.c:1485
+#, c-format
+msgid "could not read commit message: %s"
+msgstr ""
+
+#: builtin/commit.c:1499
+#, c-format
+msgid "Aborting commit due to empty commit message.\n"
+msgstr ""
+
+#: builtin/commit.c:1514
+#: builtin/merge.c:935
+#: builtin/merge.c:968
+msgid "failed to write commit object"
+msgstr ""
+
+#: builtin/commit.c:1535
+msgid "cannot lock HEAD ref"
+msgstr ""
+
+#: builtin/commit.c:1539
+msgid "cannot update HEAD ref"
+msgstr ""
+
+#: builtin/commit.c:1550
+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/describe.c:234
+#, c-format
+msgid "annotated tag %s not available"
+msgstr ""
+
+#: builtin/describe.c:238
+#, c-format
+msgid "annotated tag %s has no embedded name"
+msgstr ""
+
+#: builtin/describe.c:240
+#, c-format
+msgid "tag '%s' is really '%s' here"
+msgstr ""
+
+#: builtin/describe.c:267
+#, c-format
+msgid "Not a valid object name %s"
+msgstr ""
+
+#: builtin/describe.c:270
+#, c-format
+msgid "%s is not a valid '%s' object"
+msgstr ""
+
+#: builtin/describe.c:287
+#, c-format
+msgid "no tag exactly matches '%s'"
+msgstr ""
+
+#: builtin/describe.c:289
+#, c-format
+msgid "searching to describe %s\n"
+msgstr ""
+
+#: builtin/describe.c:329
+#, c-format
+msgid "finished search at %s\n"
+msgstr ""
+
+#: builtin/describe.c:353
+#, c-format
+msgid ""
+"No annotated tags can describe '%s'.\n"
+"However, there were unannotated tags: try --tags."
+msgstr ""
+
+#: builtin/describe.c:357
+#, c-format
+msgid ""
+"No tags can describe '%s'.\n"
+"Try --always, or create some tags."
+msgstr ""
+
+#: builtin/describe.c:378
+#, c-format
+msgid "traversed %lu commits\n"
+msgstr ""
+
+#: builtin/describe.c:381
+#, c-format
+msgid ""
+"more than %i tags found; listed %i most recent\n"
+"gave up search at %s\n"
+msgstr ""
+
+#: builtin/describe.c:436
+msgid "--long is incompatible with --abbrev=0"
+msgstr ""
+
+#: builtin/describe.c:462
+msgid "No names found, cannot describe anything."
+msgstr "Nenhum nome encontrado, não descreve nada."
+
+#: builtin/describe.c:482
+msgid "--dirty is incompatible with committishes"
+msgstr ""
+
+#: builtin/diff.c:77
+#, c-format
+msgid "'%s': not a regular file or symlink"
+msgstr ""
+
+#: builtin/diff.c:220
+#, c-format
+msgid "invalid option: %s"
+msgstr ""
+
+#: builtin/diff.c:297
+msgid "Not a git repository"
+msgstr "Não é um repositorio git"
+
+#: builtin/diff.c:347
+#, c-format
+msgid "invalid object '%s' given."
+msgstr ""
+
+#: builtin/diff.c:352
+#, c-format
+msgid "more than %d trees given: '%s'"
+msgstr ""
+
+#: builtin/diff.c:362
+#, c-format
+msgid "more than two blobs given: '%s'"
+msgstr ""
+
+#: builtin/diff.c:370
+#, c-format
+msgid "unhandled object '%s' given."
+msgstr ""
+
+#: builtin/fetch.c:200
+msgid "Couldn't find remote ref HEAD"
+msgstr ""
+
+#: builtin/fetch.c:252
+#, c-format
+msgid "object %s not found"
+msgstr ""
+
+#: builtin/fetch.c:258
+msgid "[up to date]"
+msgstr "[Actualizada]"
+
+#: builtin/fetch.c:272
+#, c-format
+msgid "! %-*s %-*s -> %s (can't fetch in current branch)"
+msgstr ""
+
+#: builtin/fetch.c:273
+#: builtin/fetch.c:351
+msgid "[rejected]"
+msgstr "[rejeitado]"
+
+#: builtin/fetch.c:284
+msgid "[tag update]"
+msgstr "[etiqueta actualizada]"
+
+#: builtin/fetch.c:286
+#: builtin/fetch.c:313
+#: builtin/fetch.c:331
+msgid " (unable to update local ref)"
+msgstr ""
+
+#: builtin/fetch.c:298
+msgid "[new tag]"
+msgstr "[nova etiqueta]"
+
+#: builtin/fetch.c:302
+msgid "[new branch]"
+msgstr "[nova rama]"
+
+#: builtin/fetch.c:347
+msgid "unable to update local ref"
+msgstr ""
+
+#: builtin/fetch.c:347
+msgid "forced update"
+msgstr "actualização forçada"
+
+#: builtin/fetch.c:353
+msgid "(non-fast-forward)"
+msgstr ""
+
+#: builtin/fetch.c:384
+#: builtin/fetch.c:676
+#, c-format
+msgid "cannot open %s: %s\n"
+msgstr ""
+
+#: builtin/fetch.c:393
+#, c-format
+msgid "%s did not send all necessary objects\n"
+msgstr ""
+
+#: builtin/fetch.c:479
+#, c-format
+msgid "From %.*s\n"
+msgstr "Para %.*s\n"
+
+#: builtin/fetch.c:490
+#, c-format
+msgid ""
+"some local refs could not be updated; try running\n"
+" 'git remote prune %s' to remove any old, conflicting branches"
+msgstr ""
+
+#: builtin/fetch.c:540
+#, c-format
+msgid " (%s will become dangling)\n"
+msgstr ""
+
+#: builtin/fetch.c:541
+#, c-format
+msgid " (%s has become dangling)\n"
+msgstr ""
+
+#: builtin/fetch.c:548
+msgid "[deleted]"
+msgstr "[eliminado]"
+
+#: builtin/fetch.c:549
+msgid "(none)"
+msgstr "(nenhum)"
+
+#: builtin/fetch.c:666
+#, c-format
+msgid "Refusing to fetch into current branch %s of non-bare repository"
+msgstr ""
+
+#: builtin/fetch.c:700
+#, c-format
+msgid "Don't know how to fetch from %s"
+msgstr ""
+
+#: builtin/fetch.c:777
+#, c-format
+msgid "Option \"%s\" value \"%s\" is not valid for %s"
+msgstr ""
+
+#: builtin/fetch.c:780
+#, c-format
+msgid "Option \"%s\" is ignored for %s\n"
+msgstr ""
+
+#: builtin/fetch.c:879
+#, c-format
+msgid "Fetching %s\n"
+msgstr "Baixando %s\n"
+
+#: builtin/fetch.c:881
+#, c-format
+msgid "Could not fetch %s"
+msgstr ""
+
+#: builtin/fetch.c:898
+msgid ""
+"No remote repository specified. Please, specify either a URL or a\n"
+"remote name from which new revisions should be fetched."
+msgstr ""
+"Nenhum repositório remoto especificado. Por favor, especifique um URL ou o\n"
+"nome remoto a partir do qual novas revisões devem ser obtida."
+
+#: builtin/fetch.c:918
+msgid "You need to specify a tag name."
+msgstr "Você precisa especificar um nome da etiqueta."
+
+#: builtin/fetch.c:970
+msgid "fetch --all does not take a repository argument"
+msgstr ""
+
+#: builtin/fetch.c:972
+msgid "fetch --all does not make sense with refspecs"
+msgstr ""
+
+#: builtin/fetch.c:983
+#, c-format
+msgid "No such remote or remote group: %s"
+msgstr ""
+
+#: builtin/fetch.c:991
+msgid "Fetching a group and specifying refspecs does not make sense"
+msgstr ""
+
+#: builtin/gc.c:63
+#, c-format
+msgid "Invalid %s: '%s'"
+msgstr "Inválido %s: '%s'"
+
+#: builtin/gc.c:78
+msgid "Too many options specified"
+msgstr "Demasiadas opções especificadas"
+
+#: builtin/gc.c:103
+#, c-format
+msgid "insanely long object directory %.*s"
+msgstr ""
+
+#: builtin/gc.c:223
+#, c-format
+msgid "Auto packing the repository for optimum performance.\n"
+msgstr ""
+
+#: builtin/gc.c:226
+#, 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/gc.c:256
+msgid "There are too many unreachable loose objects; run 'git prune' to remove them."
+msgstr ""
+
+#: builtin/grep.c:216
+#, c-format
+msgid "grep: failed to create thread: %s"
+msgstr ""
+
+#: builtin/grep.c:402
+#, c-format
+msgid "Failed to chdir: %s"
+msgstr ""
+
+#: builtin/grep.c:478
+#: builtin/grep.c:512
+#, c-format
+msgid "unable to read tree (%s)"
+msgstr ""
+
+#: builtin/grep.c:526
+#, c-format
+msgid "unable to grep from object of type %s"
+msgstr ""
+
+#: builtin/grep.c:584
+#, c-format
+msgid "switch `%c' expects a numerical value"
+msgstr ""
+
+#: builtin/grep.c:601
+#, c-format
+msgid "cannot open '%s'"
+msgstr ""
+
+#: builtin/grep.c:888
+msgid "no pattern given."
+msgstr ""
+
+#: builtin/grep.c:902
+#, c-format
+msgid "bad object %s"
+msgstr ""
+
+#: builtin/grep.c:943
+msgid "--open-files-in-pager only works on the worktree"
+msgstr ""
+
+#: builtin/grep.c:966
+msgid "--cached or --untracked cannot be used with --no-index."
+msgstr ""
+
+#: builtin/grep.c:971
+msgid "--no-index or --untracked cannot be used with revs."
+msgstr ""
+
+#: builtin/grep.c:974
+msgid "--[no-]exclude-standard cannot be used for tracked contents."
+msgstr ""
+
+#: builtin/grep.c:982
+msgid "both --cached and trees are 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:322
+#: builtin/init-db.c:325
+#, c-format
+msgid "%s already exists"
+msgstr "%s já existe"
+
+#: builtin/init-db.c:354
+#, c-format
+msgid "unable to handle file type %d"
+msgstr ""
+
+#: builtin/init-db.c:357
+#, c-format
+msgid "unable to move %s to %s"
+msgstr ""
+
+#: builtin/init-db.c:362
+#, 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:419
+#, c-format
+msgid "%s%s Git repository in %s%s\n"
+msgstr ""
+
+#: builtin/init-db.c:420
+msgid "Reinitialized existing"
+msgstr ""
+
+#: builtin/init-db.c:420
+msgid "Initialized empty"
+msgstr "Inicializada vazio"
+
+#: builtin/init-db.c:421
+msgid " shared"
+msgstr " partilhado"
+
+#: builtin/init-db.c:440
+msgid "cannot tell cwd"
+msgstr ""
+
+#: builtin/init-db.c:521
+#: builtin/init-db.c:528
+#, c-format
+msgid "cannot mkdir %s"
+msgstr ""
+
+#: builtin/init-db.c:532
+#, c-format
+msgid "cannot chdir to %s"
+msgstr ""
+
+#: builtin/init-db.c:554
+#, c-format
+msgid "%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-dir=<directory>)"
+msgstr ""
+
+#: builtin/init-db.c:578
+msgid "Cannot access current working directory"
+msgstr ""
+
+#: builtin/init-db.c:585
+#, c-format
+msgid "Cannot access work tree '%s'"
+msgstr ""
+
+#: builtin/log.c:187
+#, c-format
+msgid "Final output: %d %s\n"
+msgstr ""
+
+#: builtin/log.c:395
+#: builtin/log.c:483
+#, c-format
+msgid "Could not read object %s"
+msgstr ""
+
+#: builtin/log.c:507
+#, c-format
+msgid "Unknown type: %d"
+msgstr "Tipo desconhecido: %d"
+
+#: builtin/log.c:596
+msgid "format.headers without value"
+msgstr ""
+
+#: builtin/log.c:669
+msgid "name of output directory is too long"
+msgstr "nome do diretório de saída é demasiado longo"
+
+#: builtin/log.c:680
+#, c-format
+msgid "Cannot open patch file %s"
+msgstr "Não é possivel abrir o ficheiro patch %s"
+
+#: builtin/log.c:694
+msgid "Need exactly one range."
+msgstr "Necessita de exatamente um intervalo."
+
+#: builtin/log.c:702
+msgid "Not a range."
+msgstr "Não é um intervalo."
+
+#: builtin/log.c:739
+msgid "Could not extract email from committer identity."
+msgstr "Não foi possível extrair a identidade do committer do e-mail."
+
+#: builtin/log.c:785
+msgid "Cover letter needs email format"
+msgstr "Carta de apresentação necessita um modelo de e-mail"
+
+#: builtin/log.c:879
+#, c-format
+msgid "insane in-reply-to: %s"
+msgstr ""
+
+#: builtin/log.c:952
+msgid "Two output directories?"
+msgstr "Dois diretórios de saída?"
+
+#: builtin/log.c:1173
+#, c-format
+msgid "bogus committer info %s"
+msgstr ""
+
+#: builtin/log.c:1218
+msgid "-n and -k are mutually exclusive."
+msgstr ""
+
+#: builtin/log.c:1220
+msgid "--subject-prefix and -k are mutually exclusive."
+msgstr ""
+
+#: builtin/log.c:1225
+#: builtin/shortlog.c:284
+#, c-format
+msgid "unrecognized argument: %s"
+msgstr "argumento não reconhecido: %s"
+
+#: builtin/log.c:1228
+msgid "--name-only does not make sense"
+msgstr ""
+
+#: builtin/log.c:1230
+msgid "--name-status does not make sense"
+msgstr ""
+
+#: builtin/log.c:1232
+msgid "--check does not make sense"
+msgstr ""
+
+#: builtin/log.c:1255
+msgid "standard output, or directory, which one?"
+msgstr "saída padrão, ou diretório, qual deles?"
+
+#: builtin/log.c:1257
+#, c-format
+msgid "Could not create directory '%s'"
+msgstr ""
+
+#: builtin/log.c:1410
+msgid "Failed to create output files"
+msgstr "Falhou ao criar ficheiros de saída"
+
+#: builtin/log.c:1514
+#, c-format
+msgid "Could not find a tracked remote branch, please specify <upstream> manually.\n"
+msgstr ""
+
+#: builtin/log.c:1530
+#: builtin/log.c:1532
+#: builtin/log.c:1544
+#, c-format
+msgid "Unknown commit %s"
+msgstr "Commit desconhecido %s"
+
+#: builtin/merge.c:91
+msgid "switch `m' requires a value"
+msgstr ""
+
+#: builtin/merge.c:128
+#, c-format
+msgid "Could not find merge strategy '%s'.\n"
+msgstr ""
+
+#: builtin/merge.c:129
+#, c-format
+msgid "Available strategies are:"
+msgstr "As estratégias disponíveis são:"
+
+#: builtin/merge.c:134
+#, c-format
+msgid "Available custom strategies are:"
+msgstr "Estratégias personalizadas disponíveis são:"
+
+#: builtin/merge.c:241
+msgid "could not run stash."
+msgstr ""
+
+#: builtin/merge.c:246
+msgid "stash failed"
+msgstr "falhou o stash"
+
+#: builtin/merge.c:251
+#, c-format
+msgid "not a valid object: %s"
+msgstr ""
+
+#: builtin/merge.c:270
+#: builtin/merge.c:287
+msgid "read-tree failed"
+msgstr ""
+
+#: builtin/merge.c:317
+msgid " (nothing to squash)"
+msgstr " (nada para squash)"
+
+#: builtin/merge.c:330
+#, c-format
+msgid "Squash commit -- not updating HEAD\n"
+msgstr ""
+
+#: builtin/merge.c:362
+msgid "Writing SQUASH_MSG"
+msgstr "Escrevendo SQUASH_MSG"
+
+#: builtin/merge.c:364
+msgid "Finishing SQUASH_MSG"
+msgstr "Terminando SQUASH_MSG"
+
+#: builtin/merge.c:386
+#, c-format
+msgid "No merge message -- not updating HEAD\n"
+msgstr ""
+
+#: builtin/merge.c:437
+#, c-format
+msgid "'%s' does not point to a commit"
+msgstr ""
+
+#: builtin/merge.c:536
+#, c-format
+msgid "Bad branch.%s.mergeoptions string: %s"
+msgstr ""
+
+#: builtin/merge.c:629
+msgid "git write-tree failed to write a tree"
+msgstr ""
+
+#: builtin/merge.c:679
+msgid "failed to read the cache"
+msgstr ""
+
+#: builtin/merge.c:696
+msgid "Unable to write index."
+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 "Não commitando um merge; usa 'git commit' para completar o merge.\n"
+
+#: 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 "Mensagem de commit vazia."
+
+#: builtin/merge.c:927
+#, c-format
+msgid "Wonderful.\n"
+msgstr "Fastastico.\n"
+
+#: builtin/merge.c:1000
+#, c-format
+msgid "Automatic merge failed; fix conflicts and then commit the result.\n"
+msgstr ""
+
+#: builtin/merge.c:1016
+#, c-format
+msgid "'%s' is not a commit"
+msgstr "'%s' não é um commit"
+
+#: builtin/merge.c:1057
+msgid "No current branch."
+msgstr "Nenhuma rama actual"
+
+#: builtin/merge.c:1059
+msgid "No remote for the current branch."
+msgstr ""
+
+#: builtin/merge.c:1061
+msgid "No default upstream defined for the current branch."
+msgstr ""
+
+#: builtin/merge.c:1066
+#, c-format
+msgid "No remote tracking branch for %s from %s"
+msgstr ""
+
+#: builtin/merge.c:1188
+msgid "There is no merge to abort (MERGE_HEAD missing)."
+msgstr ""
+
+#: builtin/merge.c:1204
+#: 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:1207
+#: git-pull.sh:34
+msgid "You have not concluded your merge (MERGE_HEAD exists)."
+msgstr ""
+
+#: builtin/merge.c:1211
+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:1214
+msgid "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)."
+msgstr ""
+
+#: builtin/merge.c:1223
+msgid "You cannot combine --squash with --no-ff."
+msgstr ""
+
+#: builtin/merge.c:1228
+msgid "You cannot combine --no-ff with --ff-only."
+msgstr ""
+
+#: builtin/merge.c:1235
+msgid "No commit specified and merge.defaultToUpstream not set."
+msgstr ""
+
+#: builtin/merge.c:1266
+msgid "Can merge only exactly one commit into empty head"
+msgstr ""
+
+#: builtin/merge.c:1269
+msgid "Squash commit into empty head not supported yet"
+msgstr ""
+
+#: builtin/merge.c:1271
+msgid "Non-fast-forward commit does not make sense into an empty head"
+msgstr ""
+
+#: builtin/merge.c:1275
+#: builtin/merge.c:1319
+#, c-format
+msgid "%s - not something we can merge"
+msgstr ""
+
+#: builtin/merge.c:1385
+#, c-format
+msgid "Updating %s..%s\n"
+msgstr "Actualizando %s..%s\n"
+
+#: builtin/merge.c:1423
+#, c-format
+msgid "Trying really trivial in-index merge...\n"
+msgstr ""
+
+#: builtin/merge.c:1430
+#, c-format
+msgid "Nope.\n"
+msgstr "Não.\n"
+
+#: builtin/merge.c:1462
+msgid "Not possible to fast-forward, aborting."
+msgstr ""
+
+#: builtin/merge.c:1485
+#: builtin/merge.c:1562
+#, c-format
+msgid "Rewinding the tree to pristine...\n"
+msgstr ""
+
+#: builtin/merge.c:1489
+#, c-format
+msgid "Trying merge strategy %s...\n"
+msgstr ""
+
+#: builtin/merge.c:1553
+#, c-format
+msgid "No merge strategy handled the merge.\n"
+msgstr ""
+
+#: builtin/merge.c:1555
+#, c-format
+msgid "Merge with strategy %s failed.\n"
+msgstr "Fundir com a estratégia %s falhou.\n"
+
+#: builtin/merge.c:1564
+#, c-format
+msgid "Using the %s to prepare resolving by hand.\n"
+msgstr ""
+
+#: builtin/merge.c:1575
+#, c-format
+msgid "Automatic merge went well; stopped before committing as requested\n"
+msgstr ""
+
+#: builtin/mv.c:108
+#, c-format
+msgid "Checking rename of '%s' to '%s'\n"
+msgstr ""
+
+#: builtin/mv.c:112
+msgid "bad source"
+msgstr "fonte inválida"
+
+#: 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 "o directorio fonte está vazio"
+
+#: builtin/mv.c:171
+msgid "not under version control"
+msgstr "não está no controlo de versões"
+
+#: builtin/mv.c:173
+msgid "destination exists"
+msgstr "existe destino"
+
+#: builtin/mv.c:181
+#, c-format
+msgid "overwriting '%s'"
+msgstr "subscrevendo '%s'"
+
+#: builtin/mv.c:184
+msgid "Cannot overwrite"
+msgstr "Não consegue subscrever"
+
+#: builtin/mv.c:187
+msgid "multiple sources for the same target"
+msgstr "múltiplas fontes para o mesmo alvo"
+
+#: 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 "Mudar de nome %s para %s\n"
+
+#: builtin/mv.c:215
+#, c-format
+msgid "renaming '%s' failed"
+msgstr "mudar de nome '%s' falhou"
+
+#: builtin/notes.c:139
+#, c-format
+msgid "unable to start 'show' for object '%s'"
+msgstr ""
+
+#: builtin/notes.c:145
+msgid "can't fdopen 'show' output fd"
+msgstr ""
+
+#: builtin/notes.c:155
+#, c-format
+msgid "failed to close pipe to 'show' for object '%s'"
+msgstr ""
+
+#: builtin/notes.c:158
+#, c-format
+msgid "failed to finish 'show' for object '%s'"
+msgstr ""
+
+#: builtin/notes.c:175
+#: builtin/tag.c:343
+#, 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"
+msgstr ""
+
+#: builtin/notes.c:210
+#: builtin/notes.c:973
+#, c-format
+msgid "Removing note for object %s\n"
+msgstr ""
+
+#: builtin/notes.c:215
+msgid "unable to write note object"
+msgstr ""
+
+#: builtin/notes.c:217
+#, c-format
+msgid "The note contents has been left in %s"
+msgstr ""
+
+#: builtin/notes.c:251
+#: builtin/tag.c:521
+#, c-format
+msgid "cannot read '%s'"
+msgstr "não consegue ler '%s'"
+
+#: builtin/notes.c:253
+#: builtin/tag.c:524
+#, c-format
+msgid "could not open or read '%s'"
+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:537
+#, c-format
+msgid "Failed to resolve '%s' as a valid ref."
+msgstr ""
+
+#: builtin/notes.c:275
+#, c-format
+msgid "Failed to read object '%s'."
+msgstr ""
+
+#: builtin/notes.c:299
+msgid "Cannot commit uninitialized/unreferenced notes tree"
+msgstr ""
+
+#: builtin/notes.c:340
+#, c-format
+msgid "Bad notes.rewriteMode value: '%s'"
+msgstr ""
+
+#: builtin/notes.c:350
+#, 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:377
+#, c-format
+msgid "Bad %s value: '%s'"
+msgstr "Inválido %s valor: '%s'"
+
+#: builtin/notes.c:441
+#, c-format
+msgid "Malformed input line: '%s'."
+msgstr ""
+
+#: builtin/notes.c:456
+#, c-format
+msgid "Failed to copy notes from '%s' to '%s'"
+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"
+msgstr "demasiado parametros"
+
+#: builtin/notes.c:513
+#: builtin/notes.c:772
+#, c-format
+msgid "No note found for object %s."
+msgstr "Nenhuma nota encontrada para o objecto %s."
+
+#: builtin/notes.c:580
+#, c-format
+msgid "Cannot add notes. Found existing notes for object %s. Use '-f' to overwrite existing notes"
+msgstr ""
+
+#: builtin/notes.c:585
+#: builtin/notes.c:662
+#, c-format
+msgid "Overwriting existing notes for object %s\n"
+msgstr ""
+
+#: builtin/notes.c:635
+msgid "too few parameters"
+msgstr ""
+
+#: builtin/notes.c:656
+#, c-format
+msgid "Cannot copy notes. Found existing notes for object %s. Use '-f' to overwrite existing notes"
+msgstr ""
+
+#: builtin/notes.c:668
+#, c-format
+msgid "Missing notes on source object %s. Cannot copy."
+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"
+msgstr ""
+
+#: builtin/notes.c:971
+#, c-format
+msgid "Object %s has no note\n"
+msgstr ""
+
+#: builtin/notes.c:1103
+#, c-format
+msgid "Unknown subcommand: %s"
+msgstr ""
+
+#: builtin/pack-objects.c:2310
+#, c-format
+msgid "unsupported index version %s"
+msgstr ""
+
+#: builtin/pack-objects.c:2314
+#, c-format
+msgid "bad index version '%s'"
+msgstr ""
+
+#: builtin/pack-objects.c:2322
+#, c-format
+msgid "option %s does not accept negative form"
+msgstr "opção %s não aceita formato negativo"
+
+#: builtin/pack-objects.c:2326
+#, c-format
+msgid "unable to parse value '%s' for option %s"
+msgstr ""
+
+#: builtin/push.c:44
+msgid "tag shorthand without <tag>"
+msgstr ""
+
+#: builtin/push.c:63
+msgid "--delete only accepts plain target ref names"
+msgstr "--delete só aceita nomes simples para o ref de destino"
+
+#: builtin/push.c:73
+#, 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:80
+#, 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:88
+#, c-format
+msgid "The current branch %s has multiple upstream branches, refusing to push."
+msgstr ""
+
+#: builtin/push.c:111
+msgid "You didn't specify any refspecs to push, and push.default is \"nothing\"."
+msgstr ""
+
+#: builtin/push.c:131
+#, c-format
+msgid "Pushing to %s\n"
+msgstr "Pushing para %s\n"
+
+#: builtin/push.c:135
+#, c-format
+msgid "failed to push some refs to '%s'"
+msgstr ""
+
+#: builtin/push.c:143
+#, c-format
+msgid ""
+"To prevent you from losing history, non-fast-forward updates were rejected\n"
+"Merge the remote changes (e.g. 'git pull') before pushing again. See the\n"
+"'Note about fast-forwards' section of 'git push --help' for details.\n"
+msgstr ""
+
+#: builtin/push.c:160
+#, c-format
+msgid "bad repository '%s'"
+msgstr "repositorio inválido '%s'"
+
+#: builtin/push.c:161
+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:176
+msgid "--all and --tags are incompatible"
+msgstr "--all e --tags are são incompatíveis"
+
+#: builtin/push.c:177
+msgid "--all can't be combined with refspecs"
+msgstr ""
+
+#: builtin/push.c:182
+msgid "--mirror and --tags are incompatible"
+msgstr ""
+
+#: builtin/push.c:183
+msgid "--mirror can't be combined with refspecs"
+msgstr ""
+
+#: builtin/push.c:188
+msgid "--all and --mirror are incompatible"
+msgstr ""
+
+#: builtin/push.c:274
+msgid "--delete is incompatible with --all, --mirror and --tags"
+msgstr ""
+
+#: builtin/push.c:276
+msgid "--delete doesn't make sense without any refs"
+msgstr ""
+
+#: builtin/reset.c:33
+msgid "mixed"
+msgstr "mistura"
+
+#: builtin/reset.c:33
+msgid "soft"
+msgstr "leve"
+
+#: builtin/reset.c:33
+msgid "hard"
+msgstr "forte"
+
+#: builtin/reset.c:33
+msgid "keep"
+msgstr "manter"
+
+#: builtin/reset.c:77
+msgid "You do not have a valid HEAD."
+msgstr "Não tens a HEAD válida."
+
+#: builtin/reset.c:79
+msgid "Failed to find tree of HEAD."
+msgstr ""
+
+#: builtin/reset.c:85
+#, c-format
+msgid "Failed to find tree of %s."
+msgstr ""
+
+#: builtin/reset.c:96
+msgid "Could not write new index file."
+msgstr ""
+
+#: builtin/reset.c:106
+#, c-format
+msgid "HEAD is now at %s"
+msgstr "HEAD é agora em %s"
+
+#: 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 "Cannot do a %s reset in the middle of a merge."
+msgstr ""
+
+#: builtin/reset.c:297
+#, c-format
+msgid "Could not parse object '%s'."
+msgstr "Não foi possível analisar objeto '%s'."
+
+#: builtin/reset.c:302
+msgid "--patch is incompatible with --{hard,mixed,soft}"
+msgstr ""
+
+#: builtin/reset.c:311
+msgid "--mixed with paths is deprecated; use 'git reset -- <paths>' instead."
+msgstr ""
+
+#: builtin/reset.c:313
+#, c-format
+msgid "Cannot do %s reset with paths."
+msgstr ""
+
+#: builtin/reset.c:325
+#, c-format
+msgid "%s reset is not allowed in a bare repository"
+msgstr ""
+
+#: builtin/reset.c:341
+#, c-format
+msgid "Could not reset index file to revision '%s'."
+msgstr ""
+
+#: builtin/revert.c:70
+#: builtin/revert.c:91
+#, c-format
+msgid "%s: %s cannot be used with %s"
+msgstr ""
+
+#: builtin/revert.c:126
+msgid "program error"
+msgstr "erro do programa"
+
+#: builtin/revert.c:209
+msgid "revert failed"
+msgstr "falhou o revert"
+
+#: builtin/revert.c:224
+msgid "cherry-pick failed"
+msgstr "cherry-pick falhou"
+
+#: 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 ""
+
+#: 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 ""
+
+#: builtin/rm.c:119
+#, c-format
+msgid ""
+"'%s' has local modifications\n"
+"(use --cached to keep the file, or -f to force removal)"
+msgstr ""
+
+#: builtin/rm.c:194
+#, c-format
+msgid "not removing '%s' recursively without -r"
+msgstr ""
+
+#: builtin/rm.c:230
+#, c-format
+msgid "git rm: unable to remove %s"
+msgstr ""
+
+#: builtin/shortlog.c:157
+#, c-format
+msgid "Missing author: %s"
+msgstr "Autor em falta: %s"
+
+#: builtin/tag.c:58
+#, c-format
+msgid "malformed object at '%s'"
+msgstr ""
+
+#: builtin/tag.c:205
+#, c-format
+msgid "tag name too long: %.*s..."
+msgstr ""
+
+#: builtin/tag.c:210
+#, c-format
+msgid "tag '%s' not found."
+msgstr "etiqueta '%s' não foi encontrada."
+
+#: builtin/tag.c:225
+#, c-format
+msgid "Deleted tag '%s' (was %s)\n"
+msgstr ""
+
+#: builtin/tag.c:237
+#, c-format
+msgid "could not verify the tag '%s'"
+msgstr ""
+
+#: builtin/tag.c:247
+msgid ""
+"\n"
+"#\n"
+"# Write a tag message\n"
+"# Lines starting with '#' will be ignored.\n"
+"#\n"
+msgstr ""
+
+#: builtin/tag.c:254
+msgid ""
+"\n"
+"#\n"
+"# Write a tag message\n"
+"# Lines starting with '#' will be kept; you may remove them yourself if you want to.\n"
+"#\n"
+msgstr ""
+
+#: builtin/tag.c:294
+msgid "unable to sign the tag"
+msgstr ""
+
+#: builtin/tag.c:296
+msgid "unable to write tag file"
+msgstr ""
+
+#: builtin/tag.c:321
+msgid "bad object type."
+msgstr ""
+
+#: builtin/tag.c:334
+msgid "tag header too big."
+msgstr ""
+
+#: builtin/tag.c:366
+msgid "no tag message?"
+msgstr "nenhuma mensaje para a etiqueta?"
+
+#: builtin/tag.c:372
+#, c-format
+msgid "The tag message has been left in %s\n"
+msgstr ""
+
+#: builtin/tag.c:421
+msgid "switch 'points-at' requires an object"
+msgstr ""
+
+#: builtin/tag.c:423
+#, c-format
+msgid "malformed object name '%s'"
+msgstr ""
+
+#: builtin/tag.c:502
+msgid "-n option is only allowed with -l."
+msgstr ""
+
+#: builtin/tag.c:504
+msgid "--contains option is only allowed with -l."
+msgstr ""
+
+#: builtin/tag.c:506
+msgid "--points-at option is only allowed with -l."
+msgstr ""
+
+#: builtin/tag.c:514
+msgid "only one -F or -m option is allowed."
+msgstr ""
+
+#: builtin/tag.c:534
+msgid "too many params"
+msgstr "demasiado parametros"
+
+#: builtin/tag.c:540
+#, c-format
+msgid "'%s' is not a valid tag name."
+msgstr ""
+
+#: builtin/tag.c:545
+#, c-format
+msgid "tag '%s' already exists"
+msgstr "etiqueta '%s' já existe"
+
+#: builtin/tag.c:563
+#, c-format
+msgid "%s: cannot lock the ref"
+msgstr ""
+
+#: builtin/tag.c:565
+#, c-format
+msgid "%s: cannot update the ref"
+msgstr ""
+
+#: builtin/tag.c:567
+#, c-format
+msgid "Updated tag '%s' (was %s)\n"
+msgstr ""
+
+#: git-am.sh:49
+msgid "You need to set your committer info first"
+msgstr "Necessitas primeiro de especificiar os teus dados de committer"
+
+#: git-am.sh:136
+msgid "Repository lacks necessary blobs to fall back on 3-way merge."
+msgstr ""
+
+#: git-am.sh:147
+msgid ""
+"Did you hand edit your patch?\n"
+"It does not apply to blobs recorded in its index."
+msgstr ""
+
+#: git-am.sh:156
+msgid "Falling back to patching base and 3-way merge..."
+msgstr ""
+
+#: git-am.sh:268
+msgid "Only one StGIT patch series can be applied at once"
+msgstr ""
+
+#: git-am.sh:355
+#, sh-format
+msgid "Patch format $patch_format is not supported."
+msgstr ""
+
+#: git-am.sh:357
+msgid "Patch format detection failed."
+msgstr "Falhou a detecção do formato do patch."
+
+#: git-am.sh:411
+msgid "-d option is no longer supported. Do not use."
+msgstr ""
+
+#: git-am.sh:474
+#, sh-format
+msgid "previous rebase directory $dotest still exists but mbox given."
+msgstr ""
+
+#: git-am.sh:479
+msgid "Please make up your mind. --skip or --abort?"
+msgstr ""
+
+#: git-am.sh:506
+msgid "Resolve operation not in progress, we are not resuming."
+msgstr ""
+
+#: git-am.sh:572
+#, sh-format
+msgid "Dirty index: cannot apply patches (dirty: $files)"
+msgstr ""
+
+#: git-am.sh:748
+msgid "cannot be interactive without stdin connected to a terminal."
+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:759
+msgid "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all "
+msgstr "Aplicar? Sim[y]/[n]ão/[e]ditar/[v]er patch/[a]ceitar todos "
+
+#: git-am.sh:795
+#, sh-format
+msgid "Applying: $FIRSTLINE"
+msgstr "Aplicando: $FIRSTLINE"
+
+#: git-am.sh:840
+msgid "No changes -- Patch already applied."
+msgstr "Nenhuma mudança -- Já foi aplicado o patch."
+
+#: git-am.sh:866
+msgid "applying to an empty history"
+msgstr ""
+
+#. TRANSLATORS: Make sure to include [Y] and [n] in your
+#. translation. The program will only accept English input
+#. at this point.
+#: git-bisect.sh:54
+msgid "Do you want me to do it for you [Y/n]? "
+msgstr "Queres que eu faça por sí [Y/n]?"
+
+#: git-bisect.sh:95
+#, sh-format
+msgid "unrecognised option: '$arg'"
+msgstr ""
+
+#: git-bisect.sh:99
+#, sh-format
+msgid "'$arg' does not appear to be a valid revision"
+msgstr ""
+
+#: git-bisect.sh:117
+msgid "Bad HEAD - I need a HEAD"
+msgstr ""
+
+#: git-bisect.sh:130
+#, sh-format
+msgid "Checking out '$start_head' failed. Try 'git bisect reset <validbranch>'."
+msgstr ""
+
+#: git-bisect.sh:140
+msgid "won't bisect on seeked tree"
+msgstr ""
+
+#: git-bisect.sh:144
+msgid "Bad HEAD - strange symbolic ref"
+msgstr ""
+
+#: git-bisect.sh:189
+#, sh-format
+msgid "Bad bisect_write argument: $state"
+msgstr ""
+
+#: git-bisect.sh:218
+#, sh-format
+msgid "Bad rev input: $arg"
+msgstr ""
+
+#: git-bisect.sh:232
+msgid "Please call 'bisect_state' with at least one argument."
+msgstr ""
+
+#: git-bisect.sh:244
+#, sh-format
+msgid "Bad rev input: $rev"
+msgstr ""
+
+#: git-bisect.sh:250
+msgid "'git bisect bad' can take only one argument."
+msgstr ""
+
+#. 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 "Tens a certeza [Y/n]? "
+
+#: git-bisect.sh:354
+#, sh-format
+msgid "'$invalid' is not a valid commit"
+msgstr ""
+
+#: git-bisect.sh:363
+#, sh-format
+msgid ""
+"Could not check out original HEAD '$branch'.\n"
+"Try 'git bisect reset <commit>'."
+msgstr ""
+
+#: git-bisect.sh:390
+msgid "No logfile given"
+msgstr "Nenhum ficheiro de log dado"
+
+#: git-bisect.sh:391
+#, sh-format
+msgid "cannot read $file for replaying"
+msgstr ""
+
+#: git-bisect.sh:408
+msgid "?? what are you talking about?"
+msgstr ""
+
+#: git-bisect.sh:474
+msgid "We are not bisecting."
+msgstr ""
+
+#: git-pull.sh:21
+msgid ""
+"Pull is not possible because you have unmerged files.\n"
+"Please, fix them up in the work tree, and then use 'git add/rm <file>'\n"
+"as appropriate to mark resolution, or use 'git commit -a'."
+msgstr ""
+
+#: git-pull.sh:25
+msgid "Pull is not possible because you have unmerged files."
+msgstr ""
+
+#: git-pull.sh:197
+msgid "updating an unborn branch with changes added to the index"
+msgstr ""
+
+#: git-pull.sh:253
+msgid "Cannot merge multiple branches into empty head"
+msgstr ""
+
+#: git-pull.sh:257
+msgid "Cannot rebase onto multiple branches"
+msgstr "Não é possível fazer rebase com várias ramas"
+
+#: git-stash.sh:51
+msgid "git stash clear with parameters is unimplemented"
+msgstr ""
+
+#: git-stash.sh:74
+msgid "You do not have the initial commit yet"
+msgstr "Tu ainda não tens o commit inicial"
+
+#: git-stash.sh:89
+msgid "Cannot save the current index state"
+msgstr ""
+
+#: git-stash.sh:123
+#: git-stash.sh:136
+msgid "Cannot save the current worktree state"
+msgstr ""
+
+#: git-stash.sh:140
+msgid "No changes selected"
+msgstr "Não há alterações seleccionadas"
+
+#: git-stash.sh:143
+msgid "Cannot remove temporary index (can't happen)"
+msgstr ""
+
+#: git-stash.sh:156
+msgid "Cannot record working tree state"
+msgstr ""
+
+#: git-stash.sh:223
+msgid "No local changes to save"
+msgstr "Sem alterações locais para guardar"
+
+#: git-stash.sh:227
+msgid "Cannot initialize stash"
+msgstr "Não é possível inicializar o stash"
+
+#: git-stash.sh:235
+msgid "Cannot save the current status"
+msgstr ""
+
+#: git-stash.sh:253
+msgid "Cannot remove worktree changes"
+msgstr ""
+
+#: git-stash.sh:352
+msgid "No stash found."
+msgstr "nenhum stash encontrado."
+
+#: git-stash.sh:359
+#, sh-format
+msgid "Too many revisions specified: $REV"
+msgstr ""
+
+#: git-stash.sh:365
+#, sh-format
+msgid "$reference is not valid reference"
+msgstr ""
+
+#: git-stash.sh:393
+#, sh-format
+msgid "'$args' is not a stash-like commit"
+msgstr ""
+
+#: git-stash.sh:404
+#, sh-format
+msgid "'$args' is not a stash reference"
+msgstr ""
+
+#: git-stash.sh:412
+msgid "unable to refresh index"
+msgstr ""
+
+#: git-stash.sh:416
+msgid "Cannot apply a stash in the middle of a merge"
+msgstr ""
+
+#: git-stash.sh:424
+msgid "Conflicts in index. Try without --index."
+msgstr ""
+
+#: git-stash.sh:426
+msgid "Could not save index tree"
+msgstr "Não foi posivel guardar o index tree"
+
+#: git-stash.sh:460
+msgid "Cannot unstage modified files"
+msgstr ""
+
+#: git-stash.sh:491
+#, sh-format
+msgid "Dropped ${REV} ($s)"
+msgstr "Deixado cair ${REV} ($s)"
+
+#: git-stash.sh:492
+#, sh-format
+msgid "${REV}: Could not drop stash entry"
+msgstr ""
+
+#: git-stash.sh:499
+msgid "No branch name specified"
+msgstr "Nenhum nome para a rama especificado"
+
+#: git-stash.sh:570
+msgid "(To restore them type \"git stash apply\")"
+msgstr ""
+
+#: git-submodule.sh:56
+#, sh-format
+msgid "cannot strip one component off url '$remoteurl'"
+msgstr ""
+
+#: git-submodule.sh:108
+#, sh-format
+msgid "No submodule mapping found in .gitmodules for path '$path'"
+msgstr ""
+
+#: git-submodule.sh:149
+#, sh-format
+msgid "Clone of '$url' into submodule path '$path' failed"
+msgstr ""
+
+#: git-submodule.sh:159
+#, sh-format
+msgid "Gitdir '$a' is part of the submodule path '$b' or vice versa"
+msgstr ""
+
+#: git-submodule.sh:247
+#, sh-format
+msgid "repo URL: '$repo' must be absolute or begin with ./|../"
+msgstr ""
+
+#: git-submodule.sh:264
+#, sh-format
+msgid "'$path' already exists in the index"
+msgstr ""
+
+#: git-submodule.sh:281
+#, sh-format
+msgid "'$path' already exists and is not a valid git repo"
+msgstr ""
+
+#: git-submodule.sh:295
+#, sh-format
+msgid "Unable to checkout submodule '$path'"
+msgstr ""
+
+#: git-submodule.sh:300
+#, sh-format
+msgid "Failed to add submodule '$path'"
+msgstr ""
+
+#: git-submodule.sh:305
+#, sh-format
+msgid "Failed to register submodule '$path'"
+msgstr ""
+
+#: git-submodule.sh:347
+#, sh-format
+msgid "Entering '$prefix$path'"
+msgstr "Entrando '$prefix$path'"
+
+#: git-submodule.sh:359
+#, sh-format
+msgid "Stopping at '$path'; script returned non-zero status."
+msgstr ""
+
+#: git-submodule.sh:401
+#, sh-format
+msgid "No url found for submodule path '$path' in .gitmodules"
+msgstr ""
+
+#: git-submodule.sh:410
+#, sh-format
+msgid "Failed to register url for submodule path '$path'"
+msgstr ""
+
+#: git-submodule.sh:418
+#, sh-format
+msgid "Failed to register update mode for submodule path '$path'"
+msgstr ""
+
+#: git-submodule.sh:420
+#, sh-format
+msgid "Submodule '$name' ($url) registered for path '$path'"
+msgstr ""
+
+#: git-submodule.sh:519
+#, sh-format
+msgid ""
+"Submodule path '$path' not initialized\n"
+"Maybe you want to use 'update --init'?"
+msgstr ""
+
+#: git-submodule.sh:532
+#, sh-format
+msgid "Unable to find current revision in submodule path '$path'"
+msgstr ""
+
+#: git-submodule.sh:551
+#, sh-format
+msgid "Unable to fetch in submodule path '$path'"
+msgstr ""
+
+#: git-submodule.sh:565
+#, sh-format
+msgid "Unable to rebase '$sha1' in submodule path '$path'"
+msgstr ""
+
+#: git-submodule.sh:566
+#, sh-format
+msgid "Submodule path '$path': rebased into '$sha1'"
+msgstr ""
+
+#: git-submodule.sh:571
+#, sh-format
+msgid "Unable to merge '$sha1' in submodule path '$path'"
+msgstr ""
+
+#: git-submodule.sh:572
+#, sh-format
+msgid "Submodule path '$path': merged in '$sha1'"
+msgstr ""
+
+#: git-submodule.sh:577
+#, sh-format
+msgid "Unable to checkout '$sha1' in submodule path '$path'"
+msgstr ""
+
+#: git-submodule.sh:578
+#, sh-format
+msgid "Submodule path '$path': checked out '$sha1'"
+msgstr ""
+
+#: git-submodule.sh:600
+#: git-submodule.sh:923
+#, sh-format
+msgid "Failed to recurse into submodule path '$path'"
+msgstr ""
+
+#: git-submodule.sh:708
+msgid "--"
+msgstr "--"
+
+#: git-submodule.sh:766
+#, sh-format
+msgid " Warn: $name doesn't contain commit $sha1_src"
+msgstr ""
+
+#: git-submodule.sh:769
+#, sh-format
+msgid " Warn: $name doesn't contain commit $sha1_dst"
+msgstr ""
+
+#: git-submodule.sh:772
+#, sh-format
+msgid " Warn: $name doesn't contain commits $sha1_src and $sha1_dst"
+msgstr ""
+
+#: git-submodule.sh:797
+msgid "blob"
+msgstr "blob"
+
+#: git-submodule.sh:798
+msgid "submodule"
+msgstr "submódulos"
+
+#: git-submodule.sh:969
+#, sh-format
+msgid "Synchronizing submodule url for '$name'"
+msgstr ""
+
diff --git a/po/sv.po b/po/sv.po
new file mode 100644
index 0000000000..3a9059258a
--- /dev/null
+++ b/po/sv.po
@@ -0,0 +1,3907 @@
+# Swedish translations for Git.
+# Copyright (C) 2010-2012 Peter krefting <peter@softwolves.pp.se>
+# This file is distributed under the same license as the Git package.
+# Peter Krefting <peter@softwolves.pp.se>, 2010, 2011, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: git 1.7.10\n"
+"Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
+"POT-Creation-Date: 2012-05-15 06:31+0800\n"
+"PO-Revision-Date: 2012-05-28 22:35+0100\n"
+"Last-Translator: Peter Krefting <peter@softwolves.pp.se>\n"
+"Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n"
+"Language: sv\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: advice.c:40
+#, c-format
+msgid "hint: %.*s\n"
+msgstr "tips: %.*s\n"
+
+#.
+#. * Message used both when 'git commit' fails and when
+#. * other commands doing a merge do.
+#.
+#: advice.c:70
+msgid ""
+"Fix them up in the work tree,\n"
+"and then use 'git add/rm <file>' as\n"
+"appropriate to mark resolution and make a commit,\n"
+"or use 'git commit -a'."
+msgstr ""
+"Rätta dem i din arbetskatalog,\n"
+"och använd sedan \"git add/rm <fil>\" som\n"
+"lämpligt för att ange lösning och checka in,\n"
+"eller använd \"git commit -a\"."
+
+#: commit.c:47
+#, c-format
+msgid "could not parse %s"
+msgstr "kunde inte tolka %s"
+
+#: commit.c:49
+#, c-format
+msgid "%s %s is not a commit!"
+msgstr "%s %s är inte en incheckning!"
+
+#: compat/obstack.c:406 compat/obstack.c:408
+msgid "memory exhausted"
+msgstr "minnet slut"
+
+#: connected.c:39
+msgid "Could not run 'git rev-list'"
+msgstr "Kunde inte köra \"git rev-list\""
+
+#: connected.c:48
+#, c-format
+msgid "failed write to rev-list: %s"
+msgstr "kunde inte skriva till rev-list: %s"
+
+#: connected.c:56
+#, c-format
+msgid "failed to close rev-list's stdin: %s"
+msgstr "kunde inte stänga rev-list:s standard in: %s"
+
+#: diff.c:105
+#, c-format
+msgid " Failed to parse dirstat cut-off percentage '%.*s'\n"
+msgstr " Misslyckades tolka dirstat-avskärningsprocentandel \"%.*s\"\n"
+
+#: diff.c:110
+#, c-format
+msgid " Unknown dirstat parameter '%.*s'\n"
+msgstr " Okänd dirstat-parameter \"%.*s\"\n"
+
+#: diff.c:210
+#, c-format
+msgid ""
+"Found errors in 'diff.dirstat' config variable:\n"
+"%s"
+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:3439
+#, c-format
+msgid ""
+"Failed to parse --dirstat/-X option parameter:\n"
+"%s"
+msgstr ""
+"Misslyckades tolka argument till flaggan --dirstat/-X;\n"
+"%s"
+
+#: gpg-interface.c:59
+msgid "could not run gpg."
+msgstr "kunde inte köra gpg."
+
+#: gpg-interface.c:71
+msgid "gpg did not accept the data"
+msgstr "gpg godtog inte data"
+
+#: gpg-interface.c:82
+msgid "gpg failed to sign the data"
+msgstr "gpg misslyckades signera data"
+
+#: grep.c:1280
+#, c-format
+msgid "'%s': unable to read %s"
+msgstr "\"%s\" kunde inte läsa %s"
+
+#: grep.c:1297
+#, c-format
+msgid "'%s': %s"
+msgstr "\"%s\": %s"
+
+#: grep.c:1308
+#, c-format
+msgid "'%s': short read %s"
+msgstr "\"%s\": kort läsning %s"
+
+#: help.c:287
+#, 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\" verkar vara ett git-kommando, men vi kan inte\n"
+"köra det. Kanske git-%s är trasigt?"
+
+#: remote.c:1607
+#, 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:1613
+#, 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] ""
+"Din gren ligger efter \"%s\" med %d incheckning, och kan snabbspolas.\n"
+msgstr[1] ""
+"Din gren ligger efter \"%s\" med %d incheckningar, och kan snabbspolas.\n"
+
+#: remote.c:1621
+#, c-format
+msgid ""
+"Your branch and '%s' have diverged,\n"
+"and have %d and %d different commit each, respectively.\n"
+msgid_plural ""
+"Your branch and '%s' have diverged,\n"
+"and have %d and %d different commits each, respectively.\n"
+msgstr[0] ""
+"Din gren och \"%s\" har divergerat,\n"
+"och har %d respektive %d olika incheckning.\n"
+msgstr[1] ""
+"Din gren och \"%s\" har divergerat,\n"
+"och har %d respektive %d olika incheckningar.\n"
+
+#: sequencer.c:120 builtin/merge.c:865 builtin/merge.c:978
+#: builtin/merge.c:1088 builtin/merge.c:1098
+#, c-format
+msgid "Could not open '%s' for writing"
+msgstr "Kunde inte öppna \"%s\" för skrivning"
+
+#: sequencer.c:122 builtin/merge.c:333 builtin/merge.c:868
+#: builtin/merge.c:1090 builtin/merge.c:1103
+#, c-format
+msgid "Could not write to '%s'"
+msgstr "Kunde inte skriva till \"%s\""
+
+#: sequencer.c:143
+msgid ""
+"after resolving the conflicts, mark the corrected paths\n"
+"with 'git add <paths>' or 'git rm <paths>'"
+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:146
+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 ""
+"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>\"\n"
+"och checka in resultatet med \"git commit\""
+
+#: sequencer.c:159 sequencer.c:685 sequencer.c:768
+#, c-format
+msgid "Could not write to %s"
+msgstr "Kunde inte skriva till %s"
+
+#: sequencer.c:162
+#, c-format
+msgid "Error wrapping up %s"
+msgstr "Fel vid ombrytning av %s"
+
+#: sequencer.c:177
+msgid "Your local changes would be overwritten by cherry-pick."
+msgstr "Dina lokala ändringar skulle skrivas över av \"cherry-pick\"."
+
+#: sequencer.c:179
+msgid "Your local changes would be overwritten by revert."
+msgstr "Dina lokala ändringar skulle skrivas över av \"revert\"."
+
+#: sequencer.c:182
+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:232
+#, c-format
+msgid "%s: Unable to write new index file"
+msgstr "%s: Kunde inte skriva ny indexfil"
+
+#: sequencer.c:298
+msgid "Your index file is unmerged."
+msgstr "Din indexfil har inte slagits ihop."
+
+#: sequencer.c:301
+msgid "You do not have a valid HEAD"
+msgstr "Du har ingen giltig HEAD"
+
+#: sequencer.c:316
+#, 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:324
+#, c-format
+msgid "Commit %s does not have parent %d"
+msgstr "Incheckning %s har inte förälder %d"
+
+#: sequencer.c:328
+#, 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:339
+#, c-format
+msgid "%s: cannot parse parent commit %s"
+msgstr "%s: kan inte tolka föräldraincheckningen %s"
+
+#: sequencer.c:343
+#, c-format
+msgid "Cannot get commit message for %s"
+msgstr "Kan inte hämta incheckningsmeddelande för %s"
+
+#: sequencer.c:427
+#, c-format
+msgid "could not revert %s... %s"
+msgstr "kunde inte ångra %s... %s"
+
+#: sequencer.c:428
+#, c-format
+msgid "could not apply %s... %s"
+msgstr "kunde inte applicera %s... %s"
+
+#: sequencer.c:450 sequencer.c:909 builtin/log.c:288 builtin/log.c:713
+#: builtin/log.c:1329 builtin/log.c:1548 builtin/merge.c:347
+#: builtin/shortlog.c:181
+msgid "revision walk setup failed"
+msgstr "misslyckades skapa revisionstraversering"
+
+#: sequencer.c:453
+msgid "empty commit set passed"
+msgstr "den angivna uppsättningen incheckningar är tom"
+
+#: sequencer.c:461
+#, c-format
+msgid "git %s: failed to read the index"
+msgstr "git %s: misslyckades läsa indexet"
+
+#: sequencer.c:466
+#, c-format
+msgid "git %s: failed to refresh the index"
+msgstr "git %s: misslyckades uppdatera indexet"
+
+#: sequencer.c:551
+#, c-format
+msgid "Cannot %s during a %s"
+msgstr "kan inte %s under en %s"
+
+#: sequencer.c:573
+#, c-format
+msgid "Could not parse line %d."
+msgstr "Kan inte tolka rad %d."
+
+#: sequencer.c:578
+msgid "No commits parsed."
+msgstr "Inga incheckningar lästes."
+
+#: sequencer.c:591
+#, c-format
+msgid "Could not open %s"
+msgstr "Kunde inte öppna %s"
+
+#: sequencer.c:595
+#, c-format
+msgid "Could not read %s."
+msgstr "kunde inte läsa %s."
+
+#: sequencer.c:602
+#, c-format
+msgid "Unusable instruction sheet: %s"
+msgstr "Oanvändbart manus: %s"
+
+#: sequencer.c:630
+#, c-format
+msgid "Invalid key: %s"
+msgstr "Felaktig nyckel: %s"
+
+#: sequencer.c:633
+#, c-format
+msgid "Invalid value for %s: %s"
+msgstr "Felaktigt värde för %s: %s"
+
+#: sequencer.c:645
+#, c-format
+msgid "Malformed options sheet: %s"
+msgstr "Trasigt manus: %s"
+
+#: sequencer.c:666
+msgid "a cherry-pick or revert is already in progress"
+msgstr "en \"cherry-pick\" eller \"revert\" pågår redan"
+
+#: sequencer.c:667
+msgid "try \"git cherry-pick (--continue | --quit | --abort)\""
+msgstr "testa \"git cherry-pick (--continue | --quit | --abort)\""
+
+#: sequencer.c:671
+#, c-format
+msgid "Could not create sequencer directory %s"
+msgstr "Kunde inte skapa \"sequencer\"-katalogen \"%s\""
+
+#: sequencer.c:687 sequencer.c:772
+#, c-format
+msgid "Error wrapping up %s."
+msgstr "Fel vid ombrytning av %s."
+
+#: sequencer.c:706 sequencer.c:840
+msgid "no cherry-pick or revert in progress"
+msgstr "ingen \"cherry-pick\" eller \"revert\" pågår"
+
+#: sequencer.c:708
+msgid "cannot resolve HEAD"
+msgstr "kan inte bestämma HEAD"
+
+#: sequencer.c:710
+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:732
+#, c-format
+msgid "cannot open %s: %s"
+msgstr "kan inte öppna %s: %s"
+
+#: sequencer.c:735
+#, c-format
+msgid "cannot read %s: %s"
+msgstr "kan inte läsa %s: %s"
+
+#: sequencer.c:736
+msgid "unexpected end of file"
+msgstr "oväntat filslut"
+
+#: sequencer.c:742
+#, 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:765
+#, c-format
+msgid "Could not format %s."
+msgstr "Kunde inte formatera %s."
+
+#: sequencer.c:927
+msgid "Can't revert as initial commit"
+msgstr "Kan inte ångra som första incheckning"
+
+#: sequencer.c:928
+msgid "Can't cherry-pick into empty head"
+msgstr "Kan inte göra \"cherry-pick\" i ett tomt huvud"
+
+#: wt-status.c:134
+msgid "Unmerged paths:"
+msgstr "Ej sammanslagna sökvägar:"
+
+#: wt-status.c:140 wt-status.c:157
+#, 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:142 wt-status.c:159
+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:143
+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:151
+msgid "Changes to be committed:"
+msgstr "Ändringar att checka in:"
+
+#: wt-status.c:169
+msgid "Changes not staged for commit:"
+msgstr "Ändringar ej i incheckningskön:"
+
+#: wt-status.c:173
+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:175
+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:176
+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:178
+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:187
+#, c-format
+msgid "%s files:"
+msgstr "%se filer:"
+
+#: wt-status.c:190
+#, 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)"
+
+#: wt-status.c:207
+msgid "bug"
+msgstr "programfel"
+
+#: wt-status.c:212
+msgid "both deleted:"
+msgstr "borttaget av bägge:"
+
+#: wt-status.c:213
+msgid "added by us:"
+msgstr "tillagt av oss:"
+
+#: wt-status.c:214
+msgid "deleted by them:"
+msgstr "borttaget av dem:"
+
+#: wt-status.c:215
+msgid "added by them:"
+msgstr "tillagt av dem:"
+
+#: wt-status.c:216
+msgid "deleted by us:"
+msgstr "borttaget av oss:"
+
+#: wt-status.c:217
+msgid "both added:"
+msgstr "tillagt av bägge:"
+
+#: wt-status.c:218
+msgid "both modified:"
+msgstr "ändrat av bägge:"
+
+#: wt-status.c:248
+msgid "new commits, "
+msgstr "nya incheckningar, "
+
+#: wt-status.c:250
+msgid "modified content, "
+msgstr "ändrat innehåll, "
+
+#: wt-status.c:252
+msgid "untracked content, "
+msgstr "ospårat innehåll, "
+
+#: wt-status.c:266
+#, c-format
+msgid "new file: %s"
+msgstr "ny fil: %s"
+
+#: wt-status.c:269
+#, c-format
+msgid "copied: %s -> %s"
+msgstr "kopierad: %s -> %s"
+
+#: wt-status.c:272
+#, c-format
+msgid "deleted: %s"
+msgstr "borttagen: %s"
+
+#: wt-status.c:275
+#, c-format
+msgid "modified: %s"
+msgstr "ändrad: %s"
+
+#: wt-status.c:278
+#, c-format
+msgid "renamed: %s -> %s"
+msgstr "namnbyte: %s -> %s"
+
+#: wt-status.c:281
+#, c-format
+msgid "typechange: %s"
+msgstr "typbyte: %s"
+
+#: wt-status.c:284
+#, c-format
+msgid "unknown: %s"
+msgstr "okänd: %s"
+
+#: wt-status.c:287
+#, c-format
+msgid "unmerged: %s"
+msgstr "osammansl.: %s"
+
+#: wt-status.c:290
+#, c-format
+msgid "bug: unhandled diff status %c"
+msgstr "programfel: diff-status %c ej hanterad"
+
+#: wt-status.c:713
+msgid "On branch "
+msgstr "På grenen "
+
+#: wt-status.c:720
+msgid "Not currently on any branch."
+msgstr "Inte på någon gren för närvarande."
+
+#: wt-status.c:731
+msgid "Initial commit"
+msgstr "Första incheckning"
+
+#: wt-status.c:745
+msgid "Untracked"
+msgstr "Ospårad"
+
+#: wt-status.c:747
+msgid "Ignored"
+msgstr "Ignorerad"
+
+# %s är nästa sträng eller tom.
+#: wt-status.c:749
+#, c-format
+msgid "Untracked files not listed%s"
+msgstr "Ospårade filer visas ej%s"
+
+#: wt-status.c:751
+msgid " (use -u option to show untracked files)"
+msgstr " (använd flaggan -u för att visa ospårade filer)"
+
+#: wt-status.c:757
+msgid "No changes"
+msgstr "Inga ändringar"
+
+#: wt-status.c:761
+#, c-format
+msgid "no changes added to commit%s\n"
+msgstr "inga ändringar att checka in%s\n"
+
+#: wt-status.c:763
+msgid " (use \"git add\" and/or \"git commit -a\")"
+msgstr " (använd \"git add\" och/eller \"git commit -a\")"
+
+#: wt-status.c:765
+#, 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"
+
+#: wt-status.c:767
+msgid " (use \"git add\" to track)"
+msgstr " (använd \"git add\" för att spåra)"
+
+#: wt-status.c:769 wt-status.c:772 wt-status.c:775
+#, c-format
+msgid "nothing to commit%s\n"
+msgstr "inget att checka in%s\n"
+
+#: wt-status.c:770
+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:773
+msgid " (use -u to show untracked files)"
+msgstr " (använd -u för att visa ospårade filer)"
+
+#: wt-status.c:776
+msgid " (working directory clean)"
+msgstr " (arbetskatalogen ren)"
+
+#: wt-status.c:884
+msgid "HEAD (no branch)"
+msgstr "HEAD (ingen gren)"
+
+#: wt-status.c:890
+msgid "Initial commit on "
+msgstr "Första incheckning på "
+
+#: wt-status.c:905
+msgid "behind "
+msgstr "efter "
+
+#: wt-status.c:908 wt-status.c:911
+msgid "ahead "
+msgstr "före "
+
+#: wt-status.c:913
+msgid ", behind "
+msgstr ", efter "
+
+#: 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:298
+msgid "updating files failed"
+msgstr "misslyckades uppdatera filer"
+
+#: builtin/add.c:77
+#, c-format
+msgid "remove '%s'\n"
+msgstr "ta bort \"%s\"\n"
+
+#: builtin/add.c:176
+#, c-format
+msgid "Path '%s' is in submodule '%.*s'"
+msgstr "Sökvägen \"%s\" är i undermodulen \"%.*s\""
+
+#: builtin/add.c:192
+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
+#, c-format
+msgid "pathspec '%s' did not match any files"
+msgstr "sökvägsangivelsen \"%s\" motsvarade inte några filer"
+
+#: builtin/add.c:209
+#, c-format
+msgid "'%s' is beyond a symbolic link"
+msgstr "\"%s\" är på andra sidan av en symbolisk länk"
+
+#: builtin/add.c:276
+msgid "Could not read the index"
+msgstr "Kunde inte läsa indexet"
+
+#: builtin/add.c:286
+#, c-format
+msgid "Could not open '%s' for writing."
+msgstr "Kunde inte öppna \"%s\" för skrivning"
+
+#: builtin/add.c:290
+msgid "Could not write patch"
+msgstr "Kunde inte skriva patch"
+
+#: builtin/add.c:295
+#, c-format
+msgid "Could not stat '%s'"
+msgstr "Kunde inte ta status på \"%s\""
+
+#: builtin/add.c:297
+msgid "Empty patch. Aborted."
+msgstr "Tom patch. Avbryter."
+
+#: builtin/add.c:303
+#, c-format
+msgid "Could not apply '%s'"
+msgstr "Kunde inte applicera \"%s\""
+
+#: builtin/add.c:312
+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
+#, 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
+msgid "no files added"
+msgstr "inga filer har lagts till"
+
+#: builtin/add.c:359
+msgid "adding files failed"
+msgstr "misslyckades lägga till filer"
+
+#: builtin/add.c:391
+msgid "-A and -u are mutually incompatible"
+msgstr "-A och -u är ömsesidigt inkompatibla"
+
+#: builtin/add.c:393
+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
+#, c-format
+msgid "Nothing specified, nothing added.\n"
+msgstr "Inget angivet, inget tillagt.\n"
+
+#: builtin/add.c:414
+#, 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:358 builtin/mv.c:82
+#: builtin/rm.c:162
+msgid "index file corrupt"
+msgstr "indexfilen trasig"
+
+#: builtin/add.c:476 builtin/mv.c:229 builtin/rm.c:260
+msgid "Unable to write new index file"
+msgstr "Kunde inte skriva ny indexfil"
+
+#: builtin/archive.c:17
+#, c-format
+msgid "could not create archive file '%s'"
+msgstr "Kunde inte skapa arkivfilen \"%s\""
+
+#: builtin/archive.c:20
+msgid "could not redirect output"
+msgstr "kunde inte omdirigera utdata"
+
+#: builtin/archive.c:37
+msgid "git archive: Remote with no URL"
+msgstr "git archive: Fjärr utan URL"
+
+#: builtin/archive.c:58
+msgid "git archive: expected ACK/NAK, got EOF"
+msgstr "git archive: förväntade ACK/NAK, fick EOF"
+
+#: builtin/archive.c:63
+#, c-format
+msgid "git archive: NACK %s"
+msgstr "git archive: NACK %s"
+
+#: builtin/archive.c:65
+#, c-format
+msgid "remote error: %s"
+msgstr "fjärrfel: %s"
+
+#: builtin/archive.c:66
+msgid "git archive: protocol error"
+msgstr "git archive: protokollfel"
+
+#: builtin/archive.c:71
+msgid "git archive: expected a flush"
+msgstr "git archive: förväntade en tömning (flush)"
+
+#: builtin/branch.c:137
+#, 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:141
+#, c-format
+msgid ""
+"not deleting branch '%s' that is not yet merged to\n"
+" '%s', even though it is merged to HEAD."
+msgstr ""
+"tar inte bort grenen \"%s\" som inte har slagits ihop med\n"
+" \"%s\", trots att den har slagits ihop med HEAD."
+
+#. TRANSLATORS: This is "remote " in "remote branch '%s' not found"
+#: builtin/branch.c:163
+msgid "remote "
+msgstr "fjärr"
+
+#: builtin/branch.c:171
+msgid "cannot use -a with -d"
+msgstr "kan inte ange -a med -d"
+
+#: builtin/branch.c:177
+msgid "Couldn't look up commit object for HEAD"
+msgstr "Kunde inte slå upp incheckningsobjekt för HEAD"
+
+#: builtin/branch.c:182
+#, 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:192
+#, c-format
+msgid "%sbranch '%s' not found."
+msgstr "%sgrenen \"%s\" hittades inte."
+
+#: builtin/branch.c:200
+#, c-format
+msgid "Couldn't look up commit object for '%s'"
+msgstr "Kunde inte slå upp incheckningsobjekt för \"%s\""
+
+#: builtin/branch.c:206
+#, c-format
+msgid ""
+"The branch '%s' is not fully merged.\n"
+"If you are sure you want to delete it, run 'git branch -D %s'."
+msgstr ""
+"Grenen \"%s\" har inte slagits samman i sin helhet.\n"
+"Om du är säker på att du vill ta bort den, kör \"git branch -D %s\"."
+
+#: builtin/branch.c:214
+#, c-format
+msgid "Error deleting %sbranch '%s'"
+msgstr "Fel vid borttagning av %sgrenen \"%s\""
+
+#: builtin/branch.c:219
+#, c-format
+msgid "Deleted %sbranch %s (was %s).\n"
+msgstr "Tog bort %sgrenen %s (var %s).\n"
+
+#: builtin/branch.c:224
+msgid "Update of config-file failed"
+msgstr "Misslyckades uppdatera konfigurationsfil"
+
+#: builtin/branch.c:322
+#, c-format
+msgid "branch '%s' does not point at a commit"
+msgstr "grenen \"%s\" pekar inte på en incheckning"
+
+#: builtin/branch.c:394
+#, c-format
+msgid "behind %d] "
+msgstr "bakom %d] "
+
+#: builtin/branch.c:396
+#, c-format
+msgid "ahead %d] "
+msgstr "före %d] "
+
+#: builtin/branch.c:398
+#, c-format
+msgid "ahead %d, behind %d] "
+msgstr "före %d, bakom %d] "
+
+#: builtin/branch.c:501
+msgid "(no branch)"
+msgstr "(ingen gren)"
+
+#: builtin/branch.c:566
+msgid "some refs could not be read"
+msgstr "vissa referenser kunde inte läsas"
+
+#: builtin/branch.c:579
+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:589
+#, c-format
+msgid "Invalid branch name: '%s'"
+msgstr "Felaktigt namn på gren: \"%s\""
+
+#: builtin/branch.c:604
+msgid "Branch rename failed"
+msgstr "Misslyckades byta namn på gren"
+
+#: builtin/branch.c:608
+#, c-format
+msgid "Renamed a misnamed branch '%s' away"
+msgstr "Bytte bort namn på en felaktigt namngiven gren \"%s\""
+
+#: builtin/branch.c:612
+#, 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:619
+msgid "Branch is renamed, but update of config-file failed"
+msgstr "Grenen namnbytt, men misslyckades uppdatera konfigurationsfilen"
+
+#: builtin/branch.c:634
+#, c-format
+msgid "malformed object name %s"
+msgstr "felformat objektnamn %s"
+
+#: builtin/branch.c:658
+#, c-format
+msgid "could not write branch description template: %s\n"
+msgstr "kunde inte skriva grenbeskrivningsmall: %s\n"
+
+#: builtin/branch.c:746
+msgid "Failed to resolve HEAD as a valid ref."
+msgstr "Misslyckades slå upp HEAD som giltig referens"
+
+#: builtin/branch.c:751 builtin/clone.c:558
+msgid "HEAD not found below refs/heads!"
+msgstr "HEAD hittades inte under refs/heads!"
+
+#: builtin/branch.c:809
+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/bundle.c:47
+#, c-format
+msgid "%s is okay\n"
+msgstr "%s är okej\n"
+
+#: builtin/bundle.c:56
+msgid "Need a repository to create a bundle."
+msgstr "Behöver ett arkiv för att skapa ett paket (bundle)."
+
+#: builtin/bundle.c:60
+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
+#, 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
+#, c-format
+msgid "path '%s' does not have their version"
+msgstr "sökvägen \"%s\" har inte deras version"
+
+#: builtin/checkout.c:131
+#, 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
+#, 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
+#, c-format
+msgid "path '%s': cannot merge"
+msgstr "sökväg \"%s\": kan inte slå ihop"
+
+#: builtin/checkout.c:209
+#, c-format
+msgid "Unable to add merge result for '%s'"
+msgstr "Kunde inte lägga till sammanslagningsresultat för \"%s\""
+
+#: builtin/checkout.c:212 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/checkout.c:234 builtin/checkout.c:392
+msgid "corrupt index file"
+msgstr "indexfilen är trasig"
+
+#: builtin/checkout.c:264 builtin/checkout.c:271
+#, 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
+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
+msgid "you need to resolve your current index first"
+msgstr "du måste lösa ditt befintliga index först"
+
+#: builtin/checkout.c:533
+#, c-format
+msgid "Can not do reflog for '%s'\n"
+msgstr "Kan inte skapa referenslog för \"%s\"\n"
+
+#: builtin/checkout.c:565
+msgid "HEAD is now at"
+msgstr "HEAD är nu på"
+
+#: builtin/checkout.c:572
+#, c-format
+msgid "Reset branch '%s'\n"
+msgstr "Återställ gren \"%s\"\n"
+
+#: builtin/checkout.c:575
+#, c-format
+msgid "Already on '%s'\n"
+msgstr "Redan på \"%s\"\n"
+
+#: builtin/checkout.c:579
+#, c-format
+msgid "Switched to and reset branch '%s'\n"
+msgstr "Växlade till och nollställde grenen \"%s\"\n"
+
+#: builtin/checkout.c:581
+#, c-format
+msgid "Switched to a new branch '%s'\n"
+msgstr "Växlade till en ny gren \"%s\"\n"
+
+#: builtin/checkout.c:583
+#, c-format
+msgid "Switched to branch '%s'\n"
+msgstr "Växlade till grenen \"%s\"\n"
+
+#: builtin/checkout.c:639
+#, c-format
+msgid " ... and %d more.\n"
+msgstr " ... och %d till.\n"
+
+#. The singular version
+#: builtin/checkout.c:645
+#, 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"
+"\n"
+"%s\n"
+msgstr[0] ""
+"Varning: du lämnar %d incheckning bakom dig som inte är ansluten till\n"
+"någon av dina grenar:\n"
+"\n"
+"%s\n"
+msgstr[1] ""
+"Varning: du lämnar %d incheckningar bakom dig som inte är ansluta till\n"
+"någon av dina grenar:\n"
+"\n"
+"%s\n"
+
+#: builtin/checkout.c:663
+#, 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"
+msgstr ""
+"Om du vill behålla dem genom att skapa en ny gren är nu en bra tidpunkt\n"
+"att göra så, med:\n"
+"\n"
+" git branch nytt_grennamn %s\n"
+"\n"
+
+#: builtin/checkout.c:693
+msgid "internal error in revision walk"
+msgstr "internt fel vid genomgång av revisioner (revision walk)"
+
+#: builtin/checkout.c:697
+msgid "Previous HEAD position was"
+msgstr "Tidigare position för HEAD var"
+
+#: builtin/checkout.c:723
+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:854
+#, c-format
+msgid "invalid reference: %s"
+msgstr "felaktig referens: %s"
+
+#. case (1): want a tree
+#: builtin/checkout.c:893
+#, c-format
+msgid "reference is not a tree: %s"
+msgstr "referensen är inte ett träd: %s"
+
+#: builtin/checkout.c:973
+msgid "-B cannot be used with -b"
+msgstr "-B kan inte användas med -b"
+
+#: builtin/checkout.c:982
+msgid "--patch is incompatible with all other options"
+msgstr "--patch är inkompatibel med alla andra flaggor"
+
+#: builtin/checkout.c:985
+msgid "--detach cannot be used with -b/-B/--orphan"
+msgstr "--detcah kan inte användas med -b/-B/--orphan"
+
+#: builtin/checkout.c:987
+msgid "--detach cannot be used with -t"
+msgstr "--detach kan inte användas med -t"
+
+#: builtin/checkout.c:993
+msgid "--track needs a branch name"
+msgstr "--track behöver ett namn på en gren"
+
+#: builtin/checkout.c:1000
+msgid "Missing branch name; try -b"
+msgstr "Grennamn saknas; försök med -b"
+
+#: builtin/checkout.c:1006
+msgid "--orphan and -b|-B are mutually exclusive"
+msgstr "--orphan och -b|-B kan inte användas samtidigt"
+
+#: builtin/checkout.c:1008
+msgid "--orphan cannot be used with -t"
+msgstr "--orphan kan inte användas med -t"
+
+#: builtin/checkout.c:1018
+msgid "git checkout: -f and -m are incompatible"
+msgstr "git checkout: -f och -m är inkompatibla"
+
+#: builtin/checkout.c:1052
+msgid "invalid path specification"
+msgstr "felaktig sökvägsangivelse"
+
+#: builtin/checkout.c:1060
+#, 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?"
+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?"
+
+#: builtin/checkout.c:1062
+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:1067
+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:1070
+msgid ""
+"git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
+"checking out of the index."
+msgstr ""
+"git checkout: --ours/--theirs, --force och --merge är inkompatibla när\n"
+"du checkar ut från indexet."
+
+#: builtin/checkout.c:1089
+msgid "Cannot switch branch to a non-commit."
+msgstr "Kan inte växla gren på en icke-incheckning."
+
+#: builtin/checkout.c:1092
+msgid "--ours/--theirs is incompatible with switching branches."
+msgstr "--ours/--theirs är inkompatibla med att byta gren."
+
+#: builtin/clean.c:78
+msgid "-x and -X cannot be used together"
+msgstr "-x och -X kan inte användas samtidigt"
+
+#: builtin/clean.c:82
+msgid ""
+"clean.requireForce set to true and neither -n nor -f given; refusing to clean"
+msgstr ""
+"clean.requireForce satt till true, men varken -n eller -f angavs; vägrar "
+"städa"
+
+#: builtin/clean.c:85
+msgid ""
+"clean.requireForce defaults to true and neither -n nor -f given; refusing to "
+"clean"
+msgstr ""
+"clean.requireForce har standardvärdet true, men varken -n eller -f angavs; "
+"vägrar städa"
+
+#: builtin/clean.c:155 builtin/clean.c:176
+#, c-format
+msgid "Would remove %s\n"
+msgstr "Skulle ta bort %s\n"
+
+#: builtin/clean.c:159 builtin/clean.c:179
+#, c-format
+msgid "Removing %s\n"
+msgstr "Tar bort %s\n"
+
+#: builtin/clean.c:162 builtin/clean.c:182
+#, c-format
+msgid "failed to remove %s"
+msgstr "misslyckades ta bort %s"
+
+#: builtin/clean.c:166
+#, c-format
+msgid "Would not remove %s\n"
+msgstr "Skulle inte ta bort %s\n"
+
+#: builtin/clean.c:168
+#, c-format
+msgid "Not removing %s\n"
+msgstr "Tar inte bort %s\n"
+
+#: 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
+#, c-format
+msgid "failed to stat '%s'"
+msgstr "misslyckades ta status på \"%s\""
+
+#: builtin/clone.c:310
+#, c-format
+msgid "%s exists and is not a directory"
+msgstr "%s finns och är ingen katalog"
+
+#: builtin/clone.c:324
+#, c-format
+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'"
+msgstr "misslyckades skapa länken \"%s\""
+
+#: builtin/clone.c:350
+#, c-format
+msgid "failed to copy file to '%s'"
+msgstr "misslyckades kopiera filen till \"%s\""
+
+#: builtin/clone.c:373
+#, c-format
+msgid "done.\n"
+msgstr "klart.\n"
+
+#: builtin/clone.c:440
+#, 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
+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
+msgid "Too many arguments."
+msgstr "För många argument."
+
+#: builtin/clone.c:643
+msgid "You must specify a repository to clone."
+msgstr "Du måste ange ett arkiv att klona."
+
+#: builtin/clone.c:654
+#, c-format
+msgid "--bare and --origin %s options are incompatible."
+msgstr "flaggorna --bare och --origin %s är inkompatibla."
+
+#: builtin/clone.c:668
+#, c-format
+msgid "repository '%s' does not exist"
+msgstr "arkivet \"%s\" finns inte"
+
+#: builtin/clone.c:673
+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
+#, 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
+#, c-format
+msgid "working tree '%s' already exists."
+msgstr "arbetsträdet \"%s\" finns redan."
+
+#: builtin/clone.c:706 builtin/clone.c:720
+#, c-format
+msgid "could not create leading directories of '%s'"
+msgstr "kunde inte skapa inledande kataloger för \"%s\""
+
+#: builtin/clone.c:709
+#, c-format
+msgid "could not create work tree dir '%s'."
+msgstr "kunde inte skapa arbetskatalogen \"%s\""
+
+#: builtin/clone.c:728
+#, c-format
+msgid "Cloning into bare repository '%s'...\n"
+msgstr "Klonar till ett naket arkiv \"%s\"...\n"
+
+#: builtin/clone.c:730
+#, c-format
+msgid "Cloning into '%s'...\n"
+msgstr "Klonar till \"%s\"...\n"
+
+#: builtin/clone.c:786
+#, c-format
+msgid "Don't know how to clone %s"
+msgstr "Vet inte hur man klonar %s"
+
+#: builtin/clone.c:835
+#, 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
+msgid "You appear to have cloned an empty repository."
+msgstr "Du verkar ha klonat ett tomt arkiv."
+
+#: builtin/commit.c:42
+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 ""
+"Ditt namn och e-postadress konfigurerades automatiskt baserat på\n"
+"ditt användar-id och värdnamn. Kontrollera att de är riktiga. Du\n"
+"kan förhindra det här meddelandet genom att ställa dem explicit:\n"
+"\n"
+" git config --global user.name \"Ditt namn\"\n"
+" git config --global user.email du@example.com\n"
+"\n"
+"När du gjort det kan du rätta identiteten som användes för den här\n"
+"incheckningen med:\n"
+"\n"
+" git commit --amend --reset-author\n"
+
+#: builtin/commit.c:54
+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 ""
+"Du bad om att utöka den senaste incheckningen, men om du gör det\n"
+"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:59
+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 ""
+"Den tidigare \"cherry-pick\":en är nu tom, kanske på grund av en löst\n"
+"konflikt. Om du vill checka in den ändå använder du:\n"
+"\n"
+" git commit --allow-empty\n"
+"\n"
+"Annars använder du \"git reset\"\n"
+
+#: builtin/commit.c:205 builtin/reset.c:33
+msgid "merge"
+msgstr "sammanslagning"
+
+#: builtin/commit.c:208
+msgid "cherry-pick"
+msgstr "cherry-pick"
+
+#: builtin/commit.c:325
+msgid "failed to unpack HEAD tree object"
+msgstr "misslyckades packa upp HEAD:s trädobjekt"
+
+#: builtin/commit.c:367
+msgid "unable to create temporary index"
+msgstr "kunde inte skapa temporär indexfil"
+
+#: builtin/commit.c:373
+msgid "interactive add failed"
+msgstr "interaktiv tilläggning misslyckades"
+
+#: builtin/commit.c:406 builtin/commit.c:427 builtin/commit.c:473
+msgid "unable to write new_index file"
+msgstr "kunde inte skriva filen new_index"
+
+# %s är antingen "merge" eller "cherry-pick".
+#: builtin/commit.c:457
+#, c-format
+msgid "cannot do a partial commit during a %s."
+msgstr "kan inte utföra en delvis incheckning under en %s"
+
+#: builtin/commit.c:466
+msgid "cannot read the index"
+msgstr "kan inte läsa indexet"
+
+#: builtin/commit.c:486
+msgid "unable to write temporary index file"
+msgstr "kunde inte skriva temporär indexfil"
+
+#: builtin/commit.c:561 builtin/commit.c:567
+#, c-format
+msgid "invalid commit: %s"
+msgstr "felaktig incheckning: %s"
+
+#: builtin/commit.c:590
+msgid "malformed --author parameter"
+msgstr "felformad \"--author\"-flagga"
+
+#: builtin/commit.c:651
+#, c-format
+msgid "Malformed ident string: '%s'"
+msgstr "Felaktig indragningssträng: \"%s\""
+
+#: builtin/commit.c:689 builtin/commit.c:722 builtin/commit.c:1033
+#, c-format
+msgid "could not lookup commit %s"
+msgstr "kunde inte slå upp incheckningen %s"
+
+#: builtin/commit.c:701 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:703
+msgid "could not read log from standard input"
+msgstr "kunde inte läsa logg från standard in"
+
+#: builtin/commit.c:707
+#, c-format
+msgid "could not read log file '%s'"
+msgstr "kunde inte läsa loggfilen \"%s\""
+
+#: builtin/commit.c:713
+msgid "commit has empty message"
+msgstr "incheckningen har ett tomt meddelande"
+
+#: builtin/commit.c:729
+msgid "could not read MERGE_MSG"
+msgstr "kunde inte läsa MERGE_MSG"
+
+#: builtin/commit.c:733
+msgid "could not read SQUASH_MSG"
+msgstr "kunde inte läsa SQUASH_MSG"
+
+#: builtin/commit.c:737
+#, c-format
+msgid "could not read '%s'"
+msgstr "kunde inte läsa \"%s\""
+
+#: builtin/commit.c:765
+#, c-format
+msgid "could not open '%s'"
+msgstr "kunde inte öppna \"%s\""
+
+#: builtin/commit.c:789
+msgid "could not write commit template"
+msgstr "kunde inte skriva incheckningsmall"
+
+# %s är "merge" eller "cherry-pick"
+#: builtin/commit.c:799
+#, c-format
+msgid ""
+"\n"
+"It looks like you may be committing a %s.\n"
+"If this is not correct, please remove the file\n"
+"\t%s\n"
+"and try again.\n"
+msgstr ""
+"\n"
+"Det verkar som du checkar in en %s.\n"
+"Om det inte stämmer tar du bort filen\n"
+"\t%s\n"
+"och försöker igen.\n"
+
+#: builtin/commit.c:812
+msgid "Please enter the commit message for your changes."
+msgstr "Ange ett incheckningsmeddelande för dina ändringar."
+
+#: builtin/commit.c:815
+msgid ""
+" Lines starting\n"
+"with '#' will be ignored, and an empty message aborts the commit.\n"
+msgstr ""
+" Rader som inleds\n"
+"med \"#\" kommer ignoreras, och ett tomt meddelande avbryter incheckningen.\n"
+
+#: builtin/commit.c:820
+msgid ""
+" 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 ""
+" Rader som inleds\n"
+"med \"#\" kommer behållas; du kan själv ta bort dem om du vill.\n"
+"Ett tomt meddelande avbryter incheckningen.\n"
+
+#: builtin/commit.c:832
+#, c-format
+msgid "%sAuthor: %s"
+msgstr "%sFörfattare: %s"
+
+#: builtin/commit.c:839
+#, c-format
+msgid "%sCommitter: %s"
+msgstr "%sIncheckare: %s"
+
+#: builtin/commit.c:859
+msgid "Cannot read index"
+msgstr "Kan inte läsa indexet"
+
+#: builtin/commit.c:896
+msgid "Error building trees"
+msgstr "Fel vid byggande av träd"
+
+#: builtin/commit.c:911 builtin/tag.c:357
+#, 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:1008
+#, c-format
+msgid "No existing author found with '%s'"
+msgstr "Hittade ingen befintlig författare med \"%s\""
+
+#: builtin/commit.c:1023 builtin/commit.c:1217
+#, c-format
+msgid "Invalid untracked files mode '%s'"
+msgstr "Ogiltigt läge för ospårade filer: \"%s\""
+
+#: builtin/commit.c:1063
+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:1074
+msgid "You have nothing to amend."
+msgstr "Du har inget att utöka."
+
+#: builtin/commit.c:1076
+#, c-format
+msgid "You are in the middle of a %s -- cannot amend."
+msgstr "Du är i mitten av en %s -- kan inte utöka."
+
+#: builtin/commit.c:1078
+msgid "Options --squash and --fixup cannot be used together"
+msgstr "Flaggorna --squash och --fixup kan inte användas samtidigt"
+
+#: builtin/commit.c:1088
+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:1090
+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:1098
+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:1115
+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:1117
+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:1119
+msgid "Clever... amending the last one with dirty index."
+msgstr "Smart... utöka den senaste med smutsigt index."
+
+#: builtin/commit.c:1121
+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:1131 builtin/tag.c:556
+#, c-format
+msgid "Invalid cleanup mode %s"
+msgstr "Felaktigt städningsläge %s"
+
+#: builtin/commit.c:1136
+msgid "Paths with -a does not make sense."
+msgstr "Kan inte ange sökvägar med -a."
+
+#: builtin/commit.c:1315
+msgid "couldn't look up newly created commit"
+msgstr "kunde inte slå upp en precis skapad incheckning"
+
+#: builtin/commit.c:1317
+msgid "could not parse newly created commit"
+msgstr "kunde inte tolka en precis skapad incheckning"
+
+#: builtin/commit.c:1358
+msgid "detached HEAD"
+msgstr "frånkopplad HEAD"
+
+#: builtin/commit.c:1360
+msgid " (root-commit)"
+msgstr " (rotincheckning)"
+
+#: builtin/commit.c:1450
+msgid "could not parse HEAD commit"
+msgstr "kunde inte tolka HEAD:s incheckning"
+
+#: builtin/commit.c:1487 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:1494
+#, c-format
+msgid "Corrupt MERGE_HEAD file (%s)"
+msgstr "Trasig MERGE_HEAD-fil (%s)"
+
+#: builtin/commit.c:1501
+msgid "could not read MERGE_MODE"
+msgstr "kunde inte läsa MERGE_MODE"
+
+#: builtin/commit.c:1520
+#, c-format
+msgid "could not read commit message: %s"
+msgstr "kunde inte läsa incheckningsmeddelande: %s"
+
+#: builtin/commit.c:1534
+#, c-format
+msgid "Aborting commit; you did not edit the message.\n"
+msgstr "Avbryter incheckning; meddelandet inte redigerat.\n"
+
+#: builtin/commit.c:1539
+#, c-format
+msgid "Aborting commit due to empty commit message.\n"
+msgstr "Avbryter på grund av tomt incheckningsmeddelande.\n"
+
+#: builtin/commit.c:1554 builtin/merge.c:936 builtin/merge.c:961
+msgid "failed to write commit object"
+msgstr "kunde inte skriva incheckningsobjekt"
+
+#: builtin/commit.c:1575
+msgid "cannot lock HEAD ref"
+msgstr "kunde inte låsa HEAD-referens"
+
+#: builtin/commit.c:1579
+msgid "cannot update HEAD ref"
+msgstr "kunde inte uppdatera HEAD-referens"
+
+#: 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 ""
+"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/describe.c:234
+#, c-format
+msgid "annotated tag %s not available"
+msgstr "den annoterade taggen %s inte tillgänglig"
+
+#: builtin/describe.c:238
+#, c-format
+msgid "annotated tag %s has no embedded name"
+msgstr "den annoterade taggen %s har inget inbäddat namn"
+
+#: builtin/describe.c:240
+#, c-format
+msgid "tag '%s' is really '%s' here"
+msgstr "taggen \"%s\" är i verkligheten \"%s\" här"
+
+#: builtin/describe.c:267
+#, c-format
+msgid "Not a valid object name %s"
+msgstr "Objektnamnet är inte giltigt: %s"
+
+#: builtin/describe.c:270
+#, c-format
+msgid "%s is not a valid '%s' object"
+msgstr "%s är inte ett giltigt \"%s\"-objekt"
+
+#: builtin/describe.c:287
+#, c-format
+msgid "no tag exactly matches '%s'"
+msgstr "ingen tagg motsvarar \"%s\" exakt"
+
+#: builtin/describe.c:289
+#, c-format
+msgid "searching to describe %s\n"
+msgstr "söker för att beskriva %s\n"
+
+#: builtin/describe.c:329
+#, c-format
+msgid "finished search at %s\n"
+msgstr "avslutade sökning på %s\n"
+
+#: builtin/describe.c:353
+#, c-format
+msgid ""
+"No annotated tags can describe '%s'.\n"
+"However, there were unannotated tags: try --tags."
+msgstr ""
+"Inga annoterade taggar kan beskriva \"%s\".\n"
+"Det finns dock oannoterade taggar: testa --tags."
+
+#: builtin/describe.c:357
+#, c-format
+msgid ""
+"No tags can describe '%s'.\n"
+"Try --always, or create some tags."
+msgstr ""
+"Inga taggar kan beskriva \"%s\".\n"
+"Testa --always, eller skapa några taggar."
+
+#: builtin/describe.c:378
+#, c-format
+msgid "traversed %lu commits\n"
+msgstr "traverserade %lu incheckningar\n"
+
+#: builtin/describe.c:381
+#, c-format
+msgid ""
+"more than %i tags found; listed %i most recent\n"
+"gave up search at %s\n"
+msgstr ""
+"mer än %i taggar hittades; listar de %i senaste\n"
+"gav upp sökningen vid %s\n"
+
+#: builtin/describe.c:436
+msgid "--long is incompatible with --abbrev=0"
+msgstr "--long är inkompatibel med --abbrev=0"
+
+#: builtin/describe.c:462
+msgid "No names found, cannot describe anything."
+msgstr "Inga namn hittades, kan inte beskriva något."
+
+#: builtin/describe.c:482
+msgid "--dirty is incompatible with committishes"
+msgstr "--dirty är inkompatibelt med \"committish\"-värden"
+
+#: builtin/diff.c:77
+#, c-format
+msgid "'%s': not a regular file or symlink"
+msgstr "\"%s\": inte en normal fil eller symbolisk länk"
+
+#: builtin/diff.c:220
+#, c-format
+msgid "invalid option: %s"
+msgstr "ogiltig flagga: %s"
+
+#: builtin/diff.c:297
+msgid "Not a git repository"
+msgstr "Inte ett git-arkiv"
+
+#: builtin/diff.c:347
+#, c-format
+msgid "invalid object '%s' given."
+msgstr "objektet \"%s\" som angavs är felaktigt."
+
+#: builtin/diff.c:352
+#, c-format
+msgid "more than %d trees given: '%s'"
+msgstr "mer än %d träd angavs: \"%s\""
+
+#: builtin/diff.c:362
+#, c-format
+msgid "more than two blobs given: '%s'"
+msgstr "mer än två blobbar angavs: \"%s\""
+
+#: builtin/diff.c:370
+#, c-format
+msgid "unhandled object '%s' given."
+msgstr "ej hanterat objekt \"%s\" angavs."
+
+#: builtin/fetch.c:200
+msgid "Couldn't find remote ref HEAD"
+msgstr "Kunde inte hitta fjärr-referensen HEAD"
+
+#: builtin/fetch.c:253
+#, c-format
+msgid "object %s not found"
+msgstr "objektet %s hittades inte"
+
+#: builtin/fetch.c:259
+msgid "[up to date]"
+msgstr "[àjour]"
+
+#: builtin/fetch.c:273
+#, c-format
+msgid "! %-*s %-*s -> %s (can't fetch in current branch)"
+msgstr "! %-*s %-*s -> %s (kan inte hämta i aktuell gren)"
+
+#: builtin/fetch.c:274 builtin/fetch.c:360
+msgid "[rejected]"
+msgstr "[refuserad]"
+
+#: builtin/fetch.c:285
+msgid "[tag update]"
+msgstr "[uppdaterad tagg]"
+
+#: builtin/fetch.c:287 builtin/fetch.c:322 builtin/fetch.c:340
+msgid " (unable to update local ref)"
+msgstr " (kunde inte uppdatera lokal ref)"
+
+#: builtin/fetch.c:305
+msgid "[new tag]"
+msgstr "[ny tagg]"
+
+#: builtin/fetch.c:308
+msgid "[new branch]"
+msgstr "[ny gren]"
+
+#: builtin/fetch.c:311
+msgid "[new ref]"
+msgstr "[ny ref]"
+
+#: builtin/fetch.c:356
+msgid "unable to update local ref"
+msgstr "kunde inte uppdatera lokal ref"
+
+#: builtin/fetch.c:356
+msgid "forced update"
+msgstr "tvingad uppdatering"
+
+#: builtin/fetch.c:362
+msgid "(non-fast-forward)"
+msgstr "(ej snabbspolad)"
+
+#: builtin/fetch.c:393 builtin/fetch.c:685
+#, c-format
+msgid "cannot open %s: %s\n"
+msgstr "kan inte öppna %s: %s\n"
+
+#: builtin/fetch.c:402
+#, c-format
+msgid "%s did not send all necessary objects\n"
+msgstr "%s sände inte alla nödvändiga objekt\n"
+
+#: builtin/fetch.c:488
+#, c-format
+msgid "From %.*s\n"
+msgstr "Från %.*s\n"
+
+#: builtin/fetch.c:499
+#, c-format
+msgid ""
+"some local refs could not be updated; try running\n"
+" 'git remote prune %s' to remove any old, conflicting branches"
+msgstr ""
+"vissa lokala referenser kunde inte uppdateras; testa att köra\n"
+" \"git remote prune %s\" för att ta bort gamla grenar som står i konflikt"
+
+#: builtin/fetch.c:549
+#, c-format
+msgid " (%s will become dangling)\n"
+msgstr " (%s kommer bli dinglande)\n"
+
+#: builtin/fetch.c:550
+#, c-format
+msgid " (%s has become dangling)\n"
+msgstr " (%s har blivit dinglande)\n"
+
+#: builtin/fetch.c:557
+msgid "[deleted]"
+msgstr "[borttagen]"
+
+#: builtin/fetch.c:558
+msgid "(none)"
+msgstr "(ingen)"
+
+#: builtin/fetch.c:675
+#, c-format
+msgid "Refusing to fetch into current branch %s of non-bare repository"
+msgstr "Vägrar hämta till aktuell gren %s i ett icke-naket arkiv"
+
+#: builtin/fetch.c:709
+#, c-format
+msgid "Don't know how to fetch from %s"
+msgstr "Vet inte hur man hämtar från %s"
+
+#: builtin/fetch.c:786
+#, c-format
+msgid "Option \"%s\" value \"%s\" is not valid for %s"
+msgstr "Flaggan \"%s\" och värdet \"%s\" är inte giltigt för %s"
+
+#: builtin/fetch.c:789
+#, c-format
+msgid "Option \"%s\" is ignored for %s\n"
+msgstr "Flaggan \"%s\" ignoreras för %s\n"
+
+#: builtin/fetch.c:888
+#, c-format
+msgid "Fetching %s\n"
+msgstr "Hämtar %s\n"
+
+#: builtin/fetch.c:890
+#, c-format
+msgid "Could not fetch %s"
+msgstr "Kunde inte hämta %s"
+
+#: 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."
+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
+msgid "You need to specify a tag name."
+msgstr "Du måste ange namnet på en tagg."
+
+#: builtin/fetch.c:979
+msgid "fetch --all does not take a repository argument"
+msgstr "fetch --all tar inte namnet på ett arkiv som argument"
+
+#: builtin/fetch.c:981
+msgid "fetch --all does not make sense with refspecs"
+msgstr "fetch --all kan inte anges med referensspecifikationer"
+
+#: builtin/fetch.c:992
+#, c-format
+msgid "No such remote or remote group: %s"
+msgstr "Fjärren eller fjärrgruppen finns inte: %s"
+
+#: builtin/fetch.c:1000
+msgid "Fetching a group and specifying refspecs does not make sense"
+msgstr "Kan inte hämta från grupp och ange referensspecifikationer"
+
+#: builtin/gc.c:63
+#, c-format
+msgid "Invalid %s: '%s'"
+msgstr "Felaktigt %s: \"%s\""
+
+#: builtin/gc.c:90
+#, c-format
+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:224
+#, 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 ""
+"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
+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
+#, c-format
+msgid "grep: failed to create thread: %s"
+msgstr "grep: misslyckades skapa tråd. %s"
+
+#: builtin/grep.c:402
+#, c-format
+msgid "Failed to chdir: %s"
+msgstr "Kunde inte byta katalog (chdir): %s"
+
+#: builtin/grep.c:478 builtin/grep.c:512
+#, c-format
+msgid "unable to read tree (%s)"
+msgstr "kunde inte läsa träd (%s)"
+
+#: builtin/grep.c:526
+#, 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
+#, c-format
+msgid "switch `%c' expects a numerical value"
+msgstr "flaggan \"%c\" antar ett numeriskt värde"
+
+#: builtin/grep.c:601
+#, c-format
+msgid "cannot open '%s'"
+msgstr "kan inte öppna \"%s\""
+
+#: builtin/grep.c:888
+msgid "no pattern given."
+msgstr "inget mönster angavs."
+
+#: builtin/grep.c:902
+#, c-format
+msgid "bad object %s"
+msgstr "felaktigt objekt %s"
+
+#: builtin/grep.c:943
+msgid "--open-files-in-pager only works on the worktree"
+msgstr "--open-files-in-pager fungerar endast i arbetskatalogen"
+
+#: builtin/grep.c:966
+msgid "--cached or --untracked cannot be used with --no-index."
+msgstr "--cached och --untracked kan inte användas med --no-index."
+
+#: builtin/grep.c:971
+msgid "--no-index or --untracked cannot be used with revs."
+msgstr "--no-index och --untracked kan inte användas med revisioner."
+
+#: builtin/grep.c:974
+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:982
+msgid "both --cached and trees are given."
+msgstr "både --cached och träd angavs."
+
+#: builtin/init-db.c:35
+#, c-format
+msgid "Could not make %s writable by group"
+msgstr "Kunde inte göra %s skrivbar för gruppen"
+
+#: builtin/init-db.c:62
+#, c-format
+msgid "insanely long template name %s"
+msgstr "tokigt långt namn på mallen %s"
+
+#: builtin/init-db.c:67
+#, c-format
+msgid "cannot stat '%s'"
+msgstr "kan inte ta status på \"%s\""
+
+#: builtin/init-db.c:73
+#, c-format
+msgid "cannot stat template '%s'"
+msgstr "kan inte ta status på mallen \"%s\""
+
+#: builtin/init-db.c:80
+#, c-format
+msgid "cannot opendir '%s'"
+msgstr "kan inte öppna katalogen (opendir) \"%s\""
+
+#: builtin/init-db.c:97
+#, c-format
+msgid "cannot readlink '%s'"
+msgstr "kan inte läsa länk (readlink) \"%s\""
+
+#: builtin/init-db.c:99
+#, c-format
+msgid "insanely long symlink %s"
+msgstr "tokigt lång symbolisk länk %s"
+
+#: builtin/init-db.c:102
+#, c-format
+msgid "cannot symlink '%s' '%s'"
+msgstr "kan inte skapa symbolisk länk \"%s\" \"%s\""
+
+#: builtin/init-db.c:106
+#, c-format
+msgid "cannot copy '%s' to '%s'"
+msgstr "kan inte kopiera \"%s\" till \"%s\""
+
+#: builtin/init-db.c:110
+#, c-format
+msgid "ignoring template %s"
+msgstr "ignorerar mallen %s"
+
+#: builtin/init-db.c:133
+#, c-format
+msgid "insanely long template path %s"
+msgstr "tokigt lång mallsökväg %s"
+
+#: builtin/init-db.c:141
+#, c-format
+msgid "templates not found %s"
+msgstr "mallarna hittades inte %s"
+
+#: builtin/init-db.c:154
+#, c-format
+msgid "not copying templates of a wrong format version %d from '%s'"
+msgstr "kopierade inte mallar från felaktig formatversion %d från \"%s\""
+
+#: builtin/init-db.c:192
+#, c-format
+msgid "insane git directory %s"
+msgstr "tokig git-katalog %s"
+
+#: builtin/init-db.c:322 builtin/init-db.c:325
+#, c-format
+msgid "%s already exists"
+msgstr "%s finns redan"
+
+#: builtin/init-db.c:354
+#, c-format
+msgid "unable to handle file type %d"
+msgstr "kan inte hantera filtyp %d"
+
+#: builtin/init-db.c:357
+#, c-format
+msgid "unable to move %s to %s"
+msgstr "kan inte flytta %s till %s"
+
+#: builtin/init-db.c:362
+#, c-format
+msgid "Could not create git link %s"
+msgstr "Kunde inte skapa gitlänk %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
+#, 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
+msgid "Reinitialized existing"
+msgstr "Ominitierade befintligt"
+
+#: builtin/init-db.c:420
+msgid "Initialized empty"
+msgstr "Initierade tomt"
+
+#: builtin/init-db.c:421
+msgid " shared"
+msgstr " delat"
+
+#: builtin/init-db.c:440
+msgid "cannot tell cwd"
+msgstr "kan inte läsa aktuell katalog (cwd)"
+
+#: builtin/init-db.c:521 builtin/init-db.c:528
+#, c-format
+msgid "cannot mkdir %s"
+msgstr "kan inte skapa katalogen (mkdir) %s"
+
+#: builtin/init-db.c:532
+#, c-format
+msgid "cannot chdir to %s"
+msgstr "kan inte byta katalog (chdir) till %s"
+
+#: builtin/init-db.c:554
+#, c-format
+msgid ""
+"%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-"
+"dir=<directory>)"
+msgstr ""
+"%s (eller --work-tree=<katalog>) inte tillåtet utan att ange %s (eller --git-"
+"dir=<katalog>)"
+
+#: builtin/init-db.c:578
+msgid "Cannot access current working directory"
+msgstr "Kan inte komma åt aktuell arbetskatalog"
+
+#: builtin/init-db.c:585
+#, c-format
+msgid "Cannot access work tree '%s'"
+msgstr "Kan inte komma åt arbetskatalogen \"%s\""
+
+#: builtin/log.c:187
+#, c-format
+msgid "Final output: %d %s\n"
+msgstr "Slututdata: %d %s\n"
+
+#: builtin/log.c:395 builtin/log.c:483
+#, c-format
+msgid "Could not read object %s"
+msgstr "Kunde inte läsa objektet %s"
+
+#: builtin/log.c:507
+#, c-format
+msgid "Unknown type: %d"
+msgstr "Okänd typ: %d"
+
+#: builtin/log.c:596
+msgid "format.headers without value"
+msgstr "format.headers utan värde"
+
+#: builtin/log.c:669
+msgid "name of output directory is too long"
+msgstr "namnet på utdatakatalogen är för långt"
+
+#: builtin/log.c:680
+#, c-format
+msgid "Cannot open patch file %s"
+msgstr "Kan inte öppna patchfilen %s"
+
+#: builtin/log.c:694
+msgid "Need exactly one range."
+msgstr "Behöver precis ett intervall."
+
+#: builtin/log.c:702
+msgid "Not a range."
+msgstr "Inte ett intervall."
+
+#: builtin/log.c:739
+msgid "Could not extract email from committer identity."
+msgstr "Kunde inte extrahera e-postadress från incheckarens identitet."
+
+#: builtin/log.c:785
+msgid "Cover letter needs email format"
+msgstr "Omslagsbrevet behöver e-postformat"
+
+#: builtin/log.c:879
+#, c-format
+msgid "insane in-reply-to: %s"
+msgstr "tokigt in-reply-to: %s"
+
+#: builtin/log.c:952
+msgid "Two output directories?"
+msgstr "Två utdatakataloger?"
+
+#: builtin/log.c:1173
+#, c-format
+msgid "bogus committer info %s"
+msgstr "felaktig incheckarinformation %s"
+
+#: builtin/log.c:1218
+msgid "-n and -k are mutually exclusive."
+msgstr "-n och -k kan inte användas samtidigt."
+
+#: builtin/log.c:1220
+msgid "--subject-prefix and -k are mutually exclusive."
+msgstr "--subject-prefix och -k kan inte användas samtidigt."
+
+#: builtin/log.c:1225 builtin/shortlog.c:284
+#, c-format
+msgid "unrecognized argument: %s"
+msgstr "okänt argument: %s"
+
+#: builtin/log.c:1228
+msgid "--name-only does not make sense"
+msgstr "kan inte använda --name-only"
+
+#: builtin/log.c:1230
+msgid "--name-status does not make sense"
+msgstr "kan inte använda --name-status"
+
+#: builtin/log.c:1232
+msgid "--check does not make sense"
+msgstr "kan inte använda --check"
+
+#: builtin/log.c:1255
+msgid "standard output, or directory, which one?"
+msgstr "standard ut, eller katalog, vilken skall det vara?"
+
+#: builtin/log.c:1257
+#, c-format
+msgid "Could not create directory '%s'"
+msgstr "Kunde inte skapa katalogen \"%s\""
+
+#: builtin/log.c:1410
+msgid "Failed to create output files"
+msgstr "Misslyckades skapa utdatafiler"
+
+#: builtin/log.c:1514
+#, 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:1530 builtin/log.c:1532 builtin/log.c:1544
+#, c-format
+msgid "Unknown commit %s"
+msgstr "Okänd incheckning %s"
+
+#: builtin/merge.c:90
+msgid "switch `m' requires a value"
+msgstr "flaggan \"m\" behöver ett värde"
+
+#: builtin/merge.c:127
+#, c-format
+msgid "Could not find merge strategy '%s'.\n"
+msgstr "Kunde inte hitta sammanslagningsstrategin \"%s\".\n"
+
+#: builtin/merge.c:128
+#, c-format
+msgid "Available strategies are:"
+msgstr "Tillgängliga strategier är:"
+
+#: builtin/merge.c:133
+#, c-format
+msgid "Available custom strategies are:"
+msgstr "Tillgängliga skräddarsydda strategier är:"
+
+#: builtin/merge.c:240
+msgid "could not run stash."
+msgstr "kunde köra stash."
+
+#: builtin/merge.c:245
+msgid "stash failed"
+msgstr "stash misslyckades"
+
+#: builtin/merge.c:250
+#, c-format
+msgid "not a valid object: %s"
+msgstr "inte ett giltigt objekt: %s"
+
+#: builtin/merge.c:269 builtin/merge.c:286
+msgid "read-tree failed"
+msgstr "read-tree misslyckades"
+
+#: builtin/merge.c:316
+msgid " (nothing to squash)"
+msgstr " (inget att platta till)"
+
+#: builtin/merge.c:329
+#, c-format
+msgid "Squash commit -- not updating HEAD\n"
+msgstr "Tillplattningsincheckning -- uppdaterar inte HEAD\n"
+
+#: builtin/merge.c:361
+msgid "Writing SQUASH_MSG"
+msgstr "Skriver SQUASH_MSG"
+
+#: builtin/merge.c:363
+msgid "Finishing SQUASH_MSG"
+msgstr "Avslutar SQUASH_MSG"
+
+#: builtin/merge.c:386
+#, c-format
+msgid "No merge message -- not updating HEAD\n"
+msgstr "Inget sammanslagningsmeddelande -- uppdaterar inte HEAD\n"
+
+#: builtin/merge.c:437
+#, c-format
+msgid "'%s' does not point to a commit"
+msgstr "\"%s\" verkar inte peka på en incheckning"
+
+#: builtin/merge.c:536
+#, c-format
+msgid "Bad branch.%s.mergeoptions string: %s"
+msgstr "Felaktig branch.%s.mergeoptions-sträng: %s"
+
+#: builtin/merge.c:629
+msgid "git write-tree failed to write a tree"
+msgstr "git write-tree misslyckades skriva ett träd"
+
+#: builtin/merge.c:679
+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
+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
+#, c-format
+msgid "Unknown option for merge-recursive: -X%s"
+msgstr "Felaktig flagga för merge-recursive: -X%s"
+
+#: builtin/merge.c:738
+#, c-format
+msgid "unable to write %s"
+msgstr "kunde inte skriva %s"
+
+#: builtin/merge.c:877
+#, c-format
+msgid "Could not read from '%s'"
+msgstr "Kunde inte läsa från \"%s\""
+
+#: builtin/merge.c:886
+#, 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
+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 ""
+"Ange ett incheckningsmeddelande för att förklara varför sammanslagningen\n"
+"är nödvändig, speciellt om den slår in en uppdaterad uppström i en\n"
+"temagren.\n"
+"\n"
+"Rader som inleds med \"#\" kommer ignoreras, och ett tomt meddelande\n"
+"avbryter incheckningen.\n"
+
+#: builtin/merge.c:916
+msgid "Empty commit message."
+msgstr "Tomt incheckningsmeddelande."
+
+#: builtin/merge.c:928
+#, c-format
+msgid "Wonderful.\n"
+msgstr "Underbart.\n"
+
+#: builtin/merge.c:993
+#, 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
+#, c-format
+msgid "'%s' is not a commit"
+msgstr "\"%s\" är inte en incheckning"
+
+#: builtin/merge.c:1050
+msgid "No current branch."
+msgstr "Inte på någon gren."
+
+#: builtin/merge.c:1052
+msgid "No remote for the current branch."
+msgstr "Ingen fjärr för aktuell gren."
+
+#: builtin/merge.c:1054
+msgid "No default upstream defined for the current branch."
+msgstr "Ingen standarduppström angiven för aktuell gren."
+
+#: builtin/merge.c:1059
+#, 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
+#, c-format
+msgid "%s - not something we can merge"
+msgstr "%s - inte något vi kan slå ihop"
+
+#: builtin/merge.c:1214
+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
+msgid ""
+"You have not concluded your merge (MERGE_HEAD exists).\n"
+"Please, commit your changes before you can merge."
+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
+msgid "You have not concluded your merge (MERGE_HEAD exists)."
+msgstr "Du har inte avslutat sammanslagningen (MERGE_HEAD finns)."
+
+#: 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."
+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
+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
+msgid "You cannot combine --squash with --no-ff."
+msgstr "Du kan inte kombinera --squash med --no-ff."
+
+#: builtin/merge.c:1254
+msgid "You cannot combine --no-ff with --ff-only."
+msgstr "Du kan inte kombinera --no-ff med --ff-only."
+
+#: builtin/merge.c:1261
+msgid "No commit specified and merge.defaultToUpstream not set."
+msgstr "Ingen incheckning angiven och merge.defaultToUpstream är ej satt."
+
+#: builtin/merge.c:1293
+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
+msgid "Squash commit into empty head not supported yet"
+msgstr "Stöder inte en tillplattningsincheckning på ett tomt huvud ännu"
+
+#: builtin/merge.c:1298
+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
+#, c-format
+msgid "Updating %s..%s\n"
+msgstr "Uppdaterar %s..%s\n"
+
+#: builtin/merge.c:1451
+#, c-format
+msgid "Trying really trivial in-index merge...\n"
+msgstr "Försöker riktigt enkel sammanslagning i indexet...\n"
+
+#: builtin/merge.c:1458
+#, c-format
+msgid "Nope.\n"
+msgstr "Nej.\n"
+
+#: builtin/merge.c:1490
+msgid "Not possible to fast-forward, aborting."
+msgstr "Kan inte snabbspola, avbryter."
+
+#: builtin/merge.c:1513 builtin/merge.c:1592
+#, c-format
+msgid "Rewinding the tree to pristine...\n"
+msgstr "Återspolar trädet till orört...\n"
+
+#: builtin/merge.c:1517
+#, c-format
+msgid "Trying merge strategy %s...\n"
+msgstr "Försöker sammanslagninsstrategin %s...\n"
+
+#: builtin/merge.c:1583
+#, c-format
+msgid "No merge strategy handled the merge.\n"
+msgstr "Ingen sammanslagningsstrategi hanterade sammanslagningen.\n"
+
+#: builtin/merge.c:1585
+#, c-format
+msgid "Merge with strategy %s failed.\n"
+msgstr "Sammanslaning med strategin %s misslyckades.\n"
+
+#: builtin/merge.c:1594
+#, 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
+#, 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/mv.c:108
+#, c-format
+msgid "Checking rename of '%s' to '%s'\n"
+msgstr "Kontrollerar namnbyte av \"%s\" till \"%s\"\n"
+
+#: builtin/mv.c:112
+msgid "bad source"
+msgstr "felaktig källa"
+
+#: builtin/mv.c:115
+msgid "can not move directory into itself"
+msgstr "kan inte flytta katalog till sig själv"
+
+#: builtin/mv.c:118
+msgid "cannot move directory over file"
+msgstr "kan inte flytta katalog över fil"
+
+#: builtin/mv.c:128
+#, c-format
+msgid "Huh? %.*s is in index?"
+msgstr "Vad? %.*s är i indexet?"
+
+#: builtin/mv.c:140
+msgid "source directory is empty"
+msgstr "källkatalogen är tom"
+
+#: builtin/mv.c:171
+msgid "not under version control"
+msgstr "inte versionshanterad"
+
+#: builtin/mv.c:173
+msgid "destination exists"
+msgstr "destinationen finns"
+
+#: builtin/mv.c:181
+#, c-format
+msgid "overwriting '%s'"
+msgstr "skriver över \"%s\""
+
+#: builtin/mv.c:184
+msgid "Cannot overwrite"
+msgstr "Kan inte skriva över"
+
+#: builtin/mv.c:187
+msgid "multiple sources for the same target"
+msgstr "flera källor för samma mål"
+
+#: builtin/mv.c:202
+#, c-format
+msgid "%s, source=%s, destination=%s"
+msgstr "%s, källa=%s, mål=%s"
+
+#: builtin/mv.c:212
+#, c-format
+msgid "Renaming %s to %s\n"
+msgstr "Byter namn på %s till %s\n"
+
+#: builtin/mv.c:215
+#, c-format
+msgid "renaming '%s' failed"
+msgstr "misslyckades byta namn på \"%s\""
+
+#: builtin/notes.c:139
+#, c-format
+msgid "unable to start 'show' for object '%s'"
+msgstr "kunde inte starta \"show\" för objektet \"%s\""
+
+#: builtin/notes.c:145
+msgid "can't fdopen 'show' output fd"
+msgstr "kunde inte öppna (fdopen) \"show\"-utdata-filhandtag"
+
+#: builtin/notes.c:155
+#, 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
+#, 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:343
+#, c-format
+msgid "could not create file '%s'"
+msgstr "kunde inte skapa filen \"%s\""
+
+#: builtin/notes.c:189
+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
+#, c-format
+msgid "Removing note for object %s\n"
+msgstr "Tar bort anteckning för objektet %s\n"
+
+#: builtin/notes.c:215
+msgid "unable to write note object"
+msgstr "kunde inte skriva anteckningsobjekt"
+
+#: builtin/notes.c:217
+#, 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:521
+#, c-format
+msgid "cannot read '%s'"
+msgstr "kunde inte läsa \"%s\""
+
+#: builtin/notes.c:253 builtin/tag.c:524
+#, 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:537
+#, 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
+#, c-format
+msgid "Failed to read object '%s'."
+msgstr "Kunde inte läsa objektet \"%s\"."
+
+#: builtin/notes.c:299
+msgid "Cannot commit uninitialized/unreferenced notes tree"
+msgstr "Kan inte checka in oinitierat/orefererat anteckningsträd"
+
+#: builtin/notes.c:340
+#, c-format
+msgid "Bad notes.rewriteMode value: '%s'"
+msgstr "Felaktigt värde för notes.rewriteMode: '%s'"
+
+#: builtin/notes.c:350
+#, 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
+#, c-format
+msgid "Bad %s value: '%s'"
+msgstr "Felaktigt värde på %s: \"%s\""
+
+#: builtin/notes.c:441
+#, c-format
+msgid "Malformed input line: '%s'."
+msgstr "Felaktig indatarad: \"%s\"."
+
+#: builtin/notes.c:456
+#, 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
+msgid "too many parameters"
+msgstr "för många parametrar"
+
+#: builtin/notes.c:513 builtin/notes.c:772
+#, c-format
+msgid "No note found for object %s."
+msgstr "Inga anteckningar hittades för objektet %s."
+
+#: builtin/notes.c:580
+#, c-format
+msgid ""
+"Cannot add notes. Found existing notes for object %s. Use '-f' to overwrite "
+"existing notes"
+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
+#, c-format
+msgid "Overwriting existing notes for object %s\n"
+msgstr "Skriver över befintliga anteckningar för objektet %s\n"
+
+#: builtin/notes.c:635
+msgid "too few parameters"
+msgstr "för få parametrar"
+
+#: builtin/notes.c:656
+#, c-format
+msgid ""
+"Cannot copy notes. Found existing notes for object %s. Use '-f' to overwrite "
+"existing notes"
+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
+#, 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
+#, 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 ""
+"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
+#, c-format
+msgid "Object %s has no note\n"
+msgstr "Objektet %s har ingen anteckning\n"
+
+#: builtin/notes.c:1103
+#, c-format
+msgid "Unknown subcommand: %s"
+msgstr "Okänt underkommando: %s"
+
+#: builtin/pack-objects.c:2315
+#, c-format
+msgid "unsupported index version %s"
+msgstr "indexversionen %s stöds ej"
+
+#: builtin/pack-objects.c:2319
+#, c-format
+msgid "bad index version '%s'"
+msgstr "felaktig indexversion \"%s\""
+
+#: builtin/pack-objects.c:2342
+#, c-format
+msgid "option %s does not accept negative form"
+msgstr "flaggan %s godtar inte negativ form"
+
+#: builtin/pack-objects.c:2346
+#, c-format
+msgid "unable to parse value '%s' for option %s"
+msgstr "kunde inte tolka värdet \"%s\" för flaggan %s"
+
+#: builtin/push.c:45
+msgid "tag shorthand without <tag>"
+msgstr "taggförkortning utan <tagg>"
+
+#: builtin/push.c:64
+msgid "--delete only accepts plain target ref names"
+msgstr "--delete godtar endast enkla målreferensnamn"
+
+#: builtin/push.c:84
+#, 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 ""
+"Du är inte på någon gren för närvarande.\n"
+"För att sända in historiken som leder till den aktuella (frånkopplat\n"
+"HEAD) situationen använder du\n"
+"\n"
+" git push %s HEAD:<namn-på-fjärrgren>\n"
+
+#: builtin/push.c:91
+#, 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 ""
+"Den aktuella grenen %s har ingen uppströmsgren.\n"
+"För att sända aktuell gren och ange fjärrarkiv som uppström använder du\n"
+"\n"
+" git push --set-upstream %s %s\n"
+
+#: builtin/push.c:99
+#, c-format
+msgid "The current branch %s has multiple upstream branches, refusing to push."
+msgstr "Den aktuella grenen %s har flera uppströmsgrenar, vägrar sända."
+
+#: builtin/push.c:102
+#, 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 ""
+"Du sänder till fjärren \"%s\", som inte är uppströms för den\n"
+"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:131
+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:138
+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 ""
+"Uppdateringar avvisades då änden på din befintliga gren är bakom\n"
+"dess fjärrmotsvarighet. Slå ihop fjärrändringarna (t.ex. \"git pull\")\n"
+"innan du sänder igen.\n"
+"Se avsnittet \"Note about fast-forward\" i \"git push --help\" för detaljer."
+
+#: builtin/push.c:144
+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."
+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."
+
+#: builtin/push.c:150
+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 ""
+"Uppdateringar avvisades då änden på en gren som sänds in är bakom dess\n"
+"fjärrmotsvarighet. Checka ut grenen och slå ihop fjärrändringarna (t.ex.\n"
+"\"git pull\") innan du sänder igen.\n"
+"Se avsnittet \"Note about fast-forward\" i \"git push --help\" för detaljer."
+
+#: builtin/push.c:190
+#, c-format
+msgid "Pushing to %s\n"
+msgstr "Sänder till %s\n"
+
+#: builtin/push.c:194
+#, c-format
+msgid "failed to push some refs to '%s'"
+msgstr "misslyckades sända vissa referenser till \"%s\""
+
+#: builtin/push.c:226
+#, c-format
+msgid "bad repository '%s'"
+msgstr "felaktigt arkiv \"%s\""
+
+#: builtin/push.c:227
+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 ""
+"Ingen destination har angivits.\n"
+"Ange antingen URL:en på kommandoraden eller ställ in ett uppströmsarkiv med\n"
+"\n"
+" git remote add <namn> <url>\n"
+"\n"
+"och sänd sedan med hjälp av fjärrnamnet\n"
+"\n"
+" git push <namn>\n"
+
+#: builtin/push.c:242
+msgid "--all and --tags are incompatible"
+msgstr "--all och --tags är inkompatibla"
+
+#: builtin/push.c:243
+msgid "--all can't be combined with refspecs"
+msgstr "--all kan inte kombineras med referensspecifikationer"
+
+#: builtin/push.c:248
+msgid "--mirror and --tags are incompatible"
+msgstr "--mirror och --tags är inkompatibla"
+
+#: builtin/push.c:249
+msgid "--mirror can't be combined with refspecs"
+msgstr "--mirror kan inte kombineras med referensspecifikationer"
+
+#: builtin/push.c:254
+msgid "--all and --mirror are incompatible"
+msgstr "--all och --mirror är inkompatibla"
+
+#: builtin/push.c:334
+msgid "--delete is incompatible with --all, --mirror and --tags"
+msgstr "--delete är imkompatibel med --all, --mirror och --tags"
+
+#: builtin/push.c:336
+msgid "--delete doesn't make sense without any refs"
+msgstr "--delete kan inte användas utan referenser"
+
+#: builtin/reset.c:33
+msgid "mixed"
+msgstr "blandad"
+
+#: builtin/reset.c:33
+msgid "soft"
+msgstr "mjuk"
+
+#: builtin/reset.c:33
+msgid "hard"
+msgstr "hård"
+
+#: builtin/reset.c:33
+msgid "keep"
+msgstr "behåll"
+
+#: builtin/reset.c:77
+msgid "You do not have a valid HEAD."
+msgstr "Du har inte en giltig HEAD."
+
+#: builtin/reset.c:79
+msgid "Failed to find tree of HEAD."
+msgstr "Kunde inte hitta träder för HEAD."
+
+#: builtin/reset.c:85
+#, c-format
+msgid "Failed to find tree of %s."
+msgstr "Kunde inte hitta träder för %s."
+
+#: builtin/reset.c:96
+msgid "Could not write new index file."
+msgstr "Kunde inte skriva ny indexfil."
+
+#: builtin/reset.c:106
+#, c-format
+msgid "HEAD is now at %s"
+msgstr "HEAD är nu på %s"
+
+#: builtin/reset.c:130
+msgid "Could not read index"
+msgstr "Kunde inte läsa indexet"
+
+#: builtin/reset.c:133
+msgid "Unstaged changes after reset:"
+msgstr "Oköade ändringar efter återställning:"
+
+#: builtin/reset.c:223
+#, c-format
+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
+#, c-format
+msgid "Could not parse object '%s'."
+msgstr "Kan inte tolka objektet \"%s\""
+
+#: builtin/reset.c:302
+msgid "--patch is incompatible with --{hard,mixed,soft}"
+msgstr "--patch är inkompatibel med --{hard,mixed,soft}"
+
+#: builtin/reset.c:311
+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
+#, 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
+#, 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
+#, c-format
+msgid "Could not reset index file to revision '%s'."
+msgstr "Kunde inte återställa indexfilen till versionen \"%s\"."
+
+#: 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:127
+msgid "program error"
+msgstr "programfel"
+
+#: builtin/revert.c:213
+msgid "revert failed"
+msgstr "\"revert\" misslyckades"
+
+#: builtin/revert.c:228
+msgid "cherry-pick failed"
+msgstr "\"cherry-pick\" misslyckades"
+
+#: 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\" har köat ändringar som skiljer sig både från filen och HEAD\n"
+"(använd -f för att tvinga borttagning)"
+
+#: builtin/rm.c:115
+#, c-format
+msgid ""
+"'%s' has changes staged in the index\n"
+"(use --cached to keep the file, or -f to force removal)"
+msgstr ""
+"\"%s\" har köade ändringar i indexet\n"
+"(använd --cached för att behålla filen eller -f för att tvinga borttagning)"
+
+#: builtin/rm.c:119
+#, c-format
+msgid ""
+"'%s' has local modifications\n"
+"(use --cached to keep the file, or -f to force removal)"
+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:194
+#, c-format
+msgid "not removing '%s' recursively without -r"
+msgstr "tar inte bort \"%s\" rekursivt utan -r"
+
+#: builtin/rm.c:230
+#, c-format
+msgid "git rm: unable to remove %s"
+msgstr "git rm: kan inte ta bort %s"
+
+#: builtin/shortlog.c:157
+#, c-format
+msgid "Missing author: %s"
+msgstr "Författare saknas: %s"
+
+#: builtin/tag.c:58
+#, c-format
+msgid "malformed object at '%s'"
+msgstr "felformat objekt vid \"%s\""
+
+#: builtin/tag.c:205
+#, c-format
+msgid "tag name too long: %.*s..."
+msgstr "taggnamnet för långt: %.*s..."
+
+#: builtin/tag.c:210
+#, c-format
+msgid "tag '%s' not found."
+msgstr "taggen \"%s\" hittades inte."
+
+#: builtin/tag.c:225
+#, c-format
+msgid "Deleted tag '%s' (was %s)\n"
+msgstr "Tog bort tagg \"%s\" (var %s)\n"
+
+#: builtin/tag.c:237
+#, c-format
+msgid "could not verify the tag '%s'"
+msgstr "kunde inte bekräfta taggen \"%s\""
+
+#: builtin/tag.c:247
+msgid ""
+"\n"
+"#\n"
+"# Write a tag message\n"
+"# Lines starting with '#' will be ignored.\n"
+"#\n"
+msgstr ""
+"\n"
+"#\n"
+"# Skriv ett taggmeddelande\n"
+"# Rader som inleds med \"#\" ignoreras.\n"
+"#\n"
+
+#: builtin/tag.c:254
+msgid ""
+"\n"
+"#\n"
+"# Write a tag message\n"
+"# Lines starting with '#' will be kept; you may remove them yourself if you "
+"want to.\n"
+"#\n"
+msgstr ""
+"\n"
+"#\n"
+"# Skriv ett taggmeddelande\n"
+"# Rader som inleds med \"#\" kommer behållas; du kan själv ta bort dem om\n"
+"# du vill.\n"
+"#\n"
+
+#: builtin/tag.c:294
+msgid "unable to sign the tag"
+msgstr "kunde inte signera taggen"
+
+#: builtin/tag.c:296
+msgid "unable to write tag file"
+msgstr "kunde inte skriva tagg-filen"
+
+#: builtin/tag.c:321
+msgid "bad object type."
+msgstr "felaktig objekttyp"
+
+#: builtin/tag.c:334
+msgid "tag header too big."
+msgstr "tagghuvud för stort."
+
+#: builtin/tag.c:366
+msgid "no tag message?"
+msgstr "inget taggmeddelande?"
+
+#: builtin/tag.c:372
+#, c-format
+msgid "The tag message has been left in %s\n"
+msgstr "Taggmeddelandet har lämnats i %s\n"
+
+#: builtin/tag.c:421
+msgid "switch 'points-at' requires an object"
+msgstr "flaggan \"points-at\" behöver ett object"
+
+#: builtin/tag.c:423
+#, c-format
+msgid "malformed object name '%s'"
+msgstr "felformat objektnamn \"%s\""
+
+#: builtin/tag.c:502
+msgid "-n option is only allowed with -l."
+msgstr "Flaggan -n är endast tillåten tillsammans med -l."
+
+#: builtin/tag.c:504
+msgid "--contains option is only allowed with -l."
+msgstr "Flaggan --contains är endast tillåten tillsammans med -l"
+
+#: builtin/tag.c:506
+msgid "--points-at option is only allowed with -l."
+msgstr "Flaggan --points-at är endast tillåten tillsammans med -l."
+
+#: builtin/tag.c:514
+msgid "only one -F or -m option is allowed."
+msgstr "endast en av flaggorna -F eller -m tillåts."
+
+#: builtin/tag.c:534
+msgid "too many params"
+msgstr "för många parametrar"
+
+#: builtin/tag.c:540
+#, c-format
+msgid "'%s' is not a valid tag name."
+msgstr "\"%s\" är inte ett giltigt taggnamn."
+
+#: builtin/tag.c:545
+#, c-format
+msgid "tag '%s' already exists"
+msgstr "taggen \"%s\" finns redan"
+
+#: builtin/tag.c:563
+#, c-format
+msgid "%s: cannot lock the ref"
+msgstr "%s: kan inte låsa referensen"
+
+#: builtin/tag.c:565
+#, c-format
+msgid "%s: cannot update the ref"
+msgstr "%s: kan inte uppdatera referensen"
+
+#: builtin/tag.c:567
+#, c-format
+msgid "Updated tag '%s' (was %s)\n"
+msgstr "Uppdaterad tagg \"%s\" (var %s)\n"
+
+#: git-am.sh:49
+msgid "You need to set your committer info first"
+msgstr "Du måste ställa in din incheckarinformation först"
+
+#: git-am.sh:136
+msgid "Repository lacks necessary blobs to fall back on 3-way merge."
+msgstr ""
+"Arkivet saknar objekt som behövs för att falla tillbaka på 3-"
+"vägssammanslagning."
+
+#: git-am.sh:147
+msgid ""
+"Did you hand edit your patch?\n"
+"It does not apply to blobs recorded in its index."
+msgstr ""
+"Har du handredigerat din patch?\n"
+"Den kan inte appliceras på blobbar som antecknats i dess index."
+
+#: git-am.sh:156
+msgid "Falling back to patching base and 3-way merge..."
+msgstr ""
+"Faller tillbaka på att pacha grundversionen och trevägssammanslagning..."
+
+#: git-am.sh:268
+msgid "Only one StGIT patch series can be applied at once"
+msgstr "Endast en StGIT-patchserie kan appliceras åt gången"
+
+#: git-am.sh:355
+#, sh-format
+msgid "Patch format $patch_format is not supported."
+msgstr "Patchformatet $patch_format stöds inte."
+
+#: git-am.sh:357
+msgid "Patch format detection failed."
+msgstr "Misslyckades detektera patchformat."
+
+#: git-am.sh:411
+msgid "-d option is no longer supported. Do not use."
+msgstr "Flaggan -d stöds inte lägre. Använd inte."
+
+#: git-am.sh:474
+#, 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:479
+msgid "Please make up your mind. --skip or --abort?"
+msgstr "Bestäm dig. --skip eller --abort?"
+
+#: git-am.sh:506
+msgid "Resolve operation not in progress, we are not resuming."
+msgstr "Lösningsoperation pågår inte, vi återupptar inte."
+
+#: git-am.sh:572
+#, sh-format
+msgid "Dirty index: cannot apply patches (dirty: $files)"
+msgstr "Smutsigt index: kan inte applicera patchar (smutsiga: $files)"
+
+#: git-am.sh:748
+msgid "cannot be interactive without stdin connected to a terminal."
+msgstr ""
+"kan inte vara interaktiv om standard in inte är ansluten till en terminal."
+
+#. 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:759
+msgid "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all "
+msgstr "Applicera? Y=ja/N=nej/E=redigera/V=visa patch/A=godta alla "
+
+#: git-am.sh:795
+#, sh-format
+msgid "Applying: $FIRSTLINE"
+msgstr "Applicerar: $FIRSTLINE"
+
+#: git-am.sh:840
+msgid "No changes -- Patch already applied."
+msgstr "Inga ändringar -- Patchen har redan applicerats."
+
+#: git-am.sh:866
+msgid "applying to an empty history"
+msgstr "applicerar på en tom historik"
+
+#. TRANSLATORS: Make sure to include [Y] and [n] in your
+#. translation. The program will only accept English input
+#. at this point.
+#: git-bisect.sh:54
+msgid "Do you want me to do it for you [Y/n]? "
+msgstr "Vill du att jag ska göra det åt dig [Y=ja/N=nej]?"
+
+#: git-bisect.sh:95
+#, sh-format
+msgid "unrecognised option: '$arg'"
+msgstr "flaggan känns inte igen: \"$arg\""
+
+#: git-bisect.sh:99
+#, sh-format
+msgid "'$arg' does not appear to be a valid revision"
+msgstr "\"$arg\" verkar inte vara en giltig revision"
+
+#: git-bisect.sh:117
+msgid "Bad HEAD - I need a HEAD"
+msgstr "Felaktigt HEAD - Jag behöver ett HEAD"
+
+#: git-bisect.sh:130
+#, sh-format
+msgid ""
+"Checking out '$start_head' failed. Try 'git bisect reset <validbranch>'."
+msgstr ""
+"Misslyckades checka ut \"$start_head\". Försök \"git bisect reset "
+"<giltiggren>\""
+
+# cogito-relaterat
+#: git-bisect.sh:140
+msgid "won't bisect on seeked tree"
+msgstr "kör inte \"bisect\" på ett \"seeked\"-träd"
+
+#: git-bisect.sh:144
+msgid "Bad HEAD - strange symbolic ref"
+msgstr "Felaktigt HEAD - konstig symbolisk referens"
+
+#: git-bisect.sh:189
+#, sh-format
+msgid "Bad bisect_write argument: $state"
+msgstr "Felaktigt argument till bisect_write: $state"
+
+#: git-bisect.sh:218
+#, sh-format
+msgid "Bad rev input: $arg"
+msgstr "Felaktig rev-indata: $arg"
+
+#: git-bisect.sh:232
+msgid "Please call 'bisect_state' with at least one argument."
+msgstr "Anropa \"bisect_state\" med minst ett argument."
+
+#: git-bisect.sh:244
+#, sh-format
+msgid "Bad rev input: $rev"
+msgstr "Felaktig rev-indata: $rev"
+
+#: git-bisect.sh:250
+msgid "'git bisect bad' can take only one argument."
+msgstr "\"git bisect bad\" kan bara ta ett argument."
+
+#. 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 "Är du säker [Y=ja/N=nej]? "
+
+#: git-bisect.sh:354
+#, sh-format
+msgid "'$invalid' is not a valid commit"
+msgstr "\"$invalid\" är inte en giltig incheckning"
+
+#: git-bisect.sh:363
+#, sh-format
+msgid ""
+"Could not check out original HEAD '$branch'.\n"
+"Try 'git bisect reset <commit>'."
+msgstr ""
+"Kunde inte checka ut original-HEAD \"$branch\".\n"
+"Försök \"git bisect reset <incheckning>\"."
+
+#: git-bisect.sh:390
+msgid "No logfile given"
+msgstr "Ingen loggfil angiven"
+
+#: git-bisect.sh:391
+#, sh-format
+msgid "cannot read $file for replaying"
+msgstr "kan inte läsa $file för uppspelning"
+
+#: git-bisect.sh:408
+msgid "?? what are you talking about?"
+msgstr "?? vad menar du?"
+
+#: git-bisect.sh:474
+msgid "We are not bisecting."
+msgstr "Vi utför ingen bisect för tillfället."
+
+#: git-pull.sh:21
+msgid ""
+"Pull is not possible because you have unmerged files.\n"
+"Please, fix them up in the work tree, and then use 'git add/rm <file>'\n"
+"as appropriate to mark resolution, or use 'git commit -a'."
+msgstr ""
+"Du kan inte göra en \"pull\" då du har ändringar som inte checkats in.\n"
+"Rätta dem i din arbetskatalog och använd sedan \"git add/rm <fil>\"\n"
+"där det är lämpligt för att ange lösning, eller använd \"git commit -a\"."
+
+#: git-pull.sh:25
+msgid "Pull is not possible because you have unmerged files."
+msgstr "Du kan inte göra en \"pull\" då du har ändringar som inte checkats in."
+
+#: git-pull.sh:197
+msgid "updating an unborn branch with changes added to the index"
+msgstr "uppdaterar en ofödd gren med ändringar som lagts till i indexet"
+
+#: git-pull.sh:253
+msgid "Cannot merge multiple branches into empty head"
+msgstr "Kan inte slå ihop flera grenar i ett tomt huvud."
+
+#: git-pull.sh:257
+msgid "Cannot rebase onto multiple branches"
+msgstr "Kan inte utföra en \"rebase\" ovanpå flera grenar"
+
+#: git-stash.sh:51
+msgid "git stash clear with parameters is unimplemented"
+msgstr "\"git stash clear\" med parametrar har inte implementerats"
+
+#: git-stash.sh:74
+msgid "You do not have the initial commit yet"
+msgstr "Du har inte den första incheckningen ännu"
+
+#: git-stash.sh:89
+msgid "Cannot save the current index state"
+msgstr "Kan inte spara aktuellt tillstånd för indexet"
+
+#: git-stash.sh:123 git-stash.sh:136
+msgid "Cannot save the current worktree state"
+msgstr "Kan inte spara aktuellt tillstånd för arbetskatalogen"
+
+#: git-stash.sh:140
+msgid "No changes selected"
+msgstr "Inga ändringar valda"
+
+#: git-stash.sh:143
+msgid "Cannot remove temporary index (can't happen)"
+msgstr "Kan inte ta bort temporärt index (kan inte inträffa)"
+
+#: git-stash.sh:156
+msgid "Cannot record working tree state"
+msgstr "Kan inte registrera tillstånd för arbetskatalog"
+
+#: git-stash.sh:223
+msgid "No local changes to save"
+msgstr "Inga lokala ändringar att spara"
+
+#: git-stash.sh:227
+msgid "Cannot initialize stash"
+msgstr "Kan inte initiera \"stash\""
+
+#: git-stash.sh:235
+msgid "Cannot save the current status"
+msgstr "Kan inte spara aktuell status"
+
+#: git-stash.sh:253
+msgid "Cannot remove worktree changes"
+msgstr "Kan inte ta bort ändringar i arbetskatalogen"
+
+#: git-stash.sh:352
+msgid "No stash found."
+msgstr "Ingen \"stash\" hittades."
+
+#: git-stash.sh:359
+#, sh-format
+msgid "Too many revisions specified: $REV"
+msgstr "För många revisioner angivna: $REV"
+
+#: git-stash.sh:365
+#, sh-format
+msgid "$reference is not valid reference"
+msgstr "$reference är inte en giltig referens."
+
+#: git-stash.sh:393
+#, sh-format
+msgid "'$args' is not a stash-like commit"
+msgstr "\"$args\" är inte en \"stash\"-liknande incheckning"
+
+#: git-stash.sh:404
+#, sh-format
+msgid "'$args' is not a stash reference"
+msgstr "\"$args\" är inte en \"stash\"-referens"
+
+#: git-stash.sh:412
+msgid "unable to refresh index"
+msgstr "kan inte uppdatera indexet"
+
+#: git-stash.sh:416
+msgid "Cannot apply a stash in the middle of a merge"
+msgstr "Kan inte applicera en \"stash\" mitt i en sammanslagning"
+
+#: git-stash.sh:424
+msgid "Conflicts in index. Try without --index."
+msgstr "Konflikter i indexet. Testa utan --index."
+
+#: git-stash.sh:426
+msgid "Could not save index tree"
+msgstr "Kunde inte spara indexträd"
+
+#: git-stash.sh:460
+msgid "Cannot unstage modified files"
+msgstr "Kan inte ta bort ändrade filer ur kön"
+
+#: git-stash.sh:491
+#, sh-format
+msgid "Dropped ${REV} ($s)"
+msgstr "Kastade ${REV} ($s)"
+
+#: git-stash.sh:492
+#, sh-format
+msgid "${REV}: Could not drop stash entry"
+msgstr "${REV}: Kunde inte kasta \"stash\"-post"
+
+#: git-stash.sh:499
+msgid "No branch name specified"
+msgstr "Inget grennamn angavs"
+
+#: git-stash.sh:570
+msgid "(To restore them type \"git stash apply\")"
+msgstr "(För att återställa dem, skriv \"git stash apply\")"
+
+#: git-submodule.sh:56
+#, 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:108
+#, sh-format
+msgid "No submodule mapping found in .gitmodules for path '$path'"
+msgstr "Hittade ingen undermodulmappning i .gitmodules för sökvägen \"$path\""
+
+#: git-submodule.sh:149
+#, sh-format
+msgid "Clone of '$url' into submodule path '$path' failed"
+msgstr "Misslyckades klona \"$url\" till undermodulsökvägen \"$path\""
+
+#: git-submodule.sh:159
+#, 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:248
+#, 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:265
+#, sh-format
+msgid "'$path' already exists in the index"
+msgstr "\"$path\" finns redan i indexet"
+
+#: git-submodule.sh:282
+#, sh-format
+msgid "'$path' already exists and is not a valid git repo"
+msgstr "\"$path\" finns redan och är inte ett giltigt git-arkiv"
+
+#: git-submodule.sh:296
+#, sh-format
+msgid "Unable to checkout submodule '$path'"
+msgstr "Kan inte checka ut undermodul \"$path\""
+
+#: git-submodule.sh:301
+#, sh-format
+msgid "Failed to add submodule '$path'"
+msgstr "Misslyckades lägga till underkatalog \"$path\""
+
+#: git-submodule.sh:306
+#, sh-format
+msgid "Failed to register submodule '$path'"
+msgstr "Misslyckades registrera undermodul \"$path\""
+
+#: git-submodule.sh:348
+#, sh-format
+msgid "Entering '$prefix$path'"
+msgstr "Går in i \"$prefix$path\""
+
+#: git-submodule.sh:360
+#, sh-format
+msgid "Stopping at '$path'; script returned non-zero status."
+msgstr "Stoppar på \"$path\"; skriptet returnerade en status skild från noll."
+
+#: git-submodule.sh:402
+#, sh-format
+msgid "No url found for submodule path '$path' in .gitmodules"
+msgstr "Hittade ingen url för undermodulsökvägen \"$path\" i .gitmodules"
+
+#: git-submodule.sh:411
+#, sh-format
+msgid "Failed to register url for submodule path '$path'"
+msgstr "Misslyckades registrera url för underkatalogsökväg \"$path\""
+
+#: git-submodule.sh:419
+#, sh-format
+msgid "Failed to register update mode for submodule path '$path'"
+msgstr ""
+"Misslyckades registrera uppdateringsläge för undermodulsökväg \"$path\""
+
+#: git-submodule.sh:421
+#, sh-format
+msgid "Submodule '$name' ($url) registered for path '$path'"
+msgstr "Undermodulen \"$name\" ($url) registrerad för sökvägen \"$path\""
+
+#: git-submodule.sh:520
+#, sh-format
+msgid ""
+"Submodule path '$path' not initialized\n"
+"Maybe you want to use 'update --init'?"
+msgstr ""
+"Undermodulen \"$path\" har inte initierats\n"
+"Kanske du vill köra \"update --init\"?"
+
+#: git-submodule.sh:533
+#, sh-format
+msgid "Unable to find current revision in submodule path '$path'"
+msgstr "Kan inte hitta aktuell revision i undermodulsökväg \"$path\""
+
+#: git-submodule.sh:552
+#, sh-format
+msgid "Unable to fetch in submodule path '$path'"
+msgstr "Kan inte hämta i undermodulsökväg \"$path\""
+
+#: git-submodule.sh:566
+#, sh-format
+msgid "Unable to rebase '$sha1' in submodule path '$path'"
+msgstr "Kan inte göra \"rebase\" av \"$sha1\" i undermodulsökväg \"$path\""
+
+#: git-submodule.sh:567
+#, sh-format
+msgid "Submodule path '$path': rebased into '$sha1'"
+msgstr "Undermodulsökvägen \"$path\": \"rebase\":ad in i \"$sha1\""
+
+#: git-submodule.sh:572
+#, sh-format
+msgid "Unable to merge '$sha1' in submodule path '$path'"
+msgstr "Kan inte slå ihop \"$sha1\" i undermodulsökvägen \"$path\""
+
+#: git-submodule.sh:573
+#, sh-format
+msgid "Submodule path '$path': merged in '$sha1'"
+msgstr "Undermodulsökvägen \"$path\": sammanslagen i \"$sha1\""
+
+#: git-submodule.sh:578
+#, sh-format
+msgid "Unable to checkout '$sha1' in submodule path '$path'"
+msgstr "Kan inte checka ut \"$sha1\" i undermodulsökvägen \"$path\""
+
+#: git-submodule.sh:579
+#, sh-format
+msgid "Submodule path '$path': checked out '$sha1'"
+msgstr "Undermodulsökvägen \"$path\": checkade ut \"$sha1\""
+
+#: git-submodule.sh:601 git-submodule.sh:924
+#, sh-format
+msgid "Failed to recurse into submodule path '$path'"
+msgstr "Misslyckades rekursera in i undermodulsökvägen \"$path\""
+
+#: git-submodule.sh:709
+msgid "--"
+msgstr "--"
+
+#: git-submodule.sh:767
+#, sh-format
+msgid " Warn: $name doesn't contain commit $sha1_src"
+msgstr " Varning: $name innehåller inte incheckning $sha1_src"
+
+#: git-submodule.sh:770
+#, sh-format
+msgid " Warn: $name doesn't contain commit $sha1_dst"
+msgstr " Varning: $name innehåller inte incheckning $sha1_dst"
+
+#: git-submodule.sh:773
+#, 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:798
+msgid "blob"
+msgstr "blob"
+
+#: git-submodule.sh:799
+msgid "submodule"
+msgstr "undermodul"
+
+#: git-submodule.sh:970
+#, sh-format
+msgid "Synchronizing submodule url for '$name'"
+msgstr "Synkroniserar undermodul-url för \"$name\""
+
+#~ msgid "Too many options specified"
+#~ msgstr "För många flaggor angavs"
+
+#~ msgid "# Changed but not updated:"
+#~ msgstr "# Ändrade men inte uppdaterade:"
+
+#~ msgid "A branch named '%s' already exists."
+#~ msgstr "Det finns redan en gren som heter \"%s\""
+
+#~ msgid "path '%s' does not have all 3 versions"
+#~ msgstr "sökvägen \"%s\" har inte alla 3 versionerna"
+
+#~ msgid "git checkout: we do not like '%s' as a branch name."
+#~ msgstr "git checkout: vi tycker inte om \"%s\" som namn på en gren."
+
+#~ msgid "git checkout: branch %s already exists"
+#~ msgstr "git checkout: grenen %s finns redan"
+
+#~ msgid "Paths with --interactive does not make sense."
+#~ msgstr "Kan inte ange sökvägar med --interactive."
+
+#~ msgid "No HEAD commit to compare with (yet)"
+#~ msgstr "Ingen HEAD-incheckning att jämföra med (ännu)"
+
+#~ 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"
+
+#~ msgid "copy"
+#~ msgstr "copy"
+
+#~ msgid "show"
+#~ msgstr "show"
+
+#~ msgid "remove"
+#~ msgstr "remove"
+
+#~ msgid "prune"
+#~ msgstr "prune"
+
+#~ msgid "The current branch %s is not tracking anything."
+#~ msgstr "Den aktuella grenen %s spårar ingenting."
+
+#~ msgid "No destination configured to push to."
+#~ msgstr "Har inte ställt in någon destination att sända till."
+
+#~ msgid "Reflog action message too long: %.*s..."
+#~ msgstr "Reflog-händelsemeddelande för långt: %.*s..."
+
+#~ msgid "Could not read commit message of %s"
+#~ msgstr "Kunde inte läsa incheckningsmeddelandet för %s"
+
+#~ msgid "Could not extract author email from %s"
+#~ msgstr "Kunde inte hämta författarens e-postadress från %s"
+
+#~ msgid "Could not extract author time from %s"
+#~ msgstr "Kunde inte hämta författartid från %s"
+
+#~ msgid "No author information found in %s"
+#~ msgstr "Hittade ingen författarinformation i %s"
+
+#~ msgid "cherry-pick --ff cannot be used with --signoff"
+#~ msgstr "cherry-pick --ff kan inte användas med --signoff"
+
+#~ msgid "cherry-pick --ff cannot be used with --no-commit"
+#~ msgstr "cherry-pick --ff kan inte användas med --no-commit"
+
+#~ msgid "cherry-pick --ff cannot be used with -x"
+#~ msgstr "cherry-pick --ff kan inte användas med -x"
+
+#~ msgid "cherry-pick --ff cannot be used with --edit"
+#~ msgstr "cherry-pick --ff kan inte användas med --edit"
+
+#~ msgid "committer info too long."
+#~ msgstr "incheckarinformation för lång."
+
+#~ msgid ""
+#~ "\n"
+#~ "#\n"
+#~ "# Write a tag message\n"
+#~ "#\n"
+#~ msgstr ""
+#~ "\n"
+#~ "#\n"
+#~ "# Skriv ett taggmeddelande\n"
+#~ "#\n"
+
+#~ msgid "signing key value too long (%.10s...)"
+#~ msgstr "signeringsnyckelvärdet för långt (%.10s...)"
+
+#~ 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 ""
+#~ "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"
+#~ "För att återställa originalgrenen och avbryta kör du \"$cmdline --abort\"."
+
+#~ msgid ""
+#~ "Patch is empty. Was it split wrong?\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 ""
+#~ "Patchen är tom. Delades den upp felaktigt?\n"
+#~ "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\"."
+
+#~ msgid "Patch does not have a valid e-mail address."
+#~ msgstr "Patchen har inte någon giltig e-postadress."
+
+#~ msgid "Commit Body is:"
+#~ msgstr "Incheckningskroppen är:"
+
+#~ 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 ""
+#~ "Inga ändringar - glömde du använda \"git add\"?\n"
+#~ "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."
+
+#~ msgid ""
+#~ "You still have unmerged paths in your index\n"
+#~ "did you forget to use 'git add'?"
+#~ msgstr ""
+#~ "Du har fortfarande sökvägar som inte slagits samman i ditt index\n"
+#~ "glömde du använda \"git add\"?"
+
+#~ msgid "Patch failed at $msgnum $FIRSTLINE"
+#~ msgstr "Patchen misslyckades vid $msgnum $FIRSTLINE"
+
+#, fuzzy
+#~ msgid "You need to start by \"git bisect start\""
+#~ msgstr "Du måste ställa in din incheckarinformation först"
+
+#, fuzzy
+#~ msgid "Index was not unstashed."
+#~ msgstr "kunde köra stash."
+
+#, fuzzy
+#~ msgid "# Submodules changed but not updated:"
+#~ msgstr "# Ändrade men inte uppdaterade:"
+
+#, fuzzy
+#~ msgid "# Submodule changes to be committed:"
+#~ msgstr "# Ändringar att checka in:"
diff --git a/po/zh_CN.po b/po/zh_CN.po
new file mode 100644
index 0000000000..3894faf342
--- /dev/null
+++ b/po/zh_CN.po
@@ -0,0 +1,3732 @@
+# Chinese translations for Git package
+# Git 软件包的简体中文翻译.
+# Copyright (C) 2012 Jiang Xin <worldhello.net AT gmail.com>
+# This file is distributed under the same license as the Git package.
+# Contributers:
+# - Jiang Xin <worldhello.net AT gmail.com>
+# - Riku <lu.riku AT gmail.com>
+# - Zhuang Ya <zhuangya AT me.com>
+# - Lian Cheng <rhythm.mail AT gmail.com>
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Git\n"
+"Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
+"POT-Creation-Date: 2012-05-15 06:31+0800\n"
+"PO-Revision-Date: 2012-01-30 00:00+0800\n"
+"Last-Translator: Jiang Xin <worldhello.net@gmail.com>\n"
+"Language-Team: GitHub <https://github.com/gotgit/git/>\n"
+"Language: zh_CN\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+
+#: advice.c:40
+#, c-format
+msgid "hint: %.*s\n"
+msgstr "提示:%.*s\n"
+
+#.
+#. * Message used both when 'git commit' fails and when
+#. * other commands doing a merge do.
+#.
+#: advice.c:70
+msgid ""
+"Fix them up in the work tree,\n"
+"and then use 'git add/rm <file>' as\n"
+"appropriate to mark resolution and make a commit,\n"
+"or use 'git commit -a'."
+msgstr ""
+"请先在工作区改正文件,然后酌情使用\n"
+"'git add/rm <file>' 标记解决方案,\n"
+"或使用 'git commit -a'。"
+
+#: commit.c:47
+#, c-format
+msgid "could not parse %s"
+msgstr "不能解析 %s"
+
+#: commit.c:49
+#, c-format
+msgid "%s %s is not a commit!"
+msgstr "%s %s 不是一个提交!"
+
+#: compat/obstack.c:406 compat/obstack.c:408
+msgid "memory exhausted"
+msgstr "内存耗尽"
+
+#: connected.c:39
+msgid "Could not run 'git rev-list'"
+msgstr "不能执行 'git rev-list'"
+
+#: connected.c:48
+#, c-format
+msgid "failed write to rev-list: %s"
+msgstr "无法写入 rev-list:%s"
+
+#: connected.c:56
+#, c-format
+msgid "failed to close rev-list's stdin: %s"
+msgstr "无法关闭 rev-list 的标准输入:%s"
+
+# 译者:注意保持前导空格
+#: diff.c:105
+#, c-format
+msgid " Failed to parse dirstat cut-off percentage '%.*s'\n"
+msgstr " 无法解析 dirstat 阈值 '%.*s'\n"
+
+# 译者:注意保持前导空格
+#: diff.c:110
+#, c-format
+msgid " Unknown dirstat parameter '%.*s'\n"
+msgstr " 未知 dirstat 参数 '%.*s'\n"
+
+#: diff.c:210
+#, c-format
+msgid ""
+"Found errors in 'diff.dirstat' config variable:\n"
+"%s"
+msgstr ""
+"发现配置变量 'diff.dirstat' 中的错误:\n"
+"%s"
+
+#: diff.c:1400
+msgid " 0 files changed\n"
+msgstr " 0 个文件被修改\n"
+
+#: diff.c:1404
+#, c-format
+msgid " %d file changed"
+msgid_plural " %d files changed"
+msgstr[0] " %d 个文件被修改"
+
+#: diff.c:1421
+#, c-format
+msgid ", %d insertion(+)"
+msgid_plural ", %d insertions(+)"
+msgstr[0] ",插入 %d 行(+)"
+
+#: diff.c:1432
+#, c-format
+msgid ", %d deletion(-)"
+msgid_plural ", %d deletions(-)"
+msgstr[0] ",删除 %d 行(-)"
+
+#: diff.c:3439
+#, c-format
+msgid ""
+"Failed to parse --dirstat/-X option parameter:\n"
+"%s"
+msgstr ""
+"无法解析 --dirstat/-X 选项的参数:\n"
+"%s"
+
+#: gpg-interface.c:59
+msgid "could not run gpg."
+msgstr "不能执行 gpg。"
+
+#: gpg-interface.c:71
+msgid "gpg did not accept the data"
+msgstr "gpg 没有接受数据"
+
+#: gpg-interface.c:82
+msgid "gpg failed to sign the data"
+msgstr "gpg 无法为数据签名"
+
+#: grep.c:1280
+#, c-format
+msgid "'%s': unable to read %s"
+msgstr "'%s':无法读取 %s"
+
+#: grep.c:1297
+#, c-format
+msgid "'%s': %s"
+msgstr "'%s':%s"
+
+#: grep.c:1308
+#, c-format
+msgid "'%s': short read %s"
+msgstr "'%s':读取不完整 %s"
+
+#: help.c:287
+#, 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' 像是一个 git 命令,但却无法运行。\n"
+"可能是 git-%s 受损?"
+
+#: remote.c:1607
+#, 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"
+
+#: remote.c:1613
+#, 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] "您的分支落后 '%s' 共 %d 个提交,并且可以快进。\n"
+
+#: remote.c:1621
+#, c-format
+msgid ""
+"Your branch and '%s' have diverged,\n"
+"and have %d and %d different commit each, respectively.\n"
+msgid_plural ""
+"Your branch and '%s' have diverged,\n"
+"and have %d and %d different commits each, respectively.\n"
+msgstr[0] ""
+"您的分支和 '%s' 出现了偏离,\n"
+"并且各自分别有 %d 和 %d 处不同的提交。\n"
+
+#: sequencer.c:120 builtin/merge.c:865 builtin/merge.c:978
+#: builtin/merge.c:1088 builtin/merge.c:1098
+#, c-format
+msgid "Could not open '%s' for writing"
+msgstr "不能为写入打开 '%s'"
+
+#: sequencer.c:122 builtin/merge.c:333 builtin/merge.c:868
+#: builtin/merge.c:1090 builtin/merge.c:1103
+#, c-format
+msgid "Could not write to '%s'"
+msgstr "不能写入 '%s'"
+
+#: sequencer.c:143
+msgid ""
+"after resolving the conflicts, mark the corrected paths\n"
+"with 'git add <paths>' or 'git rm <paths>'"
+msgstr ""
+"冲突解决完毕后,用 'git add <paths>' 或 'git rm <paths>'\n"
+"命令标记修正后的文件"
+
+#: sequencer.c:146
+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 ""
+"冲突解决完毕后,用 'git add <paths>' 或 'git rm <paths>'\n"
+"对修正后的文件做标记,然后用 'git commit' 提交"
+
+#: sequencer.c:159 sequencer.c:685 sequencer.c:768
+#, c-format
+msgid "Could not write to %s"
+msgstr "不能写入 %s"
+
+#: sequencer.c:162
+#, c-format
+msgid "Error wrapping up %s"
+msgstr "错误收尾 %s"
+
+#: sequencer.c:177
+msgid "Your local changes would be overwritten by cherry-pick."
+msgstr "您的本地修改将被拣选操作覆盖。"
+
+#: sequencer.c:179
+msgid "Your local changes would be overwritten by revert."
+msgstr "您的本地修改将被还原操作覆盖。"
+
+#: sequencer.c:182
+msgid "Commit your changes or stash them to proceed."
+msgstr "提交您的修改或保存进度后再继续。"
+
+#. TRANSLATORS: %s will be "revert" or "cherry-pick"
+#: sequencer.c:232
+#, c-format
+msgid "%s: Unable to write new index file"
+msgstr "%s:无法写入新索引文件"
+
+#: sequencer.c:298
+msgid "Your index file is unmerged."
+msgstr "您的索引文件未完成合并。"
+
+#: sequencer.c:301
+msgid "You do not have a valid HEAD"
+msgstr "您没有一个有效的 HEAD"
+
+#: sequencer.c:316
+#, c-format
+msgid "Commit %s is a merge but no -m option was given."
+msgstr "提交 %s 是一个合并提交但未提供 -m 选项。"
+
+#: sequencer.c:324
+#, c-format
+msgid "Commit %s does not have parent %d"
+msgstr "提交 %s 没有父提交 %d"
+
+#: sequencer.c:328
+#, 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:339
+#, c-format
+msgid "%s: cannot parse parent commit %s"
+msgstr "%s:不能解析父提交 %s"
+
+#: sequencer.c:343
+#, c-format
+msgid "Cannot get commit message for %s"
+msgstr "不能得到 %s 的提交说明"
+
+#: sequencer.c:427
+#, c-format
+msgid "could not revert %s... %s"
+msgstr "不能还原 %s... %s"
+
+#: sequencer.c:428
+#, c-format
+msgid "could not apply %s... %s"
+msgstr "不能应用 %s... %s"
+
+#: sequencer.c:450 sequencer.c:909 builtin/log.c:288 builtin/log.c:713
+#: builtin/log.c:1329 builtin/log.c:1548 builtin/merge.c:347
+#: builtin/shortlog.c:181
+msgid "revision walk setup failed"
+msgstr "版本遍历设置失败"
+
+#: sequencer.c:453
+msgid "empty commit set passed"
+msgstr "提供了空的提交集"
+
+#: sequencer.c:461
+#, c-format
+msgid "git %s: failed to read the index"
+msgstr "git %s:无法读取索引"
+
+#: sequencer.c:466
+#, c-format
+msgid "git %s: failed to refresh the index"
+msgstr "git %s:无法刷新索引"
+
+#: sequencer.c:551
+#, c-format
+msgid "Cannot %s during a %s"
+msgstr "无法 %s 在一个 %s 过程中"
+
+#: sequencer.c:573
+#, c-format
+msgid "Could not parse line %d."
+msgstr "不能解析第 %d 行。"
+
+#: sequencer.c:578
+msgid "No commits parsed."
+msgstr "没有提交被解析。"
+
+#: sequencer.c:591
+#, c-format
+msgid "Could not open %s"
+msgstr "不能打开 %s"
+
+#: sequencer.c:595
+#, c-format
+msgid "Could not read %s."
+msgstr "不能读取 %s。"
+
+#: sequencer.c:602
+#, c-format
+msgid "Unusable instruction sheet: %s"
+msgstr "无用的指令表单:%s"
+
+#: sequencer.c:630
+#, c-format
+msgid "Invalid key: %s"
+msgstr "无效键名:%s"
+
+#: sequencer.c:633
+#, c-format
+msgid "Invalid value for %s: %s"
+msgstr "无效的 %s 值:%s"
+
+#: sequencer.c:645
+#, c-format
+msgid "Malformed options sheet: %s"
+msgstr "非法的选项表单:%s"
+
+#: sequencer.c:666
+msgid "a cherry-pick or revert is already in progress"
+msgstr "一个拣选或还原操作已在进行"
+
+#: sequencer.c:667
+msgid "try \"git cherry-pick (--continue | --quit | --abort)\""
+msgstr "尝试 \"git cherry-pick (--continue | --quit | --abort)\""
+
+#: sequencer.c:671
+#, c-format
+msgid "Could not create sequencer directory %s"
+msgstr "不能创建序列目录 %s"
+
+#: sequencer.c:687 sequencer.c:772
+#, c-format
+msgid "Error wrapping up %s."
+msgstr "错误收尾 %s。"
+
+#: sequencer.c:706 sequencer.c:840
+msgid "no cherry-pick or revert in progress"
+msgstr "没有拣选或还原操作在进行"
+
+#: sequencer.c:708
+msgid "cannot resolve HEAD"
+msgstr "不能解析 HEAD"
+
+#: sequencer.c:710
+msgid "cannot abort from a branch yet to be born"
+msgstr "不能从尚未建立的分支终止"
+
+#: sequencer.c:732
+#, c-format
+msgid "cannot open %s: %s"
+msgstr "不能打开 %s:%s"
+
+#: sequencer.c:735
+#, c-format
+msgid "cannot read %s: %s"
+msgstr "不能读取 %s:%s"
+
+#: sequencer.c:736
+msgid "unexpected end of file"
+msgstr "未预期的文件结束"
+
+#: sequencer.c:742
+#, c-format
+msgid "stored pre-cherry-pick HEAD file '%s' is corrupt"
+msgstr "保存拣选提交前的 HEAD 文件 '%s' 损坏"
+
+#: sequencer.c:765
+#, c-format
+msgid "Could not format %s."
+msgstr "不能格式化 %s。"
+
+#: sequencer.c:927
+msgid "Can't revert as initial commit"
+msgstr "不能作为初始提交还原"
+
+#: sequencer.c:928
+msgid "Can't cherry-pick into empty head"
+msgstr "不能拣选到空分支"
+
+#: wt-status.c:134
+msgid "Unmerged paths:"
+msgstr "未合并的路径:"
+
+# 译者:注意保持前导空格
+#: wt-status.c:140 wt-status.c:157
+#, c-format
+msgid " (use \"git reset %s <file>...\" to unstage)"
+msgstr " (使用 \"git reset %s <file>...\" 撤出暂存区)"
+
+# 译者:注意保持前导空格
+#: wt-status.c:142 wt-status.c:159
+msgid " (use \"git rm --cached <file>...\" to unstage)"
+msgstr " (使用 \"git rm --cached <file>...\" 撤出暂存区)"
+
+# 译者:注意保持前导空格
+#: wt-status.c:143
+msgid " (use \"git add/rm <file>...\" as appropriate to mark resolution)"
+msgstr " (酌情使用 \"git add/rm <file>...\" 标记解决方案)"
+
+#: wt-status.c:151
+msgid "Changes to be committed:"
+msgstr "要提交的变更:"
+
+#: wt-status.c:169
+msgid "Changes not staged for commit:"
+msgstr "尚未暂存以备提交的变更:"
+
+# 译者:注意保持前导空格
+#: wt-status.c:173
+msgid " (use \"git add <file>...\" to update what will be committed)"
+msgstr " (使用 \"git add <file>...\" 更新要提交的内容)"
+
+# 译者:注意保持前导空格
+#: wt-status.c:175
+msgid " (use \"git add/rm <file>...\" to update what will be committed)"
+msgstr " (使用 \"git add/rm <file>...\" 更新要提交的内容)"
+
+# 译者:注意保持前导空格
+#: wt-status.c:176
+msgid ""
+" (use \"git checkout -- <file>...\" to discard changes in working directory)"
+msgstr " (使用 \"git checkout -- <file>...\" 丢弃工作区的改动)"
+
+# 译者:注意保持前导空格
+#: wt-status.c:178
+msgid " (commit or discard the untracked or modified content in submodules)"
+msgstr " (提交或丢弃子模组中未跟踪或修改的内容)"
+
+#: wt-status.c:187
+#, c-format
+msgid "%s files:"
+msgstr "%s文件:"
+
+# 译者:注意保持前导空格
+#: wt-status.c:190
+#, c-format
+msgid " (use \"git %s <file>...\" to include in what will be committed)"
+msgstr " (使用 \"git %s <file>...\" 以包含要提交的内容)"
+
+#: wt-status.c:207
+msgid "bug"
+msgstr "bug"
+
+#: wt-status.c:212
+msgid "both deleted:"
+msgstr "双方删除:"
+
+#: wt-status.c:213
+msgid "added by us:"
+msgstr "由我们添加:"
+
+#: wt-status.c:214
+msgid "deleted by them:"
+msgstr "由他们删除:"
+
+#: wt-status.c:215
+msgid "added by them:"
+msgstr "由他们添加:"
+
+#: wt-status.c:216
+msgid "deleted by us:"
+msgstr "由我们删除:"
+
+#: wt-status.c:217
+msgid "both added:"
+msgstr "双方添加:"
+
+#: wt-status.c:218
+msgid "both modified:"
+msgstr "双方修改:"
+
+# 译者:末尾两个字节可能被删减,如果翻译为中文标点会出现半个汉字
+#: wt-status.c:248
+msgid "new commits, "
+msgstr "新提交, "
+
+# 译者:末尾两个字节可能被删减,如果翻译为中文标点会出现半个汉字
+#: wt-status.c:250
+msgid "modified content, "
+msgstr "修改的内容, "
+
+# 译者:末尾两个字节可能被删减,如果翻译为中文标点会出现半个汉字
+#: wt-status.c:252
+msgid "untracked content, "
+msgstr "未跟踪的内容, "
+
+# 译者:为保证在输出中对齐,注意调整句中空格!
+#: wt-status.c:266
+#, c-format
+msgid "new file: %s"
+msgstr "新文件: %s"
+
+# 译者:为保证在输出中对齐,注意调整句中空格!
+#: wt-status.c:269
+#, c-format
+msgid "copied: %s -> %s"
+msgstr "拷贝: %s -> %s"
+
+# 译者:为保证在输出中对齐,注意调整句中空格!
+#: wt-status.c:272
+#, c-format
+msgid "deleted: %s"
+msgstr "删除: %s"
+
+# 译者:为保证在输出中对齐,注意调整句中空格!
+#: wt-status.c:275
+#, c-format
+msgid "modified: %s"
+msgstr "修改: %s"
+
+# 译者:为保证在输出中对齐,注意调整句中空格!
+#: wt-status.c:278
+#, c-format
+msgid "renamed: %s -> %s"
+msgstr "重命名: %s -> %s"
+
+# 译者:为保证在输出中对齐,注意调整句中空格!
+#: wt-status.c:281
+#, c-format
+msgid "typechange: %s"
+msgstr "类型变更: %s"
+
+# 译者:为保证在输出中对齐,注意调整句中空格!
+#: wt-status.c:284
+#, c-format
+msgid "unknown: %s"
+msgstr "未知: %s"
+
+# 译者:为保证在输出中对齐,注意调整句中空格!
+#: wt-status.c:287
+#, c-format
+msgid "unmerged: %s"
+msgstr "未合并: %s"
+
+#: wt-status.c:290
+#, c-format
+msgid "bug: unhandled diff status %c"
+msgstr "bug:未处理的差异状态 %c"
+
+#: wt-status.c:713
+msgid "On branch "
+msgstr "位于分支 "
+
+#: wt-status.c:720
+msgid "Not currently on any branch."
+msgstr "当前不在任何分支上。"
+
+#: wt-status.c:731
+msgid "Initial commit"
+msgstr "初始提交"
+
+#: wt-status.c:745
+msgid "Untracked"
+msgstr "未跟踪的"
+
+#: wt-status.c:747
+msgid "Ignored"
+msgstr "忽略的"
+
+#: wt-status.c:749
+#, c-format
+msgid "Untracked files not listed%s"
+msgstr "未跟踪的文件没有列出%s"
+
+# 译者:中文字符串拼接,可删除前导空格
+#: wt-status.c:751
+msgid " (use -u option to show untracked files)"
+msgstr "(使用 -u 参数显示未跟踪的文件)"
+
+#: wt-status.c:757
+msgid "No changes"
+msgstr "没有修改"
+
+#: wt-status.c:761
+#, c-format
+msgid "no changes added to commit%s\n"
+msgstr "修改尚未加入提交%s\n"
+
+# 译者:中文字符串拼接,可删除前导空格
+#: wt-status.c:763
+msgid " (use \"git add\" and/or \"git commit -a\")"
+msgstr "(使用 \"git add\" 和/或 \"git commit -a\")"
+
+#: wt-status.c:765
+#, c-format
+msgid "nothing added to commit but untracked files present%s\n"
+msgstr "空提交但存在未跟踪文件%s\n"
+
+# 译者:中文字符串拼接,可删除前导空格
+#: wt-status.c:767
+msgid " (use \"git add\" to track)"
+msgstr "(使用 \"git add\" 建立跟踪)"
+
+#: wt-status.c:769 wt-status.c:772 wt-status.c:775
+#, c-format
+msgid "nothing to commit%s\n"
+msgstr "无须提交%s\n"
+
+# 译者:中文字符串拼接,可删除前导空格
+#: wt-status.c:770
+msgid " (create/copy files and use \"git add\" to track)"
+msgstr "(新建/拷贝的文件使用 \"git add\" 建立跟踪)"
+
+# 译者:中文字符串拼接,可删除前导空格
+#: wt-status.c:773
+msgid " (use -u to show untracked files)"
+msgstr "(使用 -u 显示未跟踪文件)"
+
+# 译者:中文字符串拼接,可删除前导空格
+#: wt-status.c:776
+msgid " (working directory clean)"
+msgstr "(干净的工作区)"
+
+#: wt-status.c:884
+msgid "HEAD (no branch)"
+msgstr "HEAD(非分支)"
+
+# 译者:注意保持句尾空格
+#: wt-status.c:890
+msgid "Initial commit on "
+msgstr "初始提交于 "
+
+# 译者:注意保持句尾空格
+#: wt-status.c:905
+msgid "behind "
+msgstr "落后 "
+
+# 译者:注意保持句尾空格
+#: wt-status.c:908 wt-status.c:911
+msgid "ahead "
+msgstr "领先 "
+
+# 译者:注意保持句尾空格
+#: wt-status.c:913
+msgid ", behind "
+msgstr ",落后 "
+
+#: builtin/add.c:62
+#, c-format
+msgid "unexpected diff status %c"
+msgstr "意外的差异状态 %c"
+
+#: builtin/add.c:67 builtin/commit.c:298
+msgid "updating files failed"
+msgstr "更新文件失败"
+
+#: builtin/add.c:77
+#, c-format
+msgid "remove '%s'\n"
+msgstr "删除 '%s'\n"
+
+#: builtin/add.c:176
+#, c-format
+msgid "Path '%s' is in submodule '%.*s'"
+msgstr "路径 '%s' 属于模组 '%.*s'"
+
+#: builtin/add.c:192
+msgid "Unstaged changes after refreshing the index:"
+msgstr "刷新索引之后尚未被暂存的变更:"
+
+#: builtin/add.c:195 builtin/add.c:456 builtin/rm.c:186
+#, c-format
+msgid "pathspec '%s' did not match any files"
+msgstr "路径 '%s' 未匹配任何文件"
+
+#: builtin/add.c:209
+#, c-format
+msgid "'%s' is beyond a symbolic link"
+msgstr "'%s' 位于符号链接中"
+
+#: builtin/add.c:276
+msgid "Could not read the index"
+msgstr "不能读取索引"
+
+#: builtin/add.c:286
+#, c-format
+msgid "Could not open '%s' for writing."
+msgstr "不能为写入打开 '%s'。"
+
+#: builtin/add.c:290
+msgid "Could not write patch"
+msgstr "不能写补丁"
+
+#: builtin/add.c:295
+#, c-format
+msgid "Could not stat '%s'"
+msgstr "不能查看文件状态 '%s'"
+
+#: builtin/add.c:297
+msgid "Empty patch. Aborted."
+msgstr "空补丁。异常终止。"
+
+#: builtin/add.c:303
+#, c-format
+msgid "Could not apply '%s'"
+msgstr "不能应用 '%s'"
+
+#: builtin/add.c:312
+msgid "The following paths are ignored by one of your .gitignore files:\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:353
+msgid "no files added"
+msgstr "没有文件被添加"
+
+#: builtin/add.c:359
+msgid "adding files failed"
+msgstr "添加文件失败"
+
+#: builtin/add.c:391
+msgid "-A and -u are mutually incompatible"
+msgstr "-A 和 -u 选项互斥"
+
+#: builtin/add.c:393
+msgid "Option --ignore-missing can only be used together with --dry-run"
+msgstr "选项 --ignore-missing 只能和 --dry-run 共用"
+
+#: builtin/add.c:413
+#, c-format
+msgid "Nothing specified, nothing added.\n"
+msgstr "没有指定文件,也没有文件被添加。\n"
+
+#: builtin/add.c:414
+#, 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:358 builtin/mv.c:82
+#: builtin/rm.c:162
+msgid "index file corrupt"
+msgstr "索引文件损坏"
+
+#: builtin/add.c:476 builtin/mv.c:229 builtin/rm.c:260
+msgid "Unable to write new index file"
+msgstr "无法写入新索引文件"
+
+#: builtin/archive.c:17
+#, c-format
+msgid "could not create archive file '%s'"
+msgstr "不能创建归档文件 '%s'"
+
+#: builtin/archive.c:20
+msgid "could not redirect output"
+msgstr "不能输出重定向"
+
+#: builtin/archive.c:37
+msgid "git archive: Remote with no URL"
+msgstr "git archive:未提供远程URL"
+
+#: builtin/archive.c:58
+msgid "git archive: expected ACK/NAK, got EOF"
+msgstr "git archive:期待ACK/NACK,却得到EOF"
+
+#: builtin/archive.c:63
+#, c-format
+msgid "git archive: NACK %s"
+msgstr "git archive:NACK %s"
+
+#: builtin/archive.c:65
+#, c-format
+msgid "remote error: %s"
+msgstr "远程错误:%s"
+
+#: builtin/archive.c:66
+msgid "git archive: protocol error"
+msgstr "git archive:协议错误"
+
+#: builtin/archive.c:71
+msgid "git archive: expected a flush"
+msgstr "git archive:预期一个刷新"
+
+# 译者:保持原换行格式,在输出时 %s 的替代内容会让字符串变长
+#: builtin/branch.c:137
+#, c-format
+msgid ""
+"deleting branch '%s' that has been merged to\n"
+" '%s', but not yet merged to HEAD."
+msgstr ""
+"将要删除的分支 '%s' 已经被合并到\n"
+" '%s',但未合并到 HEAD。"
+
+# 译者:保持原换行格式,在输出时 %s 的替代内容会让字符串变长
+#: builtin/branch.c:141
+#, c-format
+msgid ""
+"not deleting branch '%s' that is not yet merged to\n"
+" '%s', even though it is merged to HEAD."
+msgstr ""
+"并未删除分支 '%s', 虽然它已经合并到 HEAD,\n"
+" 然而却尚未被合并到分支 '%s' 。"
+
+# 译者:汉字之间无空格,故删除尾部空格
+#. TRANSLATORS: This is "remote " in "remote branch '%s' not found"
+#: builtin/branch.c:163
+msgid "remote "
+msgstr "远程"
+
+#: builtin/branch.c:171
+msgid "cannot use -a with -d"
+msgstr "不能将 -a 和 -d 共用"
+
+#: builtin/branch.c:177
+msgid "Couldn't look up commit object for HEAD"
+msgstr "无法查询 HEAD 指向的提交对象"
+
+#: builtin/branch.c:182
+#, c-format
+msgid "Cannot delete the branch '%s' which you are currently on."
+msgstr "无法删除您当前所在的分支 '%s'。"
+
+#: builtin/branch.c:192
+#, c-format
+msgid "%sbranch '%s' not found."
+msgstr "%s分支 '%s' 未发现。"
+
+#: builtin/branch.c:200
+#, c-format
+msgid "Couldn't look up commit object for '%s'"
+msgstr "无法查询 '%s' 指向的提交对象"
+
+#: builtin/branch.c:206
+#, 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 ""
+"分支 '%s' 没有完全合并。\n"
+"如果您确认要删除它,执行 'git branch -D %s'。"
+
+#: builtin/branch.c:214
+#, c-format
+msgid "Error deleting %sbranch '%s'"
+msgstr "删除 %s分支 '%s' 时出错"
+
+#: builtin/branch.c:219
+#, c-format
+msgid "Deleted %sbranch %s (was %s).\n"
+msgstr "已删除 %s分支 %s(曾为 %s)。\n"
+
+#: builtin/branch.c:224
+msgid "Update of config-file failed"
+msgstr "无法更新 config 文件"
+
+#: builtin/branch.c:322
+#, c-format
+msgid "branch '%s' does not point at a commit"
+msgstr "分支 '%s' 未指向一个提交"
+
+# 译者:注意保持句尾空格
+#: builtin/branch.c:394
+#, c-format
+msgid "behind %d] "
+msgstr "落后 %d] "
+
+# 译者:注意保持句尾空格
+#: builtin/branch.c:396
+#, c-format
+msgid "ahead %d] "
+msgstr "领先 %d] "
+
+# 译者:注意保持句尾空格
+#: builtin/branch.c:398
+#, c-format
+msgid "ahead %d, behind %d] "
+msgstr "领先 %d,落后 %d] "
+
+#: builtin/branch.c:501
+msgid "(no branch)"
+msgstr "(非分支)"
+
+#: builtin/branch.c:566
+msgid "some refs could not be read"
+msgstr "一些引用不能读取"
+
+#: builtin/branch.c:579
+msgid "cannot rename the current branch while not on any."
+msgstr "无法重命名当前分支因为不处于任何分支上。"
+
+#: builtin/branch.c:589
+#, c-format
+msgid "Invalid branch name: '%s'"
+msgstr "无效的分支名:'%s'"
+
+#: builtin/branch.c:604
+msgid "Branch rename failed"
+msgstr "分支重命名失败"
+
+#: builtin/branch.c:608
+#, c-format
+msgid "Renamed a misnamed branch '%s' away"
+msgstr "重命名掉一个错误命名的旧分支 '%s'"
+
+#: builtin/branch.c:612
+#, c-format
+msgid "Branch renamed to %s, but HEAD is not updated!"
+msgstr "分支重命名为 %s,但 HEAD 没有更新!"
+
+#: builtin/branch.c:619
+msgid "Branch is renamed, but update of config-file failed"
+msgstr "分支被重命名,但更新 config 文件失败"
+
+#: builtin/branch.c:634
+#, c-format
+msgid "malformed object name %s"
+msgstr "非法的对象名 %s"
+
+#: builtin/branch.c:658
+#, c-format
+msgid "could not write branch description template: %s\n"
+msgstr "不能写分支描述模版:%s\n"
+
+#: builtin/branch.c:746
+msgid "Failed to resolve HEAD as a valid ref."
+msgstr "无法将 HEAD 解析为有效引用。"
+
+#: builtin/branch.c:751 builtin/clone.c:558
+msgid "HEAD not found below refs/heads!"
+msgstr "HEAD 没有位于 /refs/heads 之下!"
+
+#: builtin/branch.c:809
+msgid "-a and -r options to 'git branch' do not make sense with a branch name"
+msgstr "'git branch' 的 -a 和 -r 选项带一个分支名参数没有意义"
+
+#: builtin/bundle.c:47
+#, c-format
+msgid "%s is okay\n"
+msgstr "%s 可以\n"
+
+#: builtin/bundle.c:56
+msgid "Need a repository to create a bundle."
+msgstr "需要一个版本库来创建包。"
+
+#: builtin/bundle.c:60
+msgid "Need a repository to unbundle."
+msgstr "需要一个版本库来解包。"
+
+#: builtin/checkout.c:113 builtin/checkout.c:146
+#, c-format
+msgid "path '%s' does not have our version"
+msgstr "路径 '%s' 没有我们的版本"
+
+#: builtin/checkout.c:115 builtin/checkout.c:148
+#, c-format
+msgid "path '%s' does not have their version"
+msgstr "路径 '%s' 没有他们的版本"
+
+#: builtin/checkout.c:131
+#, c-format
+msgid "path '%s' does not have all necessary versions"
+msgstr "路径 '%s' 没有全部必须的版本"
+
+#: builtin/checkout.c:175
+#, c-format
+msgid "path '%s' does not have necessary versions"
+msgstr "路径 '%s' 没有必须的版本"
+
+#: builtin/checkout.c:192
+#, c-format
+msgid "path '%s': cannot merge"
+msgstr "path '%s':无法合并"
+
+#: builtin/checkout.c:209
+#, c-format
+msgid "Unable to add merge result for '%s'"
+msgstr "无法为 '%s' 添加合并结果"
+
+#: builtin/checkout.c:212 builtin/reset.c:158
+#, c-format
+msgid "make_cache_entry failed for path '%s'"
+msgstr "对路径 '%s' 的 make_cache_entry 操作失败"
+
+#: builtin/checkout.c:234 builtin/checkout.c:392
+msgid "corrupt index file"
+msgstr "损坏的索引文件"
+
+#: builtin/checkout.c:264 builtin/checkout.c:271
+#, 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
+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
+msgid "you need to resolve your current index first"
+msgstr "您需要先解决当前索引的冲突"
+
+#: builtin/checkout.c:533
+#, c-format
+msgid "Can not do reflog for '%s'\n"
+msgstr "不能对 '%s' 执行 reflog 操作\n"
+
+#: builtin/checkout.c:565
+msgid "HEAD is now at"
+msgstr "HEAD 目前位于"
+
+#: builtin/checkout.c:572
+#, c-format
+msgid "Reset branch '%s'\n"
+msgstr "重置分支 '%s'\n"
+
+#: builtin/checkout.c:575
+#, c-format
+msgid "Already on '%s'\n"
+msgstr "已经位于 '%s'\n"
+
+#: builtin/checkout.c:579
+#, c-format
+msgid "Switched to and reset branch '%s'\n"
+msgstr "切换并重置分支 '%s'\n"
+
+#: builtin/checkout.c:581
+#, c-format
+msgid "Switched to a new branch '%s'\n"
+msgstr "切换到一个新分支 '%s'\n"
+
+#: builtin/checkout.c:583
+#, c-format
+msgid "Switched to branch '%s'\n"
+msgstr "切换到分支 '%s'\n"
+
+# 译者:注意保持前导空格
+#: builtin/checkout.c:639
+#, c-format
+msgid " ... and %d more.\n"
+msgstr " ... 及其它 %d 个。\n"
+
+#. The singular version
+#: builtin/checkout.c:645
+#, 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"
+"\n"
+"%s\n"
+msgstr[0] ""
+"警告:您正丢下 %d 个提交,未和任何分支关联:\n"
+"\n"
+"%s\n"
+
+#: builtin/checkout.c:663
+#, 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"
+msgstr ""
+"如果您想要通过创建新分支保存他们,这可能是一个好时候。\n"
+"如下操作:\n"
+"\n"
+" git branch new_branch_name %s\n"
+"\n"
+
+#: builtin/checkout.c:693
+msgid "internal error in revision walk"
+msgstr "在版本遍历时遇到内部错误"
+
+#: builtin/checkout.c:697
+msgid "Previous HEAD position was"
+msgstr "之前的 HEAD 位置是"
+
+#: builtin/checkout.c:723
+msgid "You are on a branch yet to be born"
+msgstr "您位于一个尚未初始化的分支"
+
+#. case (1)
+#: builtin/checkout.c:854
+#, c-format
+msgid "invalid reference: %s"
+msgstr "无效引用:%s"
+
+#. case (1): want a tree
+#: builtin/checkout.c:893
+#, c-format
+msgid "reference is not a tree: %s"
+msgstr "引用不是一个树:%s"
+
+#: builtin/checkout.c:973
+msgid "-B cannot be used with -b"
+msgstr "-B 不能和 -b 共用"
+
+#: builtin/checkout.c:982
+msgid "--patch is incompatible with all other options"
+msgstr "--patch 选项和其他选项不兼容"
+
+#: builtin/checkout.c:985
+msgid "--detach cannot be used with -b/-B/--orphan"
+msgstr "--detach 不能和 -b/-B/--orphan 共用"
+
+#: builtin/checkout.c:987
+msgid "--detach cannot be used with -t"
+msgstr "--detach 不能和 -t 共用"
+
+#: builtin/checkout.c:993
+msgid "--track needs a branch name"
+msgstr "--track 需要一个分支名"
+
+#: builtin/checkout.c:1000
+msgid "Missing branch name; try -b"
+msgstr "缺少分支名;尝试 -b"
+
+#: builtin/checkout.c:1006
+msgid "--orphan and -b|-B are mutually exclusive"
+msgstr "--orphan 和 -b|-B 互斥"
+
+#: builtin/checkout.c:1008
+msgid "--orphan cannot be used with -t"
+msgstr "--orphan 不能和 -t 共用"
+
+#: builtin/checkout.c:1018
+msgid "git checkout: -f and -m are incompatible"
+msgstr "git checkout:-f 和 -m 不兼容"
+
+#: builtin/checkout.c:1052
+msgid "invalid path specification"
+msgstr "无效的路径规格"
+
+#: builtin/checkout.c:1060
+#, 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?"
+msgstr ""
+"git checkout:更新路径和切换分支不兼容。\n"
+"您是想要检出 '%s' 但未能将其解析为提交么?"
+
+#: builtin/checkout.c:1062
+msgid "git checkout: updating paths is incompatible with switching branches."
+msgstr "git checkout:更新路径和切换分支不兼容。"
+
+#: builtin/checkout.c:1067
+msgid "git checkout: --detach does not take a path argument"
+msgstr "git checkout:--detach 不跟路径参数"
+
+#: builtin/checkout.c:1070
+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:1089
+msgid "Cannot switch branch to a non-commit."
+msgstr "无法切换分支到一个非提交。"
+
+#: builtin/checkout.c:1092
+msgid "--ours/--theirs is incompatible with switching branches."
+msgstr "--ours/--theirs 和切换分支不兼容。"
+
+#: builtin/clean.c:78
+msgid "-x and -X cannot be used together"
+msgstr "-x 和 -X 不能共用"
+
+#: builtin/clean.c:82
+msgid ""
+"clean.requireForce set to true and neither -n nor -f given; refusing to clean"
+msgstr ""
+"clean.requireForce 设置为 true 且未提供 -n 或 -f 选项,拒绝执行清理动作"
+
+#: builtin/clean.c:85
+msgid ""
+"clean.requireForce defaults to true and neither -n nor -f given; refusing to "
+"clean"
+msgstr ""
+"clean.requireForce 默认为 true 且未提供 -n 或 -f 选项,拒绝执行清理动作"
+
+#: builtin/clean.c:155 builtin/clean.c:176
+#, c-format
+msgid "Would remove %s\n"
+msgstr "将删除 %s\n"
+
+#: builtin/clean.c:159 builtin/clean.c:179
+#, c-format
+msgid "Removing %s\n"
+msgstr "正删除 %s\n"
+
+#: builtin/clean.c:162 builtin/clean.c:182
+#, c-format
+msgid "failed to remove %s"
+msgstr "无法删除 %s"
+
+#: builtin/clean.c:166
+#, c-format
+msgid "Would not remove %s\n"
+msgstr "不会删除 %s\n"
+
+#: builtin/clean.c:168
+#, c-format
+msgid "Not removing %s\n"
+msgstr "未删除 %s\n"
+
+#: 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
+#, c-format
+msgid "failed to stat '%s'"
+msgstr "无法枚举 '%s' 状态"
+
+#: builtin/clone.c:310
+#, c-format
+msgid "%s exists and is not a directory"
+msgstr "%s 存在且不是一个目录"
+
+#: builtin/clone.c:324
+#, c-format
+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'"
+msgstr "无法创建链接 '%s'"
+
+#: builtin/clone.c:350
+#, c-format
+msgid "failed to copy file to '%s'"
+msgstr "无法拷贝文件至 '%s'"
+
+#: builtin/clone.c:373
+#, c-format
+msgid "done.\n"
+msgstr "完成。\n"
+
+#: builtin/clone.c:440
+#, c-format
+msgid "Could not find remote branch %s to clone."
+msgstr "不能发现要克隆的远程分支 %s。"
+
+#: builtin/clone.c:549
+msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n"
+msgstr "远程 HEAD 指向一个不存在的引用,无法检出。\n"
+
+#: builtin/clone.c:639
+msgid "Too many arguments."
+msgstr "太多参数。"
+
+#: builtin/clone.c:643
+msgid "You must specify a repository to clone."
+msgstr "您必须指定一个版本库来克隆。"
+
+#: builtin/clone.c:654
+#, c-format
+msgid "--bare and --origin %s options are incompatible."
+msgstr "--bare 和 --origin %s 选项不兼容。"
+
+#: builtin/clone.c:668
+#, c-format
+msgid "repository '%s' does not exist"
+msgstr "版本库 '%s' 不存在"
+
+#: builtin/clone.c:673
+msgid "--depth is ignored in local clones; use file:// instead."
+msgstr "--depth 在本地克隆被忽略,改为 file:// 协议试试。"
+
+#: builtin/clone.c:683
+#, c-format
+msgid "destination path '%s' already exists and is not an empty directory."
+msgstr "目标路径 '%s' 已经存在,并且不是一个空目录。"
+
+#: builtin/clone.c:693
+#, c-format
+msgid "working tree '%s' already exists."
+msgstr "工作区 '%s' 已经存在。"
+
+#: builtin/clone.c:706 builtin/clone.c:720
+#, c-format
+msgid "could not create leading directories of '%s'"
+msgstr "不能为 '%s' 创建先导目录"
+
+#: builtin/clone.c:709
+#, c-format
+msgid "could not create work tree dir '%s'."
+msgstr "不能为 '%s' 创建工作区目录。"
+
+#: builtin/clone.c:728
+#, c-format
+msgid "Cloning into bare repository '%s'...\n"
+msgstr "克隆到裸版本库 '%s'...\n"
+
+#: builtin/clone.c:730
+#, c-format
+msgid "Cloning into '%s'...\n"
+msgstr "正克隆到 '%s'...\n"
+
+#: builtin/clone.c:786
+#, c-format
+msgid "Don't know how to clone %s"
+msgstr "不知道如何克隆 %s"
+
+#: builtin/clone.c:835
+#, c-format
+msgid "Remote branch %s not found in upstream %s"
+msgstr "远程分支 %s 在上游 %s 未发现"
+
+#: builtin/clone.c:842
+msgid "You appear to have cloned an empty repository."
+msgstr "您似乎克隆了一个空版本库。"
+
+#: builtin/commit.c:42
+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 ""
+"您的姓名和邮件地址基于登录名和主机名进行了自动设置。请检查它们正确\n"
+"与否。您可以通过下面的命令对其进行明确地设置以免再出现本提示信息:\n"
+"\n"
+" git config --global user.name \"Your Name\"\n"
+" git config --global user.email you@example.com\n"
+"\n"
+"设置完毕后,您可以用下面的命令来修正本次提交所使用的用户身份:\n"
+"\n"
+" git commit --amend --reset-author\n"
+
+#: builtin/commit.c:54
+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 ""
+"您要修补最近的提交,但这么做会让它成为空提交。您可以重复您的命令并带上\n"
+"--allow-empty 选项,或者您可用命令 \"git reset HEAD^\" 整个删除该提交。\n"
+
+#: builtin/commit.c:59
+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 ""
+"之前的拣选操作现在是一个空提交,可能是由冲突解决导致的。如果您无论如何\n"
+"也要提交,使用命令:\n"
+"\n"
+" git commit --allow-empty\n"
+"\n"
+"否则,请使用命令 'git reset'\n"
+
+#: builtin/commit.c:205 builtin/reset.c:33
+msgid "merge"
+msgstr "合并"
+
+#: builtin/commit.c:208
+msgid "cherry-pick"
+msgstr "拣选"
+
+#: builtin/commit.c:325
+msgid "failed to unpack HEAD tree object"
+msgstr "无法解包 HEAD 树对象"
+
+#: builtin/commit.c:367
+msgid "unable to create temporary index"
+msgstr "不能创建临时索引"
+
+#: builtin/commit.c:373
+msgid "interactive add failed"
+msgstr "交互式添加失败"
+
+#: builtin/commit.c:406 builtin/commit.c:427 builtin/commit.c:473
+msgid "unable to write new_index file"
+msgstr "无法写 new_index 文件"
+
+# 译者:%s若翻为中文,前后不需要空格
+#: builtin/commit.c:457
+#, c-format
+msgid "cannot do a partial commit during a %s."
+msgstr "在%s过程中不能做部分提交。"
+
+#: builtin/commit.c:466
+msgid "cannot read the index"
+msgstr "无法读取索引"
+
+#: builtin/commit.c:486
+msgid "unable to write temporary index file"
+msgstr "无法写临时索引文件"
+
+#: builtin/commit.c:561 builtin/commit.c:567
+#, c-format
+msgid "invalid commit: %s"
+msgstr "无效的提交:%s"
+
+#: builtin/commit.c:590
+msgid "malformed --author parameter"
+msgstr "非法的 --author 参数"
+
+#: builtin/commit.c:651
+#, c-format
+msgid "Malformed ident string: '%s'"
+msgstr "非法的身份字符串:'%s'"
+
+#: builtin/commit.c:689 builtin/commit.c:722 builtin/commit.c:1033
+#, c-format
+msgid "could not lookup commit %s"
+msgstr "不能查询提交 %s"
+
+#: builtin/commit.c:701 builtin/shortlog.c:296
+#, c-format
+msgid "(reading log message from standard input)\n"
+msgstr "(正从标准输入中读取日志信息)\n"
+
+#: builtin/commit.c:703
+msgid "could not read log from standard input"
+msgstr "不能从标准输入中读取日志信息"
+
+#: builtin/commit.c:707
+#, c-format
+msgid "could not read log file '%s'"
+msgstr "不能读取日志文件 '%s'"
+
+#: builtin/commit.c:713
+msgid "commit has empty message"
+msgstr "提交说明为空"
+
+#: builtin/commit.c:729
+msgid "could not read MERGE_MSG"
+msgstr "不能读取 MERGE_MSG"
+
+#: builtin/commit.c:733
+msgid "could not read SQUASH_MSG"
+msgstr "不能读取 SQUASH_MSG"
+
+#: builtin/commit.c:737
+#, c-format
+msgid "could not read '%s'"
+msgstr "不能读取 '%s'"
+
+#: builtin/commit.c:765
+#, c-format
+msgid "could not open '%s'"
+msgstr "不能打开 '%s'"
+
+#: builtin/commit.c:789
+msgid "could not write commit template"
+msgstr "不能写提交模版"
+
+# 译者:%s若翻为中文,前后不需要空格
+#: builtin/commit.c:799
+#, c-format
+msgid ""
+"\n"
+"It looks like you may be committing a %s.\n"
+"If this is not correct, please remove the file\n"
+"\t%s\n"
+"and try again.\n"
+msgstr ""
+"\n"
+"看起来您正在提交一个%s。\n"
+"如果不是这样,请删除文件\n"
+"\t%s\n"
+"然后重试。\n"
+
+#: builtin/commit.c:812
+msgid "Please enter the commit message for your changes."
+msgstr "请为您的修改输入提交说明。"
+
+# 译者:中文字符串拼接,可删除前导空格
+#: builtin/commit.c:815
+msgid ""
+" Lines starting\n"
+"with '#' will be ignored, and an empty message aborts the commit.\n"
+msgstr ""
+"以 '#' 开头\n"
+"的行将被忽略,并且空的提交说明将会中止提交。\n"
+
+# 译者:中文字符串拼接,可删除前导空格
+#: builtin/commit.c:820
+msgid ""
+" 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 ""
+"以 '#' 开头\n"
+"的行将被保留,您可以删除它们如果您想这样做的话。空的提交说明将会\n"
+"中止提交。\n"
+
+# 译者:为保证在输出中对齐,注意调整句中空格!
+#: builtin/commit.c:832
+#, c-format
+msgid "%sAuthor: %s"
+msgstr "%s作者: %s"
+
+# 译者:为保证在输出中对齐,注意调整句中空格!
+#: builtin/commit.c:839
+#, c-format
+msgid "%sCommitter: %s"
+msgstr "%s提交者: %s"
+
+#: builtin/commit.c:859
+msgid "Cannot read index"
+msgstr "无法读取索引"
+
+#: builtin/commit.c:896
+msgid "Error building trees"
+msgstr "无法创建树对象"
+
+#: builtin/commit.c:911 builtin/tag.c:357
+#, c-format
+msgid "Please supply the message using either -m or -F option.\n"
+msgstr "请使用 -m 或者 -F 选项提供提交说明。\n"
+
+#: builtin/commit.c:1008
+#, c-format
+msgid "No existing author found with '%s'"
+msgstr "没有找到匹配 '%s' 的作者"
+
+#: builtin/commit.c:1023 builtin/commit.c:1217
+#, c-format
+msgid "Invalid untracked files mode '%s'"
+msgstr "无效的未追踪文件参数 '%s'"
+
+#: builtin/commit.c:1063
+msgid "Using both --reset-author and --author does not make sense"
+msgstr "同时使用 --reset-author 和 --author 没有意义"
+
+#: builtin/commit.c:1074
+msgid "You have nothing to amend."
+msgstr "您没有可修补的提交。"
+
+# 译者:%s若翻为中文,前后不需要空格
+#: builtin/commit.c:1076
+#, c-format
+msgid "You are in the middle of a %s -- cannot amend."
+msgstr "您正处于一个%s的过程中 -- 无法修补提交。"
+
+#: builtin/commit.c:1078
+msgid "Options --squash and --fixup cannot be used together"
+msgstr "选项 --squash 和 --fixup 不能共用"
+
+#: builtin/commit.c:1088
+msgid "Only one of -c/-C/-F/--fixup can be used."
+msgstr "只能用一个 -c/-C/-F/--fixup 选项。"
+
+#: builtin/commit.c:1090
+msgid "Option -m cannot be combined with -c/-C/-F/--fixup."
+msgstr "选项 -m 不能和 -c/-C/-F/--fixup 共用。"
+
+#: builtin/commit.c:1098
+msgid "--reset-author can be used only with -C, -c or --amend."
+msgstr "--reset-author 只能和 -C、-c 或 --amend 共用。"
+
+#: builtin/commit.c:1115
+msgid "Only one of --include/--only/--all/--interactive/--patch can be used."
+msgstr "只能用一个 --include/--only/--all/--interactive/--patch 选项。"
+
+#: builtin/commit.c:1117
+msgid "No paths with --include/--only does not make sense."
+msgstr "参数 --include/--only 不跟路径没有意义。"
+
+#: builtin/commit.c:1119
+msgid "Clever... amending the last one with dirty index."
+msgstr "聪明... 在索引不干净下修补最后的提交。"
+
+#: builtin/commit.c:1121
+msgid "Explicit paths specified without -i nor -o; assuming --only paths..."
+msgstr "指定了明确的路径而没有使用 -i 或 -o 选项;认为是 --only paths..."
+
+#: builtin/commit.c:1131 builtin/tag.c:556
+#, c-format
+msgid "Invalid cleanup mode %s"
+msgstr "无效的清理模式 %s"
+
+#: builtin/commit.c:1136
+msgid "Paths with -a does not make sense."
+msgstr "路径和 -a 选项共用没有意义。"
+
+#: builtin/commit.c:1315
+msgid "couldn't look up newly created commit"
+msgstr "无法找到新创建的提交"
+
+#: builtin/commit.c:1317
+msgid "could not parse newly created commit"
+msgstr "不能解析新创建的提交"
+
+#: builtin/commit.c:1358
+msgid "detached HEAD"
+msgstr "分离头指针"
+
+# 译者:中文字符串拼接,可删除前导空格
+#: builtin/commit.c:1360
+msgid " (root-commit)"
+msgstr "(根提交)"
+
+#: builtin/commit.c:1450
+msgid "could not parse HEAD commit"
+msgstr "不能解析 HEAD 提交"
+
+#: builtin/commit.c:1487 builtin/merge.c:509
+#, c-format
+msgid "could not open '%s' for reading"
+msgstr "不能为读入打开 '%s'"
+
+#: builtin/commit.c:1494
+#, c-format
+msgid "Corrupt MERGE_HEAD file (%s)"
+msgstr "损坏的 MERGE_HEAD 文件(%s)"
+
+#: builtin/commit.c:1501
+msgid "could not read MERGE_MODE"
+msgstr "不能读取 MERGE_MODE"
+
+#: builtin/commit.c:1520
+#, c-format
+msgid "could not read commit message: %s"
+msgstr "不能读取提交说明:%s"
+
+#: builtin/commit.c:1534
+#, c-format
+msgid "Aborting commit; you did not edit the message.\n"
+msgstr "终止提交;您未更改来自模版的提交说明。\n"
+
+#: builtin/commit.c:1539
+#, c-format
+msgid "Aborting commit due to empty commit message.\n"
+msgstr "终止提交因为提交说明为空。\n"
+
+#: builtin/commit.c:1554 builtin/merge.c:936 builtin/merge.c:961
+msgid "failed to write commit object"
+msgstr "无法写提交对象"
+
+#: builtin/commit.c:1575
+msgid "cannot lock HEAD ref"
+msgstr "无法锁定 HEAD 引用"
+
+#: builtin/commit.c:1579
+msgid "cannot update HEAD ref"
+msgstr "无法更新 HEAD 引用"
+
+#: 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 ""
+"版本库已更新,但无法写 new_index 文件。检查是否磁盘已满\n"
+"或磁盘配额已耗尽,然后执行 \"git reset HEAD\" 恢复。"
+
+#: 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' 对象"
+
+#: builtin/describe.c:287
+#, c-format
+msgid "no tag exactly matches '%s'"
+msgstr "没有 tag 准确匹配 '%s'"
+
+#: builtin/describe.c:289
+#, c-format
+msgid "searching to describe %s\n"
+msgstr "搜索描述 %s\n"
+
+#: builtin/describe.c:329
+#, c-format
+msgid "finished search at %s\n"
+msgstr "完成搜索 %s\n"
+
+#: builtin/describe.c:353
+#, c-format
+msgid ""
+"No annotated tags can describe '%s'.\n"
+"However, there were unannotated tags: try --tags."
+msgstr ""
+"没有注释 tag 能描述 '%s'。\n"
+"然而,有非注释 tag:尝试 --tags。"
+
+#: builtin/describe.c:357
+#, c-format
+msgid ""
+"No tags can describe '%s'.\n"
+"Try --always, or create some tags."
+msgstr ""
+"没有注释 tag 能描述 '%s'。\n"
+"尝试 --always,或者创建一些 tag。"
+
+#: builtin/describe.c:378
+#, c-format
+msgid "traversed %lu commits\n"
+msgstr "已遍历 %lu 个提交\n"
+
+#: builtin/describe.c:381
+#, c-format
+msgid ""
+"more than %i tags found; listed %i most recent\n"
+"gave up search at %s\n"
+msgstr ""
+"发现多于 %i 个 tag,列出最近的 %i 个\n"
+"在 %s 放弃搜索\n"
+
+#: builtin/describe.c:436
+msgid "--long is incompatible with --abbrev=0"
+msgstr "--long 与 --abbrev=0 不兼容"
+
+#: builtin/describe.c:462
+msgid "No names found, cannot describe anything."
+msgstr "没有发现名称,无法描述任何东西。"
+
+#: builtin/describe.c:482
+msgid "--dirty is incompatible with committishes"
+msgstr "--dirty 不能与提交共用"
+
+#: builtin/diff.c:77
+#, c-format
+msgid "'%s': not a regular file or symlink"
+msgstr "'%s':不是一个正规文件或符号链接"
+
+#: builtin/diff.c:220
+#, c-format
+msgid "invalid option: %s"
+msgstr "无效选项:%s"
+
+#: builtin/diff.c:297
+msgid "Not a git repository"
+msgstr "不是一个 git 版本库"
+
+#: builtin/diff.c:347
+#, c-format
+msgid "invalid object '%s' given."
+msgstr "提供了无效对象 '%s'。"
+
+#: builtin/diff.c:352
+#, c-format
+msgid "more than %d trees given: '%s'"
+msgstr "提供了超过 %d 个树对象:'%s'"
+
+#: builtin/diff.c:362
+#, c-format
+msgid "more than two blobs given: '%s'"
+msgstr "提供了超过两个 blob 对象:'%s'"
+
+#: builtin/diff.c:370
+#, c-format
+msgid "unhandled object '%s' given."
+msgstr "提供了无法处理的对象 '%s'。"
+
+#: builtin/fetch.c:200
+msgid "Couldn't find remote ref HEAD"
+msgstr "无法发现远程 HEAD 引用"
+
+#: builtin/fetch.c:253
+#, c-format
+msgid "object %s not found"
+msgstr "对象 %s 未发现"
+
+#: builtin/fetch.c:259
+msgid "[up to date]"
+msgstr "[最新]"
+
+#: builtin/fetch.c:273
+#, c-format
+msgid "! %-*s %-*s -> %s (can't fetch in current branch)"
+msgstr "! %-*s %-*s -> %s (在当前分支下不能获取)"
+
+#: builtin/fetch.c:274 builtin/fetch.c:360
+msgid "[rejected]"
+msgstr "[已拒绝]"
+
+#: builtin/fetch.c:285
+msgid "[tag update]"
+msgstr "[tag更新]"
+
+# 译者:注意保持前导空格
+#: builtin/fetch.c:287 builtin/fetch.c:322 builtin/fetch.c:340
+msgid " (unable to update local ref)"
+msgstr " (不能更新本地引用)"
+
+#: builtin/fetch.c:305
+msgid "[new tag]"
+msgstr "[新tag]"
+
+#: builtin/fetch.c:308
+msgid "[new branch]"
+msgstr "[新分支]"
+
+#: builtin/fetch.c:311
+msgid "[new ref]"
+msgstr "[新引用]"
+
+#: builtin/fetch.c:356
+msgid "unable to update local ref"
+msgstr "不能更新本地引用"
+
+#: builtin/fetch.c:356
+msgid "forced update"
+msgstr "强制更新"
+
+#: builtin/fetch.c:362
+msgid "(non-fast-forward)"
+msgstr "(非快进式)"
+
+#: builtin/fetch.c:393 builtin/fetch.c:685
+#, c-format
+msgid "cannot open %s: %s\n"
+msgstr "无法打开 %s:%s\n"
+
+#: builtin/fetch.c:402
+#, c-format
+msgid "%s did not send all necessary objects\n"
+msgstr "%s 未发送所有必须的对象\n"
+
+#: builtin/fetch.c:488
+#, c-format
+msgid "From %.*s\n"
+msgstr "来自 %.*s\n"
+
+#: builtin/fetch.c:499
+#, c-format
+msgid ""
+"some local refs could not be updated; try running\n"
+" 'git remote prune %s' to remove any old, conflicting branches"
+msgstr ""
+"一些本地引用不能被更新;尝试运行\n"
+" 'git remote prune %s' 来删除旧的、有冲突的分支"
+
+# 译者:注意保持前导空格
+#: builtin/fetch.c:549
+#, c-format
+msgid " (%s will become dangling)\n"
+msgstr " (%s 将成为悬空状态)\n"
+
+# 译者:注意保持前导空格
+#: builtin/fetch.c:550
+#, c-format
+msgid " (%s has become dangling)\n"
+msgstr " (%s 已成为悬空状态)\n"
+
+#: builtin/fetch.c:557
+msgid "[deleted]"
+msgstr "[已删除]"
+
+#: builtin/fetch.c:558
+msgid "(none)"
+msgstr "(无)"
+
+#: builtin/fetch.c:675
+#, c-format
+msgid "Refusing to fetch into current branch %s of non-bare repository"
+msgstr "拒绝获取到非裸版本库的当前分支 %s"
+
+#: builtin/fetch.c:709
+#, c-format
+msgid "Don't know how to fetch from %s"
+msgstr "不知道如何从 %s 获取"
+
+#: builtin/fetch.c:786
+#, c-format
+msgid "Option \"%s\" value \"%s\" is not valid for %s"
+msgstr "选项 \"%s\" 的值 \"%s\" 对于 %s 是无效的"
+
+#: builtin/fetch.c:789
+#, c-format
+msgid "Option \"%s\" is ignored for %s\n"
+msgstr "选项 \"%s\" 对于 %s 被忽略\n"
+
+#: builtin/fetch.c:888
+#, c-format
+msgid "Fetching %s\n"
+msgstr "正在获取 %s\n"
+
+#: builtin/fetch.c:890
+#, c-format
+msgid "Could not fetch %s"
+msgstr "不能获取 %s"
+
+#: 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."
+msgstr "未指定远程版本库。请通过一个URL或远程版本库名指定,用以获取新提交。"
+
+#: builtin/fetch.c:927
+msgid "You need to specify a tag name."
+msgstr "您需要指定一个 tag 名称。"
+
+#: builtin/fetch.c:979
+msgid "fetch --all does not take a repository argument"
+msgstr "fetch --all 不能带一个版本库参数"
+
+#: builtin/fetch.c:981
+msgid "fetch --all does not make sense with refspecs"
+msgstr "fetch --all 带引用表达式没有任何意义"
+
+#: builtin/fetch.c:992
+#, c-format
+msgid "No such remote or remote group: %s"
+msgstr "没有这样的远程或远程组:%s"
+
+#: builtin/fetch.c:1000
+msgid "Fetching a group and specifying refspecs does not make sense"
+msgstr "获取组并指定引用表达式没有意义"
+
+#: builtin/gc.c:63
+#, c-format
+msgid "Invalid %s: '%s'"
+msgstr "无效的 %s:'%s'"
+
+#: builtin/gc.c:90
+#, c-format
+msgid "insanely long object directory %.*s"
+msgstr "不正常的长对象目录 %.*s"
+
+#: builtin/gc.c:221
+#, c-format
+msgid "Auto packing the repository for optimum performance.\n"
+msgstr "自动打包版本库以求最佳性能。\n"
+
+#: builtin/gc.c:224
+#, 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 ""
+"自动打包版本库以求最佳性能。您还可以手动运行 \"git gc\"。\n"
+"参见 \"git help gc\" 以获取更多信息。\n"
+
+#: builtin/gc.c:251
+msgid ""
+"There are too many unreachable loose objects; run 'git prune' to remove them."
+msgstr "有太多不可达的松散对象,运行 'git prune' 删除它们。"
+
+#: builtin/grep.c:216
+#, c-format
+msgid "grep: failed to create thread: %s"
+msgstr "grep:无法创建线程:%s"
+
+#: builtin/grep.c:402
+#, c-format
+msgid "Failed to chdir: %s"
+msgstr "无法切换目录:%s"
+
+#: builtin/grep.c:478 builtin/grep.c:512
+#, c-format
+msgid "unable to read tree (%s)"
+msgstr "无法读取树(%s)"
+
+#: builtin/grep.c:526
+#, c-format
+msgid "unable to grep from object of type %s"
+msgstr "无法抓取来自于 %s 类型的对象"
+
+#: builtin/grep.c:584
+#, c-format
+msgid "switch `%c' expects a numerical value"
+msgstr "开关 `%c' 期望一个数字值"
+
+#: builtin/grep.c:601
+#, c-format
+msgid "cannot open '%s'"
+msgstr "不能打开 '%s'"
+
+#: builtin/grep.c:888
+msgid "no pattern given."
+msgstr "未提供模式匹配。"
+
+#: builtin/grep.c:902
+#, c-format
+msgid "bad object %s"
+msgstr "坏对象 %s"
+
+#: builtin/grep.c:943
+msgid "--open-files-in-pager only works on the worktree"
+msgstr "--open-files-in-pager 仅用于工作区"
+
+#: builtin/grep.c:966
+msgid "--cached or --untracked cannot be used with --no-index."
+msgstr "--cached 或 --untracked 不能与 --no-index 共用。"
+
+#: builtin/grep.c:971
+msgid "--no-index or --untracked cannot be used with revs."
+msgstr "--no-index 或 --untracked 不能和版本共用。"
+
+#: builtin/grep.c:974
+msgid "--[no-]exclude-standard cannot be used for tracked contents."
+msgstr "--[no-]exclude-standard 不能用于已跟踪内容。"
+
+#: builtin/grep.c:982
+msgid "both --cached and trees are given."
+msgstr "同时给出了 --cached 和树对象。"
+
+#: builtin/init-db.c:35
+#, c-format
+msgid "Could not make %s writable by group"
+msgstr "不能设置 %s 为组可写"
+
+#: builtin/init-db.c:62
+#, c-format
+msgid "insanely long template name %s"
+msgstr "太长的模版名 %s"
+
+#: builtin/init-db.c:67
+#, c-format
+msgid "cannot stat '%s'"
+msgstr "不能枚举 '%s' 状态"
+
+#: builtin/init-db.c:73
+#, c-format
+msgid "cannot stat template '%s'"
+msgstr "不能枚举模版 '%s' 状态"
+
+#: builtin/init-db.c:80
+#, c-format
+msgid "cannot opendir '%s'"
+msgstr "不能打开目录 '%s'"
+
+#: builtin/init-db.c:97
+#, c-format
+msgid "cannot readlink '%s'"
+msgstr "不能读取链接 '%s'"
+
+#: builtin/init-db.c:99
+#, c-format
+msgid "insanely long symlink %s"
+msgstr "太长的符号链接 %s"
+
+#: builtin/init-db.c:102
+#, c-format
+msgid "cannot symlink '%s' '%s'"
+msgstr "不能自 '%s' 到 '%s' 创建符号链接"
+
+#: builtin/init-db.c:106
+#, c-format
+msgid "cannot copy '%s' to '%s'"
+msgstr "不能拷贝 '%s' 至 '%s'"
+
+#: builtin/init-db.c:110
+#, c-format
+msgid "ignoring template %s"
+msgstr "忽略模版 %s"
+
+#: builtin/init-db.c:133
+#, c-format
+msgid "insanely long template path %s"
+msgstr "太长的模版路径 %s"
+
+#: builtin/init-db.c:141
+#, c-format
+msgid "templates not found %s"
+msgstr "模版未找到 %s"
+
+#: builtin/init-db.c:154
+#, c-format
+msgid "not copying templates of a wrong format version %d from '%s'"
+msgstr "未复制错误版本 %d 的模版自 '%s'"
+
+#: builtin/init-db.c:192
+#, c-format
+msgid "insane git directory %s"
+msgstr "不正常的 git 目录 %s"
+
+#: builtin/init-db.c:322 builtin/init-db.c:325
+#, c-format
+msgid "%s already exists"
+msgstr "%s 已经存在"
+
+#: builtin/init-db.c:354
+#, c-format
+msgid "unable to handle file type %d"
+msgstr "不能处理 %d 类型的文件"
+
+#: builtin/init-db.c:357
+#, c-format
+msgid "unable to move %s to %s"
+msgstr "不能移动 %s 至 %s"
+
+#: builtin/init-db.c:362
+#, c-format
+msgid "Could not create git link %s"
+msgstr "不能创建 git link %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
+#, c-format
+msgid "%s%s Git repository in %s%s\n"
+msgstr "%s%s Git 版本库于 %s%s\n"
+
+#: builtin/init-db.c:420
+msgid "Reinitialized existing"
+msgstr "重新初始化现存的"
+
+#: builtin/init-db.c:420
+msgid "Initialized empty"
+msgstr "初始化空的"
+
+# 译者:中文字符串拼接,可删除前导空格
+#: builtin/init-db.c:421
+msgid " shared"
+msgstr "共享"
+
+#: builtin/init-db.c:440
+msgid "cannot tell cwd"
+msgstr "无法获知当前路径"
+
+#: builtin/init-db.c:521 builtin/init-db.c:528
+#, c-format
+msgid "cannot mkdir %s"
+msgstr "不能创建目录 %s"
+
+#: builtin/init-db.c:532
+#, c-format
+msgid "cannot chdir to %s"
+msgstr "不能切换目录到 %s"
+
+#: builtin/init-db.c:554
+#, c-format
+msgid ""
+"%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-"
+"dir=<directory>)"
+msgstr ""
+"不允许 %s(或 --work-tree=<directory>)而没有指定 %s(或 --git-"
+"dir=<directory>)"
+
+#: builtin/init-db.c:578
+msgid "Cannot access current working directory"
+msgstr "不能访问当前工作目录"
+
+#: builtin/init-db.c:585
+#, c-format
+msgid "Cannot access work tree '%s'"
+msgstr "不能访问工作区 '%s'"
+
+#: builtin/log.c:187
+#, c-format
+msgid "Final output: %d %s\n"
+msgstr "最终输出:%d %s\n"
+
+#: builtin/log.c:395 builtin/log.c:483
+#, c-format
+msgid "Could not read object %s"
+msgstr "不能读取对象 %s"
+
+#: builtin/log.c:507
+#, c-format
+msgid "Unknown type: %d"
+msgstr "未知类型:%d"
+
+#: builtin/log.c:596
+msgid "format.headers without value"
+msgstr "format.headers 没有值"
+
+#: builtin/log.c:669
+msgid "name of output directory is too long"
+msgstr "输出目录名太长"
+
+#: builtin/log.c:680
+#, c-format
+msgid "Cannot open patch file %s"
+msgstr "无法打开补丁文件 %s"
+
+#: builtin/log.c:694
+msgid "Need exactly one range."
+msgstr "只需要一个范围。"
+
+#: builtin/log.c:702
+msgid "Not a range."
+msgstr "不是一个范围。"
+
+#: builtin/log.c:739
+msgid "Could not extract email from committer identity."
+msgstr "不能从提交者身份中提取邮件地址。"
+
+#: builtin/log.c:785
+msgid "Cover letter needs email format"
+msgstr "信封需要邮件地址格式"
+
+#: builtin/log.c:879
+#, c-format
+msgid "insane in-reply-to: %s"
+msgstr "不正常的 in-reply-to:%s"
+
+#: builtin/log.c:952
+msgid "Two output directories?"
+msgstr "两个输出目录?"
+
+#: builtin/log.c:1173
+#, c-format
+msgid "bogus committer info %s"
+msgstr "虚假的提交者信息 %s"
+
+#: builtin/log.c:1218
+msgid "-n and -k are mutually exclusive."
+msgstr "-n 和 -k 互斥。"
+
+#: builtin/log.c:1220
+msgid "--subject-prefix and -k are mutually exclusive."
+msgstr "--subject-prefix 和 -k 互斥。"
+
+#: builtin/log.c:1225 builtin/shortlog.c:284
+#, c-format
+msgid "unrecognized argument: %s"
+msgstr "未识别的参数:%s"
+
+#: builtin/log.c:1228
+msgid "--name-only does not make sense"
+msgstr "--name-only 无意义"
+
+#: builtin/log.c:1230
+msgid "--name-status does not make sense"
+msgstr "--name-status 无意义"
+
+#: builtin/log.c:1232
+msgid "--check does not make sense"
+msgstr "--check 无意义"
+
+#: builtin/log.c:1255
+msgid "standard output, or directory, which one?"
+msgstr "标准输出或目录,哪一个?"
+
+#: builtin/log.c:1257
+#, c-format
+msgid "Could not create directory '%s'"
+msgstr "不能创建目录 '%s'"
+
+#: builtin/log.c:1410
+msgid "Failed to create output files"
+msgstr "无法创建输出文件"
+
+#: builtin/log.c:1514
+#, c-format
+msgid ""
+"Could not find a tracked remote branch, please specify <upstream> manually.\n"
+msgstr "不能找到跟踪的远程分支,请手工指定 <upstream>。\n"
+
+#: builtin/log.c:1530 builtin/log.c:1532 builtin/log.c:1544
+#, c-format
+msgid "Unknown commit %s"
+msgstr "未知提交 %s"
+
+#: builtin/merge.c:90
+msgid "switch `m' requires a value"
+msgstr "开关 `m' 需要一个值"
+
+#: builtin/merge.c:127
+#, c-format
+msgid "Could not find merge strategy '%s'.\n"
+msgstr "不能找到合并策略 '%s'。\n"
+
+#: 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: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 "不是一个有效对象:%s"
+
+#: 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 "压缩提交 -- 未更新 HEAD\n"
+
+#: builtin/merge.c:361
+msgid "Writing SQUASH_MSG"
+msgstr "写入 SQUASH_MSG"
+
+#: builtin/merge.c:363
+msgid "Finishing SQUASH_MSG"
+msgstr "完成 SQUASH_MSG"
+
+#: builtin/merge.c:386
+#, c-format
+msgid "No merge message -- not updating HEAD\n"
+msgstr "无合并信息 -- 未更新 HEAD\n"
+
+#: builtin/merge.c:437
+#, c-format
+msgid "'%s' does not point to a commit"
+msgstr "'%s' 没有指向一个提交"
+
+#: builtin/merge.c:536
+#, c-format
+msgid "Bad branch.%s.mergeoptions string: %s"
+msgstr "坏的 branch.%s.mergeoptions 字符串:%s"
+
+#: builtin/merge.c:629
+msgid "git write-tree failed to write a tree"
+msgstr "git write-tree 无法写入一树对象"
+
+#: builtin/merge.c:679
+msgid "failed to read the cache"
+msgstr "无法读取缓存"
+
+#: builtin/merge.c:697
+msgid "Unable to write index."
+msgstr "不能写索引。"
+
+#: builtin/merge.c:710
+msgid "Not handling anything other than two heads merge."
+msgstr "不能处理两个头合并之外的任何操作。"
+
+#: builtin/merge.c:724
+#, c-format
+msgid "Unknown option for merge-recursive: -X%s"
+msgstr "merge-recursive 的未知选项:-X%s"
+
+#: builtin/merge.c:738
+#, c-format
+msgid "unable to write %s"
+msgstr "不能写 %s"
+
+#: builtin/merge.c:877
+#, c-format
+msgid "Could not read from '%s'"
+msgstr "不能从 '%s' 读取"
+
+#: builtin/merge.c:886
+#, c-format
+msgid "Not committing merge; use 'git commit' to complete the merge.\n"
+msgstr "未提交合并,使用 'git commit' 完成此次合并。\n"
+
+#: 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"
+msgstr ""
+"请输入一个提交信息以解释此合并的必要性,尤其是将一个更新后的上游分支\n"
+"合并到主题分支。\n"
+"\n"
+"以 '#' 开头的行将被忽略,而且空提交说明将会终止提交。\n"
+
+#: builtin/merge.c:916
+msgid "Empty commit message."
+msgstr "空提交信息。"
+
+#: builtin/merge.c:928
+#, c-format
+msgid "Wonderful.\n"
+msgstr "太棒了。\n"
+
+#: builtin/merge.c:993
+#, c-format
+msgid "Automatic merge failed; fix conflicts and then commit the result.\n"
+msgstr "自动合并失败,修正冲突然后提交修正的结果。\n"
+
+#: builtin/merge.c:1009
+#, c-format
+msgid "'%s' is not a commit"
+msgstr "'%s' 不是一个提交"
+
+#: builtin/merge.c:1050
+msgid "No current branch."
+msgstr "没有当前分支。"
+
+#: builtin/merge.c:1052
+msgid "No remote for the current branch."
+msgstr "当前分支没有对应的远程版本库。"
+
+#: builtin/merge.c:1054
+msgid "No default upstream defined for the current branch."
+msgstr "当前分支没有定义默认的上游分支。"
+
+#: builtin/merge.c:1059
+#, c-format
+msgid "No remote tracking branch for %s from %s"
+msgstr "%s 没有来自 %s 的远程跟踪分支"
+
+#: builtin/merge.c:1146 builtin/merge.c:1303
+#, c-format
+msgid "%s - not something we can merge"
+msgstr "%s - 不能被合并"
+
+#: builtin/merge.c:1214
+msgid "There is no merge to abort (MERGE_HEAD missing)."
+msgstr "没有要终止的合并(MERGE_HEAD 丢失)。"
+
+#: 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."
+msgstr ""
+"您尚未结束您的合并(存在 MERGE_HEAD)。\n"
+"请在合并前先提交您的修改。"
+
+#: builtin/merge.c:1233 git-pull.sh:34
+msgid "You have not concluded your merge (MERGE_HEAD exists)."
+msgstr "您尚未结束您的合并(存在 MERGE_HEAD)。"
+
+#: 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."
+msgstr ""
+"您尚未结束您的拣选(存在 CHERRY_PICK_HEAD)。\n"
+"请在合并前先提交您的修改。"
+
+#: builtin/merge.c:1240
+msgid "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)."
+msgstr "您尚未结束您的拣选(存在 CHERRY_PICK_HEAD)。"
+
+#: builtin/merge.c:1249
+msgid "You cannot combine --squash with --no-ff."
+msgstr "您不能将 --squash 与 --no-ff 共用。"
+
+#: builtin/merge.c:1254
+msgid "You cannot combine --no-ff with --ff-only."
+msgstr "您不能将 --no-ff 与 --ff-only 共用。"
+
+#: builtin/merge.c:1261
+msgid "No commit specified and merge.defaultToUpstream not set."
+msgstr "未指定提交并且 merge.defaultToUpstream 未设置。"
+
+#: builtin/merge.c:1293
+msgid "Can merge only exactly one commit into empty head"
+msgstr "只能将一个提交合并到空分支上"
+
+#: builtin/merge.c:1296
+msgid "Squash commit into empty head not supported yet"
+msgstr "尚不支持到空分支的压缩提交"
+
+#: builtin/merge.c:1298
+msgid "Non-fast-forward commit does not make sense into an empty head"
+msgstr "到空分支的非快进式提交没有意义"
+
+#: builtin/merge.c:1413
+#, c-format
+msgid "Updating %s..%s\n"
+msgstr "更新 %s..%s\n"
+
+#: builtin/merge.c:1451
+#, c-format
+msgid "Trying really trivial in-index merge...\n"
+msgstr "尝试非常小的索引内合并...\n"
+
+#: builtin/merge.c:1458
+#, c-format
+msgid "Nope.\n"
+msgstr "无。\n"
+
+#: builtin/merge.c:1490
+msgid "Not possible to fast-forward, aborting."
+msgstr "无法快进,终止。"
+
+#: builtin/merge.c:1513 builtin/merge.c:1592
+#, c-format
+msgid "Rewinding the tree to pristine...\n"
+msgstr "将树回滚至原始状态...\n"
+
+#: builtin/merge.c:1517
+#, c-format
+msgid "Trying merge strategy %s...\n"
+msgstr "尝试合并策略 %s...\n"
+
+#: builtin/merge.c:1583
+#, c-format
+msgid "No merge strategy handled the merge.\n"
+msgstr "没有合并策略处理此合并。\n"
+
+#: builtin/merge.c:1585
+#, c-format
+msgid "Merge with strategy %s failed.\n"
+msgstr "使用策略 %s 合并失败。\n"
+
+#: builtin/merge.c:1594
+#, c-format
+msgid "Using the %s to prepare resolving by hand.\n"
+msgstr "使用 %s 以准备手工解决。\n"
+
+#: builtin/merge.c:1606
+#, c-format
+msgid "Automatic merge went well; stopped before committing as requested\n"
+msgstr "自动合并进展顺利,按要求在提交前停止\n"
+
+#: builtin/mv.c:108
+#, c-format
+msgid "Checking rename of '%s' to '%s'\n"
+msgstr "检查 '%s' 到 '%s' 的重命名\n"
+
+#: 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 "嗯?%.*s 在索引中?"
+
+#: 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 "覆盖 '%s'"
+
+#: 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 "%s,源=%s,目标=%s"
+
+#: builtin/mv.c:212
+#, c-format
+msgid "Renaming %s to %s\n"
+msgstr "重命名 %s 至 %s\n"
+
+#: builtin/mv.c:215
+#, c-format
+msgid "renaming '%s' failed"
+msgstr "重命名 '%s' 失败"
+
+#: builtin/notes.c:139
+#, c-format
+msgid "unable to start 'show' for object '%s'"
+msgstr "不能为对象 '%s' 开始 'show'"
+
+#: builtin/notes.c:145
+msgid "can't fdopen 'show' output fd"
+msgstr "不能打开 'show' 输出文件句柄"
+
+#: builtin/notes.c:155
+#, c-format
+msgid "failed to close pipe to 'show' for object '%s'"
+msgstr "无法为对象 '%s' 的 'show' 关闭管道"
+
+#: builtin/notes.c:158
+#, c-format
+msgid "failed to finish 'show' for object '%s'"
+msgstr "无法为对象 '%s' 完成 'show'"
+
+#: builtin/notes.c:175 builtin/tag.c:343
+#, c-format
+msgid "could not create file '%s'"
+msgstr "不能创建文件 '%s'"
+
+#: builtin/notes.c:189
+msgid "Please supply the note contents using either -m or -F option"
+msgstr "请通过 -m 或 -F 选项为注解提供内容"
+
+#: builtin/notes.c:210 builtin/notes.c:973
+#, c-format
+msgid "Removing note for object %s\n"
+msgstr "删除对象 %s 的注解\n"
+
+#: builtin/notes.c:215
+msgid "unable to write note object"
+msgstr "不能写注解对象"
+
+#: builtin/notes.c:217
+#, c-format
+msgid "The note contents has been left in %s"
+msgstr "注解内容被留在文件 %s 中"
+
+#: builtin/notes.c:251 builtin/tag.c:521
+#, c-format
+msgid "cannot read '%s'"
+msgstr "不能读取 '%s'"
+
+#: builtin/notes.c:253 builtin/tag.c:524
+#, c-format
+msgid "could not open or read '%s'"
+msgstr "不能打开或读取 '%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:537
+#, c-format
+msgid "Failed to resolve '%s' as a valid ref."
+msgstr "无法解析 '%s' 为一个有效引用。"
+
+#: builtin/notes.c:275
+#, c-format
+msgid "Failed to read object '%s'."
+msgstr "无法读取对象 '%s'。"
+
+#: builtin/notes.c:299
+msgid "Cannot commit uninitialized/unreferenced notes tree"
+msgstr "不能提交未初始化/未引用的注解树"
+
+#: builtin/notes.c:340
+#, c-format
+msgid "Bad notes.rewriteMode value: '%s'"
+msgstr "坏的 notes.rewriteMode 值:'%s'"
+
+#: builtin/notes.c:350
+#, c-format
+msgid "Refusing to rewrite notes in %s (outside of refs/notes/)"
+msgstr "拒绝向 %s(在 refs/notes/ 之外)写入注解"
+
+#. 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'"
+msgstr "坏的 %s 值:'%s'"
+
+#: builtin/notes.c:441
+#, c-format
+msgid "Malformed input line: '%s'."
+msgstr "非法的输入行:'%s'。"
+
+#: builtin/notes.c:456
+#, c-format
+msgid "Failed to copy notes from '%s' to '%s'"
+msgstr "无法从 '%s' 到 '%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
+msgid "too many parameters"
+msgstr "参数太多"
+
+#: builtin/notes.c:513 builtin/notes.c:772
+#, c-format
+msgid "No note found for object %s."
+msgstr "未发现对象 %s 的注解。"
+
+#: builtin/notes.c:580
+#, c-format
+msgid ""
+"Cannot add notes. Found existing notes for object %s. Use '-f' to overwrite "
+"existing notes"
+msgstr "不能添加注解。发现对象 %s 已存在注解。使用 '-f' 覆盖现存注解"
+
+#: builtin/notes.c:585 builtin/notes.c:662
+#, c-format
+msgid "Overwriting existing notes for object %s\n"
+msgstr "覆盖对象 %s 现存注解\n"
+
+#: builtin/notes.c:635
+msgid "too few parameters"
+msgstr "参数太少"
+
+#: builtin/notes.c:656
+#, c-format
+msgid ""
+"Cannot copy notes. Found existing notes for object %s. Use '-f' to overwrite "
+"existing notes"
+msgstr "不能拷贝注解。发现对象 %s 已存在注解。使用 '-f' 覆盖现存注解"
+
+#: builtin/notes.c:668
+#, c-format
+msgid "Missing notes on source object %s. Cannot copy."
+msgstr "源对象 %s 缺少注解。不能拷贝。"
+
+#: 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"
+msgstr ""
+"子命令 'edit' 的选项 -m/-F/-c/-C 已弃用。\n"
+"请换用 'git notes add -f -m/-F/-c/-C'。\n"
+
+#: builtin/notes.c:971
+#, c-format
+msgid "Object %s has no note\n"
+msgstr "对象 %s 没有注解\n"
+
+#: builtin/notes.c:1103
+#, c-format
+msgid "Unknown subcommand: %s"
+msgstr "未知子命令:%s"
+
+#: builtin/pack-objects.c:2315
+#, c-format
+msgid "unsupported index version %s"
+msgstr "不支持的索引版本 %s"
+
+#: builtin/pack-objects.c:2319
+#, c-format
+msgid "bad index version '%s'"
+msgstr "坏的索引版本 '%s'"
+
+#: builtin/pack-objects.c:2342
+#, c-format
+msgid "option %s does not accept negative form"
+msgstr "选项 %s 不接受否定格式"
+
+#: builtin/pack-objects.c:2346
+#, c-format
+msgid "unable to parse value '%s' for option %s"
+msgstr "不能解析值 '%s' 针对于选项 %s"
+
+#: builtin/push.c:45
+msgid "tag shorthand without <tag>"
+msgstr "tag 简写没有跟 <tag> 参数"
+
+#: builtin/push.c:64
+msgid "--delete only accepts plain target ref names"
+msgstr "--delete 只接受简单的目标引用名"
+
+#: builtin/push.c:84
+#, 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 ""
+"您当前不在一个分支上。\n"
+"现在为推送当前(分离头指针)的历史,使用\n"
+"\n"
+" git push %s HEAD:<name-of-remote-branch>\n"
+
+#: builtin/push.c:91
+#, 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 ""
+"当前分支 %s 没有对应的上游分支。\n"
+"为推送当前分支并建立与远程上游的跟踪,使用\n"
+"\n"
+" git push --set-upstream %s %s\n"
+
+#: builtin/push.c:99
+#, c-format
+msgid "The current branch %s has multiple upstream branches, refusing to push."
+msgstr "当前分支 %s 有多个上游分支,拒绝推送。"
+
+#: builtin/push.c:102
+#, 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 ""
+"您正推送至远程 '%s'(其并非当前分支 '%s' 的上游),\n"
+"而没有告诉我要推送什么、更新哪个远程分支。"
+
+#: builtin/push.c:131
+msgid ""
+"You didn't specify any refspecs to push, and push.default is \"nothing\"."
+msgstr "您没有为推送指定任何引用表达式,并且 push.default 为 \"nothing\"。"
+
+#: builtin/push.c:138
+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 ""
+"更新被拒绝,因为您当前分支的最新提交落后于其对应的远程分支。\n"
+"再次推送前,先与远程变更合并(如 'git pull')。详见\n"
+"'git push --help' 中的 'Note about fast-forwards' 小节。"
+
+#: builtin/push.c:144
+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."
+msgstr ""
+"更新被拒绝,因为推送的一个分支的最新提交落后于其对应的远程分支。\n"
+"如果您并非有意推送该分支,您可以在推送时指定要推送的分支,或者将\n"
+"配置变量 'push.default' 设置为 'current' 或 'upstream' 以便只推送"
+"当前分支。"
+
+#: builtin/push.c:150
+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 ""
+"更新被拒绝,因为推送的一个分支的最新提交落后于其对应的远程分支。\n"
+"检出该分支并与远程变更合并(如 'git pull'),然后再推送。详见\n"
+"'git push --help' 中的 'Note about fast-forwards' 小节。"
+
+#: builtin/push.c:190
+#, c-format
+msgid "Pushing to %s\n"
+msgstr "推送到 %s\n"
+
+#: builtin/push.c:194
+#, c-format
+msgid "failed to push some refs to '%s'"
+msgstr "无法推送一些引用到 '%s'"
+
+#: builtin/push.c:226
+#, c-format
+msgid "bad repository '%s'"
+msgstr "坏的版本库 '%s'"
+
+#: builtin/push.c:227
+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 ""
+"没有配置推送目标。\n"
+"或者通过命令行指定URL,或者用下面命令配置一个远程版本库\n"
+"\n"
+" git remote add <name> <url>\n"
+"\n"
+"然后使用该远程版本库名执行推送\n"
+"\n"
+" git push <name>\n"
+
+#: builtin/push.c:242
+msgid "--all and --tags are incompatible"
+msgstr "--all 和 --tags 不兼容"
+
+#: builtin/push.c:243
+msgid "--all can't be combined with refspecs"
+msgstr "--all 不能和引用表达式共用"
+
+#: builtin/push.c:248
+msgid "--mirror and --tags are incompatible"
+msgstr "--mirror 和 --tags 不兼容"
+
+#: builtin/push.c:249
+msgid "--mirror can't be combined with refspecs"
+msgstr "--mirror 不能和引用表达式共用"
+
+#: builtin/push.c:254
+msgid "--all and --mirror are incompatible"
+msgstr "--all 和 --mirror 不兼容"
+
+#: builtin/push.c:334
+msgid "--delete is incompatible with --all, --mirror and --tags"
+msgstr "--delete 与 --all、--mirror 及 --tags 不兼容"
+
+#: builtin/push.c:336
+msgid "--delete doesn't make sense without any refs"
+msgstr "--delete 未接任何引用没有意义"
+
+#: builtin/reset.c:33
+msgid "mixed"
+msgstr "混杂"
+
+#: builtin/reset.c:33
+msgid "soft"
+msgstr "软性"
+
+#: builtin/reset.c:33
+msgid "hard"
+msgstr "硬性"
+
+#: builtin/reset.c:33
+msgid "keep"
+msgstr "保持"
+
+#: builtin/reset.c:77
+msgid "You do not have a valid HEAD."
+msgstr "您没有一个有效的 HEAD。"
+
+#: builtin/reset.c:79
+msgid "Failed to find tree of HEAD."
+msgstr "无法找到 HEAD 指向的树。"
+
+#: builtin/reset.c:85
+#, c-format
+msgid "Failed to find tree of %s."
+msgstr "无法找到 %s 指向的树。"
+
+#: builtin/reset.c:96
+msgid "Could not write new index file."
+msgstr "不能写入新的索引文件。"
+
+#: builtin/reset.c:106
+#, c-format
+msgid "HEAD is now at %s"
+msgstr "HEAD 现在位于 %s"
+
+#: builtin/reset.c:130
+msgid "Could not read index"
+msgstr "不能读取索引"
+
+#: builtin/reset.c:133
+msgid "Unstaged changes after reset:"
+msgstr "重置后撤出暂存区的变更:"
+
+# 译者:汉字之间无空格,故删除%s前后空格
+#: builtin/reset.c:223
+#, c-format
+msgid "Cannot do a %s reset in the middle of a merge."
+msgstr "在合并过程中不能做%s重置操作。"
+
+#: builtin/reset.c:297
+#, c-format
+msgid "Could not parse object '%s'."
+msgstr "不能解析对象 '%s'。"
+
+#: builtin/reset.c:302
+msgid "--patch is incompatible with --{hard,mixed,soft}"
+msgstr "--patch 与 --{hard,mixed,soft} 不兼容"
+
+#: builtin/reset.c:311
+msgid "--mixed with paths is deprecated; use 'git reset -- <paths>' instead."
+msgstr "--mixed 带路径已弃用,代之以 'git reset -- <paths>'。"
+
+# 译者:汉字之间无空格,故删除%s前后空格
+#: builtin/reset.c:313
+#, c-format
+msgid "Cannot do %s reset with paths."
+msgstr "不能带路径进行%s重置。"
+
+# 译者:汉字之间无空格,故删除%s前后空格
+#: builtin/reset.c:325
+#, c-format
+msgid "%s reset is not allowed in a bare repository"
+msgstr "不能对裸版本库进行%s重置"
+
+#: builtin/reset.c:341
+#, c-format
+msgid "Could not reset index file to revision '%s'."
+msgstr "不能重置索引文件至版本 '%s'。"
+
+#: 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:127
+msgid "program error"
+msgstr "程序错误"
+
+#: builtin/revert.c:213
+msgid "revert failed"
+msgstr "还原失败"
+
+#: builtin/revert.c:228
+msgid "cherry-pick failed"
+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)"
+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: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:157
+#, c-format
+msgid "Missing author: %s"
+msgstr "缺少作者:%s"
+
+#: builtin/tag.c:58
+#, c-format
+msgid "malformed object at '%s'"
+msgstr "非法的对象于 '%s'"
+
+#: builtin/tag.c:205
+#, c-format
+msgid "tag name too long: %.*s..."
+msgstr "tag 名字太长:%.*s..."
+
+#: builtin/tag.c:210
+#, c-format
+msgid "tag '%s' not found."
+msgstr "tag '%s' 未发现。"
+
+#: builtin/tag.c:225
+#, c-format
+msgid "Deleted tag '%s' (was %s)\n"
+msgstr "已删除 tag '%s'(曾为 %s)\n"
+
+#: builtin/tag.c:237
+#, c-format
+msgid "could not verify the tag '%s'"
+msgstr "不能校验 tag '%s'"
+
+#: builtin/tag.c:247
+msgid ""
+"\n"
+"#\n"
+"# Write a tag message\n"
+"# Lines starting with '#' will be ignored.\n"
+"#\n"
+msgstr ""
+"\n"
+"#\n"
+"# 输入一个 tag 说明\n"
+"# 以 '#' 开头的行将被忽略。\n"
+"#\n"
+
+#: builtin/tag.c:254
+msgid ""
+"\n"
+"#\n"
+"# Write a tag message\n"
+"# Lines starting with '#' will be kept; you may remove them yourself if you "
+"want to.\n"
+"#\n"
+msgstr ""
+"\n"
+"#\n"
+"# 输入一个 tag 说明\n"
+"# 以 '#' 开头的行将被忽略,您可以删除它们如果您想这样做。\n"
+"#\n"
+
+#: builtin/tag.c:294
+msgid "unable to sign the tag"
+msgstr "无法签署 tag"
+
+#: builtin/tag.c:296
+msgid "unable to write tag file"
+msgstr "无法写 tag 文件"
+
+#: builtin/tag.c:321
+msgid "bad object type."
+msgstr "坏的对象类型。"
+
+#: builtin/tag.c:334
+msgid "tag header too big."
+msgstr "tag 头信息太大。"
+
+#: builtin/tag.c:366
+msgid "no tag message?"
+msgstr "无 tag 说明?"
+
+#: builtin/tag.c:372
+#, c-format
+msgid "The tag message has been left in %s\n"
+msgstr "tag 说明被保留在 %s\n"
+
+#: builtin/tag.c:421
+msgid "switch 'points-at' requires an object"
+msgstr "开关 'points-at' 需要一个对象"
+
+#: builtin/tag.c:423
+#, c-format
+msgid "malformed object name '%s'"
+msgstr "非法的对象名 '%s'"
+
+#: builtin/tag.c:502
+msgid "-n option is only allowed with -l."
+msgstr "-n 选项只允许和 -l 共用。"
+
+#: builtin/tag.c:504
+msgid "--contains option is only allowed with -l."
+msgstr "--contains 选项只允许和 -l 共用。"
+
+#: builtin/tag.c:506
+msgid "--points-at option is only allowed with -l."
+msgstr "--points-at 选项只允许和 -l 共用。"
+
+#: builtin/tag.c:514
+msgid "only one -F or -m option is allowed."
+msgstr "只允许一个 -F 或 -m 选项。"
+
+#: builtin/tag.c:534
+msgid "too many params"
+msgstr "太多参数"
+
+#: builtin/tag.c:540
+#, c-format
+msgid "'%s' is not a valid tag name."
+msgstr "'%s' 不是一个有效的tag名称。"
+
+#: builtin/tag.c:545
+#, c-format
+msgid "tag '%s' already exists"
+msgstr "tag '%s' 已存在"
+
+#: builtin/tag.c:563
+#, c-format
+msgid "%s: cannot lock the ref"
+msgstr "%s:不能锁定引用"
+
+#: builtin/tag.c:565
+#, c-format
+msgid "%s: cannot update the ref"
+msgstr "%s:不能更新引用"
+
+#: builtin/tag.c:567
+#, c-format
+msgid "Updated tag '%s' (was %s)\n"
+msgstr "已更新tag '%s'(曾为 %s)\n"
+
+#: git-am.sh:49
+msgid "You need to set your committer info first"
+msgstr "您需要先设置你的提交者信息"
+
+#: git-am.sh:136
+msgid "Repository lacks necessary blobs to fall back on 3-way merge."
+msgstr "版本库缺乏必要的 blob 数据以进行三路合并。"
+
+#: git-am.sh:147
+msgid ""
+"Did you hand edit your patch?\n"
+"It does not apply to blobs recorded in its index."
+msgstr ""
+"您是否曾手动编辑过您的补丁?\n"
+"无法应用补丁到索引中的数据上。"
+
+#: git-am.sh:156
+msgid "Falling back to patching base and 3-way merge..."
+msgstr "回退到补丁基础版本并使用三路合并..."
+
+#: git-am.sh:268
+msgid "Only one StGIT patch series can be applied at once"
+msgstr "一次只能有一个 StGIT 补丁队列被应用"
+
+#: git-am.sh:355
+#, sh-format
+msgid "Patch format $patch_format is not supported."
+msgstr "不支持 $patch_format 补丁格式。"
+
+#: git-am.sh:357
+msgid "Patch format detection failed."
+msgstr "补丁格式检测失败。"
+
+#: git-am.sh:411
+msgid "-d option is no longer supported. Do not use."
+msgstr "不再支持 -d 选项。不要使用。"
+
+#: git-am.sh:474
+#, sh-format
+msgid "previous rebase directory $dotest still exists but mbox given."
+msgstr "之前的变基目录 $dotest 仍然存在但给出了mbox。"
+
+#: git-am.sh:479
+msgid "Please make up your mind. --skip or --abort?"
+msgstr "请下决心。--skip 或是 --abort ?"
+
+#: git-am.sh:506
+msgid "Resolve operation not in progress, we are not resuming."
+msgstr "解决操作未进行,我们不会继续。"
+
+#: git-am.sh:572
+#, sh-format
+msgid "Dirty index: cannot apply patches (dirty: $files)"
+msgstr "脏的索引:不能应用补丁(脏文件:$files)"
+
+#: git-am.sh:748
+msgid "cannot be interactive without stdin connected to a terminal."
+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:759
+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:795
+#, sh-format
+msgid "Applying: $FIRSTLINE"
+msgstr "正应用:$FIRSTLINE"
+
+#: git-am.sh:840
+msgid "No changes -- Patch already applied."
+msgstr "没有变更 -- 补丁已经应用过。"
+
+#: git-am.sh:866
+msgid "applying to an empty history"
+msgstr "正应用到一个空历史上"
+
+# 译者:注意保持句尾空格
+#. TRANSLATORS: Make sure to include [Y] and [n] in your
+#. translation. The program will only accept English input
+#. at this point.
+#: git-bisect.sh:54
+msgid "Do you want me to do it for you [Y/n]? "
+msgstr "您想让我为您这样做么[Y/n]? "
+
+#: git-bisect.sh:95
+#, sh-format
+msgid "unrecognised option: '$arg'"
+msgstr "未识别的选项:'$arg'"
+
+#: git-bisect.sh:99
+#, sh-format
+msgid "'$arg' does not appear to be a valid revision"
+msgstr "'$arg' 看起来不像是一个有效的版本"
+
+#: git-bisect.sh:117
+msgid "Bad HEAD - I need a HEAD"
+msgstr "坏的 HEAD - 我需要一个 HEAD"
+
+#: git-bisect.sh:130
+#, sh-format
+msgid ""
+"Checking out '$start_head' failed. Try 'git bisect reset <validbranch>'."
+msgstr "检出 '$start_head' 失败。尝试 'git bisect reset <validbranch>'。"
+
+#: git-bisect.sh:140
+msgid "won't bisect on seeked tree"
+msgstr "不会在已查找过的树上二分查找"
+
+#: git-bisect.sh:144
+msgid "Bad HEAD - strange symbolic ref"
+msgstr "坏的 HEAD - 奇怪的符号引用"
+
+#: git-bisect.sh:189
+#, sh-format
+msgid "Bad bisect_write argument: $state"
+msgstr "坏的 bisect_write 参数:$state"
+
+#: git-bisect.sh:218
+#, sh-format
+msgid "Bad rev input: $arg"
+msgstr "输入坏的版本:$arg"
+
+#: git-bisect.sh:232
+msgid "Please call 'bisect_state' with at least one argument."
+msgstr "请在调用 'bisect_state' 时跟至少一个参数。"
+
+#: git-bisect.sh:244
+#, sh-format
+msgid "Bad rev input: $rev"
+msgstr "输入坏的版本:$rev"
+
+#: git-bisect.sh:250
+msgid "'git bisect bad' can take only one argument."
+msgstr "'git bisect bad' 只能带一个参数。"
+
+# 译者:注意保持句尾空格
+#. 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 "您确认么[Y/n]? "
+
+#: git-bisect.sh:354
+#, sh-format
+msgid "'$invalid' is not a valid commit"
+msgstr "'$invalid' 不是一个有效的提交"
+
+#: git-bisect.sh:363
+#, sh-format
+msgid ""
+"Could not check out original HEAD '$branch'.\n"
+"Try 'git bisect reset <commit>'."
+msgstr ""
+"不能检出原始 HEAD '$branch'。\n"
+"尝试 'git bisect reset <commit>'。"
+
+#: git-bisect.sh:390
+msgid "No logfile given"
+msgstr "未提供日志文件"
+
+#: git-bisect.sh:391
+#, sh-format
+msgid "cannot read $file for replaying"
+msgstr "不能读取 $file 来重放"
+
+#: git-bisect.sh:408
+msgid "?? what are you talking about?"
+msgstr "?? 您在说什么?"
+
+#: git-bisect.sh:474
+msgid "We are not bisecting."
+msgstr "我们没有在二分查找。"
+
+#: git-pull.sh:21
+msgid ""
+"Pull is not possible because you have unmerged files.\n"
+"Please, fix them up in the work tree, and then use 'git add/rm <file>'\n"
+"as appropriate to mark resolution, or use 'git commit -a'."
+msgstr ""
+"Pull 不可用,因为您尚有未合并的文件。请先在工作区改正文件,\n"
+"然后酌情使用 'git add/rm <file>' 标记解决方案,\n"
+"或者使用 'git commit -a'。"
+
+#: git-pull.sh:25
+msgid "Pull is not possible because you have unmerged files."
+msgstr "Pull 不可用,因为您尚有未合并的文件。"
+
+#: git-pull.sh:197
+msgid "updating an unborn branch with changes added to the index"
+msgstr "更新尚未诞生的分支,变更添加至索引"
+
+#: git-pull.sh:253
+msgid "Cannot merge multiple branches into empty head"
+msgstr "无法将多个分支合并到空分支"
+
+#: git-pull.sh:257
+msgid "Cannot rebase onto multiple branches"
+msgstr "无法变基到多个分支"
+
+#: git-stash.sh:51
+msgid "git stash clear with parameters is unimplemented"
+msgstr "git stash clear 不支持参数"
+
+#: git-stash.sh:74
+msgid "You do not have the initial commit yet"
+msgstr "您尚未建立初始提交"
+
+#: git-stash.sh:89
+msgid "Cannot save the current index state"
+msgstr "无法保存当前索引状态"
+
+#: git-stash.sh:123 git-stash.sh:136
+msgid "Cannot save the current worktree state"
+msgstr "无法保存当前工作区状态"
+
+#: git-stash.sh:140
+msgid "No changes selected"
+msgstr "没有选择变更"
+
+#: git-stash.sh:143
+msgid "Cannot remove temporary index (can't happen)"
+msgstr "无法删除临时索引(不应发生)"
+
+#: git-stash.sh:156
+msgid "Cannot record working tree state"
+msgstr "不能记录工作区状态"
+
+#: git-stash.sh:223
+msgid "No local changes to save"
+msgstr "没有要保存的本地修改"
+
+#: git-stash.sh:227
+msgid "Cannot initialize stash"
+msgstr "无法初始化 stash"
+
+#: git-stash.sh:235
+msgid "Cannot save the current status"
+msgstr "无法保存当前状态"
+
+#: git-stash.sh:253
+msgid "Cannot remove worktree changes"
+msgstr "无法删除工作区变更"
+
+#: git-stash.sh:352
+msgid "No stash found."
+msgstr "未发现 stash。"
+
+#: git-stash.sh:359
+#, sh-format
+msgid "Too many revisions specified: $REV"
+msgstr "指定了太多的版本:$REV"
+
+#: git-stash.sh:365
+#, sh-format
+msgid "$reference is not valid reference"
+msgstr "$reference 不是有效的引用"
+
+#: git-stash.sh:393
+#, sh-format
+msgid "'$args' is not a stash-like commit"
+msgstr "'$args' 不是 stash 样提交"
+
+#: git-stash.sh:404
+#, sh-format
+msgid "'$args' is not a stash reference"
+msgstr "'$args' 不是一个 stash 引用"
+
+#: git-stash.sh:412
+msgid "unable to refresh index"
+msgstr "无法刷新索引"
+
+#: git-stash.sh:416
+msgid "Cannot apply a stash in the middle of a merge"
+msgstr "无法在合并过程中恢复进度"
+
+#: git-stash.sh:424
+msgid "Conflicts in index. Try without --index."
+msgstr "索引中有冲突。尝试不使用 --index。"
+
+#: git-stash.sh:426
+msgid "Could not save index tree"
+msgstr "不能保存索引树"
+
+#: git-stash.sh:460
+msgid "Cannot unstage modified files"
+msgstr "无法还原修改的文件"
+
+#: git-stash.sh:491
+#, sh-format
+msgid "Dropped ${REV} ($s)"
+msgstr "丢弃了 ${REV} ($s)"
+
+#: git-stash.sh:492
+#, sh-format
+msgid "${REV}: Could not drop stash entry"
+msgstr "${REV}:不能丢弃进度条目"
+
+#: git-stash.sh:499
+msgid "No branch name specified"
+msgstr "未指定分支名"
+
+#: git-stash.sh:570
+msgid "(To restore them type \"git stash apply\")"
+msgstr "(为恢复数据输入 \"git stash apply\")"
+
+#: git-submodule.sh:56
+#, sh-format
+msgid "cannot strip one component off url '$remoteurl'"
+msgstr "无法从 url '$remoteurl' 剥离一个组件"
+
+#: git-submodule.sh:108
+#, sh-format
+msgid "No submodule mapping found in .gitmodules for path '$path'"
+msgstr "未在 .gitmodules 中发现路径 '$path' 的子模组映射"
+
+#: git-submodule.sh:149
+#, sh-format
+msgid "Clone of '$url' into submodule path '$path' failed"
+msgstr "无法克隆 '$url' 到子模组路径 '$path'"
+
+#: git-submodule.sh:159
+#, sh-format
+msgid "Gitdir '$a' is part of the submodule path '$b' or vice versa"
+msgstr "Gitdir '$a' 在子模组路径 '$b' 之下或者相反"
+
+#: git-submodule.sh:248
+#, sh-format
+msgid "repo URL: '$repo' must be absolute or begin with ./|../"
+msgstr "版本库URL:'$repo' 必须是绝对路径或以 ./|../ 起始"
+
+#: git-submodule.sh:265
+#, sh-format
+msgid "'$path' already exists in the index"
+msgstr "'$path' 已经存在于索引中"
+
+#: git-submodule.sh:282
+#, sh-format
+msgid "'$path' already exists and is not a valid git repo"
+msgstr "'$path' 已存在且不是一个有效的 git 版本库"
+
+#: git-submodule.sh:296
+#, sh-format
+msgid "Unable to checkout submodule '$path'"
+msgstr "不能检出子模组 '$path'"
+
+#: git-submodule.sh:301
+#, sh-format
+msgid "Failed to add submodule '$path'"
+msgstr "无法添加子模组 '$path'"
+
+#: git-submodule.sh:306
+#, sh-format
+msgid "Failed to register submodule '$path'"
+msgstr "无法注册子模组 '$path'"
+
+#: git-submodule.sh:348
+#, sh-format
+msgid "Entering '$prefix$path'"
+msgstr "正在进入 '$prefix$path'"
+
+#: git-submodule.sh:360
+#, sh-format
+msgid "Stopping at '$path'; script returned non-zero status."
+msgstr "停止于 '$path',脚本返回非零值。"
+
+#: git-submodule.sh:402
+#, sh-format
+msgid "No url found for submodule path '$path' in .gitmodules"
+msgstr "在 .gitmodules 中未找到子模组路径 '$path' 的 url"
+
+#: git-submodule.sh:411
+#, sh-format
+msgid "Failed to register url for submodule path '$path'"
+msgstr "无法为子模组路径 '$path' 注册 url"
+
+#: git-submodule.sh:419
+#, sh-format
+msgid "Failed to register update mode for submodule path '$path'"
+msgstr "无法为子模组路径 '$path' 注册更新模式"
+
+#: git-submodule.sh:421
+#, sh-format
+msgid "Submodule '$name' ($url) registered for path '$path'"
+msgstr "子模组 '$name' ($url) 已为路径 '$path' 注册"
+
+#: git-submodule.sh:520
+#, sh-format
+msgid ""
+"Submodule path '$path' not initialized\n"
+"Maybe you want to use 'update --init'?"
+msgstr ""
+"子模组路径 '$path' 没有初始化\n"
+"也许您想用 'update --init'?"
+
+#: git-submodule.sh:533
+#, sh-format
+msgid "Unable to find current revision in submodule path '$path'"
+msgstr "无法在子模组路径 '$path' 中找到当前版本"
+
+#: git-submodule.sh:552
+#, sh-format
+msgid "Unable to fetch in submodule path '$path'"
+msgstr "无法在子模组路径 '$path' 中获取"
+
+#: git-submodule.sh:566
+#, sh-format
+msgid "Unable to rebase '$sha1' in submodule path '$path'"
+msgstr "无法在子模组路径 '$path' 中变基 '$sha1'"
+
+#: git-submodule.sh:567
+#, sh-format
+msgid "Submodule path '$path': rebased into '$sha1'"
+msgstr "子模组路径 '$path':变基至 '$sha1'"
+
+#: git-submodule.sh:572
+#, sh-format
+msgid "Unable to merge '$sha1' in submodule path '$path'"
+msgstr "无法合并 '$sha1' 到子模组路径 '$path' 中"
+
+#: git-submodule.sh:573
+#, sh-format
+msgid "Submodule path '$path': merged in '$sha1'"
+msgstr "子模组路径 '$path':已合并入 '$sha1'"
+
+#: git-submodule.sh:578
+#, sh-format
+msgid "Unable to checkout '$sha1' in submodule path '$path'"
+msgstr "无法在子模组路径 '$path' 中检出 '$sha1'"
+
+#: git-submodule.sh:579
+#, sh-format
+msgid "Submodule path '$path': checked out '$sha1'"
+msgstr "子模组路径 '$path':检出 '$sha1'"
+
+#: git-submodule.sh:601 git-submodule.sh:924
+#, sh-format
+msgid "Failed to recurse into submodule path '$path'"
+msgstr "无法递归进子模组路径 '$path'"
+
+#: git-submodule.sh:709
+msgid "--"
+msgstr "--"
+
+# 译者:注意保持前导空格
+#: git-submodule.sh:767
+#, sh-format
+msgid " Warn: $name doesn't contain commit $sha1_src"
+msgstr " 警告:$name 未包含提交 $sha1_src"
+
+# 译者:注意保持前导空格
+#: git-submodule.sh:770
+#, sh-format
+msgid " Warn: $name doesn't contain commit $sha1_dst"
+msgstr " 警告:$name 未包含提交 $sha1_dst"
+
+# 译者:注意保持前导空格
+#: git-submodule.sh:773
+#, sh-format
+msgid " Warn: $name doesn't contain commits $sha1_src and $sha1_dst"
+msgstr " 警告:$name 未包含提交 $sha1_src 和 $sha1_dst"
+
+#: git-submodule.sh:798
+msgid "blob"
+msgstr "blob"
+
+#: git-submodule.sh:799
+msgid "submodule"
+msgstr "子模组"
+
+#: git-submodule.sh:970
+#, sh-format
+msgid "Synchronizing submodule url for '$name'"
+msgstr "为 '$name' 同步子模组 url"
+
+#~ msgid "Too many options specified"
+#~ msgstr "指定了太多的选项"
diff --git a/pretty.c b/pretty.c
index cee77e48f3..8b1ea9ffad 100644
--- a/pretty.c
+++ b/pretty.c
@@ -534,41 +534,26 @@ static size_t format_person_part(struct strbuf *sb, char part,
{
/* currently all placeholders have same length */
const int placeholder_len = 2;
- int start, end, tz = 0;
+ int tz;
unsigned long date = 0;
- char *ep;
- const char *name_start, *name_end, *mail_start, *mail_end, *msg_end = msg+len;
char person_name[1024];
char person_mail[1024];
+ struct ident_split s;
+ const char *name_start, *name_end, *mail_start, *mail_end;
- /* advance 'end' to point to email start delimiter */
- for (end = 0; end < len && msg[end] != '<'; end++)
- ; /* do nothing */
-
- /*
- * When end points at the '<' that we found, it should have
- * matching '>' later, which means 'end' must be strictly
- * below len - 1.
- */
- if (end >= len - 2)
+ if (split_ident_line(&s, msg, len) < 0)
goto skip;
- /* Seek for both name and email part */
- name_start = msg;
- name_end = msg+end;
- while (name_end > name_start && isspace(*(name_end-1)))
- name_end--;
- mail_start = msg+end+1;
- mail_end = mail_start;
- while (mail_end < msg_end && *mail_end != '>')
- mail_end++;
- if (mail_end == msg_end)
- goto skip;
- end = mail_end-msg;
+ name_start = s.name_begin;
+ name_end = s.name_end;
+ mail_start = s.mail_begin;
+ mail_end = s.mail_end;
if (part == 'N' || part == 'E') { /* mailmap lookup */
- strlcpy(person_name, name_start, name_end-name_start+1);
- strlcpy(person_mail, mail_start, mail_end-mail_start+1);
+ snprintf(person_name, sizeof(person_name), "%.*s",
+ (int)(name_end - name_start), name_start);
+ snprintf(person_mail, sizeof(person_mail), "%.*s",
+ (int)(mail_end - mail_start), mail_start);
mailmap_name(person_mail, sizeof(person_mail), person_name, sizeof(person_name));
name_start = person_name;
name_end = name_start + strlen(person_name);
@@ -584,28 +569,20 @@ static size_t format_person_part(struct strbuf *sb, char part,
return placeholder_len;
}
- /* advance 'start' to point to date start delimiter */
- for (start = end + 1; start < len && isspace(msg[start]); start++)
- ; /* do nothing */
- if (start >= len)
- goto skip;
- date = strtoul(msg + start, &ep, 10);
- if (msg + start == ep)
+ if (!s.date_begin)
goto skip;
+ date = strtoul(s.date_begin, NULL, 10);
+
if (part == 't') { /* date, UNIX timestamp */
- strbuf_add(sb, msg + start, ep - (msg + start));
+ strbuf_add(sb, s.date_begin, s.date_end - s.date_begin);
return placeholder_len;
}
/* parse tz */
- for (start = ep - msg + 1; start < len && isspace(msg[start]); start++)
- ; /* do nothing */
- if (start + 1 < len) {
- tz = strtoul(msg + start + 1, NULL, 10);
- if (msg[start] == '-')
- tz = -tz;
- }
+ tz = strtoul(s.tz_begin + 1, NULL, 10);
+ if (*s.tz_begin == '-')
+ tz = -tz;
switch (part) {
case 'd': /* date */
@@ -624,8 +601,9 @@ static size_t format_person_part(struct strbuf *sb, char part,
skip:
/*
- * bogus commit, 'sb' cannot be updated, but we still need to
- * compute a valid return value.
+ * reading from either a bogus commit, or a reflog entry with
+ * %gn, %ge, etc.; 'sb' cannot be updated, but we still need
+ * to compute a valid return value.
*/
if (part == 'n' || part == 'e' || part == 't' || part == 'd'
|| part == 'D' || part == 'r' || part == 'i')
@@ -1037,6 +1015,7 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
get_reflog_selector(sb,
c->pretty_ctx->reflog_info,
c->pretty_ctx->date_mode,
+ c->pretty_ctx->date_mode_explicit,
(placeholder[1] == 'd'));
return 2;
case 's': /* reflog message */
diff --git a/read-cache.c b/read-cache.c
index 274e54b4f3..6c8f395836 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -157,16 +157,6 @@ static int ce_modified_check_fs(struct cache_entry *ce, struct stat *st)
return 0;
}
-static int is_empty_blob_sha1(const unsigned char *sha1)
-{
- static const unsigned char empty_blob_sha1[20] = {
- 0xe6,0x9d,0xe2,0x9b,0xb2,0xd1,0xd6,0x43,0x4b,0x8b,
- 0x29,0xae,0x77,0x5a,0xd8,0xc2,0xe4,0x8c,0x53,0x91
- };
-
- return !hashcmp(sha1, empty_blob_sha1);
-}
-
static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st)
{
unsigned int changed = 0;
diff --git a/reflog-walk.c b/reflog-walk.c
index 86d18843f5..b2fbdb2392 100644
--- a/reflog-walk.c
+++ b/reflog-walk.c
@@ -126,7 +126,12 @@ static void add_commit_info(struct commit *commit, void *util,
}
struct commit_reflog {
- int flag, recno;
+ int recno;
+ enum selector_type {
+ SELECTOR_NONE,
+ SELECTOR_INDEX,
+ SELECTOR_DATE
+ } selector;
struct complete_reflogs *reflogs;
};
@@ -150,6 +155,7 @@ int add_reflog_for_walk(struct reflog_walk_info *info,
struct complete_reflogs *reflogs;
char *branch, *at = strchr(name, '@');
struct commit_reflog *commit_reflog;
+ enum selector_type selector = SELECTOR_NONE;
if (commit->object.flags & UNINTERESTING)
die ("Cannot walk reflogs for %s", name);
@@ -162,7 +168,10 @@ int add_reflog_for_walk(struct reflog_walk_info *info,
if (*ep != '}') {
recno = -1;
timestamp = approxidate(at + 2);
+ selector = SELECTOR_DATE;
}
+ else
+ selector = SELECTOR_INDEX;
} else
recno = 0;
@@ -200,7 +209,6 @@ int add_reflog_for_walk(struct reflog_walk_info *info,
commit_reflog = xcalloc(sizeof(struct commit_reflog), 1);
if (recno < 0) {
- commit_reflog->flag = 1;
commit_reflog->recno = get_reflog_recno_by_time(reflogs, timestamp);
if (commit_reflog->recno < 0) {
free(branch);
@@ -209,6 +217,7 @@ int add_reflog_for_walk(struct reflog_walk_info *info,
}
} else
commit_reflog->recno = reflogs->nr - recno - 1;
+ commit_reflog->selector = selector;
commit_reflog->reflogs = reflogs;
add_commit_info(commit, commit_reflog, &info->reflogs);
@@ -247,7 +256,7 @@ void fake_reflog_parent(struct reflog_walk_info *info, struct commit *commit)
void get_reflog_selector(struct strbuf *sb,
struct reflog_walk_info *reflog_info,
- enum date_mode dmode,
+ enum date_mode dmode, int force_date,
int shorten)
{
struct commit_reflog *commit_reflog = reflog_info->last_commit_reflog;
@@ -267,7 +276,8 @@ void get_reflog_selector(struct strbuf *sb,
}
strbuf_addf(sb, "%s@{", printed_ref);
- if (commit_reflog->flag || dmode) {
+ if (commit_reflog->selector == SELECTOR_DATE ||
+ (commit_reflog->selector == SELECTOR_NONE && force_date)) {
info = &commit_reflog->reflogs->items[commit_reflog->recno+1];
strbuf_addstr(sb, show_date(info->timestamp, info->tz, dmode));
} else {
@@ -308,7 +318,7 @@ const char *get_reflog_ident(struct reflog_walk_info *reflog_info)
}
void show_reflog_message(struct reflog_walk_info *reflog_info, int oneline,
- enum date_mode dmode)
+ enum date_mode dmode, int force_date)
{
if (reflog_info && reflog_info->last_commit_reflog) {
struct commit_reflog *commit_reflog = reflog_info->last_commit_reflog;
@@ -316,7 +326,7 @@ void show_reflog_message(struct reflog_walk_info *reflog_info, int oneline,
struct strbuf selector = STRBUF_INIT;
info = &commit_reflog->reflogs->items[commit_reflog->recno+1];
- get_reflog_selector(&selector, reflog_info, dmode, 0);
+ get_reflog_selector(&selector, reflog_info, dmode, force_date, 0);
if (oneline) {
printf("%s: %s", selector.buf, info->message);
}
diff --git a/reflog-walk.h b/reflog-walk.h
index afb1ae3fde..50265f51c5 100644
--- a/reflog-walk.h
+++ b/reflog-walk.h
@@ -11,13 +11,13 @@ extern int add_reflog_for_walk(struct reflog_walk_info *info,
extern void fake_reflog_parent(struct reflog_walk_info *info,
struct commit *commit);
extern void show_reflog_message(struct reflog_walk_info *info, int,
- enum date_mode);
+ enum date_mode, int force_date);
extern void get_reflog_message(struct strbuf *sb,
struct reflog_walk_info *reflog_info);
extern const char *get_reflog_ident(struct reflog_walk_info *reflog_info);
extern void get_reflog_selector(struct strbuf *sb,
struct reflog_walk_info *reflog_info,
- enum date_mode dmode,
+ enum date_mode dmode, int force_date,
int shorten);
#endif
diff --git a/refs.c b/refs.c
index 6f436f1cb0..c9f6835351 100644
--- a/refs.c
+++ b/refs.c
@@ -17,6 +17,15 @@ struct ref_entry {
struct ref_array {
int nr, alloc;
+
+ /*
+ * Entries with index 0 <= i < sorted are sorted by name. New
+ * entries are appended to the list unsorted, and are sorted
+ * only when required; thus we avoid the need to sort the list
+ * after the addition of every reference.
+ */
+ int sorted;
+
struct ref_entry **refs;
};
@@ -105,12 +114,18 @@ static int is_dup_ref(const struct ref_entry *ref1, const struct ref_entry *ref2
}
}
+/*
+ * Sort the entries in array (if they are not already sorted).
+ */
static void sort_ref_array(struct ref_array *array)
{
int i, j;
- /* Nothing to sort unless there are at least two entries */
- if (array->nr < 2)
+ /*
+ * This check also prevents passing a zero-length array to qsort(),
+ * which is a problem on some platforms.
+ */
+ if (array->sorted == array->nr)
return;
qsort(array->refs, array->nr, sizeof(*array->refs), ref_entry_cmp);
@@ -124,7 +139,7 @@ static void sort_ref_array(struct ref_array *array)
}
array->refs[++i] = array->refs[j];
}
- array->nr = i + 1;
+ array->sorted = array->nr = i + 1;
}
static struct ref_entry *search_ref_array(struct ref_array *array, const char *refname)
@@ -137,7 +152,7 @@ static struct ref_entry *search_ref_array(struct ref_array *array, const char *r
if (!array->nr)
return NULL;
-
+ sort_ref_array(array);
len = strlen(refname) + 1;
e = xmalloc(sizeof(struct ref_entry) + len);
memcpy(e->name, refname, len);
@@ -168,15 +183,13 @@ static struct ref_cache {
static struct ref_entry *current_ref;
-static struct ref_array extra_refs;
-
static void clear_ref_array(struct ref_array *array)
{
int i;
for (i = 0; i < array->nr; i++)
free(array->refs[i]);
free(array->refs);
- array->nr = array->alloc = 0;
+ array->sorted = array->nr = array->alloc = 0;
array->refs = NULL;
}
@@ -268,17 +281,6 @@ static void read_packed_refs(FILE *f, struct ref_array *array)
!get_sha1_hex(refline + 1, sha1))
hashcpy(last->peeled, sha1);
}
- sort_ref_array(array);
-}
-
-void add_extra_ref(const char *refname, const unsigned char *sha1, int flag)
-{
- add_ref(&extra_refs, create_ref_entry(refname, sha1, flag, 0));
-}
-
-void clear_extra_refs(void)
-{
- clear_ref_array(&extra_refs);
}
static struct ref_array *get_packed_refs(struct ref_cache *refs)
@@ -301,6 +303,12 @@ static struct ref_array *get_packed_refs(struct ref_cache *refs)
return &refs->packed;
}
+void add_packed_ref(const char *refname, const unsigned char *sha1)
+{
+ add_ref(get_packed_refs(get_ref_cache(NULL)),
+ create_ref_entry(refname, sha1, REF_ISPACKED, 1));
+}
+
static void get_ref_dir(struct ref_cache *refs, const char *base,
struct ref_array *array)
{
@@ -404,7 +412,6 @@ static struct ref_array *get_loose_refs(struct ref_cache *refs)
{
if (!refs->did_loose) {
get_ref_dir(refs, "refs", &refs->loose);
- sort_ref_array(&refs->loose);
refs->did_loose = 1;
}
return &refs->loose;
@@ -710,16 +717,13 @@ fallback:
static int do_for_each_ref(const char *submodule, const char *base, each_ref_fn fn,
int trim, int flags, void *cb_data)
{
- int retval = 0, i, p = 0, l = 0;
+ int retval = 0, p = 0, l = 0;
struct ref_cache *refs = get_ref_cache(submodule);
struct ref_array *packed = get_packed_refs(refs);
struct ref_array *loose = get_loose_refs(refs);
- struct ref_array *extra = &extra_refs;
-
- for (i = 0; i < extra->nr; i++)
- retval = do_one_ref(base, fn, trim, flags, cb_data, extra->refs[i]);
-
+ sort_ref_array(packed);
+ sort_ref_array(loose);
while (p < packed->nr && l < loose->nr) {
struct ref_entry *entry;
int cmp = strcmp(packed->refs[p]->name, loose->refs[l]->name);
diff --git a/refs.h b/refs.h
index d4982915c5..33202b0d4c 100644
--- a/refs.h
+++ b/refs.h
@@ -51,13 +51,11 @@ extern int for_each_rawref(each_ref_fn, void *);
extern void warn_dangling_symref(FILE *fp, const char *msg_fmt, const char *refname);
/*
- * Extra refs will be listed by for_each_ref() before any actual refs
- * for the duration of this process or until clear_extra_refs() is
- * called. Only extra refs added before for_each_ref() is called will
- * be listed on a given call of for_each_ref().
+ * Add a reference to the in-memory packed reference cache. To actually
+ * write the reference to the packed-refs file, call pack_refs().
*/
-extern void add_extra_ref(const char *refname, const unsigned char *sha1, int flags);
-extern void clear_extra_refs(void);
+extern void add_packed_ref(const char *refname, const unsigned char *sha1);
+
extern int ref_exists(const char *);
extern int peel_ref(const char *refname, unsigned char *sha1);
diff --git a/remote-curl.c b/remote-curl.c
index d159fe7f34..04a9d6277d 100644
--- a/remote-curl.c
+++ b/remote-curl.c
@@ -290,6 +290,7 @@ static void output_refs(struct ref *refs)
struct rpc_state {
const char *service_name;
const char **argv;
+ struct strbuf *stdin_preamble;
char *service_url;
char *hdr_content_type;
char *hdr_accept;
@@ -535,6 +536,7 @@ static int rpc_service(struct rpc_state *rpc, struct discovery *heads)
{
const char *svc = rpc->service_name;
struct strbuf buf = STRBUF_INIT;
+ struct strbuf *preamble = rpc->stdin_preamble;
struct child_process client;
int err = 0;
@@ -545,6 +547,8 @@ static int rpc_service(struct rpc_state *rpc, struct discovery *heads)
client.argv = rpc->argv;
if (start_command(&client))
exit(1);
+ if (preamble)
+ write_or_die(client.in, preamble->buf, preamble->len);
if (heads)
write_or_die(client.in, heads->buf, heads->len);
@@ -626,13 +630,14 @@ static int fetch_git(struct discovery *heads,
int nr_heads, struct ref **to_fetch)
{
struct rpc_state rpc;
+ struct strbuf preamble = STRBUF_INIT;
char *depth_arg = NULL;
- const char **argv;
int argc = 0, i, err;
+ const char *argv[15];
- argv = xmalloc((15 + nr_heads) * sizeof(char*));
argv[argc++] = "fetch-pack";
argv[argc++] = "--stateless-rpc";
+ argv[argc++] = "--stdin";
argv[argc++] = "--lock-pack";
if (options.followtags)
argv[argc++] = "--include-tag";
@@ -651,24 +656,27 @@ static int fetch_git(struct discovery *heads,
argv[argc++] = depth_arg;
}
argv[argc++] = url;
+ argv[argc++] = NULL;
+
for (i = 0; i < nr_heads; i++) {
struct ref *ref = to_fetch[i];
if (!ref->name || !*ref->name)
die("cannot fetch by sha1 over smart http");
- argv[argc++] = ref->name;
+ packet_buf_write(&preamble, "%s\n", ref->name);
}
- argv[argc++] = NULL;
+ packet_buf_flush(&preamble);
memset(&rpc, 0, sizeof(rpc));
rpc.service_name = "git-upload-pack",
rpc.argv = argv;
+ rpc.stdin_preamble = &preamble;
rpc.gzip_request = 1;
err = rpc_service(&rpc, heads);
if (rpc.result.len)
safe_write(1, rpc.result.buf, rpc.result.len);
strbuf_release(&rpc.result);
- free(argv);
+ strbuf_release(&preamble);
free(depth_arg);
return err;
}
@@ -774,6 +782,7 @@ static int push_git(struct discovery *heads, int nr_spec, char **specs)
argv[argc++] = "--quiet";
else if (options.verbosity > 1)
argv[argc++] = "--verbose";
+ argv[argc++] = options.progress ? "--progress" : "--no-progress";
argv[argc++] = url;
for (i = 0; i < nr_spec; i++)
argv[argc++] = specs[i];
diff --git a/remote.c b/remote.c
index af597b3a62..b296d17404 100644
--- a/remote.c
+++ b/remote.c
@@ -8,6 +8,8 @@
#include "tag.h"
#include "string-list.h"
+enum map_direction { FROM_SRC, FROM_DST };
+
static struct refspec s_tag_refspec = {
0,
1,
@@ -978,16 +980,20 @@ static void tail_link_ref(struct ref *ref, struct ref ***tail)
*tail = &ref->next;
}
+static struct ref *alloc_delete_ref(void)
+{
+ struct ref *ref = alloc_ref("(delete)");
+ hashclr(ref->new_sha1);
+ return ref;
+}
+
static struct ref *try_explicit_object_name(const char *name)
{
unsigned char sha1[20];
struct ref *ref;
- if (!*name) {
- ref = alloc_ref("(delete)");
- hashclr(ref->new_sha1);
- return ref;
- }
+ if (!*name)
+ return alloc_delete_ref();
if (get_sha1(name, sha1))
return NULL;
ref = alloc_ref(name);
@@ -1110,10 +1116,11 @@ static int match_explicit_refs(struct ref *src, struct ref *dst,
return errs;
}
-static const struct refspec *check_pattern_match(const struct refspec *rs,
- int rs_nr,
- const struct ref *src)
+static char *get_ref_match(const struct refspec *rs, int rs_nr, const struct ref *ref,
+ int send_mirror, int direction, const struct refspec **ret_pat)
{
+ const struct refspec *pat;
+ char *name;
int i;
int matching_refs = -1;
for (i = 0; i < rs_nr; i++) {
@@ -1123,14 +1130,36 @@ static const struct refspec *check_pattern_match(const struct refspec *rs,
continue;
}
- if (rs[i].pattern && match_name_with_pattern(rs[i].src, src->name,
- NULL, NULL))
- return rs + i;
+ if (rs[i].pattern) {
+ const char *dst_side = rs[i].dst ? rs[i].dst : rs[i].src;
+ int match;
+ if (direction == FROM_SRC)
+ match = match_name_with_pattern(rs[i].src, ref->name, dst_side, &name);
+ else
+ match = match_name_with_pattern(dst_side, ref->name, rs[i].src, &name);
+ if (match) {
+ matching_refs = i;
+ break;
+ }
+ }
}
- if (matching_refs != -1)
- return rs + matching_refs;
- else
+ if (matching_refs == -1)
return NULL;
+
+ pat = rs + matching_refs;
+ if (pat->matching) {
+ /*
+ * "matching refs"; traditionally we pushed everything
+ * including refs outside refs/heads/ hierarchy, but
+ * that does not make much sense these days.
+ */
+ if (!send_mirror && prefixcmp(ref->name, "refs/heads/"))
+ return NULL;
+ name = xstrdup(ref->name);
+ }
+ if (ret_pat)
+ *ret_pat = pat;
+ return name;
}
static struct ref **tail_ref(struct ref **head)
@@ -1155,9 +1184,10 @@ int match_push_refs(struct ref *src, struct ref **dst,
struct refspec *rs;
int send_all = flags & MATCH_REFS_ALL;
int send_mirror = flags & MATCH_REFS_MIRROR;
+ int send_prune = flags & MATCH_REFS_PRUNE;
int errs;
static const char *default_refspec[] = { ":", NULL };
- struct ref **dst_tail = tail_ref(dst);
+ struct ref *ref, **dst_tail = tail_ref(dst);
if (!nr_refspec) {
nr_refspec = 1;
@@ -1167,39 +1197,23 @@ int match_push_refs(struct ref *src, struct ref **dst,
errs = match_explicit_refs(src, *dst, &dst_tail, rs, nr_refspec);
/* pick the remainder */
- for ( ; src; src = src->next) {
+ for (ref = src; ref; ref = ref->next) {
struct ref *dst_peer;
const struct refspec *pat = NULL;
char *dst_name;
- if (src->peer_ref)
- continue;
- pat = check_pattern_match(rs, nr_refspec, src);
- if (!pat)
+ if (ref->peer_ref)
continue;
- if (pat->matching) {
- /*
- * "matching refs"; traditionally we pushed everything
- * including refs outside refs/heads/ hierarchy, but
- * that does not make much sense these days.
- */
- if (!send_mirror && prefixcmp(src->name, "refs/heads/"))
- continue;
- dst_name = xstrdup(src->name);
+ dst_name = get_ref_match(rs, nr_refspec, ref, send_mirror, FROM_SRC, &pat);
+ if (!dst_name)
+ continue;
- } else {
- const char *dst_side = pat->dst ? pat->dst : pat->src;
- if (!match_name_with_pattern(pat->src, src->name,
- dst_side, &dst_name))
- die("Didn't think it matches any more");
- }
dst_peer = find_ref_by_name(*dst, dst_name);
if (dst_peer) {
if (dst_peer->peer_ref)
/* We're already sending something to this ref. */
goto free_name;
-
} else {
if (pat->matching && !(send_all || send_mirror))
/*
@@ -1211,13 +1225,30 @@ int match_push_refs(struct ref *src, struct ref **dst,
/* Create a new one and link it */
dst_peer = make_linked_ref(dst_name, &dst_tail);
- hashcpy(dst_peer->new_sha1, src->new_sha1);
+ hashcpy(dst_peer->new_sha1, ref->new_sha1);
}
- dst_peer->peer_ref = copy_ref(src);
+ dst_peer->peer_ref = copy_ref(ref);
dst_peer->force = pat->force;
free_name:
free(dst_name);
}
+ if (send_prune) {
+ /* check for missing refs on the remote */
+ for (ref = *dst; ref; ref = ref->next) {
+ char *src_name;
+
+ if (ref->peer_ref)
+ /* We're already sending something to this ref. */
+ continue;
+
+ src_name = get_ref_match(rs, nr_refspec, ref, send_mirror, FROM_DST, NULL);
+ if (src_name) {
+ if (!find_ref_by_name(src, src_name))
+ ref->peer_ref = alloc_delete_ref();
+ free(src_name);
+ }
+ }
+ }
if (errs)
return -1;
return 0;
diff --git a/remote.h b/remote.h
index b3955983ba..9ad8eb6cc6 100644
--- a/remote.h
+++ b/remote.h
@@ -145,7 +145,8 @@ int branch_merge_matches(struct branch *, int n, const char *);
enum match_refs_flags {
MATCH_REFS_NONE = 0,
MATCH_REFS_ALL = (1 << 0),
- MATCH_REFS_MIRROR = (1 << 1)
+ MATCH_REFS_MIRROR = (1 << 1),
+ MATCH_REFS_PRUNE = (1 << 2)
};
/* Reporting of tracking info */
diff --git a/revision.c b/revision.c
index 18be62b316..9a0d9c7de2 100644
--- a/revision.c
+++ b/revision.c
@@ -139,11 +139,32 @@ void mark_tree_uninteresting(struct tree *tree)
void mark_parents_uninteresting(struct commit *commit)
{
- struct commit_list *parents = commit->parents;
+ struct commit_list *parents = NULL, *l;
+
+ for (l = commit->parents; l; l = l->next)
+ commit_list_insert(l->item, &parents);
while (parents) {
struct commit *commit = parents->item;
- if (!(commit->object.flags & UNINTERESTING)) {
+ l = parents;
+ parents = parents->next;
+ free(l);
+
+ while (commit) {
+ /*
+ * A missing commit is ok iff its parent is marked
+ * uninteresting.
+ *
+ * We just mark such a thing parsed, so that when
+ * it is popped next time around, we won't be trying
+ * to parse it and get an error.
+ */
+ if (!has_sha1_file(commit->object.sha1))
+ commit->object.parsed = 1;
+
+ if (commit->object.flags & UNINTERESTING)
+ break;
+
commit->object.flags |= UNINTERESTING;
/*
@@ -154,21 +175,13 @@ void mark_parents_uninteresting(struct commit *commit)
* wasn't uninteresting), in which case we need
* to mark its parents recursively too..
*/
- if (commit->parents)
- mark_parents_uninteresting(commit);
- }
+ if (!commit->parents)
+ break;
- /*
- * A missing commit is ok iff its parent is marked
- * uninteresting.
- *
- * We just mark such a thing parsed, so that when
- * it is popped next time around, we won't be trying
- * to parse it and get an error.
- */
- if (!has_sha1_file(commit->object.sha1))
- commit->object.parsed = 1;
- parents = parents->next;
+ for (l = commit->parents->next; l; l = l->next)
+ commit_list_insert(l->item, &parents);
+ commit = commit->parents->item;
+ }
}
}
@@ -1569,6 +1582,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
revs->grep_filter.regflags |= REG_EXTENDED;
} 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;
} else if (!strcmp(arg, "--all-match")) {
@@ -1701,17 +1715,21 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
submodule = opt->submodule;
/* First, search for "--" */
- seen_dashdash = 0;
- for (i = 1; i < argc; i++) {
- const char *arg = argv[i];
- if (strcmp(arg, "--"))
- continue;
- argv[i] = NULL;
- argc = i;
- if (argv[i + 1])
- append_prune_data(&prune_data, argv + i + 1);
+ if (opt && opt->assume_dashdash) {
seen_dashdash = 1;
- break;
+ } else {
+ seen_dashdash = 0;
+ for (i = 1; i < argc; i++) {
+ const char *arg = argv[i];
+ if (strcmp(arg, "--"))
+ continue;
+ argv[i] = NULL;
+ argc = i;
+ if (argv[i + 1])
+ append_prune_data(&prune_data, argv + i + 1);
+ seen_dashdash = 1;
+ break;
+ }
}
/* Second, deal with arguments and options */
diff --git a/revision.h b/revision.h
index b8e9223954..1a0838473f 100644
--- a/revision.h
+++ b/revision.h
@@ -183,6 +183,7 @@ struct setup_revision_opt {
const char *def;
void (*tweak)(struct rev_info *, struct setup_revision_opt *);
const char *submodule;
+ int assume_dashdash;
};
extern void init_revisions(struct rev_info *revs, const char *prefix);
diff --git a/run-command.c b/run-command.c
index 1db8abf984..9c5a564ece 100644
--- a/run-command.c
+++ b/run-command.c
@@ -76,6 +76,68 @@ static inline void dup_devnull(int to)
}
#endif
+static char *locate_in_PATH(const char *file)
+{
+ const char *p = getenv("PATH");
+ struct strbuf buf = STRBUF_INIT;
+
+ if (!p || !*p)
+ return NULL;
+
+ while (1) {
+ const char *end = strchrnul(p, ':');
+
+ strbuf_reset(&buf);
+
+ /* POSIX specifies an empty entry as the current directory. */
+ if (end != p) {
+ strbuf_add(&buf, p, end - p);
+ strbuf_addch(&buf, '/');
+ }
+ strbuf_addstr(&buf, file);
+
+ if (!access(buf.buf, F_OK))
+ return strbuf_detach(&buf, NULL);
+
+ if (!*end)
+ break;
+ p = end + 1;
+ }
+
+ strbuf_release(&buf);
+ return NULL;
+}
+
+static int exists_in_PATH(const char *file)
+{
+ char *r = locate_in_PATH(file);
+ free(r);
+ return r != NULL;
+}
+
+int sane_execvp(const char *file, char * const argv[])
+{
+ if (!execvp(file, argv))
+ return 0; /* cannot happen ;-) */
+
+ /*
+ * When a command can't be found because one of the directories
+ * listed in $PATH is unsearchable, execvp reports EACCES, but
+ * careful usability testing (read: analysis of occasional bug
+ * reports) reveals that "No such file or directory" is more
+ * intuitive.
+ *
+ * We avoid commands with "/", because execvp will not do $PATH
+ * lookups in that case.
+ *
+ * The reassignment of EACCES to errno looks like a no-op below,
+ * but we need to protect against exists_in_PATH overwriting errno.
+ */
+ if (errno == EACCES && !strchr(file, '/'))
+ errno = exists_in_PATH(file) ? EACCES : ENOENT;
+ return -1;
+}
+
static const char **prepare_shell_cmd(const char **argv)
{
int argc, nargc = 0;
@@ -114,7 +176,7 @@ static int execv_shell_cmd(const char **argv)
{
const char **nargv = prepare_shell_cmd(argv);
trace_argv_printf(nargv, "trace: exec:");
- execvp(nargv[0], (char **)nargv);
+ sane_execvp(nargv[0], (char **)nargv);
free(nargv);
return -1;
}
@@ -339,7 +401,7 @@ fail_pipe:
} else if (cmd->use_shell) {
execv_shell_cmd(cmd->argv);
} else {
- execvp(cmd->argv[0], (char *const*) cmd->argv);
+ sane_execvp(cmd->argv[0], (char *const*) cmd->argv);
}
if (errno == ENOENT) {
if (!cmd->silent_exec_failure)
diff --git a/sequencer.c b/sequencer.c
index d1f28a6945..cd11e340dd 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -1,7 +1,20 @@
#include "cache.h"
#include "sequencer.h"
-#include "strbuf.h"
#include "dir.h"
+#include "object.h"
+#include "commit.h"
+#include "tag.h"
+#include "run-command.h"
+#include "exec_cmd.h"
+#include "utf8.h"
+#include "cache-tree.h"
+#include "diff.h"
+#include "revision.h"
+#include "rerere.h"
+#include "merge-recursive.h"
+#include "refs.h"
+
+#define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
void remove_sequencer_state(void)
{
@@ -11,3 +24,910 @@ void remove_sequencer_state(void)
remove_dir_recursively(&seq_dir, 0);
strbuf_release(&seq_dir);
}
+
+static const char *action_name(const struct replay_opts *opts)
+{
+ return opts->action == REPLAY_REVERT ? "revert" : "cherry-pick";
+}
+
+static char *get_encoding(const char *message);
+
+struct commit_message {
+ char *parent_label;
+ const char *label;
+ const char *subject;
+ char *reencoded_message;
+ const char *message;
+};
+
+static int get_message(struct commit *commit, struct commit_message *out)
+{
+ const char *encoding;
+ const char *abbrev, *subject;
+ int abbrev_len, subject_len;
+ char *q;
+
+ if (!commit->buffer)
+ return -1;
+ encoding = get_encoding(commit->buffer);
+ if (!encoding)
+ encoding = "UTF-8";
+ if (!git_commit_encoding)
+ git_commit_encoding = "UTF-8";
+
+ out->reencoded_message = NULL;
+ out->message = commit->buffer;
+ if (strcmp(encoding, git_commit_encoding))
+ out->reencoded_message = reencode_string(commit->buffer,
+ git_commit_encoding, encoding);
+ if (out->reencoded_message)
+ out->message = out->reencoded_message;
+
+ abbrev = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV);
+ abbrev_len = strlen(abbrev);
+
+ subject_len = find_commit_subject(out->message, &subject);
+
+ out->parent_label = xmalloc(strlen("parent of ") + abbrev_len +
+ strlen("... ") + subject_len + 1);
+ q = out->parent_label;
+ q = mempcpy(q, "parent of ", strlen("parent of "));
+ out->label = q;
+ q = mempcpy(q, abbrev, abbrev_len);
+ q = mempcpy(q, "... ", strlen("... "));
+ out->subject = q;
+ q = mempcpy(q, subject, subject_len);
+ *q = '\0';
+ return 0;
+}
+
+static void free_message(struct commit_message *msg)
+{
+ free(msg->parent_label);
+ free(msg->reencoded_message);
+}
+
+static char *get_encoding(const char *message)
+{
+ const char *p = message, *eol;
+
+ while (*p && *p != '\n') {
+ for (eol = p + 1; *eol && *eol != '\n'; eol++)
+ ; /* do nothing */
+ if (!prefixcmp(p, "encoding ")) {
+ char *result = xmalloc(eol - 8 - p);
+ strlcpy(result, p + 9, eol - 8 - p);
+ return result;
+ }
+ p = eol;
+ if (*p == '\n')
+ p++;
+ }
+ return NULL;
+}
+
+static void write_cherry_pick_head(struct commit *commit, const char *pseudoref)
+{
+ const char *filename;
+ int fd;
+ struct strbuf buf = STRBUF_INIT;
+
+ strbuf_addf(&buf, "%s\n", sha1_to_hex(commit->object.sha1));
+
+ filename = git_path("%s", pseudoref);
+ fd = open(filename, O_WRONLY | O_CREAT, 0666);
+ if (fd < 0)
+ die_errno(_("Could not open '%s' for writing"), filename);
+ if (write_in_full(fd, buf.buf, buf.len) != buf.len || close(fd))
+ die_errno(_("Could not write to '%s'"), filename);
+ strbuf_release(&buf);
+}
+
+static void print_advice(int show_hint, struct replay_opts *opts)
+{
+ char *msg = getenv("GIT_CHERRY_PICK_HELP");
+
+ if (msg) {
+ fprintf(stderr, "%s\n", msg);
+ /*
+ * A conflict has occured but the porcelain
+ * (typically rebase --interactive) wants to take care
+ * of the commit itself so remove CHERRY_PICK_HEAD
+ */
+ unlink(git_path("CHERRY_PICK_HEAD"));
+ return;
+ }
+
+ if (show_hint) {
+ if (opts->no_commit)
+ advise(_("after resolving the conflicts, mark the corrected paths\n"
+ "with 'git add <paths>' or 'git rm <paths>'"));
+ else
+ advise(_("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'"));
+ }
+}
+
+static void write_message(struct strbuf *msgbuf, const char *filename)
+{
+ static struct lock_file msg_file;
+
+ int msg_fd = hold_lock_file_for_update(&msg_file, filename,
+ LOCK_DIE_ON_ERROR);
+ if (write_in_full(msg_fd, msgbuf->buf, msgbuf->len) < 0)
+ die_errno(_("Could not write to %s"), filename);
+ strbuf_release(msgbuf);
+ if (commit_lock_file(&msg_file) < 0)
+ die(_("Error wrapping up %s"), filename);
+}
+
+static struct tree *empty_tree(void)
+{
+ return lookup_tree(EMPTY_TREE_SHA1_BIN);
+}
+
+static int error_dirty_index(struct replay_opts *opts)
+{
+ if (read_cache_unmerged())
+ return error_resolve_conflict(action_name(opts));
+
+ /* Different translation strings for cherry-pick and revert */
+ if (opts->action == REPLAY_PICK)
+ error(_("Your local changes would be overwritten by cherry-pick."));
+ else
+ error(_("Your local changes would be overwritten by revert."));
+
+ if (advice_commit_before_merge)
+ advise(_("Commit your changes or stash them to proceed."));
+ return -1;
+}
+
+static int fast_forward_to(const unsigned char *to, const unsigned char *from)
+{
+ struct ref_lock *ref_lock;
+
+ read_cache();
+ if (checkout_fast_forward(from, to))
+ exit(1); /* the callee should have complained already */
+ ref_lock = lock_any_ref_for_update("HEAD", from, 0);
+ return write_ref_sha1(ref_lock, to, "cherry-pick");
+}
+
+static int do_recursive_merge(struct commit *base, struct commit *next,
+ const char *base_label, const char *next_label,
+ unsigned char *head, struct strbuf *msgbuf,
+ struct replay_opts *opts)
+{
+ struct merge_options o;
+ struct tree *result, *next_tree, *base_tree, *head_tree;
+ int clean, index_fd;
+ const char **xopt;
+ static struct lock_file index_lock;
+
+ index_fd = hold_locked_index(&index_lock, 1);
+
+ read_cache();
+
+ init_merge_options(&o);
+ o.ancestor = base ? base_label : "(empty tree)";
+ o.branch1 = "HEAD";
+ o.branch2 = next ? next_label : "(empty tree)";
+
+ head_tree = parse_tree_indirect(head);
+ next_tree = next ? next->tree : empty_tree();
+ base_tree = base ? base->tree : empty_tree();
+
+ for (xopt = opts->xopts; xopt != opts->xopts + opts->xopts_nr; xopt++)
+ parse_merge_opt(&o, *xopt);
+
+ clean = merge_trees(&o,
+ head_tree,
+ next_tree, base_tree, &result);
+
+ if (active_cache_changed &&
+ (write_cache(index_fd, active_cache, active_nr) ||
+ commit_locked_index(&index_lock)))
+ /* TRANSLATORS: %s will be "revert" or "cherry-pick" */
+ die(_("%s: Unable to write new index file"), action_name(opts));
+ rollback_lock_file(&index_lock);
+
+ if (!clean) {
+ int i;
+ strbuf_addstr(msgbuf, "\nConflicts:\n");
+ for (i = 0; i < active_nr;) {
+ struct cache_entry *ce = active_cache[i++];
+ if (ce_stage(ce)) {
+ strbuf_addch(msgbuf, '\t');
+ strbuf_addstr(msgbuf, ce->name);
+ strbuf_addch(msgbuf, '\n');
+ while (i < active_nr && !strcmp(ce->name,
+ active_cache[i]->name))
+ i++;
+ }
+ }
+ }
+
+ return !clean;
+}
+
+/*
+ * If we are cherry-pick, and if the merge did not result in
+ * hand-editing, we will hit this commit and inherit the original
+ * author date and name.
+ * If we are revert, or if our cherry-pick results in a hand merge,
+ * we had better say that the current user is responsible for that.
+ */
+static int run_git_commit(const char *defmsg, struct replay_opts *opts)
+{
+ /* 6 is max possible length of our args array including NULL */
+ const char *args[6];
+ int i = 0;
+
+ args[i++] = "commit";
+ args[i++] = "-n";
+ if (opts->signoff)
+ args[i++] = "-s";
+ if (!opts->edit) {
+ args[i++] = "-F";
+ args[i++] = defmsg;
+ }
+ args[i] = NULL;
+
+ return run_command_v_opt(args, RUN_GIT_CMD);
+}
+
+static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
+{
+ unsigned char head[20];
+ struct commit *base, *next, *parent;
+ const char *base_label, *next_label;
+ struct commit_message msg = { NULL, NULL, NULL, NULL, NULL };
+ char *defmsg = NULL;
+ struct strbuf msgbuf = STRBUF_INIT;
+ int res;
+
+ if (opts->no_commit) {
+ /*
+ * We do not intend to commit immediately. We just want to
+ * merge the differences in, so let's compute the tree
+ * that represents the "current" state for merge-recursive
+ * to work on.
+ */
+ if (write_cache_as_tree(head, 0, NULL))
+ die (_("Your index file is unmerged."));
+ } else {
+ if (get_sha1("HEAD", head))
+ return error(_("You do not have a valid HEAD"));
+ if (index_differs_from("HEAD", 0))
+ return error_dirty_index(opts);
+ }
+ discard_cache();
+
+ if (!commit->parents) {
+ parent = NULL;
+ }
+ else if (commit->parents->next) {
+ /* Reverting or cherry-picking a merge commit */
+ int cnt;
+ struct commit_list *p;
+
+ if (!opts->mainline)
+ return error(_("Commit %s is a merge but no -m option was given."),
+ sha1_to_hex(commit->object.sha1));
+
+ for (cnt = 1, p = commit->parents;
+ cnt != opts->mainline && p;
+ cnt++)
+ p = p->next;
+ if (cnt != opts->mainline || !p)
+ return error(_("Commit %s does not have parent %d"),
+ sha1_to_hex(commit->object.sha1), opts->mainline);
+ parent = p->item;
+ } else if (0 < opts->mainline)
+ return error(_("Mainline was specified but commit %s is not a merge."),
+ sha1_to_hex(commit->object.sha1));
+ else
+ parent = commit->parents->item;
+
+ if (opts->allow_ff && parent && !hashcmp(parent->object.sha1, head))
+ return fast_forward_to(commit->object.sha1, head);
+
+ if (parent && parse_commit(parent) < 0)
+ /* TRANSLATORS: The first %s will be "revert" or
+ "cherry-pick", the second %s a SHA1 */
+ return error(_("%s: cannot parse parent commit %s"),
+ action_name(opts), sha1_to_hex(parent->object.sha1));
+
+ if (get_message(commit, &msg) != 0)
+ return error(_("Cannot get commit message for %s"),
+ sha1_to_hex(commit->object.sha1));
+
+ /*
+ * "commit" is an existing commit. We would want to apply
+ * the difference it introduces since its first parent "prev"
+ * on top of the current HEAD if we are cherry-pick. Or the
+ * reverse of it if we are revert.
+ */
+
+ defmsg = git_pathdup("MERGE_MSG");
+
+ if (opts->action == REPLAY_REVERT) {
+ base = commit;
+ base_label = msg.label;
+ next = parent;
+ next_label = msg.parent_label;
+ strbuf_addstr(&msgbuf, "Revert \"");
+ strbuf_addstr(&msgbuf, msg.subject);
+ strbuf_addstr(&msgbuf, "\"\n\nThis reverts commit ");
+ strbuf_addstr(&msgbuf, sha1_to_hex(commit->object.sha1));
+
+ if (commit->parents && commit->parents->next) {
+ strbuf_addstr(&msgbuf, ", reversing\nchanges made to ");
+ strbuf_addstr(&msgbuf, sha1_to_hex(parent->object.sha1));
+ }
+ strbuf_addstr(&msgbuf, ".\n");
+ } else {
+ const char *p;
+
+ base = parent;
+ base_label = msg.parent_label;
+ next = commit;
+ next_label = msg.label;
+
+ /*
+ * Append the commit log message to msgbuf; it starts
+ * after the tree, parent, author, committer
+ * information followed by "\n\n".
+ */
+ p = strstr(msg.message, "\n\n");
+ if (p) {
+ p += 2;
+ strbuf_addstr(&msgbuf, p);
+ }
+
+ if (opts->record_origin) {
+ strbuf_addstr(&msgbuf, "(cherry picked from commit ");
+ strbuf_addstr(&msgbuf, sha1_to_hex(commit->object.sha1));
+ strbuf_addstr(&msgbuf, ")\n");
+ }
+ }
+
+ if (!opts->strategy || !strcmp(opts->strategy, "recursive") || opts->action == REPLAY_REVERT) {
+ res = do_recursive_merge(base, next, base_label, next_label,
+ head, &msgbuf, opts);
+ write_message(&msgbuf, defmsg);
+ } else {
+ struct commit_list *common = NULL;
+ struct commit_list *remotes = NULL;
+
+ write_message(&msgbuf, defmsg);
+
+ commit_list_insert(base, &common);
+ commit_list_insert(next, &remotes);
+ res = try_merge_command(opts->strategy, opts->xopts_nr, opts->xopts,
+ common, sha1_to_hex(head), remotes);
+ free_commit_list(common);
+ free_commit_list(remotes);
+ }
+
+ /*
+ * If the merge was clean or if it failed due to conflict, we write
+ * CHERRY_PICK_HEAD for the subsequent invocation of commit to use.
+ * However, if the merge did not even start, then we don't want to
+ * write it at all.
+ */
+ if (opts->action == REPLAY_PICK && !opts->no_commit && (res == 0 || res == 1))
+ write_cherry_pick_head(commit, "CHERRY_PICK_HEAD");
+ if (opts->action == REPLAY_REVERT && ((opts->no_commit && res == 0) || res == 1))
+ write_cherry_pick_head(commit, "REVERT_HEAD");
+
+ if (res) {
+ error(opts->action == REPLAY_REVERT
+ ? _("could not revert %s... %s")
+ : _("could not apply %s... %s"),
+ find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV),
+ msg.subject);
+ print_advice(res == 1, opts);
+ rerere(opts->allow_rerere_auto);
+ } else {
+ if (!opts->no_commit)
+ res = run_git_commit(defmsg, opts);
+ }
+
+ free_message(&msg);
+ free(defmsg);
+
+ return res;
+}
+
+static void prepare_revs(struct replay_opts *opts)
+{
+ if (opts->action != REPLAY_REVERT)
+ opts->revs->reverse ^= 1;
+
+ if (prepare_revision_walk(opts->revs))
+ die(_("revision walk setup failed"));
+
+ if (!opts->revs->commits)
+ die(_("empty commit set passed"));
+}
+
+static void read_and_refresh_cache(struct replay_opts *opts)
+{
+ static struct lock_file index_lock;
+ int index_fd = hold_locked_index(&index_lock, 0);
+ if (read_index_preload(&the_index, NULL) < 0)
+ die(_("git %s: failed to read the index"), action_name(opts));
+ refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, NULL, NULL, NULL);
+ if (the_index.cache_changed) {
+ if (write_index(&the_index, index_fd) ||
+ commit_locked_index(&index_lock))
+ die(_("git %s: failed to refresh the index"), action_name(opts));
+ }
+ rollback_lock_file(&index_lock);
+}
+
+/*
+ * Append a commit to the end of the commit_list.
+ *
+ * next starts by pointing to the variable that holds the head of an
+ * empty commit_list, and is updated to point to the "next" field of
+ * the last item on the list as new commits are appended.
+ *
+ * Usage example:
+ *
+ * struct commit_list *list;
+ * struct commit_list **next = &list;
+ *
+ * next = commit_list_append(c1, next);
+ * next = commit_list_append(c2, next);
+ * assert(commit_list_count(list) == 2);
+ * return list;
+ */
+static struct commit_list **commit_list_append(struct commit *commit,
+ struct commit_list **next)
+{
+ struct commit_list *new = xmalloc(sizeof(struct commit_list));
+ new->item = commit;
+ *next = new;
+ new->next = NULL;
+ return &new->next;
+}
+
+static int format_todo(struct strbuf *buf, struct commit_list *todo_list,
+ struct replay_opts *opts)
+{
+ struct commit_list *cur = NULL;
+ const char *sha1_abbrev = NULL;
+ const char *action_str = opts->action == REPLAY_REVERT ? "revert" : "pick";
+ const char *subject;
+ int subject_len;
+
+ for (cur = todo_list; cur; cur = cur->next) {
+ sha1_abbrev = find_unique_abbrev(cur->item->object.sha1, DEFAULT_ABBREV);
+ subject_len = find_commit_subject(cur->item->buffer, &subject);
+ strbuf_addf(buf, "%s %s %.*s\n", action_str, sha1_abbrev,
+ subject_len, subject);
+ }
+ return 0;
+}
+
+static struct commit *parse_insn_line(char *bol, char *eol, struct replay_opts *opts)
+{
+ unsigned char commit_sha1[20];
+ enum replay_action action;
+ char *end_of_object_name;
+ int saved, status, padding;
+
+ if (!prefixcmp(bol, "pick")) {
+ action = REPLAY_PICK;
+ bol += strlen("pick");
+ } else if (!prefixcmp(bol, "revert")) {
+ action = REPLAY_REVERT;
+ bol += strlen("revert");
+ } else
+ return NULL;
+
+ /* Eat up extra spaces/ tabs before object name */
+ padding = strspn(bol, " \t");
+ if (!padding)
+ return NULL;
+ bol += padding;
+
+ end_of_object_name = bol + strcspn(bol, " \t\n");
+ saved = *end_of_object_name;
+ *end_of_object_name = '\0';
+ status = get_sha1(bol, commit_sha1);
+ *end_of_object_name = saved;
+
+ /*
+ * Verify that the action matches up with the one in
+ * opts; we don't support arbitrary instructions
+ */
+ if (action != opts->action) {
+ const char *action_str;
+ action_str = action == REPLAY_REVERT ? "revert" : "cherry-pick";
+ error(_("Cannot %s during a %s"), action_str, action_name(opts));
+ return NULL;
+ }
+
+ if (status < 0)
+ return NULL;
+
+ return lookup_commit_reference(commit_sha1);
+}
+
+static int parse_insn_buffer(char *buf, struct commit_list **todo_list,
+ struct replay_opts *opts)
+{
+ struct commit_list **next = todo_list;
+ struct commit *commit;
+ char *p = buf;
+ int i;
+
+ for (i = 1; *p; i++) {
+ char *eol = strchrnul(p, '\n');
+ commit = parse_insn_line(p, eol, opts);
+ if (!commit)
+ return error(_("Could not parse line %d."), i);
+ next = commit_list_append(commit, next);
+ p = *eol ? eol + 1 : eol;
+ }
+ if (!*todo_list)
+ return error(_("No commits parsed."));
+ return 0;
+}
+
+static void read_populate_todo(struct commit_list **todo_list,
+ struct replay_opts *opts)
+{
+ const char *todo_file = git_path(SEQ_TODO_FILE);
+ struct strbuf buf = STRBUF_INIT;
+ int fd, res;
+
+ fd = open(todo_file, O_RDONLY);
+ if (fd < 0)
+ die_errno(_("Could not open %s"), todo_file);
+ if (strbuf_read(&buf, fd, 0) < 0) {
+ close(fd);
+ strbuf_release(&buf);
+ die(_("Could not read %s."), todo_file);
+ }
+ close(fd);
+
+ res = parse_insn_buffer(buf.buf, todo_list, opts);
+ strbuf_release(&buf);
+ if (res)
+ die(_("Unusable instruction sheet: %s"), todo_file);
+}
+
+static int populate_opts_cb(const char *key, const char *value, void *data)
+{
+ struct replay_opts *opts = data;
+ int error_flag = 1;
+
+ if (!value)
+ error_flag = 0;
+ else if (!strcmp(key, "options.no-commit"))
+ opts->no_commit = git_config_bool_or_int(key, value, &error_flag);
+ else if (!strcmp(key, "options.edit"))
+ opts->edit = git_config_bool_or_int(key, value, &error_flag);
+ else if (!strcmp(key, "options.signoff"))
+ opts->signoff = git_config_bool_or_int(key, value, &error_flag);
+ else if (!strcmp(key, "options.record-origin"))
+ opts->record_origin = git_config_bool_or_int(key, value, &error_flag);
+ else if (!strcmp(key, "options.allow-ff"))
+ opts->allow_ff = git_config_bool_or_int(key, value, &error_flag);
+ else if (!strcmp(key, "options.mainline"))
+ opts->mainline = git_config_int(key, value);
+ else if (!strcmp(key, "options.strategy"))
+ git_config_string(&opts->strategy, key, value);
+ else if (!strcmp(key, "options.strategy-option")) {
+ ALLOC_GROW(opts->xopts, opts->xopts_nr + 1, opts->xopts_alloc);
+ opts->xopts[opts->xopts_nr++] = xstrdup(value);
+ } else
+ return error(_("Invalid key: %s"), key);
+
+ if (!error_flag)
+ return error(_("Invalid value for %s: %s"), key, value);
+
+ return 0;
+}
+
+static void read_populate_opts(struct replay_opts **opts_ptr)
+{
+ const char *opts_file = git_path(SEQ_OPTS_FILE);
+
+ if (!file_exists(opts_file))
+ return;
+ if (git_config_from_file(populate_opts_cb, opts_file, *opts_ptr) < 0)
+ die(_("Malformed options sheet: %s"), opts_file);
+}
+
+static void walk_revs_populate_todo(struct commit_list **todo_list,
+ struct replay_opts *opts)
+{
+ struct commit *commit;
+ struct commit_list **next;
+
+ prepare_revs(opts);
+
+ next = todo_list;
+ while ((commit = get_revision(opts->revs)))
+ next = commit_list_append(commit, next);
+}
+
+static int create_seq_dir(void)
+{
+ const char *seq_dir = git_path(SEQ_DIR);
+
+ if (file_exists(seq_dir)) {
+ error(_("a cherry-pick or revert is already in progress"));
+ advise(_("try \"git cherry-pick (--continue | --quit | --abort)\""));
+ return -1;
+ }
+ else if (mkdir(seq_dir, 0777) < 0)
+ die_errno(_("Could not create sequencer directory %s"), seq_dir);
+ return 0;
+}
+
+static void save_head(const char *head)
+{
+ const char *head_file = git_path(SEQ_HEAD_FILE);
+ static struct lock_file head_lock;
+ struct strbuf buf = STRBUF_INIT;
+ int fd;
+
+ fd = hold_lock_file_for_update(&head_lock, head_file, LOCK_DIE_ON_ERROR);
+ strbuf_addf(&buf, "%s\n", head);
+ if (write_in_full(fd, buf.buf, buf.len) < 0)
+ die_errno(_("Could not write to %s"), head_file);
+ if (commit_lock_file(&head_lock) < 0)
+ die(_("Error wrapping up %s."), head_file);
+}
+
+static int reset_for_rollback(const unsigned char *sha1)
+{
+ const char *argv[4]; /* reset --merge <arg> + NULL */
+ argv[0] = "reset";
+ argv[1] = "--merge";
+ argv[2] = sha1_to_hex(sha1);
+ argv[3] = NULL;
+ return run_command_v_opt(argv, RUN_GIT_CMD);
+}
+
+static int rollback_single_pick(void)
+{
+ unsigned char head_sha1[20];
+
+ if (!file_exists(git_path("CHERRY_PICK_HEAD")) &&
+ !file_exists(git_path("REVERT_HEAD")))
+ return error(_("no cherry-pick or revert in progress"));
+ if (read_ref_full("HEAD", head_sha1, 0, NULL))
+ return error(_("cannot resolve HEAD"));
+ if (is_null_sha1(head_sha1))
+ return error(_("cannot abort from a branch yet to be born"));
+ return reset_for_rollback(head_sha1);
+}
+
+static int sequencer_rollback(struct replay_opts *opts)
+{
+ const char *filename;
+ FILE *f;
+ unsigned char sha1[20];
+ struct strbuf buf = STRBUF_INIT;
+
+ filename = git_path(SEQ_HEAD_FILE);
+ f = fopen(filename, "r");
+ if (!f && errno == ENOENT) {
+ /*
+ * There is no multiple-cherry-pick in progress.
+ * If CHERRY_PICK_HEAD or REVERT_HEAD indicates
+ * a single-cherry-pick in progress, abort that.
+ */
+ return rollback_single_pick();
+ }
+ if (!f)
+ return error(_("cannot open %s: %s"), filename,
+ strerror(errno));
+ if (strbuf_getline(&buf, f, '\n')) {
+ error(_("cannot read %s: %s"), filename, ferror(f) ?
+ strerror(errno) : _("unexpected end of file"));
+ fclose(f);
+ goto fail;
+ }
+ fclose(f);
+ if (get_sha1_hex(buf.buf, sha1) || buf.buf[40] != '\0') {
+ error(_("stored pre-cherry-pick HEAD file '%s' is corrupt"),
+ filename);
+ goto fail;
+ }
+ if (reset_for_rollback(sha1))
+ goto fail;
+ remove_sequencer_state();
+ strbuf_release(&buf);
+ return 0;
+fail:
+ strbuf_release(&buf);
+ return -1;
+}
+
+static void save_todo(struct commit_list *todo_list, struct replay_opts *opts)
+{
+ const char *todo_file = git_path(SEQ_TODO_FILE);
+ static struct lock_file todo_lock;
+ struct strbuf buf = STRBUF_INIT;
+ int fd;
+
+ fd = hold_lock_file_for_update(&todo_lock, todo_file, LOCK_DIE_ON_ERROR);
+ if (format_todo(&buf, todo_list, opts) < 0)
+ die(_("Could not format %s."), todo_file);
+ if (write_in_full(fd, buf.buf, buf.len) < 0) {
+ strbuf_release(&buf);
+ die_errno(_("Could not write to %s"), todo_file);
+ }
+ if (commit_lock_file(&todo_lock) < 0) {
+ strbuf_release(&buf);
+ die(_("Error wrapping up %s."), todo_file);
+ }
+ strbuf_release(&buf);
+}
+
+static void save_opts(struct replay_opts *opts)
+{
+ const char *opts_file = git_path(SEQ_OPTS_FILE);
+
+ if (opts->no_commit)
+ git_config_set_in_file(opts_file, "options.no-commit", "true");
+ if (opts->edit)
+ git_config_set_in_file(opts_file, "options.edit", "true");
+ if (opts->signoff)
+ git_config_set_in_file(opts_file, "options.signoff", "true");
+ if (opts->record_origin)
+ git_config_set_in_file(opts_file, "options.record-origin", "true");
+ if (opts->allow_ff)
+ git_config_set_in_file(opts_file, "options.allow-ff", "true");
+ if (opts->mainline) {
+ struct strbuf buf = STRBUF_INIT;
+ strbuf_addf(&buf, "%d", opts->mainline);
+ git_config_set_in_file(opts_file, "options.mainline", buf.buf);
+ strbuf_release(&buf);
+ }
+ if (opts->strategy)
+ git_config_set_in_file(opts_file, "options.strategy", opts->strategy);
+ if (opts->xopts) {
+ int i;
+ for (i = 0; i < opts->xopts_nr; i++)
+ git_config_set_multivar_in_file(opts_file,
+ "options.strategy-option",
+ opts->xopts[i], "^$", 0);
+ }
+}
+
+static int pick_commits(struct commit_list *todo_list, struct replay_opts *opts)
+{
+ struct commit_list *cur;
+ int res;
+
+ setenv(GIT_REFLOG_ACTION, action_name(opts), 0);
+ if (opts->allow_ff)
+ assert(!(opts->signoff || opts->no_commit ||
+ opts->record_origin || opts->edit));
+ read_and_refresh_cache(opts);
+
+ for (cur = todo_list; cur; cur = cur->next) {
+ save_todo(cur, opts);
+ res = do_pick_commit(cur->item, opts);
+ if (res)
+ return res;
+ }
+
+ /*
+ * Sequence of picks finished successfully; cleanup by
+ * removing the .git/sequencer directory
+ */
+ remove_sequencer_state();
+ return 0;
+}
+
+static int continue_single_pick(void)
+{
+ const char *argv[] = { "commit", NULL };
+
+ if (!file_exists(git_path("CHERRY_PICK_HEAD")) &&
+ !file_exists(git_path("REVERT_HEAD")))
+ return error(_("no cherry-pick or revert in progress"));
+ return run_command_v_opt(argv, RUN_GIT_CMD);
+}
+
+static int sequencer_continue(struct replay_opts *opts)
+{
+ struct commit_list *todo_list = NULL;
+
+ if (!file_exists(git_path(SEQ_TODO_FILE)))
+ return continue_single_pick();
+ read_populate_opts(&opts);
+ read_populate_todo(&todo_list, opts);
+
+ /* Verify that the conflict has been resolved */
+ if (file_exists(git_path("CHERRY_PICK_HEAD")) ||
+ file_exists(git_path("REVERT_HEAD"))) {
+ int ret = continue_single_pick();
+ if (ret)
+ return ret;
+ }
+ if (index_differs_from("HEAD", 0))
+ return error_dirty_index(opts);
+ todo_list = todo_list->next;
+ return pick_commits(todo_list, opts);
+}
+
+static int single_pick(struct commit *cmit, struct replay_opts *opts)
+{
+ setenv(GIT_REFLOG_ACTION, action_name(opts), 0);
+ return do_pick_commit(cmit, opts);
+}
+
+int sequencer_pick_revisions(struct replay_opts *opts)
+{
+ struct commit_list *todo_list = NULL;
+ unsigned char sha1[20];
+
+ if (opts->subcommand == REPLAY_NONE)
+ assert(opts->revs);
+
+ read_and_refresh_cache(opts);
+
+ /*
+ * Decide what to do depending on the arguments; a fresh
+ * cherry-pick should be handled differently from an existing
+ * one that is being continued
+ */
+ if (opts->subcommand == REPLAY_REMOVE_STATE) {
+ remove_sequencer_state();
+ return 0;
+ }
+ if (opts->subcommand == REPLAY_ROLLBACK)
+ return sequencer_rollback(opts);
+ if (opts->subcommand == REPLAY_CONTINUE)
+ return sequencer_continue(opts);
+
+ /*
+ * If we were called as "git cherry-pick <commit>", just
+ * cherry-pick/revert it, set CHERRY_PICK_HEAD /
+ * REVERT_HEAD, and don't touch the sequencer state.
+ * This means it is possible to cherry-pick in the middle
+ * of a cherry-pick sequence.
+ */
+ if (opts->revs->cmdline.nr == 1 &&
+ opts->revs->cmdline.rev->whence == REV_CMD_REV &&
+ opts->revs->no_walk &&
+ !opts->revs->cmdline.rev->flags) {
+ struct commit *cmit;
+ if (prepare_revision_walk(opts->revs))
+ die(_("revision walk setup failed"));
+ cmit = get_revision(opts->revs);
+ if (!cmit || get_revision(opts->revs))
+ die("BUG: expected exactly one commit from walk");
+ return single_pick(cmit, opts);
+ }
+
+ /*
+ * Start a new cherry-pick/ revert sequence; but
+ * first, make sure that an existing one isn't in
+ * progress
+ */
+
+ walk_revs_populate_todo(&todo_list, opts);
+ if (create_seq_dir() < 0)
+ return -1;
+ if (get_sha1("HEAD", sha1)) {
+ if (opts->action == REPLAY_REVERT)
+ return error(_("Can't revert as initial commit"));
+ return error(_("Can't cherry-pick into empty head"));
+ }
+ save_head(sha1_to_hex(sha1));
+ save_opts(opts);
+ return pick_commits(todo_list, opts);
+}
diff --git a/sequencer.h b/sequencer.h
index 2d4528f292..bb4b13830e 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -6,7 +6,44 @@
#define SEQ_TODO_FILE "sequencer/todo"
#define SEQ_OPTS_FILE "sequencer/opts"
+enum replay_action {
+ REPLAY_REVERT,
+ REPLAY_PICK
+};
+
+enum replay_subcommand {
+ REPLAY_NONE,
+ REPLAY_REMOVE_STATE,
+ REPLAY_CONTINUE,
+ REPLAY_ROLLBACK
+};
+
+struct replay_opts {
+ enum replay_action action;
+ enum replay_subcommand subcommand;
+
+ /* Boolean options */
+ int edit;
+ int record_origin;
+ int no_commit;
+ int signoff;
+ int allow_ff;
+ int allow_rerere_auto;
+
+ int mainline;
+
+ /* Merge strategy */
+ const char *strategy;
+ const char **xopts;
+ size_t xopts_nr, xopts_alloc;
+
+ /* Only used by REPLAY_NONE */
+ struct rev_info *revs;
+};
+
/* Removes SEQ_DIR. */
extern void remove_sequencer_state(void);
+int sequencer_pick_revisions(struct replay_opts *opts);
+
#endif
diff --git a/setup.c b/setup.c
index 7a3618fab7..731851a4a8 100644
--- a/setup.c
+++ b/setup.c
@@ -569,13 +569,15 @@ static const char *setup_nongit(const char *cwd, int *nongit_ok)
return NULL;
}
-static dev_t get_device_or_die(const char *path, const char *prefix)
+static dev_t get_device_or_die(const char *path, const char *prefix, int prefix_len)
{
struct stat buf;
- if (stat(path, &buf))
- die_errno("failed to stat '%s%s%s'",
+ if (stat(path, &buf)) {
+ die_errno("failed to stat '%*s%s%s'",
+ prefix_len,
prefix ? prefix : "",
prefix ? "/" : "", path);
+ }
return buf.st_dev;
}
@@ -589,7 +591,7 @@ static const char *setup_git_directory_gently_1(int *nongit_ok)
static char cwd[PATH_MAX+1];
const char *gitdirenv, *ret;
char *gitfile;
- int len, offset, ceil_offset;
+ int len, offset, offset_parent, ceil_offset;
dev_t current_device = 0;
int one_filesystem = 1;
@@ -631,7 +633,7 @@ static const char *setup_git_directory_gently_1(int *nongit_ok)
*/
one_filesystem = !git_env_bool("GIT_DISCOVERY_ACROSS_FILESYSTEM", 0);
if (one_filesystem)
- current_device = get_device_or_die(".", NULL);
+ current_device = get_device_or_die(".", NULL, 0);
for (;;) {
gitfile = (char*)read_gitfile(DEFAULT_GIT_DIR_ENVIRONMENT);
if (gitfile)
@@ -653,11 +655,12 @@ static const char *setup_git_directory_gently_1(int *nongit_ok)
if (is_git_directory("."))
return setup_bare_git_dir(cwd, offset, len, nongit_ok);
- while (--offset > ceil_offset && cwd[offset] != '/');
- if (offset <= ceil_offset)
+ offset_parent = offset;
+ while (--offset_parent > ceil_offset && cwd[offset_parent] != '/');
+ if (offset_parent <= ceil_offset)
return setup_nongit(cwd, nongit_ok);
if (one_filesystem) {
- dev_t parent_device = get_device_or_die("..", cwd);
+ dev_t parent_device = get_device_or_die("..", cwd, offset);
if (parent_device != current_device) {
if (nongit_ok) {
if (chdir(cwd))
@@ -666,7 +669,7 @@ static const char *setup_git_directory_gently_1(int *nongit_ok)
return NULL;
}
cwd[offset] = '\0';
- die("Not a git repository (or any parent up to mount parent %s)\n"
+ die("Not a git repository (or any parent up to mount point %s)\n"
"Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set).", cwd);
}
}
@@ -674,6 +677,7 @@ static const char *setup_git_directory_gently_1(int *nongit_ok)
cwd[offset] = '\0';
die_errno("Cannot change to '%s/..'", cwd);
}
+ offset = offset_parent;
}
}
diff --git a/sha1_file.c b/sha1_file.c
index 4f06a0e450..f615fc7206 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -228,7 +228,6 @@ char *sha1_pack_index_name(const unsigned char *sha1)
struct alternate_object_database *alt_odb_list;
static struct alternate_object_database **alt_odb_tail;
-static void read_info_alternates(const char * alternates, int depth);
static int git_open_noatime(const char *name);
/*
@@ -353,7 +352,7 @@ static void link_alt_odb_entries(const char *alt, const char *ep, int sep,
}
}
-static void read_info_alternates(const char * relative_base, int depth)
+void read_info_alternates(const char * relative_base, int depth)
{
char *map;
size_t mapsz;
diff --git a/submodule.c b/submodule.c
index 9a28060679..b63978a161 100644
--- a/submodule.c
+++ b/submodule.c
@@ -63,6 +63,9 @@ static int add_submodule_odb(const char *path)
alt_odb->name[40] = '\0';
alt_odb->name[41] = '\0';
alt_odb_list = alt_odb;
+
+ /* add possible alternates from the submodule */
+ read_info_alternates(objects_directory.buf, 0);
prepare_alt_odb();
done:
strbuf_release(&objects_directory);
diff --git a/submodule.h b/submodule.h
index 80e04f3c8c..9c5e5c0c30 100644
--- a/submodule.h
+++ b/submodule.h
@@ -13,7 +13,7 @@ enum {
void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt,
const char *path);
int submodule_config(const char *var, const char *value, void *cb);
-void gitmodules_config();
+void gitmodules_config(void);
int parse_submodule_config_option(const char *var, const char *value);
void handle_ignore_submodules_arg(struct diff_options *diffopt, const char *);
int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg);
diff --git a/symlinks.c b/symlinks.c
index 034943bda0..290036744b 100644
--- a/symlinks.c
+++ b/symlinks.c
@@ -219,7 +219,20 @@ int has_symlink_leading_path(const char *name, int len)
*/
int check_leading_path(const char *name, int len)
{
- struct cache_def *cache = &default_cache; /* FIXME */
+ return threaded_check_leading_path(&default_cache, name, len);
+}
+
+/*
+ * Return zero if path 'name' has a leading symlink component or
+ * if some leading path component does not exists.
+ *
+ * Return -1 if leading path exists and is a directory.
+ *
+ * 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)
+{
int flags;
int match_len = lstat_cache_matchlen(cache, name, len, &flags,
FL_SYMLINK|FL_NOENT|FL_DIR, USE_ONLY_LSTAT);
@@ -240,7 +253,18 @@ int check_leading_path(const char *name, int len)
*/
int has_dirs_only_path(const char *name, int len, int prefix_len)
{
- struct cache_def *cache = &default_cache; /* FIXME */
+ return threaded_has_dirs_only_path(&default_cache, name, len, prefix_len);
+}
+
+/*
+ * Return non-zero if all path components of 'name' exists as a
+ * directory. If prefix_len > 0, we will test with the stat()
+ * function instead of the lstat() function for a prefix length of
+ * '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)
+{
return lstat_cache(cache, name, len,
FL_DIR|FL_FULLPATH, prefix_len) &
FL_DIR;
diff --git a/t/Makefile b/t/Makefile
index b5048ab77b..6091211f10 100644
--- a/t/Makefile
+++ b/t/Makefile
@@ -73,4 +73,45 @@ gitweb-test:
valgrind:
$(MAKE) GIT_TEST_OPTS="$(GIT_TEST_OPTS) --valgrind"
-.PHONY: pre-clean $(T) aggregate-results clean valgrind
+perf:
+ $(MAKE) -C perf/ all
+
+# Smoke testing targets
+-include ../GIT-VERSION-FILE
+uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo unknown')
+uname_M := $(shell sh -c 'uname -m 2>/dev/null || echo unknown')
+
+test-results:
+ mkdir -p test-results
+
+test-results/git-smoke.tar.gz: test-results
+ $(PERL_PATH) ./harness \
+ --archive="test-results/git-smoke.tar.gz" \
+ $(T)
+
+smoke: test-results/git-smoke.tar.gz
+
+SMOKE_UPLOAD_FLAGS =
+ifdef SMOKE_USERNAME
+ SMOKE_UPLOAD_FLAGS += -F username="$(SMOKE_USERNAME)" -F password="$(SMOKE_PASSWORD)"
+endif
+ifdef SMOKE_COMMENT
+ SMOKE_UPLOAD_FLAGS += -F comments="$(SMOKE_COMMENT)"
+endif
+ifdef SMOKE_TAGS
+ SMOKE_UPLOAD_FLAGS += -F tags="$(SMOKE_TAGS)"
+endif
+
+smoke_report: smoke
+ curl \
+ -H "Expect: " \
+ -F project=Git \
+ -F architecture="$(uname_M)" \
+ -F platform="$(uname_S)" \
+ -F revision="$(GIT_VERSION)" \
+ -F report_file=@test-results/git-smoke.tar.gz \
+ $(SMOKE_UPLOAD_FLAGS) \
+ http://smoke.git.nix.is/app/projects/process_add_report/1 \
+ | grep -v ^Redirecting
+
+.PHONY: pre-clean $(T) aggregate-results clean valgrind perf
diff --git a/t/README b/t/README
index 681e8b4320..3534f43d01 100644
--- a/t/README
+++ b/t/README
@@ -548,6 +548,19 @@ library for your script to use.
...
'
+ - test_pause
+
+ This command is useful for writing and debugging tests and must be
+ removed before submitting. It halts the execution of the test and
+ spawns a shell in the trash directory. Exit the shell to continue
+ the test. Example:
+
+ test_expect_success 'test' '
+ git do-something >actual &&
+ test_pause &&
+ test_cmp expected actual
+ '
+
Prerequisites
-------------
diff --git a/t/gitweb-lib.sh b/t/gitweb-lib.sh
index 21d11d6c2d..ae2dc4604f 100644
--- a/t/gitweb-lib.sh
+++ b/t/gitweb-lib.sh
@@ -69,7 +69,7 @@ gitweb_run () {
# written to web server logs, so we are not interested in that:
# we are interested only in properly formatted errors/warnings
rm -f gitweb.log &&
- perl -- "$SCRIPT_NAME" \
+ "$PERL_PATH" -- "$SCRIPT_NAME" \
>gitweb.output 2>gitweb.log &&
perl -w -e '
open O, ">gitweb.headers";
diff --git a/t/lib-git-daemon.sh b/t/lib-git-daemon.sh
new file mode 100644
index 0000000000..87f0ad8f41
--- /dev/null
+++ b/t/lib-git-daemon.sh
@@ -0,0 +1,69 @@
+#!/bin/sh
+
+if test -z "$GIT_TEST_GIT_DAEMON"
+then
+ skip_all="git-daemon testing disabled (define GIT_TEST_GIT_DAEMON to enable)"
+ test_done
+fi
+
+LIB_GIT_DAEMON_PORT=${LIB_GIT_DAEMON_PORT-'8121'}
+
+GIT_DAEMON_PID=
+GIT_DAEMON_DOCUMENT_ROOT_PATH="$PWD"/repo
+GIT_DAEMON_URL=git://127.0.0.1:$LIB_GIT_DAEMON_PORT
+
+start_git_daemon() {
+ if test -n "$GIT_DAEMON_PID"
+ then
+ error "start_git_daemon already called"
+ fi
+
+ mkdir -p "$GIT_DAEMON_DOCUMENT_ROOT_PATH"
+
+ trap 'code=$?; stop_git_daemon; (exit $code); die' EXIT
+
+ say >&3 "Starting git daemon ..."
+ mkfifo git_daemon_output
+ git daemon --listen=127.0.0.1 --port="$LIB_GIT_DAEMON_PORT" \
+ --reuseaddr --verbose \
+ --base-path="$GIT_DAEMON_DOCUMENT_ROOT_PATH" \
+ "$@" "$GIT_DAEMON_DOCUMENT_ROOT_PATH" \
+ >&3 2>git_daemon_output &
+ GIT_DAEMON_PID=$!
+ {
+ read line <&7
+ echo >&4 "$line"
+ cat <&7 >&4 &
+ } 7<git_daemon_output &&
+
+ # Check expected output
+ if test x"$(expr "$line" : "\[[0-9]*\] \(.*\)")" != x"Ready to rumble"
+ then
+ kill "$GIT_DAEMON_PID"
+ wait "$GIT_DAEMON_PID"
+ trap 'die' EXIT
+ error "git daemon failed to start"
+ fi
+}
+
+stop_git_daemon() {
+ if test -z "$GIT_DAEMON_PID"
+ then
+ return
+ fi
+
+ trap 'die' EXIT
+
+ # kill git-daemon child of git
+ say >&3 "Stopping git daemon ..."
+ kill "$GIT_DAEMON_PID"
+ wait "$GIT_DAEMON_PID" >&3 2>&4
+ ret=$?
+ # expect exit with status 143 = 128+15 for signal TERM=15
+ if test $ret -ne 143
+ then
+ error "git daemon exited with status: $ret"
+ fi
+ GIT_DAEMON_PID=
+ rm -f git_daemon_output
+}
diff --git a/t/lib-httpd.sh b/t/lib-httpd.sh
index f7dc0781d5..094d490893 100644
--- a/t/lib-httpd.sh
+++ b/t/lib-httpd.sh
@@ -160,6 +160,6 @@ test_http_push_nonff() {
'
test_expect_success 'non-fast-forward push shows help message' '
- test_i18ngrep "To prevent you from losing history, non-fast-forward updates were rejected" output
+ test_i18ngrep "Updates were rejected because" output
'
}
diff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf
index 3c12b05d60..de3762e247 100644
--- a/t/lib-httpd/apache.conf
+++ b/t/lib-httpd/apache.conf
@@ -52,8 +52,15 @@ Alias /auth/ www/auth/
<Location /smart_noexport/>
SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH}
</Location>
+<Location /smart_custom_env/>
+ SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH}
+ SetEnv GIT_HTTP_EXPORT_ALL
+ SetEnv GIT_COMMITTER_NAME "Custom User"
+ SetEnv GIT_COMMITTER_EMAIL custom@example.com
+</Location>
ScriptAlias /smart/ ${GIT_EXEC_PATH}/git-http-backend/
ScriptAlias /smart_noexport/ ${GIT_EXEC_PATH}/git-http-backend/
+ScriptAlias /smart_custom_env/ ${GIT_EXEC_PATH}/git-http-backend/
<Directory ${GIT_EXEC_PATH}>
Options None
</Directory>
diff --git a/t/perf/.gitignore b/t/perf/.gitignore
new file mode 100644
index 0000000000..50f5cc1ed9
--- /dev/null
+++ b/t/perf/.gitignore
@@ -0,0 +1,2 @@
+build/
+test-results/
diff --git a/t/perf/Makefile b/t/perf/Makefile
new file mode 100644
index 0000000000..8c47155a7c
--- /dev/null
+++ b/t/perf/Makefile
@@ -0,0 +1,15 @@
+-include ../../config.mak
+export GIT_TEST_OPTIONS
+
+all: perf
+
+perf: pre-clean
+ ./run
+
+pre-clean:
+ rm -rf test-results
+
+clean:
+ rm -rf build "trash directory".* test-results
+
+.PHONY: all perf pre-clean clean
diff --git a/t/perf/README b/t/perf/README
new file mode 100644
index 0000000000..b2dbad4d50
--- /dev/null
+++ b/t/perf/README
@@ -0,0 +1,146 @@
+Git performance tests
+=====================
+
+This directory holds performance testing scripts for git tools. The
+first part of this document describes the various ways in which you
+can run them.
+
+When fixing the tools or adding enhancements, you are strongly
+encouraged to add tests in this directory to cover what you are
+trying to fix or enhance. The later part of this short document
+describes how your test scripts should be organized.
+
+
+Running Tests
+-------------
+
+The easiest way to run tests is to say "make". This runs all
+the tests on the current git repository.
+
+ === Running 2 tests in this tree ===
+ [...]
+ Test this tree
+ ---------------------------------------------------------
+ 0001.1: rev-list --all 0.54(0.51+0.02)
+ 0001.2: rev-list --all --objects 6.14(5.99+0.11)
+ 7810.1: grep worktree, cheap regex 0.16(0.16+0.35)
+ 7810.2: grep worktree, expensive regex 7.90(29.75+0.37)
+ 7810.3: grep --cached, cheap regex 3.07(3.02+0.25)
+ 7810.4: grep --cached, expensive regex 9.39(30.57+0.24)
+
+You can compare multiple repositories and even git revisions with the
+'run' script:
+
+ $ ./run . origin/next /path/to/git-tree p0001-rev-list.sh
+
+where . stands for the current git tree. The full invocation is
+
+ ./run [<revision|directory>...] [--] [<test-script>...]
+
+A '.' argument is implied if you do not pass any other
+revisions/directories.
+
+You can also manually test this or another git build tree, and then
+call the aggregation script to summarize the results:
+
+ $ ./p0001-rev-list.sh
+ [...]
+ $ GIT_BUILD_DIR=/path/to/other/git ./p0001-rev-list.sh
+ [...]
+ $ ./aggregate.perl . /path/to/other/git ./p0001-rev-list.sh
+
+aggregate.perl has the same invocation as 'run', it just does not run
+anything beforehand.
+
+You can set the following variables (also in your config.mak):
+
+ GIT_PERF_REPEAT_COUNT
+ Number of times a test should be repeated for best-of-N
+ measurements. Defaults to 5.
+
+ GIT_PERF_MAKE_OPTS
+ Options to use when automatically building a git tree for
+ performance testing. E.g., -j6 would be useful.
+
+ GIT_PERF_REPO
+ GIT_PERF_LARGE_REPO
+ Repositories to copy for the performance tests. The normal
+ repo should be at least git.git size. The large repo should
+ probably be about linux-2.6.git size for optimal results.
+ Both default to the git.git you are running from.
+
+You can also pass the options taken by ordinary git tests; the most
+useful one is:
+
+--root=<directory>::
+ Create "trash" directories used to store all temporary data during
+ testing under <directory>, instead of the t/ directory.
+ Using this option with a RAM-based filesystem (such as tmpfs)
+ can massively speed up the test suite.
+
+
+Naming Tests
+------------
+
+The performance test files are named as:
+
+ pNNNN-commandname-details.sh
+
+where N is a decimal digit. The same conventions for choosing NNNN as
+for normal tests apply.
+
+
+Writing Tests
+-------------
+
+The perf script starts much like a normal test script, except it
+sources perf-lib.sh:
+
+ #!/bin/sh
+ #
+ # Copyright (c) 2005 Junio C Hamano
+ #
+
+ test_description='xxx performance test'
+ . ./perf-lib.sh
+
+After that you will want to use some of the following:
+
+ test_perf_default_repo # sets up a "normal" repository
+ test_perf_large_repo # sets up a "large" repository
+
+ test_perf_default_repo sub # ditto, in a subdir "sub"
+
+ test_checkout_worktree # if you need the worktree too
+
+At least one of the first two is required!
+
+You can use test_expect_success as usual. For actual performance
+tests, use
+
+ test_perf 'descriptive string' '
+ command1 &&
+ command2
+ '
+
+test_perf spawns a subshell, for lack of better options. This means
+that
+
+* you _must_ export all variables that you need in the subshell
+
+* you _must_ flag all variables that you want to persist from the
+ subshell with 'test_export':
+
+ test_perf 'descriptive string' '
+ foo=$(git rev-parse HEAD) &&
+ test_export foo
+ '
+
+ The so-exported variables are automatically marked for export in the
+ shell executing the perf test. For your convenience, test_export is
+ the same as export in the main shell.
+
+ This feature relies on a bit of magic using 'set' and 'source'.
+ While we have tried to make sure that it can cope with embedded
+ whitespace and other special characters, it will not work with
+ multi-line data.
diff --git a/t/perf/aggregate.perl b/t/perf/aggregate.perl
new file mode 100755
index 0000000000..15f7fc1b80
--- /dev/null
+++ b/t/perf/aggregate.perl
@@ -0,0 +1,166 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+use Git;
+
+sub get_times {
+ my $name = shift;
+ open my $fh, "<", $name or return undef;
+ my $line = <$fh>;
+ return undef if not defined $line;
+ close $fh or die "cannot close $name: $!";
+ $line =~ /^(?:(\d+):)?(\d+):(\d+(?:\.\d+)?) (\d+(?:\.\d+)?) (\d+(?:\.\d+)?)$/
+ or die "bad input line: $line";
+ my $rt = ((defined $1 ? $1 : 0.0)*60+$2)*60+$3;
+ return ($rt, $4, $5);
+}
+
+sub format_times {
+ my ($r, $u, $s, $firstr) = @_;
+ if (!defined $r) {
+ return "<missing>";
+ }
+ my $out = sprintf "%.2f(%.2f+%.2f)", $r, $u, $s;
+ if (defined $firstr) {
+ if ($firstr > 0) {
+ $out .= sprintf " %+.1f%%", 100.0*($r-$firstr)/$firstr;
+ } elsif ($r == 0) {
+ $out .= " =";
+ } else {
+ $out .= " +inf";
+ }
+ }
+ return $out;
+}
+
+my (@dirs, %dirnames, %dirabbrevs, %prefixes, @tests);
+while (scalar @ARGV) {
+ my $arg = $ARGV[0];
+ my $dir;
+ last if -f $arg or $arg eq "--";
+ if (! -d $arg) {
+ my $rev = Git::command_oneline(qw(rev-parse --verify), $arg);
+ $dir = "build/".$rev;
+ } else {
+ $arg =~ s{/*$}{};
+ $dir = $arg;
+ $dirabbrevs{$dir} = $dir;
+ }
+ push @dirs, $dir;
+ $dirnames{$dir} = $arg;
+ my $prefix = $dir;
+ $prefix =~ tr/^a-zA-Z0-9/_/c;
+ $prefixes{$dir} = $prefix . '.';
+ shift @ARGV;
+}
+
+if (not @dirs) {
+ @dirs = ('.');
+}
+$dirnames{'.'} = $dirabbrevs{'.'} = "this tree";
+$prefixes{'.'} = '';
+
+shift @ARGV if scalar @ARGV and $ARGV[0] eq "--";
+
+@tests = @ARGV;
+if (not @tests) {
+ @tests = glob "p????-*.sh";
+}
+
+my @subtests;
+my %shorttests;
+for my $t (@tests) {
+ $t =~ s{(?:.*/)?(p(\d+)-[^/]+)\.sh$}{$1} or die "bad test name: $t";
+ my $n = $2;
+ my $fname = "test-results/$t.subtests";
+ open my $fp, "<", $fname or die "cannot open $fname: $!";
+ for (<$fp>) {
+ chomp;
+ /^(\d+)$/ or die "malformed subtest line: $_";
+ push @subtests, "$t.$1";
+ $shorttests{"$t.$1"} = "$n.$1";
+ }
+ close $fp or die "cannot close $fname: $!";
+}
+
+sub read_descr {
+ my $name = shift;
+ open my $fh, "<", $name or return "<error reading description>";
+ my $line = <$fh>;
+ close $fh or die "cannot close $name";
+ chomp $line;
+ return $line;
+}
+
+my %descrs;
+my $descrlen = 4; # "Test"
+for my $t (@subtests) {
+ $descrs{$t} = $shorttests{$t}.": ".read_descr("test-results/$t.descr");
+ $descrlen = length $descrs{$t} if length $descrs{$t}>$descrlen;
+}
+
+sub have_duplicate {
+ my %seen;
+ for (@_) {
+ return 1 if exists $seen{$_};
+ $seen{$_} = 1;
+ }
+ return 0;
+}
+sub have_slash {
+ for (@_) {
+ return 1 if m{/};
+ }
+ return 0;
+}
+
+my %newdirabbrevs = %dirabbrevs;
+while (!have_duplicate(values %newdirabbrevs)) {
+ %dirabbrevs = %newdirabbrevs;
+ last if !have_slash(values %dirabbrevs);
+ %newdirabbrevs = %dirabbrevs;
+ for (values %newdirabbrevs) {
+ s{^[^/]*/}{};
+ }
+}
+
+my %times;
+my @colwidth = ((0)x@dirs);
+for my $i (0..$#dirs) {
+ my $d = $dirs[$i];
+ my $w = length (exists $dirabbrevs{$d} ? $dirabbrevs{$d} : $dirnames{$d});
+ $colwidth[$i] = $w if $w > $colwidth[$i];
+}
+for my $t (@subtests) {
+ my $firstr;
+ for my $i (0..$#dirs) {
+ my $d = $dirs[$i];
+ $times{$prefixes{$d}.$t} = [get_times("test-results/$prefixes{$d}$t.times")];
+ my ($r,$u,$s) = @{$times{$prefixes{$d}.$t}};
+ my $w = length format_times($r,$u,$s,$firstr);
+ $colwidth[$i] = $w if $w > $colwidth[$i];
+ $firstr = $r unless defined $firstr;
+ }
+}
+my $totalwidth = 3*@dirs+$descrlen;
+$totalwidth += $_ for (@colwidth);
+
+printf "%-${descrlen}s", "Test";
+for my $i (0..$#dirs) {
+ my $d = $dirs[$i];
+ printf " %-$colwidth[$i]s", (exists $dirabbrevs{$d} ? $dirabbrevs{$d} : $dirnames{$d});
+}
+print "\n";
+print "-"x$totalwidth, "\n";
+for my $t (@subtests) {
+ printf "%-${descrlen}s", $descrs{$t};
+ my $firstr;
+ for my $i (0..$#dirs) {
+ my $d = $dirs[$i];
+ my ($r,$u,$s) = @{$times{$prefixes{$d}.$t}};
+ printf " %-$colwidth[$i]s", format_times($r,$u,$s,$firstr);
+ $firstr = $r unless defined $firstr;
+ }
+ print "\n";
+}
diff --git a/t/perf/min_time.perl b/t/perf/min_time.perl
new file mode 100755
index 0000000000..c1a2717e07
--- /dev/null
+++ b/t/perf/min_time.perl
@@ -0,0 +1,21 @@
+#!/usr/bin/perl
+
+my $minrt = 1e100;
+my $min;
+
+while (<>) {
+ # [h:]m:s.xx U.xx S.xx
+ /^(?:(\d+):)?(\d+):(\d+(?:\.\d+)?) (\d+(?:\.\d+)?) (\d+(?:\.\d+)?)$/
+ or die "bad input line: $_";
+ my $rt = ((defined $1 ? $1 : 0.0)*60+$2)*60+$3;
+ if ($rt < $minrt) {
+ $min = $_;
+ $minrt = $rt;
+ }
+}
+
+if (!defined $min) {
+ die "no input found";
+}
+
+print $min;
diff --git a/t/perf/p0000-perf-lib-sanity.sh b/t/perf/p0000-perf-lib-sanity.sh
new file mode 100755
index 0000000000..cf8e1efce7
--- /dev/null
+++ b/t/perf/p0000-perf-lib-sanity.sh
@@ -0,0 +1,55 @@
+#!/bin/sh
+
+test_description='Tests whether perf-lib facilities work'
+. ./perf-lib.sh
+
+test_perf_default_repo
+
+test_perf 'test_perf_default_repo works' '
+ foo=$(git rev-parse HEAD) &&
+ test_export foo
+'
+
+test_checkout_worktree
+
+test_perf 'test_checkout_worktree works' '
+ wt=$(find . | wc -l) &&
+ idx=$(git ls-files | wc -l) &&
+ test $wt -gt $idx
+'
+
+baz=baz
+test_export baz
+
+test_expect_success 'test_export works' '
+ echo "$foo" &&
+ test "$foo" = "$(git rev-parse HEAD)" &&
+ echo "$baz" &&
+ test "$baz" = baz
+'
+
+test_perf 'export a weird var' '
+ bar="weird # variable" &&
+ test_export bar
+'
+
+test_expect_success 'test_export works with weird vars' '
+ echo "$bar" &&
+ test "$bar" = "weird # variable"
+'
+
+test_perf 'important variables available in subshells' '
+ test -n "$HOME" &&
+ test -n "$TEST_DIRECTORY" &&
+ test -n "$TRASH_DIRECTORY" &&
+ test -n "$GIT_BUILD_DIR"
+'
+
+test_perf 'test-lib-functions correctly loaded in subshells' '
+ : >a &&
+ test_path_is_file a &&
+ : >b &&
+ test_cmp a b
+'
+
+test_done
diff --git a/t/perf/p0001-rev-list.sh b/t/perf/p0001-rev-list.sh
new file mode 100755
index 0000000000..4f71a63b0a
--- /dev/null
+++ b/t/perf/p0001-rev-list.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+test_description="Tests history walking performance"
+
+. ./perf-lib.sh
+
+test_perf_default_repo
+
+test_perf 'rev-list --all' '
+ git rev-list --all >/dev/null
+'
+
+test_perf 'rev-list --all --objects' '
+ git rev-list --all --objects >/dev/null
+'
+
+test_done
diff --git a/t/perf/p4000-diff-algorithms.sh b/t/perf/p4000-diff-algorithms.sh
new file mode 100755
index 0000000000..7e00c9da47
--- /dev/null
+++ b/t/perf/p4000-diff-algorithms.sh
@@ -0,0 +1,29 @@
+#!/bin/sh
+
+test_description="Tests diff generation performance"
+
+. ./perf-lib.sh
+
+test_perf_default_repo
+
+test_perf 'log -3000 (baseline)' '
+ git log -3000 >/dev/null
+'
+
+test_perf 'log --raw -3000 (tree-only)' '
+ git log --raw -3000 >/dev/null
+'
+
+test_perf 'log -p -3000 (Myers)' '
+ git log -p -3000 >/dev/null
+'
+
+test_perf 'log -p -3000 --histogram' '
+ git log -p -3000 --histogram >/dev/null
+'
+
+test_perf 'log -p -3000 --patience' '
+ git log -p -3000 --patience >/dev/null
+'
+
+test_done
diff --git a/t/perf/p7810-grep.sh b/t/perf/p7810-grep.sh
new file mode 100755
index 0000000000..9f4ade639f
--- /dev/null
+++ b/t/perf/p7810-grep.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+test_description="git-grep performance in various modes"
+
+. ./perf-lib.sh
+
+test_perf_large_repo
+test_checkout_worktree
+
+test_perf 'grep worktree, cheap regex' '
+ git grep some_nonexistent_string || :
+'
+test_perf 'grep worktree, expensive regex' '
+ git grep "^.* *some_nonexistent_string$" || :
+'
+test_perf 'grep --cached, cheap regex' '
+ git grep --cached some_nonexistent_string || :
+'
+test_perf 'grep --cached, expensive regex' '
+ git grep --cached "^.* *some_nonexistent_string$" || :
+'
+
+test_done
diff --git a/t/perf/perf-lib.sh b/t/perf/perf-lib.sh
new file mode 100644
index 0000000000..5580c22812
--- /dev/null
+++ b/t/perf/perf-lib.sh
@@ -0,0 +1,202 @@
+#!/bin/sh
+#
+# Copyright (c) 2011 Thomas Rast
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see http://www.gnu.org/licenses/ .
+
+# do the --tee work early; it otherwise confuses our careful
+# GIT_BUILD_DIR mangling
+case "$GIT_TEST_TEE_STARTED, $* " in
+done,*)
+ # do not redirect again
+ ;;
+*' --tee '*|*' --va'*)
+ mkdir -p test-results
+ BASE=test-results/$(basename "$0" .sh)
+ (GIT_TEST_TEE_STARTED=done ${SHELL-sh} "$0" "$@" 2>&1;
+ echo $? > $BASE.exit) | tee $BASE.out
+ test "$(cat $BASE.exit)" = 0
+ exit
+ ;;
+esac
+
+TEST_DIRECTORY=$(pwd)/..
+TEST_OUTPUT_DIRECTORY=$(pwd)
+if test -z "$GIT_TEST_INSTALLED"; then
+ perf_results_prefix=
+else
+ perf_results_prefix=$(printf "%s" "${GIT_TEST_INSTALLED%/bin-wrappers}" | tr -c "[a-zA-Z0-9]" "[_*]")"."
+ # make the tested dir absolute
+ GIT_TEST_INSTALLED=$(cd "$GIT_TEST_INSTALLED" && pwd)
+fi
+
+TEST_NO_CREATE_REPO=t
+
+. ../test-lib.sh
+
+# Variables from test-lib that are normally internal to the tests; we
+# need to export them for test_perf subshells
+export TEST_DIRECTORY TRASH_DIRECTORY GIT_BUILD_DIR GIT_TEST_CMP
+
+perf_results_dir=$TEST_OUTPUT_DIRECTORY/test-results
+mkdir -p "$perf_results_dir"
+rm -f "$perf_results_dir"/$(basename "$0" .sh).subtests
+
+if test -z "$GIT_PERF_REPEAT_COUNT"; then
+ GIT_PERF_REPEAT_COUNT=3
+fi
+die_if_build_dir_not_repo () {
+ if ! ( cd "$TEST_DIRECTORY/.." &&
+ git rev-parse --build-dir >/dev/null 2>&1 ); then
+ error "No $1 defined, and your build directory is not a repo"
+ fi
+}
+
+if test -z "$GIT_PERF_REPO"; then
+ die_if_build_dir_not_repo '$GIT_PERF_REPO'
+ GIT_PERF_REPO=$TEST_DIRECTORY/..
+fi
+if test -z "$GIT_PERF_LARGE_REPO"; then
+ die_if_build_dir_not_repo '$GIT_PERF_LARGE_REPO'
+ GIT_PERF_LARGE_REPO=$TEST_DIRECTORY/..
+fi
+
+test_perf_create_repo_from () {
+ test "$#" = 2 ||
+ error "bug in the test script: not 2 parameters to test-create-repo"
+ repo="$1"
+ source="$2"
+ source_git=$source/$(cd "$source" && git rev-parse --git-dir)
+ mkdir -p "$repo/.git"
+ (
+ cd "$repo/.git" &&
+ { cp -Rl "$source_git/objects" . 2>/dev/null ||
+ cp -R "$source_git/objects" .; } &&
+ for stuff in "$source_git"/*; do
+ case "$stuff" in
+ */objects|*/hooks|*/config)
+ ;;
+ *)
+ cp -R "$stuff" . || break
+ ;;
+ esac
+ done &&
+ cd .. &&
+ git init -q &&
+ mv .git/hooks .git/hooks-disabled 2>/dev/null
+ ) || error "failed to copy repository '$source' to '$repo'"
+}
+
+# call at least one of these to establish an appropriately-sized repository
+test_perf_default_repo () {
+ test_perf_create_repo_from "${1:-$TRASH_DIRECTORY}" "$GIT_PERF_REPO"
+}
+test_perf_large_repo () {
+ if test "$GIT_PERF_LARGE_REPO" = "$GIT_BUILD_DIR"; then
+ echo "warning: \$GIT_PERF_LARGE_REPO is \$GIT_BUILD_DIR." >&2
+ echo "warning: This will work, but may not be a sufficiently large repo" >&2
+ echo "warning: for representative measurements." >&2
+ fi
+ test_perf_create_repo_from "${1:-$TRASH_DIRECTORY}" "$GIT_PERF_LARGE_REPO"
+}
+test_checkout_worktree () {
+ git checkout-index -u -a ||
+ error "git checkout-index failed"
+}
+
+# Performance tests should never fail. If they do, stop immediately
+immediate=t
+
+test_run_perf_ () {
+ test_cleanup=:
+ test_export_="test_cleanup"
+ export test_cleanup test_export_
+ /usr/bin/time -f "%E %U %S" -o test_time.$i "$SHELL" -c '
+. '"$TEST_DIRECTORY"/test-lib-functions.sh'
+test_export () {
+ [ $# != 0 ] || return 0
+ test_export_="$test_export_\\|$1"
+ shift
+ test_export "$@"
+}
+'"$1"'
+ret=$?
+set | sed -n "s'"/'/'\\\\''/g"';s/^\\($test_export_\\)/export '"'&'"'/p" >test_vars
+exit $ret' >&3 2>&4
+ eval_ret=$?
+
+ if test $eval_ret = 0 || test -n "$expecting_failure"
+ then
+ test_eval_ "$test_cleanup"
+ . ./test_vars || error "failed to load updated environment"
+ fi
+ if test "$verbose" = "t" && test -n "$HARNESS_ACTIVE"; then
+ echo ""
+ fi
+ return "$eval_ret"
+}
+
+
+test_perf () {
+ test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq=
+ test "$#" = 2 ||
+ error "bug in the test script: not 2 or 3 parameters to test-expect-success"
+ export test_prereq
+ if ! test_skip "$@"
+ then
+ base=$(basename "$0" .sh)
+ echo "$test_count" >>"$perf_results_dir"/$base.subtests
+ echo "$1" >"$perf_results_dir"/$base.$test_count.descr
+ if test -z "$verbose"; then
+ echo -n "perf $test_count - $1:"
+ else
+ echo "perf $test_count - $1:"
+ fi
+ for i in $(seq 1 $GIT_PERF_REPEAT_COUNT); do
+ say >&3 "running: $2"
+ if test_run_perf_ "$2"
+ then
+ if test -z "$verbose"; then
+ echo -n " $i"
+ else
+ echo "* timing run $i/$GIT_PERF_REPEAT_COUNT:"
+ fi
+ else
+ test -z "$verbose" && echo
+ test_failure_ "$@"
+ break
+ fi
+ done
+ if test -z "$verbose"; then
+ echo " ok"
+ else
+ test_ok_ "$1"
+ fi
+ base="$perf_results_dir"/"$perf_results_prefix$(basename "$0" .sh)"."$test_count"
+ "$TEST_DIRECTORY"/perf/min_time.perl test_time.* >"$base".times
+ fi
+ echo >&3 ""
+}
+
+# We extend test_done to print timings at the end (./run disables this
+# and does it after running everything)
+test_at_end_hook_ () {
+ if test -z "$GIT_PERF_AGGREGATING_LATER"; then
+ ( cd "$TEST_DIRECTORY"/perf && ./aggregate.perl $(basename "$0") )
+ fi
+}
+
+test_export () {
+ export "$@"
+}
diff --git a/t/perf/run b/t/perf/run
new file mode 100755
index 0000000000..cfd70129bb
--- /dev/null
+++ b/t/perf/run
@@ -0,0 +1,82 @@
+#!/bin/sh
+
+case "$1" in
+ --help)
+ echo "usage: $0 [other_git_tree...] [--] [test_scripts]"
+ exit 0
+ ;;
+esac
+
+die () {
+ echo >&2 "error: $*"
+ exit 1
+}
+
+run_one_dir () {
+ if test $# -eq 0; then
+ set -- p????-*.sh
+ fi
+ echo "=== Running $# tests in ${GIT_TEST_INSTALLED:-this tree} ==="
+ for t in "$@"; do
+ ./$t $GIT_TEST_OPTS
+ done
+}
+
+unpack_git_rev () {
+ rev=$1
+ mkdir -p build/$rev
+ (cd "$(git rev-parse --show-cdup)" && git archive --format=tar $rev) |
+ (cd build/$rev && tar x)
+}
+build_git_rev () {
+ rev=$1
+ cp ../../config.mak build/$rev/config.mak
+ (cd build/$rev && make $GIT_PERF_MAKE_OPTS) ||
+ die "failed to build revision '$mydir'"
+}
+
+run_dirs_helper () {
+ mydir=${1%/}
+ shift
+ while test $# -gt 0 -a "$1" != -- -a ! -f "$1"; do
+ shift
+ done
+ if test $# -gt 0 -a "$1" = --; then
+ shift
+ fi
+ if [ ! -d "$mydir" ]; then
+ rev=$(git rev-parse --verify "$mydir" 2>/dev/null) ||
+ die "'$mydir' is neither a directory nor a valid revision"
+ if [ ! -d build/$rev ]; then
+ unpack_git_rev $rev
+ fi
+ build_git_rev $rev
+ mydir=build/$rev
+ fi
+ if test "$mydir" = .; then
+ unset GIT_TEST_INSTALLED
+ else
+ GIT_TEST_INSTALLED="$mydir/bin-wrappers"
+ export GIT_TEST_INSTALLED
+ fi
+ run_one_dir "$@"
+}
+
+run_dirs () {
+ while test $# -gt 0 -a "$1" != -- -a ! -f "$1"; do
+ run_dirs_helper "$@"
+ shift
+ done
+}
+
+GIT_PERF_AGGREGATING_LATER=t
+export GIT_PERF_AGGREGATING_LATER
+
+cd "$(dirname $0)"
+. ../../GIT-BUILD-OPTIONS
+
+if test $# = 0 -o "$1" = -- -o -f "$1"; then
+ set -- . "$@"
+fi
+run_dirs "$@"
+./aggregate.perl "$@"
diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh
index f4e8f43bae..ccb5435b2a 100755
--- a/t/t0000-basic.sh
+++ b/t/t0000-basic.sh
@@ -34,69 +34,69 @@ fi
# git init has been done in an empty repository.
# make sure it is empty.
-find .git/objects -type f -print >should-be-empty
-test_expect_success \
- '.git/objects should be empty after git init in an empty repo.' \
- 'cmp -s /dev/null should-be-empty'
+test_expect_success '.git/objects should be empty after git init in an empty repo' '
+ find .git/objects -type f -print >should-be-empty &&
+ test_line_count = 0 should-be-empty
+'
# also it should have 2 subdirectories; no fan-out anymore, pack, and info.
# 3 is counting "objects" itself
-find .git/objects -type d -print >full-of-directories
-test_expect_success \
- '.git/objects should have 3 subdirectories.' \
- 'test $(wc -l < full-of-directories) = 3'
+test_expect_success '.git/objects should have 3 subdirectories' '
+ find .git/objects -type d -print >full-of-directories &&
+ test_line_count = 3 full-of-directories
+'
################################################################
# Test harness
test_expect_success 'success is reported like this' '
- :
+ :
'
test_expect_failure 'pretend we have a known breakage' '
- false
+ false
'
test_expect_success 'pretend we have fixed a known breakage (run in sub test-lib)' "
- mkdir passing-todo &&
- (cd passing-todo &&
- cat >passing-todo.sh <<EOF &&
-#!$SHELL_PATH
-
-test_description='A passing TODO test
-
-This is run in a sub test-lib so that we do not get incorrect passing
-metrics
-'
-
-# Point to the t/test-lib.sh, which isn't in ../ as usual
-TEST_DIRECTORY=\"$TEST_DIRECTORY\"
-. \"\$TEST_DIRECTORY\"/test-lib.sh
-
-test_expect_failure 'pretend we have fixed a known breakage' '
- :
-'
-
-test_done
-EOF
- chmod +x passing-todo.sh &&
- ./passing-todo.sh >out 2>err &&
- ! test -s err &&
-sed -e 's/^> //' >expect <<EOF &&
-> ok 1 - pretend we have fixed a known breakage # TODO known breakage
-> # fixed 1 known breakage(s)
-> # passed all 1 test(s)
-> 1..1
-EOF
- test_cmp expect out)
+ mkdir passing-todo &&
+ (cd passing-todo &&
+ cat >passing-todo.sh <<-EOF &&
+ #!$SHELL_PATH
+
+ test_description='A passing TODO test
+
+ This is run in a sub test-lib so that we do not get incorrect
+ passing metrics
+ '
+
+ # Point to the t/test-lib.sh, which isn't in ../ as usual
+ TEST_DIRECTORY=\"$TEST_DIRECTORY\"
+ . \"\$TEST_DIRECTORY\"/test-lib.sh
+
+ test_expect_failure 'pretend we have fixed a known breakage' '
+ :
+ '
+
+ test_done
+ EOF
+ chmod +x passing-todo.sh &&
+ ./passing-todo.sh >out 2>err &&
+ ! test -s err &&
+ sed -e 's/^> //' >expect <<-\\EOF &&
+ > ok 1 - pretend we have fixed a known breakage # TODO known breakage
+ > # fixed 1 known breakage(s)
+ > # passed all 1 test(s)
+ > 1..1
+ EOF
+ test_cmp expect out)
"
test_set_prereq HAVEIT
haveit=no
test_expect_success HAVEIT 'test runs if prerequisite is satisfied' '
- test_have_prereq HAVEIT &&
- haveit=yes
+ test_have_prereq HAVEIT &&
+ haveit=yes
'
donthaveit=yes
test_expect_success DONTHAVEIT 'unmet prerequisite causes test to be skipped' '
- donthaveit=no
+ donthaveit=no
'
if test $haveit$donthaveit != yesyes
then
@@ -107,17 +107,17 @@ fi
test_set_prereq HAVETHIS
haveit=no
test_expect_success HAVETHIS,HAVEIT 'test runs if prerequisites are satisfied' '
- test_have_prereq HAVEIT &&
- test_have_prereq HAVETHIS &&
- haveit=yes
+ test_have_prereq HAVEIT &&
+ test_have_prereq HAVETHIS &&
+ haveit=yes
'
donthaveit=yes
test_expect_success HAVEIT,DONTHAVEIT 'unmet prerequisites causes test to be skipped' '
- donthaveit=no
+ donthaveit=no
'
donthaveiteither=yes
test_expect_success DONTHAVEIT,HAVEIT 'unmet prerequisites causes test to be skipped' '
- donthaveiteither=no
+ donthaveiteither=no
'
if test $haveit$donthaveit$donthaveiteither != yesyesyes
then
@@ -127,7 +127,7 @@ fi
clean=no
test_expect_success 'tests clean up after themselves' '
- test_when_finished clean=yes
+ test_when_finished clean=yes
'
if test $clean != yes
@@ -137,106 +137,100 @@ then
fi
test_expect_success 'tests clean up even on failures' "
- mkdir failing-cleanup &&
- (cd failing-cleanup &&
- cat >failing-cleanup.sh <<EOF &&
-#!$SHELL_PATH
-
-test_description='Failing tests with cleanup commands'
-
-# Point to the t/test-lib.sh, which isn't in ../ as usual
-TEST_DIRECTORY=\"$TEST_DIRECTORY\"
-. \"\$TEST_DIRECTORY\"/test-lib.sh
-
-test_expect_success 'tests clean up even after a failure' '
- touch clean-after-failure &&
- test_when_finished rm clean-after-failure &&
- (exit 1)
-'
-
-test_expect_success 'failure to clean up causes the test to fail' '
- test_when_finished \"(exit 2)\"
-'
-
-test_done
-EOF
- chmod +x failing-cleanup.sh &&
- test_must_fail ./failing-cleanup.sh >out 2>err &&
- ! test -s err &&
- ! test -f \"trash directory.failing-cleanup/clean-after-failure\" &&
-sed -e 's/Z$//' -e 's/^> //' >expect <<\EOF &&
-> not ok - 1 tests clean up even after a failure
-> # Z
-> # touch clean-after-failure &&
-> # test_when_finished rm clean-after-failure &&
-> # (exit 1)
-> # Z
-> not ok - 2 failure to clean up causes the test to fail
-> # Z
-> # test_when_finished \"(exit 2)\"
-> # Z
-> # failed 2 among 2 test(s)
-> 1..2
-EOF
- test_cmp expect out)
+ mkdir failing-cleanup &&
+ (
+ cd failing-cleanup &&
+
+ cat >failing-cleanup.sh <<-EOF &&
+ #!$SHELL_PATH
+
+ test_description='Failing tests with cleanup commands'
+
+ # Point to the t/test-lib.sh, which isn't in ../ as usual
+ TEST_DIRECTORY=\"$TEST_DIRECTORY\"
+ . \"\$TEST_DIRECTORY\"/test-lib.sh
+
+ test_expect_success 'tests clean up even after a failure' '
+ touch clean-after-failure &&
+ test_when_finished rm clean-after-failure &&
+ (exit 1)
+ '
+ test_expect_success 'failure to clean up causes the test to fail' '
+ test_when_finished \"(exit 2)\"
+ '
+ test_done
+
+ EOF
+
+ chmod +x failing-cleanup.sh &&
+ test_must_fail ./failing-cleanup.sh >out 2>err &&
+ ! test -s err &&
+ ! test -f \"trash directory.failing-cleanup/clean-after-failure\" &&
+ sed -e 's/Z$//' -e 's/^> //' >expect <<-\\EOF &&
+ > not ok - 1 tests clean up even after a failure
+ > # Z
+ > # touch clean-after-failure &&
+ > # test_when_finished rm clean-after-failure &&
+ > # (exit 1)
+ > # Z
+ > not ok - 2 failure to clean up causes the test to fail
+ > # Z
+ > # test_when_finished \"(exit 2)\"
+ > # Z
+ > # failed 2 among 2 test(s)
+ > 1..2
+ EOF
+ test_cmp expect out
+ )
"
################################################################
# Basics of the basics
# updating a new file without --add should fail.
-test_expect_success 'git update-index without --add should fail adding.' '
- test_must_fail git update-index should-be-empty
+test_expect_success 'git update-index without --add should fail adding' '
+ test_must_fail git update-index should-be-empty
'
# and with --add it should succeed, even if it is empty (it used to fail).
-test_expect_success \
- 'git update-index with --add should succeed.' \
- 'git update-index --add should-be-empty'
+test_expect_success 'git update-index with --add should succeed' '
+ git update-index --add should-be-empty
+'
-test_expect_success \
- 'writing tree out with git write-tree' \
- 'tree=$(git write-tree)'
+test_expect_success 'writing tree out with git write-tree' '
+ tree=$(git write-tree)
+'
# we know the shape and contents of the tree and know the object ID for it.
-test_expect_success \
- 'validate object ID of a known tree.' \
- 'test "$tree" = 7bb943559a305bdd6bdee2cef6e5df2413c3d30a'
+test_expect_success 'validate object ID of a known tree' '
+ test "$tree" = 7bb943559a305bdd6bdee2cef6e5df2413c3d30a
+ '
# Removing paths.
-rm -f should-be-empty full-of-directories
-test_expect_success 'git update-index without --remove should fail removing.' '
- test_must_fail git update-index should-be-empty
+test_expect_success 'git update-index without --remove should fail removing' '
+ rm -f should-be-empty full-of-directories &&
+ test_must_fail git update-index should-be-empty
'
-test_expect_success \
- 'git update-index with --remove should be able to remove.' \
- 'git update-index --remove should-be-empty'
+test_expect_success 'git update-index with --remove should be able to remove' '
+ git update-index --remove should-be-empty
+'
# Empty tree can be written with recent write-tree.
-test_expect_success \
- 'git write-tree should be able to write an empty tree.' \
- 'tree=$(git write-tree)'
+test_expect_success 'git write-tree should be able to write an empty tree' '
+ tree=$(git write-tree)
+'
-test_expect_success \
- 'validate object ID of a known tree.' \
- 'test "$tree" = 4b825dc642cb6eb9a060e54bf8d69288fbee4904'
+test_expect_success 'validate object ID of a known tree' '
+ test "$tree" = 4b825dc642cb6eb9a060e54bf8d69288fbee4904
+'
# Various types of objects
+
# Some filesystems do not support symblic links; on such systems
# some expected values are different
-mkdir path2 path3 path3/subp3
-paths='path0 path2/file2 path3/file3 path3/subp3/file3'
-for p in $paths
-do
- echo "hello $p" >$p
-done
if test_have_prereq SYMLINKS
then
- for p in $paths
- do
- ln -s "hello $p" ${p}sym
- done
expectfilter=cat
expectedtree=087704a96baf1c2d1c869a8b084481e121c88b5b
expectedptree1=21ae8269cacbe57ae09138dcc3a2887f904d02b3
@@ -248,135 +242,154 @@ else
expectedptree2=ce580448f0148b985a513b693fdf7d802cacb44f
fi
-test_expect_success \
- 'adding various types of objects with git update-index --add.' \
- 'find path* ! -type d -print | xargs git update-index --add'
+
+test_expect_success 'adding various types of objects with git update-index --add' '
+ mkdir path2 path3 path3/subp3 &&
+ paths="path0 path2/file2 path3/file3 path3/subp3/file3" &&
+ (
+ for p in $paths
+ do
+ echo "hello $p" >$p || exit 1
+ if test_have_prereq SYMLINKS
+ then
+ ln -s "hello $p" ${p}sym || exit 1
+ fi
+ done
+ ) &&
+ find path* ! -type d -print | xargs git update-index --add
+'
# Show them and see that matches what we expect.
-test_expect_success \
- 'showing stage with git ls-files --stage' \
- 'git ls-files --stage >current'
-
-$expectfilter >expected <<\EOF
-100644 f87290f8eb2cbbea7857214459a0739927eab154 0 path0
-120000 15a98433ae33114b085f3eb3bb03b832b3180a01 0 path0sym
-100644 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 0 path2/file2
-120000 d8ce161addc5173867a3c3c730924388daedbc38 0 path2/file2sym
-100644 0aa34cae68d0878578ad119c86ca2b5ed5b28376 0 path3/file3
-120000 8599103969b43aff7e430efea79ca4636466794f 0 path3/file3sym
-100644 00fb5908cb97c2564a9783c0c64087333b3b464f 0 path3/subp3/file3
-120000 6649a1ebe9e9f1c553b66f5a6e74136a07ccc57c 0 path3/subp3/file3sym
-EOF
-test_expect_success \
- 'validate git ls-files output for a known tree.' \
- 'test_cmp expected current'
-
-test_expect_success \
- 'writing tree out with git write-tree.' \
- 'tree=$(git write-tree)'
-test_expect_success \
- 'validate object ID for a known tree.' \
- 'test "$tree" = "$expectedtree"'
-
-test_expect_success \
- 'showing tree with git ls-tree' \
- 'git ls-tree $tree >current'
-cat >expected <<\EOF
-100644 blob f87290f8eb2cbbea7857214459a0739927eab154 path0
-120000 blob 15a98433ae33114b085f3eb3bb03b832b3180a01 path0sym
-040000 tree 58a09c23e2ca152193f2786e06986b7b6712bdbe path2
-040000 tree 21ae8269cacbe57ae09138dcc3a2887f904d02b3 path3
-EOF
-test_expect_success SYMLINKS \
- 'git ls-tree output for a known tree.' \
- 'test_cmp expected current'
+test_expect_success 'showing stage with git ls-files --stage' '
+ git ls-files --stage >current
+'
+
+test_expect_success 'validate git ls-files output for a known tree' '
+ $expectfilter >expected <<-\EOF &&
+ 100644 f87290f8eb2cbbea7857214459a0739927eab154 0 path0
+ 120000 15a98433ae33114b085f3eb3bb03b832b3180a01 0 path0sym
+ 100644 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 0 path2/file2
+ 120000 d8ce161addc5173867a3c3c730924388daedbc38 0 path2/file2sym
+ 100644 0aa34cae68d0878578ad119c86ca2b5ed5b28376 0 path3/file3
+ 120000 8599103969b43aff7e430efea79ca4636466794f 0 path3/file3sym
+ 100644 00fb5908cb97c2564a9783c0c64087333b3b464f 0 path3/subp3/file3
+ 120000 6649a1ebe9e9f1c553b66f5a6e74136a07ccc57c 0 path3/subp3/file3sym
+ EOF
+ test_cmp expected current
+'
+
+test_expect_success 'writing tree out with git write-tree' '
+ tree=$(git write-tree)
+'
+
+test_expect_success 'validate object ID for a known tree' '
+ test "$tree" = "$expectedtree"
+'
+
+test_expect_success 'showing tree with git ls-tree' '
+ git ls-tree $tree >current
+'
+
+test_expect_success SYMLINKS 'git ls-tree output for a known tree' '
+ cat >expected <<-\EOF &&
+ 100644 blob f87290f8eb2cbbea7857214459a0739927eab154 path0
+ 120000 blob 15a98433ae33114b085f3eb3bb03b832b3180a01 path0sym
+ 040000 tree 58a09c23e2ca152193f2786e06986b7b6712bdbe path2
+ 040000 tree 21ae8269cacbe57ae09138dcc3a2887f904d02b3 path3
+ EOF
+ test_cmp expected current
+'
# This changed in ls-tree pathspec change -- recursive does
# not show tree nodes anymore.
-test_expect_success \
- 'showing tree with git ls-tree -r' \
- 'git ls-tree -r $tree >current'
-$expectfilter >expected <<\EOF
-100644 blob f87290f8eb2cbbea7857214459a0739927eab154 path0
-120000 blob 15a98433ae33114b085f3eb3bb03b832b3180a01 path0sym
-100644 blob 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 path2/file2
-120000 blob d8ce161addc5173867a3c3c730924388daedbc38 path2/file2sym
-100644 blob 0aa34cae68d0878578ad119c86ca2b5ed5b28376 path3/file3
-120000 blob 8599103969b43aff7e430efea79ca4636466794f path3/file3sym
-100644 blob 00fb5908cb97c2564a9783c0c64087333b3b464f path3/subp3/file3
-120000 blob 6649a1ebe9e9f1c553b66f5a6e74136a07ccc57c path3/subp3/file3sym
-EOF
-test_expect_success \
- 'git ls-tree -r output for a known tree.' \
- 'test_cmp expected current'
+test_expect_success 'showing tree with git ls-tree -r' '
+ git ls-tree -r $tree >current
+'
+
+test_expect_success 'git ls-tree -r output for a known tree' '
+ $expectfilter >expected <<-\EOF &&
+ 100644 blob f87290f8eb2cbbea7857214459a0739927eab154 path0
+ 120000 blob 15a98433ae33114b085f3eb3bb03b832b3180a01 path0sym
+ 100644 blob 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 path2/file2
+ 120000 blob d8ce161addc5173867a3c3c730924388daedbc38 path2/file2sym
+ 100644 blob 0aa34cae68d0878578ad119c86ca2b5ed5b28376 path3/file3
+ 120000 blob 8599103969b43aff7e430efea79ca4636466794f path3/file3sym
+ 100644 blob 00fb5908cb97c2564a9783c0c64087333b3b464f path3/subp3/file3
+ 120000 blob 6649a1ebe9e9f1c553b66f5a6e74136a07ccc57c path3/subp3/file3sym
+ EOF
+ test_cmp expected current
+'
# But with -r -t we can have both.
-test_expect_success \
- 'showing tree with git ls-tree -r -t' \
- 'git ls-tree -r -t $tree >current'
-cat >expected <<\EOF
-100644 blob f87290f8eb2cbbea7857214459a0739927eab154 path0
-120000 blob 15a98433ae33114b085f3eb3bb03b832b3180a01 path0sym
-040000 tree 58a09c23e2ca152193f2786e06986b7b6712bdbe path2
-100644 blob 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 path2/file2
-120000 blob d8ce161addc5173867a3c3c730924388daedbc38 path2/file2sym
-040000 tree 21ae8269cacbe57ae09138dcc3a2887f904d02b3 path3
-100644 blob 0aa34cae68d0878578ad119c86ca2b5ed5b28376 path3/file3
-120000 blob 8599103969b43aff7e430efea79ca4636466794f path3/file3sym
-040000 tree 3c5e5399f3a333eddecce7a9b9465b63f65f51e2 path3/subp3
-100644 blob 00fb5908cb97c2564a9783c0c64087333b3b464f path3/subp3/file3
-120000 blob 6649a1ebe9e9f1c553b66f5a6e74136a07ccc57c path3/subp3/file3sym
-EOF
-test_expect_success SYMLINKS \
- 'git ls-tree -r output for a known tree.' \
- 'test_cmp expected current'
-
-test_expect_success \
- 'writing partial tree out with git write-tree --prefix.' \
- 'ptree=$(git write-tree --prefix=path3)'
-test_expect_success \
- 'validate object ID for a known tree.' \
- 'test "$ptree" = "$expectedptree1"'
-
-test_expect_success \
- 'writing partial tree out with git write-tree --prefix.' \
- 'ptree=$(git write-tree --prefix=path3/subp3)'
-test_expect_success \
- 'validate object ID for a known tree.' \
- 'test "$ptree" = "$expectedptree2"'
-
-cat >badobjects <<EOF
-100644 blob 1000000000000000000000000000000000000000 dir/file1
-100644 blob 2000000000000000000000000000000000000000 dir/file2
-100644 blob 3000000000000000000000000000000000000000 dir/file3
-100644 blob 4000000000000000000000000000000000000000 dir/file4
-100644 blob 5000000000000000000000000000000000000000 dir/file5
-EOF
+test_expect_success 'showing tree with git ls-tree -r -t' '
+ git ls-tree -r -t $tree >current
+'
-rm .git/index
-test_expect_success \
- 'put invalid objects into the index.' \
- 'git update-index --index-info < badobjects'
+test_expect_success SYMLINKS 'git ls-tree -r output for a known tree' '
+ cat >expected <<-\EOF &&
+ 100644 blob f87290f8eb2cbbea7857214459a0739927eab154 path0
+ 120000 blob 15a98433ae33114b085f3eb3bb03b832b3180a01 path0sym
+ 040000 tree 58a09c23e2ca152193f2786e06986b7b6712bdbe path2
+ 100644 blob 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 path2/file2
+ 120000 blob d8ce161addc5173867a3c3c730924388daedbc38 path2/file2sym
+ 040000 tree 21ae8269cacbe57ae09138dcc3a2887f904d02b3 path3
+ 100644 blob 0aa34cae68d0878578ad119c86ca2b5ed5b28376 path3/file3
+ 120000 blob 8599103969b43aff7e430efea79ca4636466794f path3/file3sym
+ 040000 tree 3c5e5399f3a333eddecce7a9b9465b63f65f51e2 path3/subp3
+ 100644 blob 00fb5908cb97c2564a9783c0c64087333b3b464f path3/subp3/file3
+ 120000 blob 6649a1ebe9e9f1c553b66f5a6e74136a07ccc57c path3/subp3/file3sym
+ EOF
+ test_cmp expected current
+'
-test_expect_success 'writing this tree without --missing-ok.' '
- test_must_fail git write-tree
+test_expect_success 'writing partial tree out with git write-tree --prefix' '
+ ptree=$(git write-tree --prefix=path3)
'
-test_expect_success \
- 'writing this tree with --missing-ok.' \
- 'git write-tree --missing-ok'
+test_expect_success 'validate object ID for a known tree' '
+ test "$ptree" = "$expectedptree1"
+'
+
+test_expect_success 'writing partial tree out with git write-tree --prefix' '
+ ptree=$(git write-tree --prefix=path3/subp3)
+'
+
+test_expect_success 'validate object ID for a known tree' '
+ test "$ptree" = "$expectedptree2"
+'
+
+test_expect_success 'put invalid objects into the index' '
+ rm -f .git/index &&
+ cat >badobjects <<-\EOF &&
+ 100644 blob 1000000000000000000000000000000000000000 dir/file1
+ 100644 blob 2000000000000000000000000000000000000000 dir/file2
+ 100644 blob 3000000000000000000000000000000000000000 dir/file3
+ 100644 blob 4000000000000000000000000000000000000000 dir/file4
+ 100644 blob 5000000000000000000000000000000000000000 dir/file5
+ EOF
+ git update-index --index-info <badobjects
+'
+
+test_expect_success 'writing this tree without --missing-ok' '
+ test_must_fail git write-tree
+'
+
+test_expect_success 'writing this tree with --missing-ok' '
+ git write-tree --missing-ok
+'
################################################################
-rm .git/index
-test_expect_success \
- 'git read-tree followed by write-tree should be idempotent.' \
- 'git read-tree $tree &&
- test -f .git/index &&
- newtree=$(git write-tree) &&
- test "$newtree" = "$tree"'
-
-$expectfilter >expected <<\EOF
+test_expect_success 'git read-tree followed by write-tree should be idempotent' '
+ rm -f .git/index
+ git read-tree $tree &&
+ test -f .git/index &&
+ newtree=$(git write-tree) &&
+ test "$newtree" = "$tree"
+'
+
+test_expect_success 'validate git diff-files output for a know cache/work tree state' '
+ $expectfilter >expected <<\EOF &&
:100644 100644 f87290f8eb2cbbea7857214459a0739927eab154 0000000000000000000000000000000000000000 M path0
:120000 120000 15a98433ae33114b085f3eb3bb03b832b3180a01 0000000000000000000000000000000000000000 M path0sym
:100644 100644 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 0000000000000000000000000000000000000000 M path2/file2
@@ -386,45 +399,47 @@ $expectfilter >expected <<\EOF
:100644 100644 00fb5908cb97c2564a9783c0c64087333b3b464f 0000000000000000000000000000000000000000 M path3/subp3/file3
:120000 120000 6649a1ebe9e9f1c553b66f5a6e74136a07ccc57c 0000000000000000000000000000000000000000 M path3/subp3/file3sym
EOF
-test_expect_success \
- 'validate git diff-files output for a know cache/work tree state.' \
- 'git diff-files >current && test_cmp current expected >/dev/null'
+ git diff-files >current &&
+ test_cmp current expected
+'
-test_expect_success \
- 'git update-index --refresh should succeed.' \
- 'git update-index --refresh'
+test_expect_success 'git update-index --refresh should succeed' '
+ git update-index --refresh
+'
-test_expect_success \
- 'no diff after checkout and git update-index --refresh.' \
- 'git diff-files >current && cmp -s current /dev/null'
+test_expect_success 'no diff after checkout and git update-index --refresh' '
+ git diff-files >current &&
+ cmp -s current /dev/null
+'
################################################################
P=$expectedtree
-test_expect_success \
- 'git commit-tree records the correct tree in a commit.' \
- 'commit0=$(echo NO | git commit-tree $P) &&
- tree=$(git show --pretty=raw $commit0 |
- sed -n -e "s/^tree //p" -e "/^author /q") &&
- test "z$tree" = "z$P"'
-
-test_expect_success \
- 'git commit-tree records the correct parent in a commit.' \
- 'commit1=$(echo NO | git commit-tree $P -p $commit0) &&
- parent=$(git show --pretty=raw $commit1 |
- sed -n -e "s/^parent //p" -e "/^author /q") &&
- test "z$commit0" = "z$parent"'
-
-test_expect_success \
- 'git commit-tree omits duplicated parent in a commit.' \
- 'commit2=$(echo NO | git commit-tree $P -p $commit0 -p $commit0) &&
- parent=$(git show --pretty=raw $commit2 |
- sed -n -e "s/^parent //p" -e "/^author /q" |
- sort -u) &&
- test "z$commit0" = "z$parent" &&
- numparent=$(git show --pretty=raw $commit2 |
- sed -n -e "s/^parent //p" -e "/^author /q" |
- wc -l) &&
- test $numparent = 1'
+
+test_expect_success 'git commit-tree records the correct tree in a commit' '
+ commit0=$(echo NO | git commit-tree $P) &&
+ tree=$(git show --pretty=raw $commit0 |
+ sed -n -e "s/^tree //p" -e "/^author /q") &&
+ test "z$tree" = "z$P"
+'
+
+test_expect_success 'git commit-tree records the correct parent in a commit' '
+ commit1=$(echo NO | git commit-tree $P -p $commit0) &&
+ parent=$(git show --pretty=raw $commit1 |
+ sed -n -e "s/^parent //p" -e "/^author /q") &&
+ test "z$commit0" = "z$parent"
+'
+
+test_expect_success 'git commit-tree omits duplicated parent in a commit' '
+ commit2=$(echo NO | git commit-tree $P -p $commit0 -p $commit0) &&
+ parent=$(git show --pretty=raw $commit2 |
+ sed -n -e "s/^parent //p" -e "/^author /q" |
+ sort -u) &&
+ test "z$commit0" = "z$parent" &&
+ numparent=$(git show --pretty=raw $commit2 |
+ sed -n -e "s/^parent //p" -e "/^author /q" |
+ wc -l) &&
+ test $numparent = 1
+'
test_expect_success 'update-index D/F conflict' '
mv path0 tmp &&
diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh
index f19e6510d0..e50f0f742f 100755
--- a/t/t0021-conversion.sh
+++ b/t/t0021-conversion.sh
@@ -153,4 +153,41 @@ test_expect_success 'filter shell-escaped filenames' '
:
'
+test_expect_success 'required filter success' '
+ git config filter.required.smudge cat &&
+ git config filter.required.clean cat &&
+ git config filter.required.required true &&
+
+ echo "*.r filter=required" >.gitattributes &&
+
+ echo test >test.r &&
+ git add test.r &&
+ rm -f test.r &&
+ git checkout -- test.r
+'
+
+test_expect_success 'required filter smudge failure' '
+ git config filter.failsmudge.smudge false &&
+ git config filter.failsmudge.clean cat &&
+ git config filter.failsmudge.required true &&
+
+ echo "*.fs filter=failsmudge" >.gitattributes &&
+
+ echo test >test.fs &&
+ git add test.fs &&
+ rm -f test.fs &&
+ test_must_fail git checkout -- test.fs
+'
+
+test_expect_success 'required filter clean failure' '
+ git config filter.failclean.smudge cat &&
+ git config filter.failclean.clean false &&
+ git config filter.failclean.required true &&
+
+ echo "*.fc filter=failclean" >.gitattributes &&
+
+ echo test >test.fc &&
+ test_must_fail git add test.fc
+'
+
test_done
diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh
index a1e4616feb..e3f354a45e 100755
--- a/t/t0040-parse-options.sh
+++ b/t/t0040-parse-options.sh
@@ -10,7 +10,10 @@ test_description='our own option parser'
cat > expect << EOF
usage: test-parse-options <options>
- -b, --boolean get a boolean
+ --yes get a boolean
+ -D, --no-doubt begins with 'no-'
+ -B, --no-fear be brave
+ -b, --boolean increment by one
-4, --or4 bitwise-or boolean with ...0100
--neg-or4 same as --no-or4
@@ -53,6 +56,59 @@ test_expect_success 'test help' '
mv expect expect.err
+cat >expect.template <<EOF
+boolean: 0
+integer: 0
+timestamp: 0
+string: (not set)
+abbrev: 7
+verbose: 0
+quiet: no
+dry run: no
+file: (not set)
+EOF
+
+check() {
+ 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_cmp expect output
+}
+
+check_unknown() {
+ 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_cmp 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'
+test_expect_success 'OPT_BOOL() #4' 'check boolean: 1 --no-fear'
+test_expect_success 'OPT_BOOL() #5' 'check boolean: 1 -B'
+
+test_expect_success 'OPT_BOOL() is idempotent #1' 'check boolean: 1 --yes --yes'
+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() positivation' 'check boolean: 0 -D --doubt'
+
cat > expect << EOF
boolean: 2
integer: 1729
@@ -180,6 +236,16 @@ test_expect_success 'detect possible typos' '
test_cmp typo.err output.err
'
+cat > typo.err << EOF
+error: did you mean \`--ambiguous\` (with two dashes ?)
+EOF
+
+test_expect_success 'detect possible typos' '
+ test_must_fail test-parse-options -ambiguous > output 2> output.err &&
+ test ! -s output &&
+ test_cmp typo.err output.err
+'
+
cat > expect <<EOF
boolean: 0
integer: 0
@@ -296,7 +362,7 @@ test_expect_success 'OPT_NEGBIT() works' '
test_cmp expect output
'
-test_expect_success 'OPT_BOOLEAN() with PARSE_OPT_NODASH works' '
+test_expect_success 'OPT_COUNTUP() with PARSE_OPT_NODASH works' '
test-parse-options + + + + + + > output 2> output.err &&
test ! -s output.err &&
test_cmp expect output
diff --git a/t/t0061-run-command.sh b/t/t0061-run-command.sh
index 8d4938f019..17e969df60 100755
--- a/t/t0061-run-command.sh
+++ b/t/t0061-run-command.sh
@@ -34,4 +34,17 @@ test_expect_success POSIXPERM 'run_command reports EACCES' '
grep "fatal: cannot exec.*hello.sh" err
'
+test_expect_success POSIXPERM 'unreadable directory in PATH' '
+ mkdir local-command &&
+ test_when_finished "chmod u+rwx local-command && rm -fr local-command" &&
+ git config alias.nitfol "!echo frotz" &&
+ chmod a-rx local-command &&
+ (
+ PATH=./local-command:$PATH &&
+ git nitfol >actual
+ ) &&
+ echo frotz >expect &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t0080-vcs-svn.sh b/t/t0080-vcs-svn.sh
deleted file mode 100755
index 99a314b080..0000000000
--- a/t/t0080-vcs-svn.sh
+++ /dev/null
@@ -1,117 +0,0 @@
-#!/bin/sh
-
-test_description='check infrastructure for svn importer'
-
-. ./test-lib.sh
-uint32_max=4294967295
-
-test_expect_success 'obj pool: store data' '
- cat <<-\EOF >expected &&
- 0
- 1
- EOF
-
- test-obj-pool <<-\EOF >actual &&
- alloc one 16
- set one 13
- test one 13
- reset one
- EOF
- test_cmp expected actual
-'
-
-test_expect_success 'obj pool: NULL is offset ~0' '
- echo "$uint32_max" >expected &&
- echo null one | test-obj-pool >actual &&
- test_cmp expected actual
-'
-
-test_expect_success 'obj pool: out-of-bounds access' '
- cat <<-EOF >expected &&
- 0
- 0
- $uint32_max
- $uint32_max
- 16
- 20
- $uint32_max
- EOF
-
- test-obj-pool <<-\EOF >actual &&
- alloc one 16
- alloc two 16
- offset one 20
- offset two 20
- alloc one 5
- offset one 20
- free one 1
- offset one 20
- reset one
- reset two
- EOF
- test_cmp expected actual
-'
-
-test_expect_success 'obj pool: high-water mark' '
- cat <<-\EOF >expected &&
- 0
- 0
- 10
- 20
- 20
- 20
- EOF
-
- test-obj-pool <<-\EOF >actual &&
- alloc one 10
- committed one
- alloc one 10
- commit one
- committed one
- alloc one 10
- free one 20
- committed one
- reset one
- EOF
- test_cmp expected actual
-'
-
-test_expect_success 'string pool' '
- echo a does not equal b >expected.differ &&
- echo a equals a >expected.match &&
- echo equals equals equals >expected.matchmore &&
-
- test-string-pool "a,--b" >actual.differ &&
- test-string-pool "a,a" >actual.match &&
- test-string-pool "equals-equals" >actual.matchmore &&
- test_must_fail test-string-pool a,a,a &&
- test_must_fail test-string-pool a &&
-
- test_cmp expected.differ actual.differ &&
- test_cmp expected.match actual.match &&
- test_cmp expected.matchmore actual.matchmore
-'
-
-test_expect_success 'treap sort' '
- cat <<-\EOF >unsorted &&
- 68
- 12
- 13
- 13
- 68
- 13
- 13
- 21
- 10
- 11
- 12
- 13
- 13
- EOF
- sort unsorted >expected &&
-
- test-treap <unsorted >actual &&
- test_cmp expected actual
-'
-
-test_done
diff --git a/t/t0204-gettext-reencode-sanity.sh b/t/t0204-gettext-reencode-sanity.sh
index 189af90c02..8437e51eb5 100755
--- a/t/t0204-gettext-reencode-sanity.sh
+++ b/t/t0204-gettext-reencode-sanity.sh
@@ -7,6 +7,10 @@ test_description="Gettext reencoding of our *.po/*.mo files works"
. ./lib-gettext.sh
+# The constants used in a tricky observation for undefined behaviour
+RUNES="TILRAUN: ᚻᛖ ᚳᚹᚫᚦ ᚦᚫᛏ ᚻᛖ ᛒᚢᛞᛖ ᚩᚾ ᚦᚫᛗ ᛚᚪᚾᛞᛖ ᚾᚩᚱᚦᚹᛖᚪᚱᛞᚢᛗ ᚹᛁᚦ ᚦᚪ ᚹᛖᛥᚫ"
+PUNTS="TILRAUN: ?? ???? ??? ?? ???? ?? ??? ????? ??????????? ??? ?? ????"
+MSGKEY="TEST: Old English Runes"
test_expect_success GETTEXT_LOCALE 'gettext: Emitting UTF-8 from our UTF-8 *.mo files / Icelandic' '
printf "TILRAUN: Halló Heimur!" >expect &&
@@ -15,8 +19,8 @@ test_expect_success GETTEXT_LOCALE 'gettext: Emitting UTF-8 from our UTF-8 *.mo
'
test_expect_success GETTEXT_LOCALE 'gettext: Emitting UTF-8 from our UTF-8 *.mo files / Runes' '
- printf "TILRAUN: ᚻᛖ ᚳᚹᚫᚦ ᚦᚫᛏ ᚻᛖ ᛒᚢᛞᛖ ᚩᚾ ᚦᚫᛗ ᛚᚪᚾᛞᛖ ᚾᚩᚱᚦᚹᛖᚪᚱᛞᚢᛗ ᚹᛁᚦ ᚦᚪ ᚹᛖᛥᚫ" >expect &&
- LANGUAGE=is LC_ALL="$is_IS_locale" gettext "TEST: Old English Runes" >actual &&
+ printf "%s" "$RUNES" >expect &&
+ LANGUAGE=is LC_ALL="$is_IS_locale" gettext "$MSGKEY" >actual &&
test_cmp expect actual
'
@@ -26,18 +30,23 @@ test_expect_success GETTEXT_ISO_LOCALE 'gettext: Emitting ISO-8859-1 from our UT
test_cmp expect actual
'
-test_expect_success GETTEXT_ISO_LOCALE 'gettext: Emitting ISO-8859-1 from our UTF-8 *.mo files / Runes' '
- LANGUAGE=is LC_ALL="$is_IS_iso_locale" gettext "TEST: Old English Runes" >runes &&
-
- if grep "^TEST: Old English Runes$" runes
- then
- say "Your system can not handle this complexity and returns the string as-is"
- else
- # Both Solaris and GNU libintl will return this stream of
- # question marks, so it is s probably portable enough
- printf "TILRAUN: ?? ???? ??? ?? ???? ?? ??? ????? ??????????? ??? ?? ????" >runes-expect &&
- test_cmp runes-expect runes
- fi
+test_expect_success GETTEXT_ISO_LOCALE 'gettext: impossible ISO-8859-1 output' '
+ LANGUAGE=is LC_ALL="$is_IS_iso_locale" gettext "$MSGKEY" >runes &&
+ case "$(cat runes)" in
+ "$MSGKEY")
+ say "Your system gives back the key to message catalog"
+ ;;
+ "$PUNTS")
+ say "Your system replaces an impossible character with ?"
+ ;;
+ "$RUNES")
+ say "Your system gives back the raw message for an impossible request"
+ ;;
+ *)
+ say "We never saw the error behaviour your system exhibits"
+ false
+ ;;
+ esac
'
test_expect_success GETTEXT_LOCALE 'gettext: Fetching a UTF-8 msgid -> UTF-8' '
diff --git a/t/t0300-credentials.sh b/t/t0300-credentials.sh
index c1c8108148..20e28e34e7 100755
--- a/t/t0300-credentials.sh
+++ b/t/t0300-credentials.sh
@@ -17,22 +17,18 @@ test_expect_success 'setup helper scripts' '
IFS=$OIFS
EOF
- cat >git-credential-useless <<-\EOF &&
- #!/bin/sh
+ write_script git-credential-useless <<-\EOF &&
. ./dump
exit 0
EOF
- chmod +x git-credential-useless &&
- cat >git-credential-verbatim <<-\EOF &&
- #!/bin/sh
+ write_script git-credential-verbatim <<-\EOF &&
user=$1; shift
pass=$1; shift
. ./dump
test -z "$user" || echo username=$user
test -z "$pass" || echo password=$pass
EOF
- chmod +x git-credential-verbatim &&
PATH="$PWD:$PATH"
'
diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh
index 728a965669..a477453e2e 100755
--- a/t/t1300-repo-config.sh
+++ b/t/t1300-repo-config.sh
@@ -451,13 +451,21 @@ test_expect_success 'refer config from subdirectory' '
mkdir x &&
(
cd x &&
- echo strasse >expect
+ echo strasse >expect &&
git config --get --file ../other-config ein.bahn >actual &&
test_cmp expect actual
)
'
+test_expect_success 'refer config from subdirectory via GIT_CONFIG' '
+ (
+ cd x &&
+ GIT_CONFIG=../other-config git config --get ein.bahn >actual &&
+ test_cmp expect actual
+ )
+'
+
cat > expect << EOF
[ein]
bahn = strasse
@@ -542,6 +550,14 @@ EOF
test_expect_success "rename succeeded" "test_cmp expect .git/config"
+test_expect_success 'renaming empty section name is rejected' '
+ test_must_fail git config --rename-section branch.zwei ""
+'
+
+test_expect_success 'renaming to bogus section is rejected' '
+ test_must_fail git config --rename-section branch.zwei "bogus name"
+'
+
cat >> .git/config << EOF
[branch "zwei"] a = 1 [branch "vier"]
EOF
@@ -960,6 +976,23 @@ test_expect_success 'git -c complains about empty key and value' '
test_must_fail git -c "" rev-parse
'
+test_expect_success 'git config --edit works' '
+ git config -f tmp test.value no &&
+ echo test.value=yes >expect &&
+ GIT_EDITOR="echo [test]value=yes >" git config -f tmp --edit &&
+ git config -f tmp --list >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git config --edit respects core.editor' '
+ git config -f tmp test.value no &&
+ echo test.value=yes >expect &&
+ test_config core.editor "echo [test]value=yes >" &&
+ git config -f tmp --edit &&
+ git config -f tmp --list >actual &&
+ test_cmp expect actual
+'
+
# malformed configuration files
test_expect_success 'barf on syntax error' '
cat >.git/config <<-\EOF &&
diff --git a/t/t1305-config-include.sh b/t/t1305-config-include.sh
new file mode 100755
index 0000000000..a70707620f
--- /dev/null
+++ b/t/t1305-config-include.sh
@@ -0,0 +1,142 @@
+#!/bin/sh
+
+test_description='test config file include directives'
+. ./test-lib.sh
+
+test_expect_success 'include file by absolute path' '
+ echo "[test]one = 1" >one &&
+ echo "[include]path = \"$(pwd)/one\"" >.gitconfig &&
+ echo 1 >expect &&
+ git config test.one >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'include file by relative path' '
+ echo "[test]one = 1" >one &&
+ echo "[include]path = one" >.gitconfig &&
+ echo 1 >expect &&
+ git config test.one >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'chained relative paths' '
+ mkdir subdir &&
+ echo "[test]three = 3" >subdir/three &&
+ echo "[include]path = three" >subdir/two &&
+ echo "[include]path = subdir/two" >.gitconfig &&
+ echo 3 >expect &&
+ git config test.three >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'include paths get tilde-expansion' '
+ echo "[test]one = 1" >one &&
+ echo "[include]path = ~/one" >.gitconfig &&
+ echo 1 >expect &&
+ git config test.one >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'include options can still be examined' '
+ echo "[test]one = 1" >one &&
+ echo "[include]path = one" >.gitconfig &&
+ echo one >expect &&
+ git config include.path >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'listing includes option and expansion' '
+ echo "[test]one = 1" >one &&
+ echo "[include]path = one" >.gitconfig &&
+ cat >expect <<-\EOF &&
+ include.path=one
+ test.one=1
+ EOF
+ git config --list >actual.full &&
+ grep -v ^core actual.full >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'single file lookup does not expand includes by default' '
+ echo "[test]one = 1" >one &&
+ echo "[include]path = one" >.gitconfig &&
+ test_must_fail git config -f .gitconfig test.one &&
+ test_must_fail git config --global test.one &&
+ echo 1 >expect &&
+ git config --includes -f .gitconfig test.one >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'single file list does not expand includes by default' '
+ echo "[test]one = 1" >one &&
+ echo "[include]path = one" >.gitconfig &&
+ echo "include.path=one" >expect &&
+ git config -f .gitconfig --list >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'writing config file does not expand includes' '
+ echo "[test]one = 1" >one &&
+ echo "[include]path = one" >.gitconfig &&
+ git config test.two 2 &&
+ echo 2 >expect &&
+ git config --no-includes test.two >actual &&
+ test_cmp expect actual &&
+ test_must_fail git config --no-includes test.one
+'
+
+test_expect_success 'config modification does not affect includes' '
+ echo "[test]one = 1" >one &&
+ echo "[include]path = one" >.gitconfig &&
+ git config test.one 2 &&
+ echo 1 >expect &&
+ git config -f one test.one >actual &&
+ test_cmp expect actual &&
+ cat >expect <<-\EOF &&
+ 1
+ 2
+ EOF
+ git config --get-all test.one >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'missing include files are ignored' '
+ cat >.gitconfig <<-\EOF &&
+ [include]path = foo
+ [test]value = yes
+ EOF
+ echo yes >expect &&
+ git config test.value >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'absolute includes from command line work' '
+ echo "[test]one = 1" >one &&
+ echo 1 >expect &&
+ git -c include.path="$PWD/one" config test.one >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'relative includes from command line fail' '
+ echo "[test]one = 1" >one &&
+ test_must_fail git -c include.path=one config test.one
+'
+
+test_expect_success 'include cycles are detected' '
+ cat >.gitconfig <<-\EOF &&
+ [test]value = gitconfig
+ [include]path = cycle
+ EOF
+ cat >cycle <<-\EOF &&
+ [test]value = cycle
+ [include]path = .gitconfig
+ EOF
+ cat >expect <<-\EOF &&
+ gitconfig
+ cycle
+ EOF
+ test_must_fail git config --get-all test.value 2>stderr &&
+ grep "exceeded maximum include depth" stderr
+'
+
+test_done
diff --git a/t/t1410-reflog.sh b/t/t1410-reflog.sh
index 252fc82837..236b13a3ab 100755
--- a/t/t1410-reflog.sh
+++ b/t/t1410-reflog.sh
@@ -100,8 +100,7 @@ test_expect_success setup '
check_fsck &&
- loglen=$(wc -l <.git/logs/refs/heads/master) &&
- test $loglen = 4
+ test_line_count = 4 .git/logs/refs/heads/master
'
test_expect_success rewind '
@@ -117,8 +116,7 @@ test_expect_success rewind '
check_have A B C D E F G H I J K L &&
- loglen=$(wc -l <.git/logs/refs/heads/master) &&
- test $loglen = 5
+ test_line_count = 5 .git/logs/refs/heads/master
'
test_expect_success 'corrupt and check' '
@@ -136,8 +134,7 @@ test_expect_success 'reflog expire --dry-run should not touch reflog' '
--stale-fix \
--all &&
- loglen=$(wc -l <.git/logs/refs/heads/master) &&
- test $loglen = 5 &&
+ test_line_count = 5 .git/logs/refs/heads/master &&
check_fsck "missing blob $F"
'
@@ -150,8 +147,7 @@ test_expect_success 'reflog expire' '
--stale-fix \
--all &&
- loglen=$(wc -l <.git/logs/refs/heads/master) &&
- test $loglen = 2 &&
+ test_line_count = 2 .git/logs/refs/heads/master &&
check_fsck "dangling commit $K"
'
@@ -217,9 +213,7 @@ test_expect_success 'delete' '
test_expect_success 'rewind2' '
test_tick && git reset --hard HEAD~2 &&
- loglen=$(wc -l <.git/logs/refs/heads/master) &&
- test $loglen = 4
-
+ test_line_count = 4 .git/logs/refs/heads/master
'
test_expect_success '--expire=never' '
@@ -228,9 +222,7 @@ test_expect_success '--expire=never' '
--expire=never \
--expire-unreachable=never \
--all &&
- loglen=$(wc -l <.git/logs/refs/heads/master) &&
- test $loglen = 4
-
+ test_line_count = 4 .git/logs/refs/heads/master
'
test_expect_success 'gc.reflogexpire=never' '
@@ -238,8 +230,7 @@ test_expect_success 'gc.reflogexpire=never' '
git config gc.reflogexpire never &&
git config gc.reflogexpireunreachable never &&
git reflog expire --verbose --all &&
- loglen=$(wc -l <.git/logs/refs/heads/master) &&
- test $loglen = 4
+ test_line_count = 4 .git/logs/refs/heads/master
'
test_expect_success 'gc.reflogexpire=false' '
@@ -247,8 +238,7 @@ test_expect_success 'gc.reflogexpire=false' '
git config gc.reflogexpire false &&
git config gc.reflogexpireunreachable false &&
git reflog expire --verbose --all &&
- loglen=$(wc -l <.git/logs/refs/heads/master) &&
- test $loglen = 4 &&
+ test_line_count = 4 .git/logs/refs/heads/master &&
git config --unset gc.reflogexpire &&
git config --unset gc.reflogexpireunreachable
diff --git a/t/t1411-reflog-show.sh b/t/t1411-reflog-show.sh
index caa687b5b4..9a105fe21f 100755
--- a/t/t1411-reflog-show.sh
+++ b/t/t1411-reflog-show.sh
@@ -65,20 +65,73 @@ test_expect_success 'using @{now} syntax shows reflog date (oneline)' '
'
cat >expect <<'EOF'
-Reflog: HEAD@{1112911993 -0700} (C O Mitter <committer@example.com>)
+HEAD@{Thu Apr 7 15:13:13 2005 -0700}
+EOF
+test_expect_success 'using @{now} syntax shows reflog date (format=%gd)' '
+ git log -g -1 --format=%gd HEAD@{now} >actual &&
+ test_cmp expect actual
+'
+
+cat >expect <<'EOF'
+Reflog: HEAD@{Thu Apr 7 15:13:13 2005 -0700} (C O Mitter <committer@example.com>)
Reflog message: commit (initial): one
EOF
test_expect_success 'using --date= shows reflog date (multiline)' '
- git log -g -1 --date=raw >tmp &&
+ git log -g -1 --date=default >tmp &&
grep ^Reflog <tmp >actual &&
test_cmp expect actual
'
cat >expect <<'EOF'
-e46513e HEAD@{1112911993 -0700}: commit (initial): one
+e46513e HEAD@{Thu Apr 7 15:13:13 2005 -0700}: commit (initial): one
EOF
test_expect_success 'using --date= shows reflog date (oneline)' '
- git log -g -1 --oneline --date=raw >actual &&
+ git log -g -1 --oneline --date=default >actual &&
+ test_cmp expect actual
+'
+
+cat >expect <<'EOF'
+HEAD@{1112911993 -0700}
+EOF
+test_expect_success 'using --date= shows reflog date (format=%gd)' '
+ git log -g -1 --format=%gd --date=raw >actual &&
+ test_cmp expect actual
+'
+
+cat >expect <<'EOF'
+Reflog: HEAD@{0} (C O Mitter <committer@example.com>)
+Reflog message: commit (initial): one
+EOF
+test_expect_success 'log.date does not invoke "--date" magic (multiline)' '
+ test_config log.date raw &&
+ git log -g -1 >tmp &&
+ grep ^Reflog <tmp >actual &&
+ test_cmp expect actual
+'
+
+cat >expect <<'EOF'
+e46513e HEAD@{0}: commit (initial): one
+EOF
+test_expect_success 'log.date does not invoke "--date" magic (oneline)' '
+ test_config log.date raw &&
+ git log -g -1 --oneline >actual &&
+ test_cmp expect actual
+'
+
+cat >expect <<'EOF'
+HEAD@{0}
+EOF
+test_expect_success 'log.date does not invoke "--date" magic (format=%gd)' '
+ test_config log.date raw &&
+ git log -g -1 --format=%gd >actual &&
+ test_cmp expect actual
+'
+
+cat >expect <<'EOF'
+HEAD@{0}
+EOF
+test_expect_success '--date magic does not override explicit @{0} syntax' '
+ git log -g -1 --format=%gd --date=raw HEAD@{0} >actual &&
test_cmp expect actual
'
diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh
index 5b8ebd8053..5b79c51b8c 100755
--- a/t/t1450-fsck.sh
+++ b/t/t1450-fsck.sh
@@ -27,12 +27,8 @@ test_expect_success 'loose objects borrowed from alternate are not missing' '
git init &&
echo ../../../.git/objects >.git/objects/info/alternates &&
test_commit C fileC one &&
- git fsck >../out 2>&1
+ git fsck --no-dangling >../actual 2>&1
) &&
- {
- grep -v dangling out >actual ||
- :
- } &&
test_cmp empty actual
'
diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh
index e661147c57..8f36aa9fc4 100755
--- a/t/t1501-worktree.sh
+++ b/t/t1501-worktree.sh
@@ -68,7 +68,7 @@ test_expect_success 'inside work tree' '
)
'
-test_expect_failure 'empty prefix is actually written out' '
+test_expect_success 'empty prefix is actually written out' '
echo >expected &&
(
cd work &&
diff --git a/t/t2004-checkout-cache-temp.sh b/t/t2004-checkout-cache-temp.sh
index 36cca14d95..0f4b2896af 100755
--- a/t/t2004-checkout-cache-temp.sh
+++ b/t/t2004-checkout-cache-temp.sh
@@ -40,7 +40,7 @@ test_expect_success \
rm -f path* .merge_* out .git/index &&
git read-tree $t1 &&
git checkout-index --temp -- path1 >out &&
-test $(wc -l <out) = 1 &&
+test_line_count = 1 out &&
test $(cut "-d " -f2 out) = path1 &&
p=$(cut "-d " -f1 out) &&
test -f $p &&
@@ -51,7 +51,7 @@ test_expect_success \
rm -f path* .merge_* out .git/index &&
git read-tree $t1 &&
git checkout-index -a --temp >out &&
-test $(wc -l <out) = 5 &&
+test_line_count = 5 out &&
for f in path0 path1 path3 path4 asubdir/path5
do
test $(grep $f out | cut "-d " -f2) = $f &&
@@ -69,7 +69,7 @@ test_expect_success \
'checkout one stage 2 to temporary file' '
rm -f path* .merge_* out &&
git checkout-index --stage=2 --temp -- path1 >out &&
-test $(wc -l <out) = 1 &&
+test_line_count = 1 out &&
test $(cut "-d " -f2 out) = path1 &&
p=$(cut "-d " -f1 out) &&
test -f $p &&
@@ -79,7 +79,7 @@ test_expect_success \
'checkout all stage 2 to temporary files' '
rm -f path* .merge_* out &&
git checkout-index --all --stage=2 --temp >out &&
-test $(wc -l <out) = 3 &&
+test_line_count = 3 out &&
for f in path1 path2 path4
do
test $(grep $f out | cut "-d " -f2) = $f &&
@@ -92,13 +92,13 @@ test_expect_success \
'checkout all stages/one file to nothing' '
rm -f path* .merge_* out &&
git checkout-index --stage=all --temp -- path0 >out &&
-test $(wc -l <out) = 0'
+test_line_count = 0 out'
test_expect_success \
'checkout all stages/one file to temporary files' '
rm -f path* .merge_* out &&
git checkout-index --stage=all --temp -- path1 >out &&
-test $(wc -l <out) = 1 &&
+test_line_count = 1 out &&
test $(cut "-d " -f2 out) = path1 &&
cut "-d " -f1 out | (read s1 s2 s3 &&
test -f $s1 &&
@@ -112,7 +112,7 @@ test_expect_success \
'checkout some stages/one file to temporary files' '
rm -f path* .merge_* out &&
git checkout-index --stage=all --temp -- path2 >out &&
-test $(wc -l <out) = 1 &&
+test_line_count = 1 out &&
test $(cut "-d " -f2 out) = path2 &&
cut "-d " -f1 out | (read s1 s2 s3 &&
test $s1 = . &&
@@ -125,7 +125,7 @@ test_expect_success \
'checkout all stages/all files to temporary files' '
rm -f path* .merge_* out &&
git checkout-index -a --stage=all --temp >out &&
-test $(wc -l <out) = 5'
+test_line_count = 5 out'
test_expect_success \
'-- path0: no entry' '
@@ -185,7 +185,7 @@ test_expect_success \
'checkout --temp within subdir' '
(cd asubdir &&
git checkout-index -a --stage=all >out &&
- test $(wc -l <out) = 1 &&
+ test_line_count = 1 out &&
test $(grep path5 out | cut "-d " -f2) = path5 &&
grep path5 out | cut "-d " -f1 | (read s1 s2 s3 &&
test -f ../$s1 &&
@@ -203,7 +203,7 @@ t4=$(git write-tree) &&
rm -f .git/index &&
git read-tree $t4 &&
git checkout-index --temp -a >out &&
-test $(wc -l <out) = 1 &&
+test_line_count = 1 out &&
test $(cut "-d " -f2 out) = a &&
p=$(cut "-d " -f1 out) &&
test -f $p &&
diff --git a/t/t2015-checkout-unborn.sh b/t/t2015-checkout-unborn.sh
index 6352b74e2e..37bdcedcc9 100755
--- a/t/t2015-checkout-unborn.sh
+++ b/t/t2015-checkout-unborn.sh
@@ -46,4 +46,15 @@ test_expect_success 'checking out another branch from unborn state' '
test_cmp expect actual
'
+test_expect_success 'checking out in a newly created repo' '
+ test_create_repo empty &&
+ (
+ cd empty &&
+ git symbolic-ref HEAD >expect &&
+ test_must_fail git checkout &&
+ git symbolic-ref HEAD >actual &&
+ test_cmp expect actual
+ )
+'
+
test_done
diff --git a/t/t2020-checkout-detach.sh b/t/t2020-checkout-detach.sh
index 068fba4c8e..f63333b64e 100755
--- a/t/t2020-checkout-detach.sh
+++ b/t/t2020-checkout-detach.sh
@@ -11,14 +11,13 @@ check_not_detached () {
git symbolic-ref -q HEAD >/dev/null
}
-ORPHAN_WARNING='you are leaving .* commit.*behind'
PREV_HEAD_DESC='Previous HEAD position was'
check_orphan_warning() {
- test_i18ngrep "$ORPHAN_WARNING" "$1" &&
+ test_i18ngrep "you are leaving $2 behind" "$1" &&
test_i18ngrep ! "$PREV_HEAD_DESC" "$1"
}
check_no_orphan_warning() {
- test_i18ngrep ! "$ORPHAN_WARNING" "$1" &&
+ test_i18ngrep ! "you are leaving .* commit.*behind" "$1" &&
test_i18ngrep "$PREV_HEAD_DESC" "$1"
}
@@ -110,12 +109,24 @@ test_expect_success 'checkout warns on orphan commits' '
git checkout --detach two &&
echo content >orphan &&
git add orphan &&
- git commit -a -m orphan &&
+ git commit -a -m orphan1 &&
+ echo new content >orphan &&
+ git commit -a -m orphan2 &&
+ orphan2=$(git rev-parse HEAD) &&
git checkout master 2>stderr
'
test_expect_success 'checkout warns on orphan commits: output' '
- check_orphan_warning stderr
+ check_orphan_warning stderr "2 commits"
+'
+
+test_expect_success 'checkout warns orphaning 1 of 2 commits' '
+ git checkout "$orphan2" &&
+ git checkout HEAD^ 2>stderr
+'
+
+test_expect_success 'checkout warns orphaning 1 of 2 commits: output' '
+ check_orphan_warning stderr "1 commit"
'
test_expect_success 'checkout does not warn leaving ref tip' '
diff --git a/t/t2030-unresolve-info.sh b/t/t2030-unresolve-info.sh
index cb7effe0a3..f2620650ce 100755
--- a/t/t2030-unresolve-info.sh
+++ b/t/t2030-unresolve-info.sh
@@ -113,7 +113,7 @@ test_expect_success 'unmerge with plumbing' '
prime_resolve_undo &&
git update-index --unresolve fi/le &&
git ls-files -u >actual &&
- test $(wc -l <actual) = 3
+ test_line_count = 3 actual
'
test_expect_success 'rerere and rerere forget' '
diff --git a/t/t3310-notes-merge-manual-resolve.sh b/t/t3310-notes-merge-manual-resolve.sh
index 4367197953..195bb97f85 100755
--- a/t/t3310-notes-merge-manual-resolve.sh
+++ b/t/t3310-notes-merge-manual-resolve.sh
@@ -324,7 +324,7 @@ y and z notes on 4th commit
EOF
git notes merge --commit &&
# No .git/NOTES_MERGE_* files left
- test_must_fail ls .git/NOTES_MERGE_* >output 2>/dev/null &&
+ test_might_fail ls .git/NOTES_MERGE_* >output 2>/dev/null &&
test_cmp /dev/null output &&
# Merge commit has pre-merge y and pre-merge z as parents
test "$(git rev-parse refs/notes/m^1)" = "$(cat pre_merge_y)" &&
@@ -386,7 +386,7 @@ test_expect_success 'redo merge of z into m (== y) with default ("manual") resol
test_expect_success 'abort notes merge' '
git notes merge --abort &&
# No .git/NOTES_MERGE_* files left
- test_must_fail ls .git/NOTES_MERGE_* >output 2>/dev/null &&
+ test_might_fail ls .git/NOTES_MERGE_* >output 2>/dev/null &&
test_cmp /dev/null output &&
# m has not moved (still == y)
test "$(git rev-parse refs/notes/m)" = "$(cat pre_merge_y)" &&
@@ -453,7 +453,7 @@ EOF
# Finalize merge
git notes merge --commit &&
# No .git/NOTES_MERGE_* files left
- test_must_fail ls .git/NOTES_MERGE_* >output 2>/dev/null &&
+ test_might_fail ls .git/NOTES_MERGE_* >output 2>/dev/null &&
test_cmp /dev/null output &&
# Merge commit has pre-merge y and pre-merge z as parents
test "$(git rev-parse refs/notes/m^1)" = "$(cat pre_merge_y)" &&
@@ -542,7 +542,7 @@ EOF
test_expect_success 'resolve situation by aborting the notes merge' '
git notes merge --abort &&
# No .git/NOTES_MERGE_* files left
- test_must_fail ls .git/NOTES_MERGE_* >output 2>/dev/null &&
+ test_might_fail ls .git/NOTES_MERGE_* >output 2>/dev/null &&
test_cmp /dev/null output &&
# m has not moved (still == w)
test "$(git rev-parse refs/notes/m)" = "$(git rev-parse refs/notes/w)" &&
@@ -553,4 +553,23 @@ test_expect_success 'resolve situation by aborting the notes merge' '
verify_notes z
'
+cat >expect_notes <<EOF
+foo
+bar
+EOF
+
+test_expect_success 'switch cwd before committing notes merge' '
+ git notes add -m foo HEAD &&
+ git notes --ref=other add -m bar HEAD &&
+ test_must_fail git notes merge refs/notes/other &&
+ (
+ cd .git/NOTES_MERGE_WORKTREE &&
+ echo "foo" > $(git rev-parse HEAD) &&
+ echo "bar" >> $(git rev-parse HEAD) &&
+ git notes merge --commit
+ ) &&
+ git notes show HEAD > actual_notes &&
+ test_cmp expect_notes actual_notes
+'
+
test_done
diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh
index e647272a01..7788ae02ad 100755
--- a/t/t3400-rebase.sh
+++ b/t/t3400-rebase.sh
@@ -160,14 +160,12 @@ rm -f B
test_expect_success 'fail when upstream arg is missing and not on branch' '
git checkout topic &&
- test_must_fail git rebase >output.out &&
- grep "You are not currently on a branch" output.out
+ test_must_fail git rebase
'
test_expect_success 'fail when upstream arg is missing and not configured' '
git checkout -b no-config topic &&
- test_must_fail git rebase >output.out &&
- grep "branch.no-config.merge" output.out
+ test_must_fail git rebase
'
test_expect_success 'default to @{upstream} when upstream arg is missing' '
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index b981572d73..eab8501e11 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -247,6 +247,7 @@ test_expect_success '-p handles "no changes" gracefully' '
'
test_expect_failure 'exchange two commits with -p' '
+ git checkout H &&
FAKE_LINES="2 1" git rebase -i -p HEAD~2 &&
test H = $(git cat-file commit HEAD^ | sed -ne \$p) &&
test G = $(git cat-file commit HEAD | sed -ne \$p)
@@ -624,8 +625,38 @@ test_expect_success 'submodule rebase -i' '
FAKE_LINES="1 squash 2 3" git rebase -i A
'
+test_expect_success 'submodule conflict setup' '
+ git tag submodule-base &&
+ git checkout HEAD^ &&
+ (
+ cd sub && git checkout HEAD^ && echo 4 >elif &&
+ git add elif && git commit -m "submodule conflict"
+ ) &&
+ git add sub &&
+ test_tick &&
+ git commit -m "Conflict in submodule" &&
+ git tag submodule-topic
+'
+
+test_expect_success 'rebase -i continue with only submodule staged' '
+ test_must_fail git rebase -i submodule-base &&
+ git add sub &&
+ git rebase --continue &&
+ test $(git rev-parse submodule-base) != $(git rev-parse HEAD)
+'
+
+test_expect_success 'rebase -i continue with unstaged submodule' '
+ git checkout submodule-topic &&
+ git reset --hard &&
+ test_must_fail git rebase -i submodule-base &&
+ git reset &&
+ git rebase --continue &&
+ test $(git rev-parse submodule-base) = $(git rev-parse HEAD)
+'
+
test_expect_success 'avoid unnecessary reset' '
git checkout master &&
+ git reset --hard &&
test-chmtime =123456789 file3 &&
git update-index --refresh &&
HEAD=$(git rev-parse HEAD) &&
diff --git a/t/t3415-rebase-autosquash.sh b/t/t3415-rebase-autosquash.sh
index b38be8e937..a1e86c4097 100755
--- a/t/t3415-rebase-autosquash.sh
+++ b/t/t3415-rebase-autosquash.sh
@@ -33,7 +33,7 @@ test_auto_fixup () {
test_tick &&
git rebase $2 -i HEAD^^^ &&
git log --oneline >actual &&
- test 3 = $(wc -l <actual) &&
+ test_line_count = 3 actual &&
git diff --exit-code $1 &&
test 1 = "$(git cat-file blob HEAD^:file1)" &&
test 1 = $(git cat-file commit HEAD^ | grep first | wc -l)
@@ -62,7 +62,7 @@ test_auto_squash () {
test_tick &&
git rebase $2 -i HEAD^^^ &&
git log --oneline >actual &&
- test 3 = $(wc -l <actual) &&
+ test_line_count = 3 actual &&
git diff --exit-code $1 &&
test 1 = "$(git cat-file blob HEAD^:file1)" &&
test 2 = $(git cat-file commit HEAD^ | grep first | wc -l)
@@ -90,7 +90,7 @@ test_expect_success 'misspelled auto squash' '
test_tick &&
git rebase --autosquash -i HEAD^^^ &&
git log --oneline >actual &&
- test 4 = $(wc -l <actual) &&
+ test_line_count = 4 actual &&
git diff --exit-code final-missquash &&
test 0 = $(git rev-list final-missquash...HEAD | wc -l)
'
@@ -109,7 +109,7 @@ test_expect_success 'auto squash that matches 2 commits' '
test_tick &&
git rebase --autosquash -i HEAD~4 &&
git log --oneline >actual &&
- test 4 = $(wc -l <actual) &&
+ test_line_count = 4 actual &&
git diff --exit-code final-multisquash &&
test 1 = "$(git cat-file blob HEAD^^:file1)" &&
test 2 = $(git cat-file commit HEAD^^ | grep first | wc -l) &&
@@ -130,7 +130,7 @@ test_expect_success 'auto squash that matches a commit after the squash' '
test_tick &&
git rebase --autosquash -i HEAD~4 &&
git log --oneline >actual &&
- test 5 = $(wc -l <actual) &&
+ test_line_count = 5 actual &&
git diff --exit-code final-presquash &&
test 0 = "$(git cat-file blob HEAD^^:file1)" &&
test 1 = "$(git cat-file blob HEAD^:file1)" &&
@@ -147,7 +147,7 @@ test_expect_success 'auto squash that matches a sha1' '
test_tick &&
git rebase --autosquash -i HEAD^^^ &&
git log --oneline >actual &&
- test 3 = $(wc -l <actual) &&
+ test_line_count = 3 actual &&
git diff --exit-code final-shasquash &&
test 1 = "$(git cat-file blob HEAD^:file1)" &&
test 1 = $(git cat-file commit HEAD^ | grep squash | wc -l)
@@ -163,7 +163,7 @@ test_expect_success 'auto squash that matches longer sha1' '
test_tick &&
git rebase --autosquash -i HEAD^^^ &&
git log --oneline >actual &&
- test 3 = $(wc -l <actual) &&
+ test_line_count = 3 actual &&
git diff --exit-code final-longshasquash &&
test 1 = "$(git cat-file blob HEAD^:file1)" &&
test 1 = $(git cat-file commit HEAD^ | grep squash | wc -l)
@@ -179,7 +179,7 @@ test_auto_commit_flags () {
test_tick &&
git rebase --autosquash -i HEAD^^^ &&
git log --oneline >actual &&
- test 3 = $(wc -l <actual) &&
+ test_line_count = 3 actual &&
git diff --exit-code final-commit-$1 &&
test 1 = "$(git cat-file blob HEAD^:file1)" &&
test $2 = $(git cat-file commit HEAD^ | grep first | wc -l)
diff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh
index ee1659c178..0c81b3c427 100755
--- a/t/t3507-cherry-pick-conflict.sh
+++ b/t/t3507-cherry-pick-conflict.sh
@@ -59,6 +59,20 @@ test_expect_success 'advice from failed cherry-pick' "
test_i18ncmp expected actual
"
+test_expect_success 'advice from failed cherry-pick --no-commit' "
+ pristine_detach initial &&
+
+ picked=\$(git rev-parse --short picked) &&
+ cat <<-EOF >expected &&
+ error: could not apply \$picked... picked
+ hint: after resolving the conflicts, mark the corrected paths
+ hint: with 'git add <paths>' or 'git rm <paths>'
+ EOF
+ test_must_fail git cherry-pick --no-commit picked 2>actual &&
+
+ test_i18ncmp expected actual
+"
+
test_expect_success 'failed cherry-pick sets CHERRY_PICK_HEAD' '
pristine_detach initial &&
test_must_fail git cherry-pick picked &&
diff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh
index 9e236f9cc0..098a6ae4a0 100755
--- a/t/t3701-add-interactive.sh
+++ b/t/t3701-add-interactive.sh
@@ -330,4 +330,30 @@ test_expect_success PERL 'split hunk "add -p (edit)"' '
! grep "^+15" actual
'
+test_expect_success 'patch mode ignores unmerged entries' '
+ git reset --hard &&
+ test_commit conflict &&
+ test_commit non-conflict &&
+ git checkout -b side &&
+ test_commit side conflict.t &&
+ git checkout master &&
+ test_commit master conflict.t &&
+ test_must_fail git merge side &&
+ echo changed >non-conflict.t &&
+ echo y | git add -p >output &&
+ ! grep a/conflict.t output &&
+ cat >expected <<-\EOF &&
+ * Unmerged path conflict.t
+ diff --git a/non-conflict.t b/non-conflict.t
+ index f766221..5ea2ed4 100644
+ --- a/non-conflict.t
+ +++ b/non-conflict.t
+ @@ -1 +1 @@
+ -non-conflict
+ +changed
+ EOF
+ git diff --cached >diff &&
+ test_cmp expected diff
+'
+
test_done
diff --git a/t/t3900-i18n-commit.sh b/t/t3900-i18n-commit.sh
index d48a7c002d..37ddabba2d 100755
--- a/t/t3900-i18n-commit.sh
+++ b/t/t3900-i18n-commit.sh
@@ -160,7 +160,7 @@ test_commit_autosquash_flags () {
git config --unset-all i18n.commitencoding &&
git rebase --autosquash -i HEAD^^^ &&
git log --oneline >actual &&
- test 3 = $(wc -l <actual)
+ test_line_count = 3 actual
'
}
diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh
index 9059bcd69e..cc3db1304e 100755
--- a/t/t4015-diff-whitespace.sh
+++ b/t/t4015-diff-whitespace.sh
@@ -103,7 +103,7 @@ test_expect_success 'another test, with -w --ignore-space-at-eol' 'test_cmp expe
git diff -w -b --ignore-space-at-eol > out
test_expect_success 'another test, with -w -b --ignore-space-at-eol' 'test_cmp expect out'
-tr 'Q' '\015' << EOF > expect
+tr 'Q_' '\015 ' << EOF > expect
diff --git a/x b/x
index d99af23..8b32fb5 100644
--- a/x
@@ -111,19 +111,19 @@ index d99af23..8b32fb5 100644
@@ -1,6 +1,6 @@
-whitespace at beginning
+ whitespace at beginning
- whitespace change
+ whitespace change
-whitespace in the middle
+white space in the middle
- whitespace at end
+ whitespace at end__
unchanged line
- CR at endQ
+ CR at end
EOF
git diff -b > out
test_expect_success 'another test, with -b' 'test_cmp expect out'
git diff -b --ignore-space-at-eol > out
test_expect_success 'another test, with -b --ignore-space-at-eol' 'test_cmp expect out'
-tr 'Q' '\015' << EOF > expect
+tr 'Q_' '\015 ' << EOF > expect
diff --git a/x b/x
index d99af23..8b32fb5 100644
--- a/x
@@ -135,9 +135,9 @@ index d99af23..8b32fb5 100644
+ whitespace at beginning
+whitespace change
+white space in the middle
- whitespace at end
+ whitespace at end__
unchanged line
- CR at endQ
+ CR at end
EOF
git diff --ignore-space-at-eol > out
test_expect_success 'another test, with --ignore-space-at-eol' 'test_cmp expect out'
diff --git a/t/t4034-diff-words.sh b/t/t4034-diff-words.sh
index 5c2012111c..30d42cb3bf 100755
--- a/t/t4034-diff-words.sh
+++ b/t/t4034-diff-words.sh
@@ -3,6 +3,7 @@
test_description='word diff colors'
. ./test-lib.sh
+. "$TEST_DIRECTORY"/diff-lib.sh
cat >pre.simple <<-\EOF
h(4)
@@ -293,6 +294,10 @@ test_expect_success '--word-diff=none' '
word_diff --word-diff=plain --word-diff=none
'
+test_expect_success 'unset default driver' '
+ test_unconfig diff.wordregex
+'
+
test_language_driver bibtex
test_language_driver cpp
test_language_driver csharp
@@ -348,4 +353,35 @@ test_expect_success 'word-diff with no newline at EOF' '
word_diff --word-diff=plain
'
+test_expect_success 'setup history with two files' '
+ echo "a b; c" >a.tex &&
+ echo "a b; c" >z.txt &&
+ git add a.tex z.txt &&
+ git commit -minitial &&
+
+ # modify both
+ echo "a bx; c" >a.tex &&
+ echo "a bx; c" >z.txt &&
+ git commit -mmodified -a
+'
+
+test_expect_success 'wordRegex for the first file does not apply to the second' '
+ echo "*.tex diff=tex" >.gitattributes &&
+ git config diff.tex.wordRegex "[a-z]+|." &&
+ cat >expect <<-\EOF &&
+ diff --git a/a.tex b/a.tex
+ --- a/a.tex
+ +++ b/a.tex
+ @@ -1 +1 @@
+ a [-b-]{+bx+}; c
+ diff --git a/z.txt b/z.txt
+ --- a/z.txt
+ +++ b/z.txt
+ @@ -1 +1 @@
+ a [-b;-]{+bx;+} c
+ EOF
+ git diff --word-diff HEAD~ >actual &&
+ compare_diff_patch expect actual
+'
+
test_done
diff --git a/t/t4035-diff-quiet.sh b/t/t4035-diff-quiet.sh
index e747e84227..cdb9202f57 100755
--- a/t/t4035-diff-quiet.sh
+++ b/t/t4035-diff-quiet.sh
@@ -15,65 +15,65 @@ test_expect_success 'setup' '
test_expect_success 'git diff-tree HEAD^ HEAD' '
git diff-tree --quiet HEAD^ HEAD >cnt
- test $? = 1 && test $(wc -l <cnt) = 0
+ test $? = 1 && test_line_count = 0 cnt
'
test_expect_success 'git diff-tree HEAD^ HEAD -- a' '
git diff-tree --quiet HEAD^ HEAD -- a >cnt
- test $? = 0 && test $(wc -l <cnt) = 0
+ test $? = 0 && test_line_count = 0 cnt
'
test_expect_success 'git diff-tree HEAD^ HEAD -- b' '
git diff-tree --quiet HEAD^ HEAD -- b >cnt
- test $? = 1 && test $(wc -l <cnt) = 0
+ test $? = 1 && test_line_count = 0 cnt
'
# this diff outputs one line: sha1 of the given head
test_expect_success 'echo HEAD | git diff-tree --stdin' '
echo $(git rev-parse HEAD) | git diff-tree --quiet --stdin >cnt
- test $? = 1 && test $(wc -l <cnt) = 1
+ test $? = 1 && test_line_count = 1 cnt
'
test_expect_success 'git diff-tree HEAD HEAD' '
git diff-tree --quiet HEAD HEAD >cnt
- test $? = 0 && test $(wc -l <cnt) = 0
+ test $? = 0 && test_line_count = 0 cnt
'
test_expect_success 'git diff-files' '
git diff-files --quiet >cnt
- test $? = 0 && test $(wc -l <cnt) = 0
+ test $? = 0 && test_line_count = 0 cnt
'
test_expect_success 'git diff-index --cached HEAD' '
git diff-index --quiet --cached HEAD >cnt
- test $? = 0 && test $(wc -l <cnt) = 0
+ test $? = 0 && test_line_count = 0 cnt
'
test_expect_success 'git diff-index --cached HEAD^' '
git diff-index --quiet --cached HEAD^ >cnt
- test $? = 1 && test $(wc -l <cnt) = 0
+ test $? = 1 && test_line_count = 0 cnt
'
test_expect_success 'git diff-index --cached HEAD^' '
echo text >>b &&
echo 3 >c &&
git add . && {
git diff-index --quiet --cached HEAD^ >cnt
- test $? = 1 && test $(wc -l <cnt) = 0
+ test $? = 1 && test_line_count = 0 cnt
}
'
test_expect_success 'git diff-tree -Stext HEAD^ HEAD -- b' '
git commit -m "text in b" && {
git diff-tree --quiet -Stext HEAD^ HEAD -- b >cnt
- test $? = 1 && test $(wc -l <cnt) = 0
+ test $? = 1 && test_line_count = 0 cnt
}
'
test_expect_success 'git diff-tree -Snot-found HEAD^ HEAD -- b' '
git diff-tree --quiet -Snot-found HEAD^ HEAD -- b >cnt
- test $? = 0 && test $(wc -l <cnt) = 0
+ test $? = 0 && test_line_count = 0 cnt
'
test_expect_success 'git diff-files' '
echo 3 >>c && {
git diff-files --quiet >cnt
- test $? = 1 && test $(wc -l <cnt) = 0
+ test $? = 1 && test_line_count = 0 cnt
}
'
test_expect_success 'git diff-index --cached HEAD' '
git update-index c && {
git diff-index --quiet --cached HEAD >cnt
- test $? = 1 && test $(wc -l <cnt) = 0
+ test $? = 1 && test_line_count = 0 cnt
}
'
diff --git a/t/t4041-diff-submodule-option.sh b/t/t4041-diff-submodule-option.sh
index bf9a7526bd..6c01d0c056 100755
--- a/t/t4041-diff-submodule-option.sh
+++ b/t/t4041-diff-submodule-option.sh
@@ -458,4 +458,38 @@ EOF
test_cmp expected actual
'
+test_expect_success 'diff --submodule with objects referenced by alternates' '
+ mkdir sub_alt &&
+ (cd sub_alt &&
+ git init &&
+ echo a >a &&
+ git add a &&
+ git commit -m a
+ ) &&
+ mkdir super &&
+ (cd super &&
+ git clone -s ../sub_alt sub &&
+ git init &&
+ git add sub &&
+ git commit -m "sub a"
+ ) &&
+ (cd sub_alt &&
+ sha1_before=$(git rev-parse --short HEAD)
+ echo b >b &&
+ git add b &&
+ git commit -m b
+ sha1_after=$(git rev-parse --short HEAD)
+ echo "Submodule sub $sha1_before..$sha1_after:
+ > b" >../expected
+ ) &&
+ (cd super &&
+ (cd sub &&
+ git fetch &&
+ git checkout origin/master
+ ) &&
+ git diff --submodule > ../actual
+ )
+ test_cmp expected actual
+'
+
test_done
diff --git a/t/t4052-stat-output.sh b/t/t4052-stat-output.sh
new file mode 100755
index 0000000000..ddd94976c2
--- /dev/null
+++ b/t/t4052-stat-output.sh
@@ -0,0 +1,336 @@
+#!/bin/sh
+#
+# Copyright (c) 2012 Zbigniew Jędrzejewski-Szmek
+#
+
+test_description='test --stat output of various commands'
+
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-terminal.sh
+
+# 120 character name
+name=aaaaaaaaaa
+name=$name$name$name$name$name$name$name$name$name$name$name$name
+test_expect_success 'preparation' '
+ >"$name" &&
+ git add "$name" &&
+ git commit -m message &&
+ echo a >"$name" &&
+ git commit -m message "$name"
+'
+
+while read cmd args
+do
+ cat >expect <<-'EOF'
+ ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1 +
+ EOF
+ test_expect_success "$cmd: small change with long name gives more space to the name" '
+ git $cmd $args >output &&
+ grep " | " output >actual &&
+ test_cmp expect actual
+ '
+
+ cat >expect <<-'EOF'
+ ...aaaaaaaaaaaaaaaaaaaaaaaaaa | 1 +
+ EOF
+ test_expect_success "$cmd --stat=width: a long name is given more room when the bar is short" '
+ git $cmd $args --stat=40 >output &&
+ grep " | " output >actual &&
+ test_cmp expect actual
+ '
+
+ test_expect_success "$cmd --stat-width=width with long name" '
+ git $cmd $args --stat-width=40 >output &&
+ grep " | " output >actual &&
+ test_cmp expect actual
+ '
+
+ cat >expect <<-'EOF'
+ ...aaaaaaaaaaaaaaaaaaaaaaaaaaa | 1 +
+ EOF
+ test_expect_success "$cmd --stat=...,name-width with long name" '
+ git $cmd $args --stat=60,30 >output &&
+ grep " | " output >actual &&
+ test_cmp expect actual
+ '
+
+ test_expect_success "$cmd --stat-name-width with long name" '
+ git $cmd $args --stat-name-width=30 >output &&
+ grep " | " output >actual &&
+ test_cmp expect actual
+ '
+done <<\EOF
+format-patch -1 --stdout
+diff HEAD^ HEAD --stat
+show --stat
+log -1 --stat
+EOF
+
+
+test_expect_success 'preparation for big change tests' '
+ >abcd &&
+ git add abcd &&
+ git commit -m message &&
+ i=0 &&
+ while test $i -lt 1000
+ do
+ echo $i && i=$(($i + 1))
+ done >abcd &&
+ git commit -m message abcd
+'
+
+cat >expect80 <<'EOF'
+ abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+EOF
+cat >expect80-graph <<'EOF'
+| abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+EOF
+cat >expect200 <<'EOF'
+ abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+EOF
+cat >expect200-graph <<'EOF'
+| abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+EOF
+while read verb expect cmd args
+do
+ test_expect_success "$cmd $verb COLUMNS (big change)" '
+ COLUMNS=200 git $cmd $args >output
+ grep " | " output >actual &&
+ test_cmp "$expect" actual
+ '
+
+ test "$cmd" != diff || continue
+
+ test_expect_success "$cmd --graph $verb COLUMNS (big change)" '
+ COLUMNS=200 git $cmd $args --graph >output
+ grep " | " output >actual &&
+ test_cmp "$expect-graph" actual
+ '
+done <<\EOF
+ignores expect80 format-patch -1 --stdout
+respects expect200 diff HEAD^ HEAD --stat
+respects expect200 show --stat
+respects expect200 log -1 --stat
+EOF
+
+cat >expect40 <<'EOF'
+ abcd | 1000 ++++++++++++++++++++++++++
+EOF
+cat >expect40-graph <<'EOF'
+| abcd | 1000 ++++++++++++++++++++++++
+EOF
+while read verb expect cmd args
+do
+ test_expect_success "$cmd $verb not enough COLUMNS (big change)" '
+ COLUMNS=40 git $cmd $args >output
+ grep " | " output >actual &&
+ test_cmp "$expect" actual
+ '
+
+ test "$cmd" != diff || continue
+
+ test_expect_success "$cmd --graph $verb not enough COLUMNS (big change)" '
+ COLUMNS=40 git $cmd $args --graph >output
+ grep " | " output >actual &&
+ test_cmp "$expect-graph" actual
+ '
+done <<\EOF
+ignores expect80 format-patch -1 --stdout
+respects expect40 diff HEAD^ HEAD --stat
+respects expect40 show --stat
+respects expect40 log -1 --stat
+EOF
+
+cat >expect40 <<'EOF'
+ abcd | 1000 ++++++++++++++++++++++++++
+EOF
+cat >expect40-graph <<'EOF'
+| abcd | 1000 ++++++++++++++++++++++++++
+EOF
+while read verb expect cmd args
+do
+ test_expect_success "$cmd $verb statGraphWidth config" '
+ git -c diff.statGraphWidth=26 $cmd $args >output
+ grep " | " output >actual &&
+ test_cmp "$expect" actual
+ '
+
+ test "$cmd" != diff || continue
+
+ test_expect_success "$cmd --graph $verb statGraphWidth config" '
+ git -c diff.statGraphWidth=26 $cmd $args --graph >output
+ grep " | " output >actual &&
+ test_cmp "$expect-graph" actual
+ '
+done <<\EOF
+ignores expect80 format-patch -1 --stdout
+respects expect40 diff HEAD^ HEAD --stat
+respects expect40 show --stat
+respects expect40 log -1 --stat
+EOF
+
+
+cat >expect <<'EOF'
+ abcd | 1000 ++++++++++++++++++++++++++
+EOF
+cat >expect-graph <<'EOF'
+| abcd | 1000 ++++++++++++++++++++++++++
+EOF
+while read cmd args
+do
+ test_expect_success "$cmd --stat=width with big change" '
+ git $cmd $args --stat=40 >output
+ grep " | " output >actual &&
+ test_cmp expect actual
+ '
+
+ test_expect_success "$cmd --stat-width=width with big change" '
+ git $cmd $args --stat-width=40 >output
+ grep " | " output >actual &&
+ test_cmp expect actual
+ '
+
+ test_expect_success "$cmd --stat-graph-width with big change" '
+ git $cmd $args --stat-graph-width=26 >output
+ grep " | " output >actual &&
+ test_cmp expect actual
+ '
+
+ test "$cmd" != diff || continue
+
+ test_expect_success "$cmd --stat-width=width --graph with big change" '
+ git $cmd $args --stat-width=40 --graph >output
+ grep " | " output >actual &&
+ test_cmp expect-graph actual
+ '
+
+ test_expect_success "$cmd --stat-graph-width --graph with big change" '
+ git $cmd $args --stat-graph-width=26 --graph >output
+ grep " | " output >actual &&
+ test_cmp expect-graph actual
+ '
+done <<\EOF
+format-patch -1 --stdout
+diff HEAD^ HEAD --stat
+show --stat
+log -1 --stat
+EOF
+
+test_expect_success 'preparation for long filename tests' '
+ cp abcd aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &&
+ git add aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &&
+ git commit -m message
+'
+
+cat >expect <<'EOF'
+ ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 ++++++++++++
+EOF
+cat >expect-graph <<'EOF'
+| ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 ++++++++++++
+EOF
+while read cmd args
+do
+ test_expect_success "$cmd --stat=width with big change is more balanced" '
+ git $cmd $args --stat-width=60 >output &&
+ grep " | " output >actual &&
+ test_cmp expect actual
+ '
+
+ test "$cmd" != diff || continue
+
+ test_expect_success "$cmd --stat=width --graph with big change is balanced" '
+ git $cmd $args --stat-width=60 --graph >output &&
+ grep " | " output >actual &&
+ test_cmp expect-graph actual
+ '
+done <<\EOF
+format-patch -1 --stdout
+diff HEAD^ HEAD --stat
+show --stat
+log -1 --stat
+EOF
+
+cat >expect80 <<'EOF'
+ ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 ++++++++++++++++++++
+EOF
+cat >expect80-graph <<'EOF'
+| ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 ++++++++++++++++++++
+EOF
+cat >expect200 <<'EOF'
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+EOF
+cat >expect200-graph <<'EOF'
+| aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+EOF
+while read verb expect cmd args
+do
+ test_expect_success "$cmd $verb COLUMNS (long filename)" '
+ COLUMNS=200 git $cmd $args >output
+ grep " | " output >actual &&
+ test_cmp "$expect" actual
+ '
+
+ test "$cmd" != diff || continue
+
+ test_expect_success "$cmd --graph $verb COLUMNS (long filename)" '
+ COLUMNS=200 git $cmd $args --graph >output
+ grep " | " output >actual &&
+ test_cmp "$expect-graph" actual
+ '
+done <<\EOF
+ignores expect80 format-patch -1 --stdout
+respects expect200 diff HEAD^ HEAD --stat
+respects expect200 show --stat
+respects expect200 log -1 --stat
+EOF
+
+cat >expect1 <<'EOF'
+ ...aaaaaaa | 1000 ++++++
+EOF
+cat >expect1-graph <<'EOF'
+| ...aaaaaaa | 1000 ++++++
+EOF
+while read verb expect cmd args
+do
+ test_expect_success COLUMNS_CAN_BE_1 \
+ "$cmd $verb prefix greater than COLUMNS (big change)" '
+ COLUMNS=1 git $cmd $args >output
+ grep " | " output >actual &&
+ test_cmp "$expect" actual
+ '
+
+ test "$cmd" != diff || continue
+
+ test_expect_success COLUMNS_CAN_BE_1 \
+ "$cmd --graph $verb prefix greater than COLUMNS (big change)" '
+ COLUMNS=1 git $cmd $args --graph >output
+ grep " | " output >actual &&
+ test_cmp "$expect-graph" actual
+ '
+done <<\EOF
+ignores expect80 format-patch -1 --stdout
+respects expect1 diff HEAD^ HEAD --stat
+respects expect1 show --stat
+respects expect1 log -1 --stat
+EOF
+
+cat >expect <<'EOF'
+ abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+EOF
+test_expect_success 'merge --stat respects COLUMNS (big change)' '
+ git checkout -b branch HEAD^^ &&
+ COLUMNS=100 git merge --stat --no-ff master^ >output &&
+ grep " | " output >actual
+ test_cmp expect actual
+'
+
+cat >expect <<'EOF'
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 +++++++++++++++++++++++++++++++++++++++
+EOF
+test_expect_success 'merge --stat respects COLUMNS (long filename)' '
+ COLUMNS=100 git merge --stat --no-ff master >output &&
+ grep " | " output >actual
+ test_cmp expect actual
+'
+
+test_done
diff --git a/t/t4053-diff-no-index.sh b/t/t4053-diff-no-index.sh
new file mode 100755
index 0000000000..4dc8c67edc
--- /dev/null
+++ b/t/t4053-diff-no-index.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+test_description='diff --no-index'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+ mkdir a &&
+ mkdir b &&
+ echo 1 >a/1 &&
+ echo 2 >a/2
+'
+
+test_expect_success 'git diff --no-index directories' '
+ git diff --no-index a b >cnt
+ test $? = 1 && test_line_count = 14 cnt
+'
+
+test_done
diff --git a/t/t4150-am.sh b/t/t4150-am.sh
index 658354a6ce..ccc0280f52 100755
--- a/t/t4150-am.sh
+++ b/t/t4150-am.sh
@@ -238,7 +238,7 @@ test_expect_success 'am stays in branch' '
test_expect_success 'am --signoff does not add Signed-off-by: line if already there' '
git format-patch --stdout HEAD^ >patch3 &&
- sed -e "/^Subject/ s,\[PATCH,Re: Re: Re: & 1/5 v2," patch3 >patch4 &&
+ sed -e "/^Subject/ s,\[PATCH,Re: Re: Re: & 1/5 v2] [foo," patch3 >patch4 &&
rm -fr .git/rebase-apply &&
git reset --hard &&
git checkout HEAD^ &&
@@ -260,7 +260,17 @@ test_expect_success 'am --keep really keeps the subject' '
git am --keep patch4 &&
! test -d .git/rebase-apply &&
git cat-file commit HEAD >actual &&
- grep "Re: Re: Re: \[PATCH 1/5 v2\] third" actual
+ grep "Re: Re: Re: \[PATCH 1/5 v2\] \[foo\] third" actual
+'
+
+test_expect_success 'am --keep-non-patch really keeps the non-patch part' '
+ rm -fr .git/rebase-apply &&
+ git reset --hard &&
+ git checkout HEAD^ &&
+ git am --keep-non-patch patch4 &&
+ ! test -d .git/rebase-apply &&
+ git cat-file commit HEAD >actual &&
+ grep "^\[foo\] third" actual
'
test_expect_success 'am -3 falls back to 3-way merge' '
diff --git a/t/t4202-log.sh b/t/t4202-log.sh
index 222f7559e9..32cf0bd218 100755
--- a/t/t4202-log.sh
+++ b/t/t4202-log.sh
@@ -516,4 +516,294 @@ test_expect_success 'show added path under "--follow -M"' '
)
'
+cat >expect <<\EOF
+* commit COMMIT_OBJECT_NAME
+|\ Merge: MERGE_PARENTS
+| | Author: A U Thor <author@example.com>
+| |
+| | Merge HEADS DESCRIPTION
+| |
+| * commit COMMIT_OBJECT_NAME
+| | Author: A U Thor <author@example.com>
+| |
+| | reach
+| | ---
+| | reach.t | 1 +
+| | 1 file changed, 1 insertion(+)
+| |
+| | diff --git a/reach.t b/reach.t
+| | new file mode 100644
+| | index 0000000..10c9591
+| | --- /dev/null
+| | +++ b/reach.t
+| | @@ -0,0 +1 @@
+| | +reach
+| |
+| \
+*-. \ commit COMMIT_OBJECT_NAME
+|\ \ \ Merge: MERGE_PARENTS
+| | | | Author: A U Thor <author@example.com>
+| | | |
+| | | | Merge HEADS DESCRIPTION
+| | | |
+| | * | commit COMMIT_OBJECT_NAME
+| | |/ Author: A U Thor <author@example.com>
+| | |
+| | | octopus-b
+| | | ---
+| | | octopus-b.t | 1 +
+| | | 1 file changed, 1 insertion(+)
+| | |
+| | | diff --git a/octopus-b.t b/octopus-b.t
+| | | new file mode 100644
+| | | index 0000000..d5fcad0
+| | | --- /dev/null
+| | | +++ b/octopus-b.t
+| | | @@ -0,0 +1 @@
+| | | +octopus-b
+| | |
+| * | commit COMMIT_OBJECT_NAME
+| |/ Author: A U Thor <author@example.com>
+| |
+| | octopus-a
+| | ---
+| | octopus-a.t | 1 +
+| | 1 file changed, 1 insertion(+)
+| |
+| | diff --git a/octopus-a.t b/octopus-a.t
+| | new file mode 100644
+| | index 0000000..11ee015
+| | --- /dev/null
+| | +++ b/octopus-a.t
+| | @@ -0,0 +1 @@
+| | +octopus-a
+| |
+* | commit COMMIT_OBJECT_NAME
+|/ Author: A U Thor <author@example.com>
+|
+| seventh
+| ---
+| seventh.t | 1 +
+| 1 file changed, 1 insertion(+)
+|
+| diff --git a/seventh.t b/seventh.t
+| new file mode 100644
+| index 0000000..9744ffc
+| --- /dev/null
+| +++ b/seventh.t
+| @@ -0,0 +1 @@
+| +seventh
+|
+* commit COMMIT_OBJECT_NAME
+|\ Merge: MERGE_PARENTS
+| | Author: A U Thor <author@example.com>
+| |
+| | Merge branch 'tangle'
+| |
+| * commit COMMIT_OBJECT_NAME
+| |\ Merge: MERGE_PARENTS
+| | | Author: A U Thor <author@example.com>
+| | |
+| | | Merge branch 'side' (early part) into tangle
+| | |
+| * | commit COMMIT_OBJECT_NAME
+| |\ \ Merge: MERGE_PARENTS
+| | | | Author: A U Thor <author@example.com>
+| | | |
+| | | | Merge branch 'master' (early part) into tangle
+| | | |
+| * | | commit COMMIT_OBJECT_NAME
+| | | | Author: A U Thor <author@example.com>
+| | | |
+| | | | tangle-a
+| | | | ---
+| | | | tangle-a | 1 +
+| | | | 1 file changed, 1 insertion(+)
+| | | |
+| | | | diff --git a/tangle-a b/tangle-a
+| | | | new file mode 100644
+| | | | index 0000000..7898192
+| | | | --- /dev/null
+| | | | +++ b/tangle-a
+| | | | @@ -0,0 +1 @@
+| | | | +a
+| | | |
+* | | | commit COMMIT_OBJECT_NAME
+|\ \ \ \ Merge: MERGE_PARENTS
+| | | | | Author: A U Thor <author@example.com>
+| | | | |
+| | | | | Merge branch 'side'
+| | | | |
+| * | | | commit COMMIT_OBJECT_NAME
+| | |_|/ Author: A U Thor <author@example.com>
+| |/| |
+| | | | side-2
+| | | | ---
+| | | | 2 | 1 +
+| | | | 1 file changed, 1 insertion(+)
+| | | |
+| | | | diff --git a/2 b/2
+| | | | new file mode 100644
+| | | | index 0000000..0cfbf08
+| | | | --- /dev/null
+| | | | +++ b/2
+| | | | @@ -0,0 +1 @@
+| | | | +2
+| | | |
+| * | | commit COMMIT_OBJECT_NAME
+| | | | Author: A U Thor <author@example.com>
+| | | |
+| | | | side-1
+| | | | ---
+| | | | 1 | 1 +
+| | | | 1 file changed, 1 insertion(+)
+| | | |
+| | | | diff --git a/1 b/1
+| | | | new file mode 100644
+| | | | index 0000000..d00491f
+| | | | --- /dev/null
+| | | | +++ b/1
+| | | | @@ -0,0 +1 @@
+| | | | +1
+| | | |
+* | | | commit COMMIT_OBJECT_NAME
+| | | | Author: A U Thor <author@example.com>
+| | | |
+| | | | Second
+| | | | ---
+| | | | one | 1 +
+| | | | 1 file changed, 1 insertion(+)
+| | | |
+| | | | diff --git a/one b/one
+| | | | new file mode 100644
+| | | | index 0000000..9a33383
+| | | | --- /dev/null
+| | | | +++ b/one
+| | | | @@ -0,0 +1 @@
+| | | | +case
+| | | |
+* | | | commit COMMIT_OBJECT_NAME
+| |_|/ Author: A U Thor <author@example.com>
+|/| |
+| | | sixth
+| | | ---
+| | | a/two | 1 -
+| | | 1 file changed, 1 deletion(-)
+| | |
+| | | diff --git a/a/two b/a/two
+| | | deleted file mode 100644
+| | | index 9245af5..0000000
+| | | --- a/a/two
+| | | +++ /dev/null
+| | | @@ -1 +0,0 @@
+| | | -ni
+| | |
+* | | commit COMMIT_OBJECT_NAME
+| | | Author: A U Thor <author@example.com>
+| | |
+| | | fifth
+| | | ---
+| | | a/two | 1 +
+| | | 1 file changed, 1 insertion(+)
+| | |
+| | | diff --git a/a/two b/a/two
+| | | new file mode 100644
+| | | index 0000000..9245af5
+| | | --- /dev/null
+| | | +++ b/a/two
+| | | @@ -0,0 +1 @@
+| | | +ni
+| | |
+* | | commit COMMIT_OBJECT_NAME
+|/ / Author: A U Thor <author@example.com>
+| |
+| | fourth
+| | ---
+| | ein | 1 +
+| | 1 file changed, 1 insertion(+)
+| |
+| | diff --git a/ein b/ein
+| | new file mode 100644
+| | index 0000000..9d7e69f
+| | --- /dev/null
+| | +++ b/ein
+| | @@ -0,0 +1 @@
+| | +ichi
+| |
+* | commit COMMIT_OBJECT_NAME
+|/ Author: A U Thor <author@example.com>
+|
+| third
+| ---
+| ichi | 1 +
+| one | 1 -
+| 2 files changed, 1 insertion(+), 1 deletion(-)
+|
+| diff --git a/ichi b/ichi
+| new file mode 100644
+| index 0000000..9d7e69f
+| --- /dev/null
+| +++ b/ichi
+| @@ -0,0 +1 @@
+| +ichi
+| diff --git a/one b/one
+| deleted file mode 100644
+| index 9d7e69f..0000000
+| --- a/one
+| +++ /dev/null
+| @@ -1 +0,0 @@
+| -ichi
+|
+* commit COMMIT_OBJECT_NAME
+| Author: A U Thor <author@example.com>
+|
+| second
+| ---
+| one | 2 +-
+| 1 file changed, 1 insertion(+), 1 deletion(-)
+|
+| diff --git a/one b/one
+| index 5626abf..9d7e69f 100644
+| --- a/one
+| +++ b/one
+| @@ -1 +1 @@
+| -one
+| +ichi
+|
+* commit COMMIT_OBJECT_NAME
+ Author: A U Thor <author@example.com>
+
+ initial
+ ---
+ one | 1 +
+ 1 file changed, 1 insertion(+)
+
+ diff --git a/one b/one
+ new file mode 100644
+ index 0000000..5626abf
+ --- /dev/null
+ +++ b/one
+ @@ -0,0 +1 @@
+ +one
+EOF
+
+sanitize_output () {
+ sed -e 's/ *$//' \
+ -e 's/commit [0-9a-f]*$/commit COMMIT_OBJECT_NAME/' \
+ -e 's/Merge: [ 0-9a-f]*$/Merge: MERGE_PARENTS/' \
+ -e 's/Merge tag.*/Merge HEADS DESCRIPTION/' \
+ -e 's/Merge commit.*/Merge HEADS DESCRIPTION/' \
+ -e 's/, 0 deletions(-)//' \
+ -e 's/, 0 insertions(+)//' \
+ -e 's/ 1 files changed, / 1 file changed, /' \
+ -e 's/, 1 deletions(-)/, 1 deletion(-)/' \
+ -e 's/, 1 insertions(+)/, 1 insertion(+)/'
+}
+
+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_done
diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh
index 2ae9faa8b3..4afd77815f 100755
--- a/t/t4205-log-pretty-formats.sh
+++ b/t/t4205-log-pretty-formats.sh
@@ -71,4 +71,32 @@ test_expect_success 'alias loop' '
test_must_fail git log --pretty=test-foo
'
+test_expect_success 'NUL separation' '
+ printf "add bar\0initial" >expected &&
+ git log -z --pretty="format:%s" >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'NUL termination' '
+ printf "add bar\0initial\0" >expected &&
+ git log -z --pretty="tformat:%s" >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'NUL separation with --stat' '
+ stat0_part=$(git diff --stat HEAD^ HEAD) &&
+ 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_expect_failure 'NUL termination with --stat' '
+ stat0_part=$(git diff --stat HEAD^ HEAD) &&
+ 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_done
diff --git a/t/t4209-log-pickaxe.sh b/t/t4209-log-pickaxe.sh
new file mode 100755
index 0000000000..eed727341d
--- /dev/null
+++ b/t/t4209-log-pickaxe.sh
@@ -0,0 +1,119 @@
+#!/bin/sh
+
+test_description='log --grep/--author/--regexp-ignore-case/-S/-G'
+. ./test-lib.sh
+
+test_expect_success setup '
+ >file &&
+ git add file &&
+ test_tick &&
+ git commit -m initial &&
+
+ echo Picked >file &&
+ test_tick &&
+ git commit -a --author="Another Person <another@example.com>" -m second
+'
+
+test_expect_success 'log --grep' '
+ git log --grep=initial --format=%H >actual &&
+ git rev-parse --verify HEAD^ >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'log --grep --regexp-ignore-case' '
+ git log --regexp-ignore-case --grep=InItial --format=%H >actual &&
+ git rev-parse --verify HEAD^ >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'log --grep -i' '
+ git log -i --grep=InItial --format=%H >actual &&
+ git rev-parse --verify HEAD^ >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'log --author --regexp-ignore-case' '
+ git log --regexp-ignore-case --author=person --format=%H >actual &&
+ git rev-parse --verify HEAD >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'log --author -i' '
+ git log -i --author=person --format=%H >actual &&
+ git rev-parse --verify HEAD >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'log -G (nomatch)' '
+ git log -Gpicked --format=%H >actual &&
+ >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'log -G (match)' '
+ git log -GPicked --format=%H >actual &&
+ git rev-parse --verify HEAD >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'log -G --regexp-ignore-case (nomatch)' '
+ git log --regexp-ignore-case -Gpickle --format=%H >actual &&
+ >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'log -G -i (nomatch)' '
+ git log -i -Gpickle --format=%H >actual &&
+ >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'log -G --regexp-ignore-case (match)' '
+ git log --regexp-ignore-case -Gpicked --format=%H >actual &&
+ git rev-parse --verify HEAD >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'log -G -i (match)' '
+ git log -i -Gpicked --format=%H >actual &&
+ git rev-parse --verify HEAD >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'log -S (nomatch)' '
+ git log -Spicked --format=%H >actual &&
+ >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'log -S (match)' '
+ git log -SPicked --format=%H >actual &&
+ git rev-parse --verify HEAD >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'log -S --regexp-ignore-case (match)' '
+ git log --regexp-ignore-case -Spicked --format=%H >actual &&
+ git rev-parse --verify HEAD >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'log -S -i (match)' '
+ git log -i -Spicked --format=%H >actual &&
+ git rev-parse --verify HEAD >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'log -S --regexp-ignore-case (nomatch)' '
+ git log --regexp-ignore-case -Spickle --format=%H >actual &&
+ >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'log -S -i (nomatch)' '
+ git log -i -Spickle --format=%H >actual &&
+ >expect &&
+ test_cmp expect actual
+'
+
+test_done
diff --git a/t/t5100-mailinfo.sh b/t/t5100-mailinfo.sh
index ebc36c1758..81904d9ec8 100755
--- a/t/t5100-mailinfo.sh
+++ b/t/t5100-mailinfo.sh
@@ -65,7 +65,7 @@ test_expect_success 'respect NULs' '
git mailsplit -d3 -o. "$TEST_DIRECTORY"/t5100/nul-plain &&
test_cmp "$TEST_DIRECTORY"/t5100/nul-plain 001 &&
(cat 001 | git mailinfo msg patch) &&
- test 4 = $(wc -l < patch)
+ test_line_count = 4 patch
'
diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh
index 602806d09c..d9d856b87b 100755
--- a/t/t5300-pack-object.sh
+++ b/t/t5300-pack-object.sh
@@ -38,6 +38,10 @@ test_expect_success \
'pack without delta' \
'packname_1=$(git pack-objects --window=0 test-1 <obj-list)'
+test_expect_success \
+ 'pack-objects with bogus arguments' \
+ 'test_must_fail git pack-objects --window=0 test-1 blah blah <obj-list'
+
rm -fr .git2
mkdir .git2
diff --git a/t/t5302-pack-index.sh b/t/t5302-pack-index.sh
index f8fa92446c..fe82025d4a 100755
--- a/t/t5302-pack-index.sh
+++ b/t/t5302-pack-index.sh
@@ -74,6 +74,10 @@ test_expect_success 'index-pack --verify on index version 2' '
'
test_expect_success \
+ 'pack-objects --index-version=2, is not accepted' \
+ 'test_must_fail git pack-objects --index-version=2, test-3 <obj-list'
+
+test_expect_success \
'index v2: force some 64-bit offsets with pack-objects' \
'pack3=$(git pack-objects --index-version=2,0x40000 test-3 <obj-list)'
diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh
index 9bf69e9a0f..1d1ca98588 100755
--- a/t/t5500-fetch-pack.sh
+++ b/t/t5500-fetch-pack.sh
@@ -114,8 +114,19 @@ pull_to_client 2nd "refs/heads/B" $((64*3))
pull_to_client 3rd "refs/heads/A" $((1*3))
+test_expect_success 'single branch clone' '
+ git clone --single-branch "file://$(pwd)/." singlebranch
+'
+
+test_expect_success 'single branch object count' '
+ GIT_DIR=singlebranch/.git git count-objects -v |
+ grep "^in-pack:" > count.singlebranch &&
+ echo "in-pack: 198" >expected &&
+ test_cmp expected count.singlebranch
+'
+
test_expect_success 'clone shallow' '
- git clone --depth 2 "file://$(pwd)/." shallow
+ git clone --no-single-branch --depth 2 "file://$(pwd)/." shallow
'
test_expect_success 'clone shallow object count' '
@@ -248,4 +259,137 @@ test_expect_success 'clone shallow object count' '
grep "^count: 52" count.shallow
'
+test_expect_success 'clone shallow without --no-single-branch' '
+ git clone --depth 1 "file://$(pwd)/." shallow2
+'
+
+test_expect_success 'clone shallow object count' '
+ (
+ cd shallow2 &&
+ git count-objects -v
+ ) > count.shallow2 &&
+ grep "^in-pack: 6" count.shallow2
+'
+
+test_expect_success 'clone shallow with --branch' '
+ git clone --depth 1 --branch A "file://$(pwd)/." shallow3
+'
+
+test_expect_success 'clone shallow object count' '
+ echo "in-pack: 12" > count3.expected &&
+ GIT_DIR=shallow3/.git git count-objects -v |
+ grep "^in-pack" > count3.actual &&
+ test_cmp count3.expected count3.actual
+'
+
+test_expect_success 'clone shallow with detached HEAD' '
+ git checkout HEAD^ &&
+ git clone --depth 1 "file://$(pwd)/." shallow5 &&
+ git checkout - &&
+ GIT_DIR=shallow5/.git git rev-parse HEAD >actual &&
+ git rev-parse HEAD^ >expected &&
+ test_cmp expected actual
+'
+
+test_expect_success 'shallow clone pulling tags' '
+ git tag -a -m A TAGA1 A &&
+ git tag -a -m B TAGB1 B &&
+ git tag TAGA2 A &&
+ git tag TAGB2 B &&
+ git clone --depth 1 "file://$(pwd)/." shallow6 &&
+
+ cat >taglist.expected <<\EOF &&
+TAGB1
+TAGB2
+EOF
+ GIT_DIR=shallow6/.git git tag -l >taglist.actual &&
+ test_cmp taglist.expected taglist.actual &&
+
+ echo "in-pack: 7" > count6.expected &&
+ GIT_DIR=shallow6/.git git count-objects -v |
+ grep "^in-pack" > count6.actual &&
+ test_cmp count6.expected count6.actual
+'
+
+test_expect_success 'shallow cloning single tag' '
+ git clone --depth 1 --branch=TAGB1 "file://$(pwd)/." shallow7 &&
+ cat >taglist.expected <<\EOF &&
+TAGB1
+TAGB2
+EOF
+ GIT_DIR=shallow7/.git git tag -l >taglist.actual &&
+ test_cmp taglist.expected taglist.actual &&
+
+ echo "in-pack: 7" > count7.expected &&
+ GIT_DIR=shallow7/.git git count-objects -v |
+ grep "^in-pack" > count7.actual &&
+ test_cmp count7.expected count7.actual
+'
+
+test_expect_success 'setup tests for the --stdin parameter' '
+ for head in C D E F
+ do
+ add $head
+ done &&
+ for head in A B C D E F
+ do
+ git tag $head $head
+ done &&
+ cat >input <<-\EOF
+ refs/heads/C
+ refs/heads/A
+ refs/heads/D
+ refs/tags/C
+ refs/heads/B
+ refs/tags/A
+ refs/heads/E
+ refs/tags/B
+ refs/tags/E
+ refs/tags/D
+ EOF
+ sort <input >expect &&
+ (
+ echo refs/heads/E &&
+ echo refs/tags/E &&
+ cat input
+ ) >input.dup
+'
+
+test_expect_success 'fetch refs from cmdline' '
+ (
+ cd client &&
+ git fetch-pack --no-progress .. $(cat ../input)
+ ) >output &&
+ cut -d " " -f 2 <output | sort >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'fetch refs from stdin' '
+ (
+ cd client &&
+ git fetch-pack --stdin --no-progress .. <../input
+ ) >output &&
+ cut -d " " -f 2 <output | sort >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'fetch mixed refs from cmdline and stdin' '
+ (
+ cd client &&
+ tail -n +5 ../input |
+ git fetch-pack --stdin --no-progress .. $(head -n 4 ../input)
+ ) >output &&
+ cut -d " " -f 2 <output | sort >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'test duplicate refs from stdin' '
+ (
+ cd client &&
+ test_must_fail git fetch-pack --stdin --no-progress .. <../input.dup
+ ) >output &&
+ cut -d " " -f 2 <output | sort >actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh
index 308c02ea75..d7a19a1829 100755
--- a/t/t5510-fetch.sh
+++ b/t/t5510-fetch.sh
@@ -162,6 +162,36 @@ test_expect_success 'fetch following tags' '
'
+test_expect_success 'fetch uses remote ref names to describe new refs' '
+ cd "$D" &&
+ git init descriptive &&
+ (
+ cd descriptive &&
+ git config remote.o.url .. &&
+ git config remote.o.fetch "refs/heads/*:refs/crazyheads/*" &&
+ git config --add remote.o.fetch "refs/others/*:refs/heads/*" &&
+ git fetch o
+ ) &&
+ git tag -a -m "Descriptive tag" descriptive-tag &&
+ git branch descriptive-branch &&
+ git checkout descriptive-branch &&
+ echo "Nuts" >crazy &&
+ git add crazy &&
+ git commit -a -m "descriptive commit" &&
+ git update-ref refs/others/crazy HEAD &&
+ (
+ cd descriptive &&
+ git fetch o 2>actual &&
+ grep " -> refs/crazyheads/descriptive-branch$" actual |
+ test_i18ngrep "new branch" &&
+ grep " -> descriptive-tag$" actual |
+ test_i18ngrep "new tag" &&
+ grep " -> crazy$" actual |
+ test_i18ngrep "new ref"
+ ) &&
+ git checkout master
+'
+
test_expect_success 'fetch must not resolve short tag name' '
cd "$D" &&
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index b69cf574d7..b5417cc951 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -979,4 +979,20 @@ test_expect_success 'push --porcelain --dry-run rejected' '
test_cmp .git/foo .git/bar
'
+test_expect_success 'push --prune' '
+ mk_test heads/master heads/second heads/foo heads/bar &&
+ git push --prune testrepo &&
+ check_push_result $the_commit heads/master &&
+ check_push_result $the_first_commit heads/second &&
+ ! check_push_result $the_first_commit heads/foo heads/bar
+'
+
+test_expect_success 'push --prune refspec' '
+ mk_test tmp/master tmp/second tmp/foo tmp/bar &&
+ git push --prune testrepo "refs/heads/*:refs/tmp/*" &&
+ check_push_result $the_commit tmp/master &&
+ check_push_result $the_first_commit tmp/second &&
+ ! check_push_result $the_first_commit tmp/foo tmp/bar
+'
+
test_done
diff --git a/t/t5528-push-default.sh b/t/t5528-push-default.sh
new file mode 100755
index 0000000000..c334c51a07
--- /dev/null
+++ b/t/t5528-push-default.sh
@@ -0,0 +1,54 @@
+#!/bin/sh
+
+test_description='check various push.default settings'
+. ./test-lib.sh
+
+test_expect_success 'setup bare remotes' '
+ git init --bare repo1 &&
+ git remote add parent1 repo1 &&
+ git init --bare repo2 &&
+ git remote add parent2 repo2 &&
+ test_commit one &&
+ git push parent1 HEAD &&
+ git push parent2 HEAD
+'
+
+test_expect_success '"upstream" pushes to configured upstream' '
+ git checkout master &&
+ test_config branch.master.remote parent1 &&
+ test_config branch.master.merge refs/heads/foo &&
+ test_config push.default upstream &&
+ test_commit two &&
+ git push &&
+ echo two >expect &&
+ git --git-dir=repo1 log -1 --format=%s foo >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success '"upstream" does not push on unconfigured remote' '
+ git checkout master &&
+ test_unconfig branch.master.remote &&
+ test_config push.default upstream &&
+ test_commit three &&
+ test_must_fail git push
+'
+
+test_expect_success '"upstream" does not push on unconfigured branch' '
+ git checkout master &&
+ test_config branch.master.remote parent1 &&
+ test_unconfig branch.master.merge &&
+ test_config push.default upstream
+ test_commit four &&
+ test_must_fail git push
+'
+
+test_expect_success '"upstream" does not push when remotes do not match' '
+ git checkout master &&
+ test_config branch.master.remote parent1 &&
+ test_config branch.master.merge refs/heads/foo &&
+ test_config push.default upstream &&
+ test_commit five &&
+ test_must_fail git push parent2
+'
+
+test_done
diff --git a/t/t5541-http-push.sh b/t/t5541-http-push.sh
index cc6f081711..312e484090 100755
--- a/t/t5541-http-push.sh
+++ b/t/t5541-http-push.sh
@@ -30,6 +30,7 @@ test_expect_success 'setup remote repository' '
git clone --bare test_repo test_repo.git &&
cd test_repo.git &&
git config http.receivepack true &&
+ git config core.logallrefupdates true &&
ORIG_HEAD=$(git rev-parse --verify HEAD) &&
cd - &&
mv test_repo.git "$HTTPD_DOCUMENT_ROOT_PATH"
@@ -167,7 +168,7 @@ test_expect_success 'push fails for non-fast-forward refs unmatched by remote he
'
test_expect_success 'push fails for non-fast-forward refs unmatched by remote helper: our output' '
- test_i18ngrep "To prevent you from losing history, non-fast-forward updates were rejected" \
+ test_i18ngrep "Updates were rejected because" \
output
'
@@ -215,12 +216,55 @@ test_expect_success 'push --mirror to repo with alternates' '
git push --mirror "$HTTPD_URL"/smart/alternates-mirror.git
'
-test_expect_success TTY 'quiet push' '
+test_expect_success TTY 'push shows progress when stderr is a tty' '
+ cd "$ROOT_PATH"/test_repo_clone &&
+ test_commit noisy &&
+ test_terminal git push >output 2>&1 &&
+ grep "^Writing objects" output
+'
+
+test_expect_success TTY 'push --quiet silences status and progress' '
cd "$ROOT_PATH"/test_repo_clone &&
test_commit quiet &&
- test_terminal git push --quiet --no-progress 2>&1 | tee output &&
+ test_terminal git push --quiet >output 2>&1 &&
test_cmp /dev/null output
'
+test_expect_success TTY 'push --no-progress silences progress but not status' '
+ cd "$ROOT_PATH"/test_repo_clone &&
+ test_commit no-progress &&
+ test_terminal git push --no-progress >output 2>&1 &&
+ grep "^To http" output &&
+ ! grep "^Writing objects"
+'
+
+test_expect_success 'push --progress shows progress to non-tty' '
+ cd "$ROOT_PATH"/test_repo_clone &&
+ test_commit progress &&
+ git push --progress >output 2>&1 &&
+ grep "^To http" output &&
+ grep "^Writing objects" output
+'
+
+test_expect_success 'http push gives sane defaults to reflog' '
+ cd "$ROOT_PATH"/test_repo_clone &&
+ test_commit reflog-test &&
+ git push "$HTTPD_URL"/smart/test_repo.git &&
+ git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git" \
+ log -g -1 --format="%gn <%ge>" >actual &&
+ echo "anonymous <anonymous@http.127.0.0.1>" >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'http push respects GIT_COMMITTER_* in reflog' '
+ cd "$ROOT_PATH"/test_repo_clone &&
+ test_commit custom-reflog-test &&
+ git push "$HTTPD_URL"/smart_custom_env/test_repo.git &&
+ git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git" \
+ log -g -1 --format="%gn <%ge>" >actual &&
+ echo "Custom User <custom@example.com>" >expect &&
+ test_cmp expect actual
+'
+
stop_httpd
test_done
diff --git a/t/t5550-http-fetch.sh b/t/t5550-http-fetch.sh
index e5e6b8f643..b06f817af3 100755
--- a/t/t5550-http-fetch.sh
+++ b/t/t5550-http-fetch.sh
@@ -13,17 +13,22 @@ LIB_HTTPD_PORT=${LIB_HTTPD_PORT-'5550'}
start_httpd
test_expect_success 'setup repository' '
- echo content >file &&
+ echo content1 >file &&
git add file &&
git commit -m one
+ echo content2 >file &&
+ git add file &&
+ git commit -m two
'
-test_expect_success 'create http-accessible bare repository' '
- mkdir "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
+test_expect_success 'create http-accessible bare repository with loose objects' '
+ cp -a .git "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
(cd "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
- git --bare init &&
+ git config core.bare true &&
+ mkdir -p hooks &&
echo "exec git update-server-info" >hooks/post-update &&
- chmod +x hooks/post-update
+ chmod +x hooks/post-update &&
+ hooks/post-update
) &&
git remote add public "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
git push public master:master
diff --git a/t/t5551-http-fetch.sh b/t/t5551-http-fetch.sh
index 26d355725f..be6094be77 100755
--- a/t/t5551-http-fetch.sh
+++ b/t/t5551-http-fetch.sh
@@ -109,5 +109,36 @@ test_expect_success 'follow redirects (302)' '
git clone $HTTPD_URL/smart-redir-temp/repo.git --quiet repo-t
'
+test -n "$GIT_TEST_LONG" && test_set_prereq EXPENSIVE
+
+test_expect_success EXPENSIVE 'create 50,000 tags in the repo' '
+ (
+ cd "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
+ for i in `seq 50000`
+ do
+ echo "commit refs/heads/too-many-refs"
+ echo "mark :$i"
+ echo "committer git <git@example.com> $i +0000"
+ echo "data 0"
+ echo "M 644 inline bla.txt"
+ echo "data 4"
+ echo "bla"
+ # make every commit dangling by always
+ # rewinding the branch after each commit
+ echo "reset refs/heads/too-many-refs"
+ echo "from :1"
+ done | git fast-import --export-marks=marks &&
+
+ # now assign tags to all the dangling commits we created above
+ tag=$(perl -e "print \"bla\" x 30") &&
+ sed -e "s/^:\(.\+\) \(.\+\)$/\2 refs\/tags\/$tag-\1/" <marks >>packed-refs
+ )
+'
+
+test_expect_success EXPENSIVE 'clone the 50,000 tag repo to check OS command line overflow' '
+ git clone $HTTPD_URL/smart/repo.git too-many-refs 2>err &&
+ test_line_count = 0 err
+'
+
stop_httpd
test_done
diff --git a/t/t5570-git-daemon.sh b/t/t5570-git-daemon.sh
new file mode 100755
index 0000000000..7cbc9994a3
--- /dev/null
+++ b/t/t5570-git-daemon.sh
@@ -0,0 +1,148 @@
+#!/bin/sh
+
+test_description='test fetching over git protocol'
+. ./test-lib.sh
+
+LIB_GIT_DAEMON_PORT=${LIB_GIT_DAEMON_PORT-5570}
+. "$TEST_DIRECTORY"/lib-git-daemon.sh
+start_git_daemon
+
+test_expect_success 'setup repository' '
+ echo content >file &&
+ git add file &&
+ git commit -m one
+'
+
+test_expect_success 'create git-accessible bare repository' '
+ mkdir "$GIT_DAEMON_DOCUMENT_ROOT_PATH/repo.git" &&
+ (cd "$GIT_DAEMON_DOCUMENT_ROOT_PATH/repo.git" &&
+ git --bare init &&
+ : >git-daemon-export-ok
+ ) &&
+ git remote add public "$GIT_DAEMON_DOCUMENT_ROOT_PATH/repo.git" &&
+ git push public master:master
+'
+
+test_expect_success 'clone git repository' '
+ git clone "$GIT_DAEMON_URL/repo.git" clone &&
+ test_cmp file clone/file
+'
+
+test_expect_success 'fetch changes via git protocol' '
+ echo content >>file &&
+ git commit -a -m two &&
+ git push public &&
+ (cd clone && git pull) &&
+ test_cmp file clone/file
+'
+
+test_expect_failure 'remote detects correct HEAD' '
+ git push public master:other &&
+ (cd clone &&
+ git remote set-head -d origin &&
+ git remote set-head -a origin &&
+ git symbolic-ref refs/remotes/origin/HEAD > output &&
+ echo refs/remotes/origin/master > expect &&
+ test_cmp expect output
+ )
+'
+
+test_expect_success 'prepare pack objects' '
+ cp -R "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo.git "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_pack.git &&
+ (cd "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_pack.git &&
+ git --bare repack -a -d
+ )
+'
+
+test_expect_success 'fetch notices corrupt pack' '
+ cp -R "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_pack.git "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_bad1.git &&
+ (cd "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_bad1.git &&
+ p=`ls objects/pack/pack-*.pack` &&
+ chmod u+w $p &&
+ printf %0256d 0 | dd of=$p bs=256 count=1 seek=1 conv=notrunc
+ ) &&
+ mkdir repo_bad1.git &&
+ (cd repo_bad1.git &&
+ git --bare init &&
+ test_must_fail git --bare fetch "$GIT_DAEMON_URL/repo_bad1.git" &&
+ test 0 = `ls objects/pack/pack-*.pack | wc -l`
+ )
+'
+
+test_expect_success 'fetch notices corrupt idx' '
+ cp -R "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_pack.git "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_bad2.git &&
+ (cd "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_bad2.git &&
+ p=`ls objects/pack/pack-*.idx` &&
+ chmod u+w $p &&
+ printf %0256d 0 | dd of=$p bs=256 count=1 seek=1 conv=notrunc
+ ) &&
+ mkdir repo_bad2.git &&
+ (cd repo_bad2.git &&
+ git --bare init &&
+ test_must_fail git --bare fetch "$GIT_DAEMON_URL/repo_bad2.git" &&
+ test 0 = `ls objects/pack | wc -l`
+ )
+'
+
+test_remote_error()
+{
+ do_export=YesPlease
+ while test $# -gt 0
+ do
+ case $1 in
+ -x)
+ shift
+ chmod -x "$GIT_DAEMON_DOCUMENT_ROOT_PATH/repo.git"
+ ;;
+ -n)
+ shift
+ do_export=
+ ;;
+ *)
+ break
+ esac
+ done
+
+ if test $# -ne 3
+ then
+ error "invalid number of arguments"
+ fi
+
+ cmd=$1
+ repo=$2
+ msg=$3
+
+ if test -x "$GIT_DAEMON_DOCUMENT_ROOT_PATH/$repo"
+ then
+ if test -n "$do_export"
+ then
+ : >"$GIT_DAEMON_DOCUMENT_ROOT_PATH/$repo/git-daemon-export-ok"
+ else
+ rm -f "$GIT_DAEMON_DOCUMENT_ROOT_PATH/$repo/git-daemon-export-ok"
+ fi
+ fi
+
+ test_must_fail git "$cmd" "$GIT_DAEMON_URL/$repo" 2>output &&
+ echo "fatal: remote error: $msg: /$repo" >expect &&
+ test_cmp expect output
+ ret=$?
+ chmod +x "$GIT_DAEMON_DOCUMENT_ROOT_PATH/repo.git"
+ (exit $ret)
+}
+
+msg="access denied or repository not exported"
+test_expect_success 'clone non-existent' "test_remote_error clone nowhere.git '$msg'"
+test_expect_success 'push disabled' "test_remote_error push repo.git '$msg'"
+test_expect_success 'read access denied' "test_remote_error -x fetch repo.git '$msg'"
+test_expect_success 'not exported' "test_remote_error -n fetch repo.git '$msg'"
+
+stop_git_daemon
+start_git_daemon --informative-errors
+
+test_expect_success 'clone non-existent' "test_remote_error clone nowhere.git 'no such repository'"
+test_expect_success 'push disabled' "test_remote_error push repo.git 'service not enabled'"
+test_expect_success 'read access denied' "test_remote_error -x fetch repo.git 'no such repository'"
+test_expect_success 'not exported' "test_remote_error -n fetch repo.git 'repository not exported'"
+
+stop_git_daemon
+test_done
diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh
index 87ee01662c..67869b4813 100755
--- a/t/t5601-clone.sh
+++ b/t/t5601-clone.sh
@@ -9,10 +9,13 @@ test_expect_success setup '
rm -fr .git &&
test_create_repo src &&
(
- cd src
- >file
- git add file
- git commit -m initial
+ cd src &&
+ >file &&
+ git add file &&
+ git commit -m initial &&
+ echo 1 >file &&
+ git add file &&
+ git commit -m updated
)
'
@@ -88,6 +91,26 @@ test_expect_success 'clone --mirror' '
'
+test_expect_success 'clone --mirror with detached HEAD' '
+
+ ( cd src && git checkout HEAD^ && git rev-parse HEAD >../expected ) &&
+ git clone --mirror src mirror.detached &&
+ ( cd src && git checkout - ) &&
+ GIT_DIR=mirror.detached git rev-parse HEAD >actual &&
+ test_cmp expected actual
+
+'
+
+test_expect_success 'clone --bare with detached HEAD' '
+
+ ( cd src && git checkout HEAD^ && git rev-parse HEAD >../expected ) &&
+ git clone --bare src bare.detached &&
+ ( cd src && git checkout - ) &&
+ GIT_DIR=bare.detached git rev-parse HEAD >actual &&
+ test_cmp expected actual
+
+'
+
test_expect_success 'clone --bare names the local repository <name>.git' '
git clone --bare src &&
@@ -248,4 +271,13 @@ test_expect_success 'clone from original with relative alternate' '
grep /src/\\.git/objects target-10/objects/info/alternates
'
+test_expect_success 'clone checking out a tag' '
+ git clone --branch=some-tag src dst.tag &&
+ GIT_DIR=src/.git git rev-parse some-tag >expected &&
+ test_cmp expected dst.tag/.git/HEAD &&
+ GIT_DIR=dst.tag/.git git config remote.origin.fetch >fetch.actual &&
+ echo "+refs/heads/*:refs/remotes/origin/*" >fetch.expected &&
+ test_cmp fetch.expected fetch.actual
+'
+
test_done
diff --git a/t/t5700-clone-reference.sh b/t/t5700-clone-reference.sh
index c4c375ac04..c47d450cc3 100755
--- a/t/t5700-clone-reference.sh
+++ b/t/t5700-clone-reference.sh
@@ -34,7 +34,7 @@ test_expect_success 'cloning with reference (-l -s)' \
cd "$base_dir"
test_expect_success 'existence of info/alternates' \
-'test `wc -l <C/.git/objects/info/alternates` = 2'
+'test_line_count = 2 C/.git/objects/info/alternates'
cd "$base_dir"
@@ -52,18 +52,18 @@ test_cmp expected current'
cd "$base_dir"
-rm -f "$U"
+rm -f "$U.D"
test_expect_success 'cloning with reference (no -l -s)' \
-'GIT_DEBUG_SEND_PACK=3 git clone --reference B "file://$(pwd)/A" D 3>"$U"'
+'GIT_DEBUG_SEND_PACK=3 git clone --reference B "file://$(pwd)/A" D 3>"$U.D"'
test_expect_success 'fetched no objects' \
-'! grep "^want" "$U"'
+'! grep "^want" "$U.D"'
cd "$base_dir"
test_expect_success 'existence of info/alternates' \
-'test `wc -l <D/.git/objects/info/alternates` = 1'
+'test_line_count = 1 D/.git/objects/info/alternates'
cd "$base_dir"
@@ -153,4 +153,32 @@ test_expect_success 'clone with reference from a tagged repository' '
git clone --reference=A A I
'
+test_expect_success 'prepare branched repository' '
+ git clone A J &&
+ (
+ cd J &&
+ git checkout -b other master^ &&
+ echo other >otherfile &&
+ git add otherfile &&
+ git commit -m other &&
+ git checkout master
+ )
+'
+
+rm -f "$U.K"
+
+test_expect_success 'fetch with incomplete alternates' '
+ git init K &&
+ echo "$base_dir/A/.git/objects" >K/.git/objects/info/alternates &&
+ (
+ cd K &&
+ git remote add J "file://$base_dir/J" &&
+ GIT_DEBUG_SEND_PACK=3 git fetch J 3>"$U.K"
+ ) &&
+ master_object=$(cd A && git for-each-ref --format="%(objectname)" refs/heads/master) &&
+ ! grep "^want $master_object" "$U.K" &&
+ tag_object=$(cd A && git for-each-ref --format="%(objectname)" refs/tags/HEAD) &&
+ ! grep "^want $tag_object" "$U.K"
+'
+
test_done
diff --git a/t/t5706-clone-branch.sh b/t/t5706-clone-branch.sh
index f3f9a76056..56be67e07e 100755
--- a/t/t5706-clone-branch.sh
+++ b/t/t5706-clone-branch.sh
@@ -57,12 +57,8 @@ test_expect_success 'clone -b does not munge remotes/origin/HEAD' '
)
'
-test_expect_success 'clone -b with bogus branch chooses HEAD' '
- git clone -b bogus parent clone-bogus &&
- (cd clone-bogus &&
- check_HEAD master &&
- check_file one
- )
+test_expect_success 'clone -b with bogus branch' '
+ test_must_fail git clone -b bogus parent clone-bogus
'
test_done
diff --git a/t/t5710-info-alternate.sh b/t/t5710-info-alternate.sh
index ef7127c1b3..aa045295de 100755
--- a/t/t5710-info-alternate.sh
+++ b/t/t5710-info-alternate.sh
@@ -18,7 +18,7 @@ reachable_via() {
test_valid_repo() {
git fsck --full > fsck.log &&
- test `wc -l < fsck.log` = 0
+ test_line_count = 0 fsck.log
}
base_dir=`pwd`
diff --git a/t/t5800-remote-helpers.sh b/t/t5800-remote-helpers.sh
index 1c62001fce..5702334510 100755
--- a/t/t5800-remote-helpers.sh
+++ b/t/t5800-remote-helpers.sh
@@ -72,6 +72,19 @@ test_expect_success 'pushing to local repo' '
compare_refs localclone HEAD server HEAD
'
+# Generally, skip this test. It demonstrates a now-fixed race in
+# 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 &&
+ git clone "testgit::${PWD}/server2" localclone2 &&
+ (cd localclone2 &&
+ echo content >>file &&
+ git commit -a -m three &&
+ GIT_REMOTE_TESTGIT_SLEEPY=2 git push) &&
+ compare_refs localclone2 HEAD server2 HEAD
+'
+
test_expect_success 'synch with changes from localclone' '
(cd clone &&
git pull)
diff --git a/t/t6006-rev-list-format.sh b/t/t6006-rev-list-format.sh
index 444279077e..a01d244502 100755
--- a/t/t6006-rev-list-format.sh
+++ b/t/t6006-rev-list-format.sh
@@ -188,23 +188,23 @@ test_expect_success 'empty email' '
test_expect_success 'del LF before empty (1)' '
git show -s --pretty=format:"%s%n%-b%nThanks%n" HEAD^^ >actual &&
- test $(wc -l <actual) = 2
+ test_line_count = 2 actual
'
test_expect_success 'del LF before empty (2)' '
git show -s --pretty=format:"%s%n%-b%nThanks%n" HEAD >actual &&
- test $(wc -l <actual) = 6 &&
+ test_line_count = 6 actual &&
grep "^$" actual
'
test_expect_success 'add LF before non-empty (1)' '
git show -s --pretty=format:"%s%+b%nThanks%n" HEAD^^ >actual &&
- test $(wc -l <actual) = 2
+ test_line_count = 2 actual
'
test_expect_success 'add LF before non-empty (2)' '
git show -s --pretty=format:"%s%+b%nThanks%n" HEAD >actual &&
- test $(wc -l <actual) = 6 &&
+ test_line_count = 6 actual &&
grep "^$" actual
'
@@ -278,8 +278,9 @@ test_expect_success 'oneline with empty message' '
git commit -m "dummy" --allow-empty &&
git filter-branch --msg-filter "sed -e s/dummy//" HEAD^^.. &&
git rev-list --oneline HEAD >test.txt &&
- test $(git rev-list --oneline HEAD | wc -l) -eq 5 &&
- test $(git rev-list --oneline --graph HEAD | wc -l) -eq 5
+ test_line_count = 5 test.txt &&
+ git rev-list --oneline --graph HEAD >testg.txt &&
+ test_line_count = 5 testg.txt
'
test_done
diff --git a/t/t6022-merge-rename.sh b/t/t6022-merge-rename.sh
index 9d8584e957..1104249182 100755
--- a/t/t6022-merge-rename.sh
+++ b/t/t6022-merge-rename.sh
@@ -884,4 +884,20 @@ test_expect_success 'no spurious "refusing to lose untracked" message' '
! grep "refusing to lose untracked file" errors.txt
'
+test_expect_success 'do not follow renames for empty files' '
+ git checkout -f -b empty-base &&
+ >empty1 &&
+ git add empty1 &&
+ git commit -m base &&
+ echo content >empty1 &&
+ git add empty1 &&
+ git commit -m fill &&
+ git checkout -b empty-topic HEAD^ &&
+ git mv empty1 empty2 &&
+ git commit -m rename &&
+ test_must_fail git merge empty-base &&
+ >expect &&
+ test_cmp expect empty2
+'
+
test_done
diff --git a/t/t6028-merge-up-to-date.sh b/t/t6028-merge-up-to-date.sh
index a91644e3b2..c518e9c30c 100755
--- a/t/t6028-merge-up-to-date.sh
+++ b/t/t6028-merge-up-to-date.sh
@@ -16,7 +16,12 @@ test_expect_success setup '
test_tick &&
git commit -m second &&
git tag c1 &&
- git branch test
+ git branch test &&
+ echo third >file &&
+ git add file &&
+ test_tick &&
+ git commit -m third &&
+ git tag c2
'
test_expect_success 'merge -s recursive up-to-date' '
@@ -74,4 +79,14 @@ test_expect_success 'merge -s subtree up-to-date' '
'
+test_expect_success 'merge fast-forward octopus' '
+
+ git reset --hard c0 &&
+ test_tick &&
+ git merge c1 c2
+ expect=$(git rev-parse c2) &&
+ current=$(git rev-parse HEAD) &&
+ test "$expect" = "$current"
+'
+
test_done
diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 691e4a4481..72e28ee535 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -480,7 +480,7 @@ test_expect_success 'many merge bases creation' '
git merge -m "merge HASH7 and SIDE_HASH7" "$HASH7" &&
B_HASH=$(git rev-parse --verify HEAD) &&
git merge-base --all "$A_HASH" "$B_HASH" > merge_bases.txt &&
- test $(wc -l < merge_bases.txt) = "2" &&
+ test_line_count = 2 merge_bases.txt &&
grep "$HASH5" merge_bases.txt &&
grep "$SIDE_HASH5" merge_bases.txt
'
diff --git a/t/t6032-merge-large-rename.sh b/t/t6032-merge-large-rename.sh
index 94f010be8a..15beecc3c6 100755
--- a/t/t6032-merge-large-rename.sh
+++ b/t/t6032-merge-large-rename.sh
@@ -97,7 +97,7 @@ test_expect_success 'setup large simple rename' '
test_expect_success 'massive simple rename does not spam added files' '
sane_unset GIT_MERGE_VERBOSITY &&
git merge --no-stat simple-rename | grep -v Removing >output &&
- test 5 -gt "$(wc -l < output)"
+ test_line_count -lt 5 output
'
test_done
diff --git a/t/t6042-merge-rename-corner-cases.sh b/t/t6042-merge-rename-corner-cases.sh
index 32591f9413..466fa3804b 100755
--- a/t/t6042-merge-rename-corner-cases.sh
+++ b/t/t6042-merge-rename-corner-cases.sh
@@ -104,7 +104,7 @@ test_expect_failure 'conflict caused if rename not detected' '
test 0 -eq $(git ls-files -u | wc -l) &&
test 0 -eq $(git ls-files -o | wc -l) &&
- test 6 -eq $(wc -l < c) &&
+ test_line_count = 6 c &&
test $(git rev-parse HEAD:a) = $(git rev-parse B:a) &&
test $(git rev-parse HEAD:b) = $(git rev-parse A:b)
'
diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh
index 4ef79aabc4..f8c247a750 100755
--- a/t/t7004-tag.sh
+++ b/t/t7004-tag.sh
@@ -1282,4 +1282,43 @@ test_expect_success 'mixing incompatibles modes and options is forbidden' '
test_must_fail git tag -v -s
'
+# check points-at
+
+test_expect_success '--points-at cannot be used in non-list mode' '
+ test_must_fail git tag --points-at=v4.0 foo
+'
+
+test_expect_success '--points-at finds lightweight tags' '
+ echo v4.0 >expect &&
+ git tag --points-at v4.0 >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success '--points-at finds annotated tags of commits' '
+ git tag -m "v4.0, annotated" annotated-v4.0 v4.0 &&
+ echo annotated-v4.0 >expect &&
+ git tag -l --points-at v4.0 "annotated*" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success '--points-at finds annotated tags of tags' '
+ git tag -m "describing the v4.0 tag object" \
+ annotated-again-v4.0 annotated-v4.0 &&
+ cat >expect <<-\EOF &&
+ annotated-again-v4.0
+ annotated-v4.0
+ EOF
+ git tag --points-at=annotated-v4.0 >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'multiple --points-at are OR-ed together' '
+ cat >expect <<-\EOF &&
+ v2.0
+ v3.0
+ EOF
+ git tag --points-at=v2.0 --points-at=v3.0 >actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t7201-co.sh b/t/t7201-co.sh
index 07fb53adcb..be9672e5a0 100755
--- a/t/t7201-co.sh
+++ b/t/t7201-co.sh
@@ -229,7 +229,7 @@ test_expect_success 'checkout to detach HEAD (with advice declined)' '
git checkout -f renamer && git clean -f &&
git checkout renamer^ 2>messages &&
test_i18ngrep "HEAD is now at 7329388" messages &&
- test 1 -eq $(wc -l <messages) &&
+ test_line_count = 1 messages &&
H=$(git rev-parse --verify HEAD) &&
M=$(git show-ref -s --verify refs/heads/master) &&
test "z$H" = "z$M" &&
@@ -247,7 +247,7 @@ test_expect_success 'checkout to detach HEAD' '
git checkout -f renamer && git clean -f &&
git checkout renamer^ 2>messages &&
test_i18ngrep "HEAD is now at 7329388" messages &&
- test 1 -lt $(wc -l <messages) &&
+ test_line_count -gt 1 messages &&
H=$(git rev-parse --verify HEAD) &&
M=$(git show-ref -s --verify refs/heads/master) &&
test "z$H" = "z$M" &&
diff --git a/t/t7300-clean.sh b/t/t7300-clean.sh
index 800b5368a5..ccfb54de7a 100755
--- a/t/t7300-clean.sh
+++ b/t/t7300-clean.sh
@@ -399,8 +399,8 @@ test_expect_success SANITY 'removal failure' '
'
test_expect_success 'nested git work tree' '
- rm -fr foo bar &&
- mkdir foo bar &&
+ rm -fr foo bar baz &&
+ mkdir -p foo bar baz/boo &&
(
cd foo &&
git init &&
@@ -412,15 +412,24 @@ test_expect_success 'nested git work tree' '
cd bar &&
>goodbye.people
) &&
+ (
+ cd baz/boo &&
+ git init &&
+ >deeper.world
+ git add . &&
+ git commit -a -m deeply.nested
+ ) &&
git clean -f -d &&
test -f foo/.git/index &&
test -f foo/hello.world &&
+ test -f baz/boo/.git/index &&
+ test -f baz/boo/deeper.world &&
! test -d bar
'
test_expect_success 'force removal of nested git work tree' '
- rm -fr foo bar &&
- mkdir foo bar &&
+ rm -fr foo bar baz &&
+ mkdir -p foo bar baz/boo &&
(
cd foo &&
git init &&
@@ -432,9 +441,17 @@ test_expect_success 'force removal of nested git work tree' '
cd bar &&
>goodbye.people
) &&
+ (
+ cd baz/boo &&
+ git init &&
+ >deeper.world
+ git add . &&
+ git commit -a -m deeply.nested
+ ) &&
git clean -f -f -d &&
! test -d foo &&
- ! test -d bar
+ ! test -d bar &&
+ ! test -d baz
'
test_expect_success 'git clean -e' '
diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh
index 695f7afdf3..81827e696f 100755
--- a/t/t7400-submodule-basic.sh
+++ b/t/t7400-submodule-basic.sh
@@ -79,6 +79,15 @@ test_expect_success 'submodule add' '
cd addtest &&
git submodule add -q "$submodurl" submod >actual &&
test ! -s actual &&
+ echo "gitdir: ../.git/modules/submod" >expect &&
+ test_cmp expect submod/.git &&
+ (
+ cd submod &&
+ git config core.worktree >actual &&
+ echo "../../../submod" >expect &&
+ test_cmp expect actual &&
+ rm -f actual expect
+ ) &&
git submodule init
) &&
@@ -225,7 +234,7 @@ EOF
test_expect_success 'status should only print one line' '
git submodule status >lines &&
- test $(wc -l <lines) = 1
+ test_line_count = 1 lines
'
test_expect_success 'setup - fetch commit name from submodule' '
@@ -498,4 +507,17 @@ test_expect_success 'relative path works with user@host:path' '
)
'
+test_expect_success 'moving the superproject does not break submodules' '
+ (
+ cd addtest &&
+ git submodule status >expect
+ )
+ mv addtest addtest2 &&
+ (
+ cd addtest2 &&
+ git submodule status >actual &&
+ test_cmp expect actual
+ )
+'
+
test_done
diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh
index 5b97222c48..dcb195b4cf 100755
--- a/t/t7406-submodule-update.sh
+++ b/t/t7406-submodule-update.sh
@@ -619,4 +619,21 @@ test_expect_success 'submodule add properly re-creates deeper level submodules'
)
'
+test_expect_success 'submodule update properly revives a moved submodule' '
+ (cd super &&
+ git commit -am "pre move" &&
+ git status >expect&&
+ H=$(cd submodule2; git rev-parse HEAD) &&
+ git rm --cached submodule2 &&
+ rm -rf submodule2 &&
+ mkdir -p "moved/sub module" &&
+ git update-index --add --cacheinfo 160000 $H "moved/sub module" &&
+ git config -f .gitmodules submodule.submodule2.path "moved/sub module"
+ git commit -am "post move" &&
+ git submodule update &&
+ git status >actual &&
+ test_cmp expect actual
+ )
+'
+
test_done
diff --git a/t/t7408-submodule-reference.sh b/t/t7408-submodule-reference.sh
index ab37c368d0..b770b2f04d 100755
--- a/t/t7408-submodule-reference.sh
+++ b/t/t7408-submodule-reference.sh
@@ -28,7 +28,7 @@ git prune'
cd "$base_dir"
-test_expect_success 'preparing supermodule' \
+test_expect_success 'preparing superproject' \
'test_create_repo super && cd super &&
echo file > file &&
git add file &&
@@ -43,7 +43,7 @@ git commit -m B-super-added'
cd "$base_dir"
test_expect_success 'after add: existence of info/alternates' \
-'test `wc -l <super/.git/modules/sub/objects/info/alternates` = 1'
+'test_line_count = 1 super/.git/modules/sub/objects/info/alternates'
cd "$base_dir"
@@ -55,7 +55,7 @@ diff expected current'
cd "$base_dir"
-test_expect_success 'cloning supermodule' \
+test_expect_success 'cloning superproject' \
'git clone super super-clone'
cd "$base_dir"
@@ -66,7 +66,7 @@ test_expect_success 'update with reference' \
cd "$base_dir"
test_expect_success 'after update: existence of info/alternates' \
-'test `wc -l <super-clone/.git/modules/sub/objects/info/alternates` = 1'
+'test_line_count = 1 super-clone/.git/modules/sub/objects/info/alternates'
cd "$base_dir"
diff --git a/t/t7501-commit.sh b/t/t7501-commit.sh
index 8bb38337a9..b20ca0eace 100755
--- a/t/t7501-commit.sh
+++ b/t/t7501-commit.sh
@@ -30,10 +30,12 @@ test_expect_success 'setup: initial commit' '
'
test_expect_success '-m and -F do not mix' '
+ git checkout HEAD file && echo >>file && git add file &&
test_must_fail git commit -m foo -m bar -F file
'
test_expect_success '-m and -C do not mix' '
+ git checkout HEAD file && echo >>file && git add file &&
test_must_fail git commit -C HEAD -m illegal
'
@@ -79,7 +81,19 @@ test_expect_success 'empty commit message' '
test_must_fail git commit -F msg -a
'
+test_expect_success 'template "emptyness" check does not kick in with -F' '
+ git checkout HEAD file && echo >>file && git add file &&
+ git commit -t file -F file
+'
+
+test_expect_success 'template "emptyness" check' '
+ git checkout HEAD file && echo >>file && git add file &&
+ test_must_fail git commit -t file 2>err &&
+ test_i18ngrep "did not edit" err
+'
+
test_expect_success 'setup: commit message from file' '
+ git checkout HEAD file && echo >>file && git add file &&
echo this is the commit message, coming from a file >msg &&
git commit -F msg -a
'
diff --git a/t/t7502-commit.sh b/t/t7502-commit.sh
index 3f3adc31b9..181456aa9a 100755
--- a/t/t7502-commit.sh
+++ b/t/t7502-commit.sh
@@ -335,7 +335,7 @@ test_expect_success 'A single-liner subject with a token plus colon is not a foo
git reset --hard &&
git commit -s -m "hello: kitty" --allow-empty &&
git cat-file commit HEAD | sed -e "1,/^$/d" >actual &&
- test $(wc -l <actual) = 3
+ test_line_count = 3 actual
'
diff --git a/t/t7503-pre-commit-hook.sh b/t/t7503-pre-commit-hook.sh
index ee7f0cd459..984889b39d 100755
--- a/t/t7503-pre-commit-hook.sh
+++ b/t/t7503-pre-commit-hook.sh
@@ -118,4 +118,22 @@ test_expect_success 'with failing hook requiring GIT_PREFIX' '
git checkout -- file
'
+test_expect_success 'check the author in hook' '
+ write_script "$HOOK" <<-\EOF &&
+ test "$GIT_AUTHOR_NAME" = "New Author" &&
+ test "$GIT_AUTHOR_EMAIL" = "newauthor@example.com"
+ EOF
+ test_must_fail git commit --allow-empty -m "by a.u.thor" &&
+ (
+ GIT_AUTHOR_NAME="New Author" &&
+ GIT_AUTHOR_EMAIL="newauthor@example.com" &&
+ export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL &&
+ git commit --allow-empty -m "by new.author via env" &&
+ git show -s
+ ) &&
+ git commit --author="New Author <newauthor@example.com>" \
+ --allow-empty -m "by new.author via command line" &&
+ git show -s
+'
+
test_done
diff --git a/t/t7508-status.sh b/t/t7508-status.sh
index fc57b135c5..5d0e79fe2a 100755
--- a/t/t7508-status.sh
+++ b/t/t7508-status.sh
@@ -271,6 +271,15 @@ test_expect_success 'status -s -b' '
'
+test_expect_success 'status -s -z -b' '
+ tr "\\n" Q <expect >expect.q &&
+ mv expect.q expect &&
+ git status -s -z -b >output &&
+ nul_to_q <output >output.q &&
+ mv output.q output &&
+ test_cmp expect output
+'
+
test_expect_success 'setup dir3' '
mkdir dir3 &&
: >dir3/untracked1 &&
@@ -647,9 +656,14 @@ test_expect_success 'status --porcelain ignores color.status' '
git config --unset color.status
git config --unset color.ui
-test_expect_success 'status --porcelain ignores -b' '
+test_expect_success 'status --porcelain respects -b' '
git status --porcelain -b >output &&
+ {
+ echo "## master" &&
+ cat expect
+ } >tmp &&
+ mv tmp expect &&
test_cmp expect output
'
diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh
index 5783ebf3ab..7117b57ccc 100755
--- a/t/t7602-merge-octopus-many.sh
+++ b/t/t7602-merge-octopus-many.sh
@@ -70,17 +70,15 @@ test_expect_success 'merge output uses pretty names' '
'
cat >expected <<\EOF
-Already up-to-date with c4
-Trying simple merge with c5
-Merge made by the 'octopus' strategy.
+Merge made by the 'recursive' strategy.
c5.c | 1 +
1 file changed, 1 insertion(+)
create mode 100644 c5.c
EOF
-test_expect_success 'merge up-to-date output uses pretty names' '
- git merge c4 c5 >actual &&
- test_cmp actual expected
+test_expect_success 'merge reduces irrelevant remote heads' '
+ GIT_MERGE_VERBOSITY=0 git merge c4 c5 >actual &&
+ test_cmp expected actual
'
cat >expected <<\EOF
diff --git a/t/t7603-merge-reduce-heads.sh b/t/t7603-merge-reduce-heads.sh
index 7e17eb490d..98948955ae 100755
--- a/t/t7603-merge-reduce-heads.sh
+++ b/t/t7603-merge-reduce-heads.sh
@@ -57,7 +57,36 @@ test_expect_success 'merge c1 with c2, c3, c4, c5' '
test -f c2.c &&
test -f c3.c &&
test -f c4.c &&
- test -f c5.c
+ test -f c5.c &&
+ git show --format=%s -s >actual &&
+ ! grep c1 actual &&
+ grep c2 actual &&
+ grep c3 actual &&
+ ! grep c4 actual &&
+ grep c5 actual
+'
+
+test_expect_success 'pull c2, c3, c4, c5 into c1' '
+ git reset --hard c1 &&
+ git pull . c2 c3 c4 c5 &&
+ test "$(git rev-parse c1)" != "$(git rev-parse HEAD)" &&
+ test "$(git rev-parse c1)" = "$(git rev-parse HEAD^1)" &&
+ test "$(git rev-parse c2)" = "$(git rev-parse HEAD^2)" &&
+ test "$(git rev-parse c3)" = "$(git rev-parse HEAD^3)" &&
+ test "$(git rev-parse c5)" = "$(git rev-parse HEAD^4)" &&
+ git diff --exit-code &&
+ test -f c0.c &&
+ test -f c1.c &&
+ test -f c2.c &&
+ test -f c3.c &&
+ test -f c4.c &&
+ test -f c5.c &&
+ git show --format=%s -s >actual &&
+ ! grep c1 actual &&
+ grep c2 actual &&
+ grep c3 actual &&
+ ! grep c4 actual &&
+ grep c5 actual
'
test_expect_success 'setup' '
@@ -113,4 +142,23 @@ test_expect_success 'verify merge result' '
test $(git rev-parse HEAD^1) = $(git rev-parse E2) &&
test $(git rev-parse HEAD^2) = $(git rev-parse I2)
'
+
+test_expect_success 'fast-forward to redundant refs' '
+ git reset --hard c0 &&
+ git merge c4 c5
+'
+
+test_expect_success 'verify merge result' '
+ test $(git rev-parse HEAD) = $(git rev-parse c5)
+'
+
+test_expect_success 'merge up-to-date redundant refs' '
+ git reset --hard c5 &&
+ git merge c0 c4
+'
+
+test_expect_success 'verify merge result' '
+ test $(git rev-parse HEAD) = $(git rev-parse c5)
+'
+
test_done
diff --git a/t/t7701-repack-unpack-unreachable.sh b/t/t7701-repack-unpack-unreachable.sh
index 200ab61278..b8d4cdea8c 100755
--- a/t/t7701-repack-unpack-unreachable.sh
+++ b/t/t7701-repack-unpack-unreachable.sh
@@ -95,4 +95,18 @@ test_expect_success 'unpacked objects receive timestamp of pack file' '
compare_mtimes < mtimes
'
+test_expect_success 'do not bother loosening old objects' '
+ obj1=$(echo one | git hash-object -w --stdin) &&
+ obj2=$(echo two | git hash-object -w --stdin) &&
+ pack1=$(echo $obj1 | git pack-objects .git/objects/pack/pack) &&
+ pack2=$(echo $obj2 | git pack-objects .git/objects/pack/pack) &&
+ git prune-packed &&
+ git cat-file -p $obj1 &&
+ git cat-file -p $obj2 &&
+ test-chmtime =-86400 .git/objects/pack/pack-$pack2.pack &&
+ git repack -A -d --unpack-unreachable=1.hour.ago &&
+ git cat-file -p $obj1 &&
+ test_must_fail git cat-file -p $obj2
+'
+
test_done
diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh
index 75f4716d8c..d9ad633310 100755
--- a/t/t7810-grep.sh
+++ b/t/t7810-grep.sh
@@ -47,6 +47,13 @@ test_expect_success setup '
echo vvv >t/v &&
mkdir t/a &&
echo vvv >t/a/v &&
+ {
+ echo "line without leading space1"
+ echo " line with leading space1"
+ echo " line with leading space2"
+ echo " line with leading space3"
+ echo "line without leading space2"
+ } >space &&
git add . &&
test_tick &&
git commit -m initial
@@ -893,4 +900,20 @@ test_expect_success 'mimic ack-grep --group' '
test_cmp expected actual
'
+cat >expected <<EOF
+space: line with leading space1
+space: line with leading space2
+space: line with leading space3
+EOF
+
+test_expect_success LIBPCRE 'grep -E "^ "' '
+ git grep -E "^ " space >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success LIBPCRE 'grep -P "^ "' '
+ git grep -P "^ " space >actual &&
+ test_cmp expected actual
+'
+
test_done
diff --git a/t/t9010-svn-fe.sh b/t/t9010-svn-fe.sh
index 6f6175a8f7..b7eed2489f 100755
--- a/t/t9010-svn-fe.sh
+++ b/t/t9010-svn-fe.sh
@@ -5,8 +5,27 @@ test_description='check svn dumpfile importer'
. ./test-lib.sh
reinit_git () {
+ if ! test_declared_prereq PIPE
+ then
+ echo >&4 "reinit_git: need to declare PIPE prerequisite"
+ return 127
+ fi
rm -fr .git &&
- git init
+ rm -f stream backflow &&
+ git init &&
+ mkfifo stream backflow
+}
+
+try_dump () {
+ input=$1 &&
+ maybe_fail_svnfe=${2:+test_$2} &&
+ maybe_fail_fi=${3:+test_$3} &&
+
+ {
+ $maybe_fail_svnfe test-svn-fe "$input" >stream 3<backflow &
+ } &&
+ $maybe_fail_fi git fast-import --cat-blob-fd=3 <stream 3>backflow &&
+ wait $!
}
properties () {
@@ -35,21 +54,27 @@ text_no_props () {
>empty
-test_expect_success 'empty dump' '
+test_expect_success 'setup: have pipes?' '
+ rm -f frob &&
+ if mkfifo frob
+ then
+ test_set_prereq PIPE
+ fi
+'
+
+test_expect_success PIPE 'empty dump' '
reinit_git &&
echo "SVN-fs-dump-format-version: 2" >input &&
- test-svn-fe input >stream &&
- git fast-import <stream
+ try_dump input
'
-test_expect_success 'v4 dumps not supported' '
+test_expect_success PIPE 'v4 dumps not supported' '
reinit_git &&
echo "SVN-fs-dump-format-version: 4" >v4.dump &&
- test_must_fail test-svn-fe v4.dump >stream &&
- test_cmp empty stream
+ try_dump v4.dump must_fail
'
-test_expect_failure 'empty revision' '
+test_expect_failure PIPE 'empty revision' '
reinit_git &&
printf "rev <nobody, nobody@local>: %s\n" "" "" >expect &&
cat >emptyrev.dump <<-\EOF &&
@@ -64,13 +89,12 @@ test_expect_failure 'empty revision' '
Content-length: 0
EOF
- test-svn-fe emptyrev.dump >stream &&
- git fast-import <stream &&
+ try_dump emptyrev.dump &&
git log -p --format="rev <%an, %ae>: %s" HEAD >actual &&
test_cmp expect actual
'
-test_expect_success 'empty properties' '
+test_expect_success PIPE 'empty properties' '
reinit_git &&
printf "rev <nobody, nobody@local>: %s\n" "" "" >expect &&
cat >emptyprop.dump <<-\EOF &&
@@ -88,13 +112,12 @@ test_expect_success 'empty properties' '
PROPS-END
EOF
- test-svn-fe emptyprop.dump >stream &&
- git fast-import <stream &&
+ try_dump emptyprop.dump &&
git log -p --format="rev <%an, %ae>: %s" HEAD >actual &&
test_cmp expect actual
'
-test_expect_success 'author name and commit message' '
+test_expect_success PIPE 'author name and commit message' '
reinit_git &&
echo "<author@example.com, author@example.com@local>" >expect.author &&
cat >message <<-\EOF &&
@@ -121,15 +144,14 @@ test_expect_success 'author name and commit message' '
echo &&
cat props
} >log.dump &&
- test-svn-fe log.dump >stream &&
- git fast-import <stream &&
+ try_dump log.dump &&
git log -p --format="%B" HEAD >actual.log &&
git log --format="<%an, %ae>" >actual.author &&
test_cmp message actual.log &&
test_cmp expect.author actual.author
'
-test_expect_success 'unsupported properties are ignored' '
+test_expect_success PIPE 'unsupported properties are ignored' '
reinit_git &&
echo author >expect &&
cat >extraprop.dump <<-\EOF &&
@@ -149,13 +171,12 @@ test_expect_success 'unsupported properties are ignored' '
author
PROPS-END
EOF
- test-svn-fe extraprop.dump >stream &&
- git fast-import <stream &&
+ try_dump extraprop.dump &&
git log -p --format=%an HEAD >actual &&
test_cmp expect actual
'
-test_expect_failure 'timestamp and empty file' '
+test_expect_failure PIPE 'timestamp and empty file' '
echo author@example.com >expect.author &&
echo 1999-01-01 >expect.date &&
echo file >expect.files &&
@@ -186,8 +207,7 @@ test_expect_failure 'timestamp and empty file' '
EOF
} >emptyfile.dump &&
- test-svn-fe emptyfile.dump >stream &&
- git fast-import <stream &&
+ try_dump emptyfile.dump &&
git log --format=%an HEAD >actual.author &&
git log --date=short --format=%ad HEAD >actual.date &&
git ls-tree -r --name-only HEAD >actual.files &&
@@ -198,7 +218,7 @@ test_expect_failure 'timestamp and empty file' '
test_cmp empty file
'
-test_expect_success 'directory with files' '
+test_expect_success PIPE 'directory with files' '
reinit_git &&
printf "%s\n" directory/file1 directory/file2 >expect.files &&
echo hi >hi &&
@@ -242,8 +262,7 @@ test_expect_success 'directory with files' '
EOF
text_no_props hi
} >directory.dump &&
- test-svn-fe directory.dump >stream &&
- git fast-import <stream &&
+ try_dump directory.dump &&
git ls-tree -r --name-only HEAD >actual.files &&
git checkout HEAD directory &&
@@ -252,7 +271,107 @@ test_expect_success 'directory with files' '
test_cmp hi directory/file2
'
-test_expect_success 'node without action' '
+test_expect_success PIPE 'branch name with backslash' '
+ reinit_git &&
+ sort <<-\EOF >expect.branch-files &&
+ trunk/file1
+ trunk/file2
+ "branches/UpdateFOPto094\\/file1"
+ "branches/UpdateFOPto094\\/file2"
+ EOF
+
+ echo hi >hi &&
+ echo hello >hello &&
+ {
+ properties \
+ svn:author author@example.com \
+ svn:date "1999-02-02T00:01:02.000000Z" \
+ svn:log "add directory with some files in it" &&
+ echo PROPS-END
+ } >props.setup &&
+ {
+ properties \
+ svn:author brancher@example.com \
+ svn:date "2007-12-06T21:38:34.000000Z" \
+ svn:log "Updating fop to .94 and adjust fo-stylesheets" &&
+ echo PROPS-END
+ } >props.branch &&
+ {
+ cat <<-EOF &&
+ SVN-fs-dump-format-version: 3
+
+ Revision-number: 1
+ EOF
+ echo Prop-content-length: $(wc -c <props.setup) &&
+ echo Content-length: $(wc -c <props.setup) &&
+ echo &&
+ cat props.setup &&
+ cat <<-\EOF &&
+
+ Node-path: trunk
+ Node-kind: dir
+ Node-action: add
+ Prop-content-length: 10
+ Content-length: 10
+
+ PROPS-END
+
+ Node-path: branches
+ Node-kind: dir
+ Node-action: add
+ Prop-content-length: 10
+ Content-length: 10
+
+ PROPS-END
+
+ Node-path: trunk/file1
+ Node-kind: file
+ Node-action: add
+ EOF
+ text_no_props hello &&
+ cat <<-\EOF &&
+ Node-path: trunk/file2
+ Node-kind: file
+ Node-action: add
+ EOF
+ text_no_props hi &&
+ cat <<-\EOF &&
+
+ Revision-number: 2
+ EOF
+ echo Prop-content-length: $(wc -c <props.branch) &&
+ echo Content-length: $(wc -c <props.branch) &&
+ echo &&
+ cat props.branch &&
+ cat <<-\EOF
+
+ Node-path: branches/UpdateFOPto094\
+ Node-kind: dir
+ Node-action: add
+ Node-copyfrom-rev: 1
+ Node-copyfrom-path: trunk
+
+ Node-kind: dir
+ Node-action: add
+ Prop-content-length: 34
+ Content-length: 34
+
+ K 13
+ svn:mergeinfo
+ V 0
+
+ PROPS-END
+ EOF
+ } >branch.dump &&
+ try_dump branch.dump &&
+
+ git ls-tree -r --name-only HEAD |
+ sort >actual.branch-files &&
+ test_cmp expect.branch-files actual.branch-files
+'
+
+test_expect_success PIPE 'node without action' '
+ reinit_git &&
cat >inaction.dump <<-\EOF &&
SVN-fs-dump-format-version: 3
@@ -269,10 +388,11 @@ test_expect_success 'node without action' '
PROPS-END
EOF
- test_must_fail test-svn-fe inaction.dump
+ try_dump inaction.dump must_fail
'
-test_expect_success 'action: add node without text' '
+test_expect_success PIPE 'action: add node without text' '
+ reinit_git &&
cat >textless.dump <<-\EOF &&
SVN-fs-dump-format-version: 3
@@ -290,10 +410,10 @@ test_expect_success 'action: add node without text' '
PROPS-END
EOF
- test_must_fail test-svn-fe textless.dump
+ try_dump textless.dump must_fail
'
-test_expect_failure 'change file mode but keep old content' '
+test_expect_failure PIPE 'change file mode but keep old content' '
reinit_git &&
cat >expect <<-\EOF &&
OBJID
@@ -356,8 +476,7 @@ test_expect_failure 'change file mode but keep old content' '
PROPS-END
EOF
- test-svn-fe filemode.dump >stream &&
- git fast-import <stream &&
+ try_dump filemode.dump &&
{
git rev-list HEAD |
git diff-tree --root --stdin |
@@ -370,7 +489,7 @@ test_expect_failure 'change file mode but keep old content' '
test_cmp hello actual.target
'
-test_expect_success 'NUL in property value' '
+test_expect_success PIPE 'NUL in property value' '
reinit_git &&
echo "commit message" >expect.message &&
{
@@ -391,13 +510,12 @@ test_expect_success 'NUL in property value' '
echo &&
cat props
} >nulprop.dump &&
- test-svn-fe nulprop.dump >stream &&
- git fast-import <stream &&
+ try_dump nulprop.dump &&
git diff-tree --always -s --format=%s HEAD >actual.message &&
test_cmp expect.message actual.message
'
-test_expect_success 'NUL in log message, file content, and property name' '
+test_expect_success PIPE 'NUL in log message, file content, and property name' '
# Caveat: svnadmin 1.6.16 (r1073529) truncates at \0 in the
# svn:specialQnotreally example.
reinit_git &&
@@ -458,8 +576,7 @@ test_expect_success 'NUL in log message, file content, and property name' '
link hello
EOF
} >8bitclean.dump &&
- test-svn-fe 8bitclean.dump >stream &&
- git fast-import <stream &&
+ try_dump 8bitclean.dump &&
{
git rev-list HEAD |
git diff-tree --root --stdin |
@@ -478,7 +595,7 @@ test_expect_success 'NUL in log message, file content, and property name' '
test_cmp expect.hello2 actual.hello2
'
-test_expect_success 'change file mode and reiterate content' '
+test_expect_success PIPE 'change file mode and reiterate content' '
reinit_git &&
cat >expect <<-\EOF &&
OBJID
@@ -490,7 +607,7 @@ test_expect_success 'change file mode and reiterate content' '
EOF
echo "link hello" >expect.blob &&
echo hello >hello &&
- cat >filemode.dump <<-\EOF &&
+ cat >filemode2.dump <<-\EOF &&
SVN-fs-dump-format-version: 3
Revision-number: 1
@@ -545,8 +662,7 @@ test_expect_success 'change file mode and reiterate content' '
PROPS-END
link hello
EOF
- test-svn-fe filemode.dump >stream &&
- git fast-import <stream &&
+ try_dump filemode2.dump &&
{
git rev-list HEAD |
git diff-tree --root --stdin |
@@ -559,7 +675,8 @@ test_expect_success 'change file mode and reiterate content' '
test_cmp hello actual.target
'
-test_expect_success 'deltas not supported' '
+test_expect_success PIPE 'deltas supported' '
+ reinit_git &&
{
# (old) h + (inline) ello + (old) \n
printf "SVNQ%b%b%s" "Q\003\006\005\004" "\001Q\0204\001\002" "ello" |
@@ -619,10 +736,10 @@ test_expect_success 'deltas not supported' '
echo PROPS-END &&
cat delta
} >delta.dump &&
- test_must_fail test-svn-fe delta.dump
+ try_dump delta.dump
'
-test_expect_success 'property deltas supported' '
+test_expect_success PIPE 'property deltas supported' '
reinit_git &&
cat >expect <<-\EOF &&
OBJID
@@ -678,8 +795,7 @@ test_expect_success 'property deltas supported' '
PROPS-END
EOF
} >propdelta.dump &&
- test-svn-fe propdelta.dump >stream &&
- git fast-import <stream &&
+ try_dump propdelta.dump &&
{
git rev-list HEAD |
git diff-tree --stdin |
@@ -688,7 +804,7 @@ test_expect_success 'property deltas supported' '
test_cmp expect actual
'
-test_expect_success 'properties on /' '
+test_expect_success PIPE 'properties on /' '
reinit_git &&
cat <<-\EOF >expect &&
OBJID
@@ -733,8 +849,7 @@ test_expect_success 'properties on /' '
PROPS-END
EOF
- test-svn-fe changeroot.dump >stream &&
- git fast-import <stream &&
+ try_dump changeroot.dump &&
{
git rev-list HEAD |
git diff-tree --root --always --stdin |
@@ -743,7 +858,7 @@ test_expect_success 'properties on /' '
test_cmp expect actual
'
-test_expect_success 'deltas for typechange' '
+test_expect_success PIPE 'deltas for typechange' '
reinit_git &&
cat >expect <<-\EOF &&
OBJID
@@ -819,8 +934,7 @@ test_expect_success 'deltas for typechange' '
PROPS-END
link testing 321
EOF
- test-svn-fe deleteprop.dump >stream &&
- git fast-import <stream &&
+ try_dump deleteprop.dump &&
{
git rev-list HEAD |
git diff-tree --root --stdin |
@@ -829,6 +943,143 @@ test_expect_success 'deltas for typechange' '
test_cmp expect actual
'
+test_expect_success PIPE 'deltas need not consume the whole preimage' '
+ reinit_git &&
+ cat >expect <<-\EOF &&
+ OBJID
+ :120000 100644 OBJID OBJID T postimage
+ OBJID
+ :100644 120000 OBJID OBJID T postimage
+ OBJID
+ :000000 100644 OBJID OBJID A postimage
+ EOF
+ echo "first preimage" >expect.1 &&
+ printf target >expect.2 &&
+ printf lnk >expect.3 &&
+ {
+ printf "SVNQ%b%b%b" "QQ\017\001\017" "\0217" "first preimage\n" |
+ q_to_nul
+ } >delta.1 &&
+ {
+ properties svn:special "*" &&
+ echo PROPS-END
+ } >symlink.props &&
+ {
+ printf "SVNQ%b%b%b" "Q\002\013\004\012" "\0201\001\001\0211" "lnk target" |
+ q_to_nul
+ } >delta.2 &&
+ {
+ printf "SVNQ%b%b" "Q\004\003\004Q" "\001Q\002\002" |
+ q_to_nul
+ } >delta.3 &&
+ {
+ cat <<-\EOF &&
+ SVN-fs-dump-format-version: 3
+
+ Revision-number: 1
+ Prop-content-length: 10
+ Content-length: 10
+
+ PROPS-END
+
+ Node-path: postimage
+ Node-kind: file
+ Node-action: add
+ Text-delta: true
+ Prop-content-length: 10
+ EOF
+ echo Text-content-length: $(wc -c <delta.1) &&
+ echo Content-length: $((10 + $(wc -c <delta.1))) &&
+ echo &&
+ echo PROPS-END &&
+ cat delta.1 &&
+ cat <<-\EOF &&
+
+ Revision-number: 2
+ Prop-content-length: 10
+ Content-length: 10
+
+ PROPS-END
+
+ Node-path: postimage
+ Node-kind: file
+ Node-action: change
+ Text-delta: true
+ EOF
+ echo Prop-content-length: $(wc -c <symlink.props) &&
+ echo Text-content-length: $(wc -c <delta.2) &&
+ echo Content-length: $(($(wc -c <symlink.props) + $(wc -c <delta.2))) &&
+ echo &&
+ cat symlink.props &&
+ cat delta.2 &&
+ cat <<-\EOF &&
+
+ Revision-number: 3
+ Prop-content-length: 10
+ Content-length: 10
+
+ PROPS-END
+
+ Node-path: postimage
+ Node-kind: file
+ Node-action: change
+ Text-delta: true
+ Prop-content-length: 10
+ EOF
+ echo Text-content-length: $(wc -c <delta.3) &&
+ echo Content-length: $((10 + $(wc -c <delta.3))) &&
+ echo &&
+ echo PROPS-END &&
+ cat delta.3 &&
+ echo
+ } >deltapartial.dump &&
+ try_dump deltapartial.dump &&
+ {
+ git rev-list HEAD |
+ git diff-tree --root --stdin |
+ sed "s/$_x40/OBJID/g"
+ } >actual &&
+ test_cmp expect actual &&
+ git show HEAD:postimage >actual.3 &&
+ git show HEAD^:postimage >actual.2 &&
+ git show HEAD^^:postimage >actual.1 &&
+ test_cmp expect.1 actual.1 &&
+ test_cmp expect.2 actual.2 &&
+ test_cmp expect.3 actual.3
+'
+
+test_expect_success PIPE 'no hang for delta trying to read past end of preimage' '
+ reinit_git &&
+ {
+ # COPY 1
+ printf "SVNQ%b%b" "Q\001\001\002Q" "\001Q" |
+ q_to_nul
+ } >greedy.delta &&
+ {
+ cat <<-\EOF &&
+ SVN-fs-dump-format-version: 3
+
+ Revision-number: 1
+ Prop-content-length: 10
+ Content-length: 10
+
+ PROPS-END
+
+ Node-path: bootstrap
+ Node-kind: file
+ Node-action: add
+ Text-delta: true
+ Prop-content-length: 10
+ EOF
+ echo Text-content-length: $(wc -c <greedy.delta) &&
+ echo Content-length: $((10 + $(wc -c <greedy.delta))) &&
+ echo &&
+ echo PROPS-END &&
+ cat greedy.delta &&
+ echo
+ } >greedydelta.dump &&
+ try_dump greedydelta.dump must_fail might_fail
+'
test_expect_success 'set up svn repo' '
svnconf=$PWD/svnconf &&
@@ -844,12 +1095,12 @@ test_expect_success 'set up svn repo' '
fi
'
-test_expect_success SVNREPO 't9135/svn.dump' '
- git init simple-git &&
- test-svn-fe "$TEST_DIRECTORY/t9135/svn.dump" >simple.fe &&
+test_expect_success SVNREPO,PIPE 't9135/svn.dump' '
+ mkdir -p simple-git &&
(
cd simple-git &&
- git fast-import <../simple.fe
+ reinit_git &&
+ try_dump "$TEST_DIRECTORY/t9135/svn.dump"
) &&
(
cd simple-svnco &&
diff --git a/t/t9011-svn-da.sh b/t/t9011-svn-da.sh
new file mode 100755
index 0000000000..b38d16f9db
--- /dev/null
+++ b/t/t9011-svn-da.sh
@@ -0,0 +1,248 @@
+#!/bin/sh
+
+test_description='test parsing of svndiff0 files
+
+Using the "test-svn-fe -d" helper, check that svn-fe correctly
+interprets deltas using various facilities (some from the spec,
+some only learned from practice).
+'
+. ./test-lib.sh
+
+>empty
+printf foo >preimage
+
+test_expect_success 'reject empty delta' '
+ test_must_fail test-svn-fe -d preimage empty 0
+'
+
+test_expect_success 'delta can empty file' '
+ printf "SVNQ" | q_to_nul >clear.delta &&
+ test-svn-fe -d preimage clear.delta 4 >actual &&
+ test_cmp empty actual
+'
+
+test_expect_success 'reject svndiff2' '
+ printf "SVN\002" >bad.filetype &&
+ test_must_fail test-svn-fe -d preimage bad.filetype 4
+'
+
+test_expect_success 'one-window empty delta' '
+ printf "SVNQ%s" "QQQQQ" | q_to_nul >clear.onewindow &&
+ test-svn-fe -d preimage clear.onewindow 9 >actual &&
+ test_cmp empty actual
+'
+
+test_expect_success 'reject incomplete window header' '
+ printf "SVNQ%s" "QQQQQ" | q_to_nul >clear.onewindow &&
+ printf "SVNQ%s" "QQ" | q_to_nul >clear.partialwindow &&
+ test_must_fail test-svn-fe -d preimage clear.onewindow 6 &&
+ test_must_fail test-svn-fe -d preimage clear.partialwindow 6
+'
+
+test_expect_success 'reject declared delta longer than actual delta' '
+ printf "SVNQ%s" "QQQQQ" | q_to_nul >clear.onewindow &&
+ printf "SVNQ%s" "QQ" | q_to_nul >clear.partialwindow &&
+ test_must_fail test-svn-fe -d preimage clear.onewindow 14 &&
+ test_must_fail test-svn-fe -d preimage clear.partialwindow 9
+'
+
+test_expect_success 'two-window empty delta' '
+ printf "SVNQ%s%s" "QQQQQ" "QQQQQ" | q_to_nul >clear.twowindow &&
+ test-svn-fe -d preimage clear.twowindow 14 >actual &&
+ test_must_fail test-svn-fe -d preimage clear.twowindow 13 &&
+ test_cmp empty actual
+'
+
+test_expect_success 'noisy zeroes' '
+ printf "SVNQ%s" \
+ "RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQ" |
+ tr R "\200" |
+ q_to_nul >clear.noisy &&
+ len=$(wc -c <clear.noisy) &&
+ test-svn-fe -d preimage clear.noisy $len &&
+ test_cmp empty actual
+'
+
+test_expect_success 'reject variable-length int in magic' '
+ printf "SVNRQ" | tr R "\200" | q_to_nul >clear.badmagic &&
+ test_must_fail test-svn-fe -d preimage clear.badmagic 5
+'
+
+test_expect_success 'reject truncated integer' '
+ printf "SVNQ%s%s" "QQQQQ" "QQQQRRQ" |
+ tr R "\200" |
+ q_to_nul >clear.fullint &&
+ printf "SVNQ%s%s" "QQQQQ" "QQQQRR" |
+ tr RT "\201" |
+ q_to_nul >clear.partialint &&
+ test_must_fail test-svn-fe -d preimage clear.fullint 15 &&
+ test-svn-fe -d preimage clear.fullint 16 &&
+ test_must_fail test-svn-fe -d preimage clear.partialint 15
+'
+
+test_expect_success 'nonempty (but unused) preimage view' '
+ printf "SVNQ%b" "Q\003QQQ" | q_to_nul >clear.readpreimage &&
+ test-svn-fe -d preimage clear.readpreimage 9 >actual &&
+ test_cmp empty actual
+'
+
+test_expect_success 'preimage view: right endpoint cannot backtrack' '
+ printf "SVNQ%b%b" "Q\003QQQ" "Q\002QQQ" |
+ q_to_nul >clear.backtrack &&
+ test_must_fail test-svn-fe -d preimage clear.backtrack 14
+'
+
+test_expect_success 'preimage view: left endpoint can advance' '
+ printf "SVNQ%b%b" "Q\003QQQ" "\001\002QQQ" |
+ q_to_nul >clear.preshrink &&
+ printf "SVNQ%b%b" "Q\003QQQ" "\001\001QQQ" |
+ q_to_nul >clear.shrinkbacktrack &&
+ test-svn-fe -d preimage clear.preshrink 14 >actual &&
+ test_must_fail test-svn-fe -d preimage clear.shrinkbacktrack 14 &&
+ test_cmp empty actual
+'
+
+test_expect_success 'preimage view: offsets compared by value' '
+ printf "SVNQ%b%b" "\001\001QQQ" "\0200Q\003QQQ" |
+ q_to_nul >clear.noisybacktrack &&
+ printf "SVNQ%b%b" "\001\001QQQ" "\0200\001\002QQQ" |
+ q_to_nul >clear.noisyadvance &&
+ test_must_fail test-svn-fe -d preimage clear.noisybacktrack 15 &&
+ test-svn-fe -d preimage clear.noisyadvance 15 &&
+ test_cmp empty actual
+'
+
+test_expect_success 'preimage view: reject truncated preimage' '
+ printf "SVNQ%b" "\010QQQQ" | q_to_nul >clear.lateemptyread &&
+ printf "SVNQ%b" "\010\001QQQ" | q_to_nul >clear.latenonemptyread &&
+ printf "SVNQ%b" "\001\010QQQ" | q_to_nul >clear.longread &&
+ test_must_fail test-svn-fe -d preimage clear.lateemptyread 9 &&
+ test_must_fail test-svn-fe -d preimage clear.latenonemptyread 9 &&
+ test_must_fail test-svn-fe -d preimage clear.longread 9
+'
+
+test_expect_success 'forbid unconsumed inline data' '
+ printf "SVNQ%b%s%b%s" "QQQQ\003" "bar" "QQQQ\001" "x" |
+ q_to_nul >inline.clear &&
+ test_must_fail test-svn-fe -d preimage inline.clear 18 >actual
+'
+
+test_expect_success 'reject truncated inline data' '
+ printf "SVNQ%b%s" "QQQQ\003" "b" | q_to_nul >inline.trunc &&
+ test_must_fail test-svn-fe -d preimage inline.trunc 10
+'
+
+test_expect_success 'reject truncated inline data (after instruction section)' '
+ printf "SVNQ%b%b%s" "QQ\001\001\003" "\0201" "b" | q_to_nul >insn.trunc &&
+ test_must_fail test-svn-fe -d preimage insn.trunc 11
+'
+
+test_expect_success 'copyfrom_data' '
+ echo hi >expect &&
+ printf "SVNQ%b%b%b" "QQ\003\001\003" "\0203" "hi\n" | q_to_nul >copydat &&
+ test-svn-fe -d preimage copydat 13 >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'multiple copyfrom_data' '
+ echo hi >expect &&
+ printf "SVNQ%b%b%b%b%b" "QQ\003\002\003" "\0201\0202" "hi\n" \
+ "QQQ\002Q" "\0200Q" | q_to_nul >copy.multi &&
+ len=$(wc -c <copy.multi) &&
+ test-svn-fe -d preimage copy.multi $len >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'incomplete multiple insn' '
+ printf "SVNQ%b%b%b" "QQ\003\002\003" "\0203\0200" "hi\n" |
+ q_to_nul >copy.partial &&
+ len=$(wc -c <copy.partial) &&
+ test_must_fail test-svn-fe -d preimage copy.partial $len
+'
+
+test_expect_success 'catch attempt to copy missing data' '
+ printf "SVNQ%b%b%s%b%s" "QQ\002\002\001" "\0201\0201" "X" \
+ "QQQQ\002" "YZ" |
+ q_to_nul >copy.incomplete &&
+ len=$(wc -c <copy.incomplete) &&
+ test_must_fail test-svn-fe -d preimage copy.incomplete $len
+'
+
+test_expect_success 'copyfrom target to repeat data' '
+ printf foofoo >expect &&
+ printf "SVNQ%b%b%s" "QQ\006\004\003" "\0203\0100\003Q" "foo" |
+ q_to_nul >copytarget.repeat &&
+ len=$(wc -c <copytarget.repeat) &&
+ test-svn-fe -d preimage copytarget.repeat $len >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'copyfrom target out of order' '
+ printf foooof >expect &&
+ printf "SVNQ%b%b%s" \
+ "QQ\006\007\003" "\0203\0101\002\0101\001\0101Q" "foo" |
+ q_to_nul >copytarget.reverse &&
+ len=$(wc -c <copytarget.reverse) &&
+ test-svn-fe -d preimage copytarget.reverse $len >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'catch copyfrom future' '
+ printf "SVNQ%b%b%s" "QQ\004\004\003" "\0202\0101\002\0201" "XYZ" |
+ q_to_nul >copytarget.infuture &&
+ len=$(wc -c <copytarget.infuture) &&
+ test_must_fail test-svn-fe -d preimage copytarget.infuture $len
+'
+
+test_expect_success 'copy to sustain' '
+ printf XYXYXYXYXYXZ >expect &&
+ printf "SVNQ%b%b%s" "QQ\014\004\003" "\0202\0111Q\0201" "XYZ" |
+ q_to_nul >copytarget.sustain &&
+ len=$(wc -c <copytarget.sustain) &&
+ test-svn-fe -d preimage copytarget.sustain $len >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'catch copy that overflows' '
+ printf "SVNQ%b%b%s" "QQ\003\003\001" "\0201\0177Q" X |
+ q_to_nul >copytarget.overflow &&
+ len=$(wc -c <copytarget.overflow) &&
+ test_must_fail test-svn-fe -d preimage copytarget.overflow $len
+'
+
+test_expect_success 'copyfrom source' '
+ printf foo >expect &&
+ printf "SVNQ%b%b" "Q\003\003\002Q" "\003Q" | q_to_nul >copysource.all &&
+ test-svn-fe -d preimage copysource.all 11 >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'copy backwards' '
+ printf oof >expect &&
+ printf "SVNQ%b%b" "Q\003\003\006Q" "\001\002\001\001\001Q" |
+ q_to_nul >copysource.rev &&
+ test-svn-fe -d preimage copysource.rev 15 >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'offsets are relative to window' '
+ printf fo >expect &&
+ printf "SVNQ%b%b%b%b" "Q\003\001\002Q" "\001Q" \
+ "\002\001\001\002Q" "\001Q" |
+ q_to_nul >copysource.two &&
+ test-svn-fe -d preimage copysource.two 18 >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'example from notes/svndiff' '
+ printf aaaaccccdddddddd >expect &&
+ printf aaaabbbbcccc >source &&
+ printf "SVNQ%b%b%s" "Q\014\020\007\001" \
+ "\004Q\004\010\0201\0107\010" d |
+ q_to_nul >delta.example &&
+ len=$(wc -c <delta.example) &&
+ test-svn-fe -d source delta.example $len >actual &&
+ test_cmp expect actual
+'
+
+test_done
diff --git a/t/t9100-git-svn-basic.sh b/t/t9100-git-svn-basic.sh
index b041516a1d..749b75e8d4 100755
--- a/t/t9100-git-svn-basic.sh
+++ b/t/t9100-git-svn-basic.sh
@@ -65,7 +65,8 @@ test_expect_success "$name" "
git update-index --add dir/file/file &&
git commit -m '$name' &&
test_must_fail git svn set-tree --find-copies-harder --rmdir \
- ${remotes_git_svn}..mybranch" || true
+ ${remotes_git_svn}..mybranch
+"
name='detect node change from directory to file #1'
@@ -79,7 +80,8 @@ test_expect_success "$name" '
git update-index --add -- bar &&
git commit -m "$name" &&
test_must_fail git svn set-tree --find-copies-harder --rmdir \
- ${remotes_git_svn}..mybranch2' || true
+ ${remotes_git_svn}..mybranch2
+'
name='detect node change from file to directory #2'
@@ -92,9 +94,12 @@ test_expect_success "$name" '
echo yyy > bar/zzz/yyy &&
git update-index --add bar/zzz/yyy &&
git commit -m "$name" &&
- test_must_fail git svn set-tree --find-copies-harder --rmdir \
- ${remotes_git_svn}..mybranch3' || true
-
+ git svn set-tree --find-copies-harder --rmdir \
+ ${remotes_git_svn}..mybranch3 &&
+ svn_cmd up "$SVN_TREE" &&
+ test -d "$SVN_TREE"/bar/zzz &&
+ test -e "$SVN_TREE"/bar/zzz/yyy
+'
name='detect node change from directory to file #2'
test_expect_success "$name" '
@@ -107,7 +112,8 @@ test_expect_success "$name" '
git update-index --add -- dir &&
git commit -m "$name" &&
test_must_fail git svn set-tree --find-copies-harder --rmdir \
- ${remotes_git_svn}..mybranch4' || true
+ ${remotes_git_svn}..mybranch4
+'
name='remove executable bit from a file'
@@ -134,10 +140,10 @@ test_expect_success "$name" '
test -x "$SVN_TREE"/exec.sh'
-name='executable file becomes a symlink to bar/zzz (file)'
+name='executable file becomes a symlink to file'
test_expect_success "$name" '
rm exec.sh &&
- ln -s bar/zzz exec.sh &&
+ ln -s file exec.sh &&
git update-index exec.sh &&
git commit -m "$name" &&
git svn set-tree --find-copies-harder --rmdir \
@@ -148,19 +154,19 @@ test_expect_success "$name" '
name='new symlink is added to a file that was also just made executable'
test_expect_success "$name" '
- chmod +x bar/zzz &&
- ln -s bar/zzz exec-2.sh &&
- git update-index --add bar/zzz exec-2.sh &&
+ chmod +x file &&
+ ln -s file exec-2.sh &&
+ git update-index --add file exec-2.sh &&
git commit -m "$name" &&
git svn set-tree --find-copies-harder --rmdir \
${remotes_git_svn}..mybranch5 &&
svn_cmd up "$SVN_TREE" &&
- test -x "$SVN_TREE"/bar/zzz &&
+ test -x "$SVN_TREE"/file &&
test -h "$SVN_TREE"/exec-2.sh'
name='modify a symlink to become a file'
test_expect_success "$name" '
- echo git help > help || true &&
+ echo git help >help &&
rm exec-2.sh &&
cp help exec-2.sh &&
git update-index exec-2.sh &&
@@ -195,14 +201,15 @@ name='check imported tree checksums expected tree checksums'
rm -f expected
if test_have_prereq UTF8
then
- echo tree bf522353586b1b883488f2bc73dab0d9f774b9a9 > expected
+ echo tree dc68b14b733e4ec85b04ab6f712340edc5dc936e > expected
fi
cat >> expected <<\EOF
-tree 83654bb36f019ae4fe77a0171f81075972087624
-tree 031b8d557afc6fea52894eaebb45bec52f1ba6d1
-tree 0b094cbff17168f24c302e297f55bfac65eb8bd3
-tree d667270a1f7b109f5eb3aaea21ede14b56bfdd6e
-tree 56a30b966619b863674f5978696f4a3594f2fca9
+tree c3322890dcf74901f32d216f05c5044f670ce632
+tree d3ccd5035feafd17b030c5732e7808cc49122853
+tree d03e1630363d4881e68929d532746b20b0986b83
+tree 149d63cd5878155c846e8c55d7d8487de283f89e
+tree 312b76e4f64ce14893aeac8591eb3960b065e247
+tree 149d63cd5878155c846e8c55d7d8487de283f89e
tree d667270a1f7b109f5eb3aaea21ede14b56bfdd6e
tree 8f51f74cf0163afc9ad68a4b1537288c4558b5a4
EOF
diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh
index 0f5b5e5964..2aa1824a94 100755
--- a/t/t9300-fast-import.sh
+++ b/t/t9300-fast-import.sh
@@ -24,6 +24,13 @@ head_c () {
' - "$1"
}
+verify_packs () {
+ for p in .git/objects/pack/*.pack
+ do
+ git verify-pack "$@" "$p" || return
+ done
+}
+
file2_data='file2
second line of EOF'
@@ -105,9 +112,10 @@ test_expect_success \
'A: create pack from stdin' \
'git fast-import --export-marks=marks.out <input &&
git whatchanged master'
-test_expect_success \
- 'A: verify pack' \
- 'for p in .git/objects/pack/*.pack;do git verify-pack $p||exit;done'
+
+test_expect_success 'A: verify pack' '
+ verify_packs
+'
cat >expect <<EOF
author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
@@ -252,9 +260,11 @@ test_expect_success \
'A: verify marks import does not crash' \
'git fast-import --import-marks=marks.out <input &&
git whatchanged verify--import-marks'
-test_expect_success \
- 'A: verify pack' \
- 'for p in .git/objects/pack/*.pack;do git verify-pack $p||exit;done'
+
+test_expect_success 'A: verify pack' '
+ verify_packs
+'
+
cat >expect <<EOF
:000000 100755 0000000000000000000000000000000000000000 7123f7f44e39be127c5eb701e5968176ee9d78b1 A copy-of-file2
EOF
@@ -514,9 +524,11 @@ test_expect_success \
'C: incremental import create pack from stdin' \
'git fast-import <input &&
git whatchanged branch'
-test_expect_success \
- 'C: verify pack' \
- 'for p in .git/objects/pack/*.pack;do git verify-pack $p||exit;done'
+
+test_expect_success 'C: verify pack' '
+ verify_packs
+'
+
test_expect_success \
'C: validate reuse existing blob' \
'test $newf = `git rev-parse --verify branch:file2/newf` &&
@@ -572,9 +584,10 @@ test_expect_success \
'D: inline data in commit' \
'git fast-import <input &&
git whatchanged branch'
-test_expect_success \
- 'D: verify pack' \
- 'for p in .git/objects/pack/*.pack;do git verify-pack $p||exit;done'
+
+test_expect_success 'D: verify pack' '
+ verify_packs
+'
cat >expect <<EOF
:000000 100755 0000000000000000000000000000000000000000 35a59026a33beac1569b1c7f66f3090ce9c09afc A newdir/exec.sh
@@ -618,9 +631,10 @@ test_expect_success 'E: rfc2822 date, --date-format=raw' '
test_expect_success \
'E: rfc2822 date, --date-format=rfc2822' \
'git fast-import --date-format=rfc2822 <input'
-test_expect_success \
- 'E: verify pack' \
- 'for p in .git/objects/pack/*.pack;do git verify-pack $p||exit;done'
+
+test_expect_success 'E: verify pack' '
+ verify_packs
+'
cat >expect <<EOF
author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> 1170778938 -0500
@@ -669,9 +683,10 @@ test_expect_success \
fi
fi
'
-test_expect_success \
- 'F: verify pack' \
- 'for p in .git/objects/pack/*.pack;do git verify-pack $p||exit;done'
+
+test_expect_success 'F: verify pack' '
+ verify_packs
+'
cat >expect <<EOF
tree `git rev-parse branch~1^{tree}`
@@ -705,9 +720,11 @@ INPUT_END
test_expect_success \
'G: non-fast-forward update forced' \
'git fast-import --force <input'
-test_expect_success \
- 'G: verify pack' \
- 'for p in .git/objects/pack/*.pack;do git verify-pack $p||exit;done'
+
+test_expect_success 'G: verify pack' '
+ verify_packs
+'
+
test_expect_success \
'G: branch changed, but logged' \
'test $old_branch != `git rev-parse --verify branch^0` &&
@@ -742,9 +759,10 @@ test_expect_success \
'H: deletall, add 1' \
'git fast-import <input &&
git whatchanged H'
-test_expect_success \
- 'H: verify pack' \
- 'for p in .git/objects/pack/*.pack;do git verify-pack $p||exit;done'
+
+test_expect_success 'H: verify pack' '
+ verify_packs
+'
cat >expect <<EOF
:100755 000000 f1fb5da718392694d0076d677d6d0e364c79b0bc 0000000000000000000000000000000000000000 D file2/newf
@@ -1639,7 +1657,7 @@ M 160000 :6 sub
INPUT_END
test_expect_success \
- 'P: supermodule & submodule mix' \
+ 'P: superproject & submodule mix' \
'git fast-import <input &&
git checkout subuse1 &&
rm -rf sub && mkdir sub && (cd sub &&
@@ -1857,9 +1875,10 @@ test_expect_success \
'Q: commit notes' \
'git fast-import <input &&
git whatchanged notes-test'
-test_expect_success \
- 'Q: verify pack' \
- 'for p in .git/objects/pack/*.pack;do git verify-pack $p||exit;done'
+
+test_expect_success 'Q: verify pack' '
+ verify_packs
+'
commit1=$(git rev-parse notes-test~2)
commit2=$(git rev-parse notes-test^)
@@ -2616,13 +2635,14 @@ test_expect_success \
'R: blob bigger than threshold' \
'test_create_repo R &&
git --git-dir=R/.git fast-import --big-file-threshold=1 <input'
-test_expect_success \
- 'R: verify created pack' \
- ': >verify &&
- for p in R/.git/objects/pack/*.pack;
- do
- git verify-pack -v $p >>verify || exit;
- done'
+
+test_expect_success 'R: verify created pack' '
+ (
+ cd R &&
+ verify_packs -v > ../verify
+ )
+'
+
test_expect_success \
'R: verify written objects' \
'git --git-dir=R/.git cat-file blob big-file:big1 >actual &&
@@ -2635,4 +2655,291 @@ test_expect_success \
'n=$(grep $a verify | wc -l) &&
test 1 = $n'
+###
+### series S
+###
+#
+# Make sure missing spaces and EOLs after mark references
+# cause errors.
+#
+# Setup:
+#
+# 1--2--4
+# \ /
+# -3-
+#
+# commit marks: 301, 302, 303, 304
+# blob marks: 403, 404, resp.
+# note mark: 202
+#
+# The error message when a space is missing not at the
+# end of the line is:
+#
+# Missing space after ..
+#
+# or when extra characters come after the mark at the end
+# of the line:
+#
+# Garbage after ..
+#
+# or when the dataref is neither "inline " or a known SHA1,
+#
+# Invalid dataref ..
+#
+test_tick
+
+cat >input <<INPUT_END
+commit refs/heads/S
+mark :301
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+data <<COMMIT
+commit 1
+COMMIT
+M 100644 inline hello.c
+data <<BLOB
+blob 1
+BLOB
+
+commit refs/heads/S
+mark :302
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+data <<COMMIT
+commit 2
+COMMIT
+from :301
+M 100644 inline hello.c
+data <<BLOB
+blob 2
+BLOB
+
+blob
+mark :403
+data <<BLOB
+blob 3
+BLOB
+
+blob
+mark :202
+data <<BLOB
+note 2
+BLOB
+INPUT_END
+
+test_expect_success 'S: initialize for S tests' '
+ git fast-import --export-marks=marks <input
+'
+
+#
+# filemodify, three datarefs
+#
+test_expect_success 'S: filemodify with garbage after mark must fail' '
+ test_must_fail git fast-import --import-marks=marks <<-EOF 2>err &&
+ commit refs/heads/S
+ committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+ data <<COMMIT
+ commit N
+ COMMIT
+ M 100644 :403x hello.c
+ EOF
+ cat err &&
+ test_i18ngrep "space after mark" err
+'
+
+# inline is misspelled; fast-import thinks it is some unknown dataref
+test_expect_success 'S: filemodify with garbage after inline must fail' '
+ test_must_fail git fast-import --import-marks=marks <<-EOF 2>err &&
+ commit refs/heads/S
+ committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+ data <<COMMIT
+ commit N
+ COMMIT
+ M 100644 inlineX hello.c
+ data <<BLOB
+ inline
+ BLOB
+ EOF
+ cat err &&
+ test_i18ngrep "nvalid dataref" err
+'
+
+test_expect_success 'S: filemodify with garbage after sha1 must fail' '
+ sha1=$(grep :403 marks | cut -d\ -f2) &&
+ test_must_fail git fast-import --import-marks=marks <<-EOF 2>err &&
+ commit refs/heads/S
+ committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+ data <<COMMIT
+ commit N
+ COMMIT
+ M 100644 ${sha1}x hello.c
+ EOF
+ cat err &&
+ test_i18ngrep "space after SHA1" err
+'
+
+#
+# notemodify, three ways to say dataref
+#
+test_expect_success 'S: notemodify with garabge after mark dataref must fail' '
+ test_must_fail git fast-import --import-marks=marks <<-EOF 2>err &&
+ commit refs/heads/S
+ committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+ data <<COMMIT
+ commit S note dataref markref
+ COMMIT
+ N :202x :302
+ EOF
+ cat err &&
+ test_i18ngrep "space after mark" err
+'
+
+test_expect_success 'S: notemodify with garbage after inline dataref must fail' '
+ test_must_fail git fast-import --import-marks=marks <<-EOF 2>err &&
+ commit refs/heads/S
+ committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+ data <<COMMIT
+ commit S note dataref inline
+ COMMIT
+ N inlineX :302
+ data <<BLOB
+ note blob
+ BLOB
+ EOF
+ cat err &&
+ test_i18ngrep "nvalid dataref" err
+'
+
+test_expect_success 'S: notemodify with garbage after sha1 dataref must fail' '
+ sha1=$(grep :202 marks | cut -d\ -f2) &&
+ test_must_fail git fast-import --import-marks=marks <<-EOF 2>err &&
+ commit refs/heads/S
+ committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+ data <<COMMIT
+ commit S note dataref sha1
+ COMMIT
+ N ${sha1}x :302
+ EOF
+ cat err &&
+ test_i18ngrep "space after SHA1" err
+'
+
+#
+# notemodify, mark in committish
+#
+test_expect_success 'S: notemodify with garbarge after mark committish must fail' '
+ test_must_fail git fast-import --import-marks=marks <<-EOF 2>err &&
+ commit refs/heads/Snotes
+ committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+ data <<COMMIT
+ commit S note committish
+ COMMIT
+ N :202 :302x
+ EOF
+ cat err &&
+ test_i18ngrep "after mark" err
+'
+
+#
+# from
+#
+test_expect_success 'S: from with garbage after mark must fail' '
+ # no &&
+ git fast-import --import-marks=marks --export-marks=marks <<-EOF 2>err
+ commit refs/heads/S2
+ mark :303
+ committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+ data <<COMMIT
+ commit 3
+ COMMIT
+ from :301x
+ M 100644 :403 hello.c
+ EOF
+
+ ret=$? &&
+ echo returned $ret &&
+ test $ret -ne 0 && # failed, but it created the commit
+
+ # go create the commit, need it for merge test
+ git fast-import --import-marks=marks --export-marks=marks <<-EOF &&
+ commit refs/heads/S2
+ mark :303
+ committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+ data <<COMMIT
+ commit 3
+ COMMIT
+ from :301
+ M 100644 :403 hello.c
+ EOF
+
+ # now evaluate the error
+ cat err &&
+ test_i18ngrep "after mark" err
+'
+
+
+#
+# merge
+#
+test_expect_success 'S: merge with garbage after mark must fail' '
+ test_must_fail git fast-import --import-marks=marks <<-EOF 2>err &&
+ commit refs/heads/S
+ mark :304
+ committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+ data <<COMMIT
+ merge 4
+ COMMIT
+ from :302
+ merge :303x
+ M 100644 :403 hello.c
+ EOF
+ cat err &&
+ test_i18ngrep "after mark" err
+'
+
+#
+# tag, from markref
+#
+test_expect_success 'S: tag with garbage after mark must fail' '
+ test_must_fail git fast-import --import-marks=marks <<-EOF 2>err &&
+ tag refs/tags/Stag
+ from :302x
+ tagger $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+ data <<TAG
+ tag S
+ TAG
+ EOF
+ cat err &&
+ test_i18ngrep "after mark" err
+'
+
+#
+# cat-blob markref
+#
+test_expect_success 'S: cat-blob with garbage after mark must fail' '
+ test_must_fail git fast-import --import-marks=marks <<-EOF 2>err &&
+ cat-blob :403x
+ EOF
+ cat err &&
+ test_i18ngrep "after mark" err
+'
+
+#
+# ls markref
+#
+test_expect_success 'S: ls with garbage after mark must fail' '
+ test_must_fail git fast-import --import-marks=marks <<-EOF 2>err &&
+ ls :302x hello.c
+ EOF
+ cat err &&
+ test_i18ngrep "space after mark" err
+'
+
+test_expect_success 'S: ls with garbage after sha1 must fail' '
+ sha1=$(grep :302 marks | cut -d\ -f2) &&
+ test_must_fail git fast-import --import-marks=marks <<-EOF 2>err &&
+ ls ${sha1}x hello.c
+ EOF
+ cat err &&
+ test_i18ngrep "space after tree-ish" err
+'
+
test_done
diff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh
index 950d0ff498..b00196bd23 100755
--- a/t/t9350-fast-export.sh
+++ b/t/t9350-fast-export.sh
@@ -86,7 +86,7 @@ test_expect_success 'import/export-marks' '
git checkout -b marks master &&
git fast-export --export-marks=tmp-marks HEAD &&
test -s tmp-marks &&
- test $(wc -l < tmp-marks) -eq 3 &&
+ test_line_count = 3 tmp-marks &&
test $(
git fast-export --import-marks=tmp-marks\
--export-marks=tmp-marks HEAD |
@@ -101,7 +101,7 @@ test_expect_success 'import/export-marks' '
grep ^commit\ |
wc -l) \
-eq 1 &&
- test $(wc -l < tmp-marks) -eq 4
+ test_line_count = 4 tmp-marks
'
diff --git a/t/t9400-git-cvsserver-server.sh b/t/t9400-git-cvsserver-server.sh
index 9199550ef4..806623e885 100755
--- a/t/t9400-git-cvsserver-server.sh
+++ b/t/t9400-git-cvsserver-server.sh
@@ -476,14 +476,14 @@ test_expect_success 'cvs status' '
cd cvswork &&
GIT_CONFIG="$git_config" cvs update &&
GIT_CONFIG="$git_config" cvs status | grep "^File: status.file" >../out &&
- test $(wc -l <../out) = 2
+ test_line_count = 2 ../out
'
cd "$WORKDIR"
test_expect_success 'cvs status (nonrecursive)' '
cd cvswork &&
GIT_CONFIG="$git_config" cvs status -l | grep "^File: status.file" >../out &&
- test $(wc -l <../out) = 1
+ test_line_count = 1 ../out
'
cd "$WORKDIR"
@@ -500,8 +500,8 @@ test_expect_success 'cvs status (no subdirs in header)' '
cd "$WORKDIR"
test_expect_success 'cvs co -c (shows module database)' '
GIT_CONFIG="$git_config" cvs co -c > out &&
- grep "^master[ ]\+master$" < out &&
- ! grep -v "^master[ ]\+master$" < out
+ grep "^master[ ][ ]*master$" <out &&
+ ! grep -v "^master[ ][ ]*master$" <out
'
#------------
diff --git a/t/t9801-git-p4-branch.sh b/t/t9801-git-p4-branch.sh
index a25f18d36a..d414705416 100755
--- a/t/t9801-git-p4-branch.sh
+++ b/t/t9801-git-p4-branch.sh
@@ -172,9 +172,9 @@ test_expect_success 'add simple p4 branches' '
echo file1 >file1 &&
echo file2 >file2 &&
p4 add file1 file2 &&
- p4 submit -d "branch1" &&
+ p4 submit -d "Create branch1" &&
p4 integrate //depot/branch1/... //depot/branch2/... &&
- p4 submit -d "branch2" &&
+ p4 submit -d "Integrate branch2 from branch1" &&
echo file3 >file3 &&
p4 add file3 &&
p4 submit -d "add file3 in branch1" &&
@@ -182,7 +182,7 @@ test_expect_success 'add simple p4 branches' '
echo update >>file2 &&
p4 submit -d "update file2 in branch1" &&
p4 integrate //depot/branch1/... //depot/branch3/... &&
- p4 submit -d "branch3"
+ p4 submit -d "Integrate branch3 from branch1"
)
'
@@ -203,17 +203,17 @@ test_expect_success 'git-p4 clone simple branches' '
test -f file1 &&
test -f file2 &&
test -f file3 &&
- grep -q update file2 &&
+ grep update file2 &&
git reset --hard p4/depot/branch2 &&
test -f file1 &&
test -f file2 &&
test ! -f file3 &&
- test_must_fail grep -q update file2 &&
+ ! grep update file2 &&
git reset --hard p4/depot/branch3 &&
test -f file1 &&
test -f file2 &&
test -f file3 &&
- grep -q update file2 &&
+ grep update file2 &&
cd "$cli" &&
cd branch1 &&
p4 edit file2 &&
@@ -222,7 +222,87 @@ test_expect_success 'git-p4 clone simple branches' '
cd "$git" &&
git reset --hard p4/depot/branch1 &&
"$GITP4" rebase &&
- grep -q file2_ file2
+ grep file2_ file2
+ )
+'
+
+# Create a complex branch structure in P4 depot to check if they are correctly
+# cloned. The branches are created from older changelists to check if git-p4 is
+# able to correctly detect them.
+# The final expected structure is:
+# `branch1
+# | `- file1
+# | `- file2 (updated)
+# | `- file3
+# `branch2
+# | `- file1
+# | `- file2
+# `branch3
+# | `- file1
+# | `- file2 (updated)
+# | `- file3
+# `branch4
+# | `- file1
+# | `- file2
+# `branch5
+# `- file1
+# `- file2
+# `- file3
+test_expect_success 'git-p4 add complex branches' '
+ test_when_finished cleanup_git &&
+ test_create_repo "$git" &&
+ (
+ cd "$cli" &&
+ changelist=$(p4 changes -m1 //depot/... | cut -d" " -f2) &&
+ changelist=$(($changelist - 5)) &&
+ p4 integrate //depot/branch1/...@$changelist //depot/branch4/... &&
+ p4 submit -d "Integrate branch4 from branch1@${changelist}" &&
+ changelist=$(($changelist + 2)) &&
+ p4 integrate //depot/branch1/...@$changelist //depot/branch5/... &&
+ p4 submit -d "Integrate branch5 from branch1@${changelist}"
+ )
+'
+
+# Configure branches through git-config and clone them. git-p4 will only be able
+# to clone the original structure if it is able to detect the origin changelist
+# of each branch.
+test_expect_success 'git-p4 clone complex branches' '
+ test_when_finished cleanup_git &&
+ test_create_repo "$git" &&
+ (
+ cd "$git" &&
+ git config git-p4.branchList branch1:branch2 &&
+ git config --add git-p4.branchList branch1:branch3 &&
+ git config --add git-p4.branchList branch1:branch4 &&
+ git config --add git-p4.branchList branch1:branch5 &&
+ "$GITP4" clone --dest=. --detect-branches //depot@all &&
+ git log --all --graph --decorate --stat &&
+ git reset --hard p4/depot/branch1 &&
+ test_path_is_file file1 &&
+ test_path_is_file file2 &&
+ test_path_is_file file3 &&
+ grep update file2 &&
+ git reset --hard p4/depot/branch2 &&
+ test_path_is_file file1 &&
+ test_path_is_file file2 &&
+ test_path_is_missing file3 &&
+ ! grep update file2 &&
+ git reset --hard p4/depot/branch3 &&
+ test_path_is_file file1 &&
+ test_path_is_file file2 &&
+ test_path_is_file file3 &&
+ grep update file2 &&
+ git reset --hard p4/depot/branch4 &&
+ test_path_is_file file1 &&
+ test_path_is_file file2 &&
+ test_path_is_missing file3 &&
+ ! grep update file2 &&
+ git reset --hard p4/depot/branch5 &&
+ test_path_is_file file1 &&
+ test_path_is_file file2 &&
+ test_path_is_file file3 &&
+ ! grep update file2 &&
+ test_path_is_missing .git/git-p4-tmp
)
'
diff --git a/t/t9803-git-p4-shell-metachars.sh b/t/t9803-git-p4-shell-metachars.sh
index db04375a13..db670207bd 100755
--- a/t/t9803-git-p4-shell-metachars.sh
+++ b/t/t9803-git-p4-shell-metachars.sh
@@ -57,6 +57,54 @@ test_expect_success 'deleting with shell metachars' '
)
'
+# Create a branch with a shell metachar in its name
+#
+# 1. //depot/main
+# 2. //depot/branch$3
+
+test_expect_success 'branch with shell char' '
+ test_when_finished cleanup_git &&
+ test_create_repo "$git" &&
+ (
+ cd "$cli" &&
+
+ mkdir -p main &&
+
+ echo f1 >main/f1 &&
+ p4 add main/f1 &&
+ p4 submit -d "main/f1" &&
+
+ p4 integrate //depot/main/... //depot/branch\$3/... &&
+ p4 submit -d "integrate main to branch\$3" &&
+
+ echo f1 >branch\$3/shell_char_branch_file &&
+ p4 add branch\$3/shell_char_branch_file &&
+ p4 submit -d "branch\$3/shell_char_branch_file" &&
+
+ p4 branch -i <<-EOF &&
+ Branch: branch\$3
+ View: //depot/main/... //depot/branch\$3/...
+ EOF
+
+ p4 edit main/f1 &&
+ echo "a change" >> main/f1 &&
+ p4 submit -d "a change" main/f1 &&
+
+ p4 integrate -b branch\$3 &&
+ p4 resolve -am branch\$3/... &&
+ p4 submit -d "integrate main to branch\$3" &&
+
+ cd "$git" &&
+
+ git config git-p4.branchList main:branch\$3 &&
+ "$GITP4" clone --dest=. --detect-branches //depot@all &&
+ git log --all --graph --decorate --stat &&
+ git reset --hard p4/depot/branch\$3 &&
+ test -f shell_char_branch_file &&
+ test -f f1
+ )
+'
+
test_expect_success 'kill p4d' '
kill_p4d
'
diff --git a/t/t9804-git-p4-label.sh b/t/t9804-git-p4-label.sh
new file mode 100755
index 0000000000..a9e04efb88
--- /dev/null
+++ b/t/t9804-git-p4-label.sh
@@ -0,0 +1,115 @@
+#!/bin/sh
+
+test_description='git-p4 p4 label tests'
+
+. ./lib-git-p4.sh
+
+test_expect_success 'start p4d' '
+ start_p4d
+'
+
+# Basic p4 label tests.
+#
+# Note: can't have more than one label per commit - others
+# are silently discarded.
+#
+test_expect_success 'basic p4 labels' '
+ test_when_finished cleanup_git &&
+ (
+ cd "$cli" &&
+ mkdir -p main &&
+
+ echo f1 >main/f1 &&
+ p4 add main/f1 &&
+ p4 submit -d "main/f1" &&
+
+ echo f2 >main/f2 &&
+ p4 add main/f2 &&
+ p4 submit -d "main/f2" &&
+
+ echo f3 >main/file_with_\$metachar &&
+ p4 add main/file_with_\$metachar &&
+ p4 submit -d "file with metachar" &&
+
+ p4 tag -l tag_f1_only main/f1 &&
+ p4 tag -l tag_with\$_shell_char main/... &&
+
+ echo f4 >main/f4 &&
+ p4 add main/f4 &&
+ p4 submit -d "main/f4" &&
+
+ p4 label -i <<-EOF &&
+ Label: long_label
+ Description:
+ A Label first line
+ A Label second line
+ View: //depot/...
+ EOF
+
+ p4 tag -l long_label ... &&
+
+ p4 labels ... &&
+
+ "$GITP4" clone --dest="$git" --detect-labels //depot@all &&
+ cd "$git" &&
+
+ git tag &&
+ git tag >taglist &&
+ test_line_count = 3 taglist &&
+
+ cd main &&
+ git checkout tag_tag_f1_only &&
+ ! test -f f2 &&
+ git checkout tag_tag_with\$_shell_char &&
+ test -f f1 && test -f f2 && test -f file_with_\$metachar &&
+
+ git show tag_long_label | grep -q "A Label second line"
+ )
+'
+
+# Test some label corner cases:
+#
+# - two tags on the same file; both should be available
+# - a tag that is only on one file; this kind of tag
+# cannot be imported (at least not easily).
+
+test_expect_failure 'two labels on the same changelist' '
+ test_when_finished cleanup_git &&
+ (
+ cd "$cli" &&
+ mkdir -p main &&
+
+ p4 edit main/f1 main/f2 &&
+ echo "hello world" >main/f1 &&
+ echo "not in the tag" >main/f2 &&
+ p4 submit -d "main/f[12]: testing two labels" &&
+
+ p4 tag -l tag_f1_1 main/... &&
+ p4 tag -l tag_f1_2 main/... &&
+
+ p4 labels ... &&
+
+ "$GITP4" clone --dest="$git" --detect-labels //depot@all &&
+ cd "$git" &&
+
+ git tag | grep tag_f1 &&
+ git tag | grep -q tag_f1_1 &&
+ git tag | grep -q tag_f1_2 &&
+
+ cd main &&
+
+ git checkout tag_tag_f1_1 &&
+ ls &&
+ test -f f1 &&
+
+ git checkout tag_tag_f1_2 &&
+ ls &&
+ test -f f1
+ )
+'
+
+test_expect_success 'kill p4d' '
+ kill_p4d
+'
+
+test_done
diff --git a/t/t9806-git-p4-options.sh b/t/t9806-git-p4-options.sh
index 1f1952a657..0571602129 100755
--- a/t/t9806-git-p4-options.sh
+++ b/t/t9806-git-p4-options.sh
@@ -146,7 +146,7 @@ test_expect_success 'clone --use-client-spec' '
(
cd "$git" &&
test_path_is_file bus/dir/f4 &&
- test_path_is_file file1
+ test_path_is_missing file1
) &&
cleanup_git &&
@@ -159,7 +159,7 @@ test_expect_success 'clone --use-client-spec' '
"$GITP4" sync //depot/... &&
git checkout -b master p4/master &&
test_path_is_file bus/dir/f4 &&
- test_path_is_file file1
+ test_path_is_missing file1
)
'
diff --git a/t/t9809-git-p4-client-view.sh b/t/t9809-git-p4-client-view.sh
index b0c6d4391d..773a516ff0 100755
--- a/t/t9809-git-p4-client-view.sh
+++ b/t/t9809-git-p4-client-view.sh
@@ -105,12 +105,18 @@ test_expect_success 'unsupported view wildcard *' '
test_must_fail "$GITP4" clone --use-client-spec --dest="$git" //depot
'
-test_expect_success 'wildcard ... only supported at end of spec' '
+test_expect_success 'wildcard ... only supported at end of spec 1' '
client_view "//depot/.../file11 //client/.../file11" &&
test_when_finished cleanup_git &&
test_must_fail "$GITP4" clone --use-client-spec --dest="$git" //depot
'
+test_expect_success 'wildcard ... only supported at end of spec 2' '
+ client_view "//depot/.../a/... //client/.../a/..." &&
+ test_when_finished cleanup_git &&
+ test_must_fail "$GITP4" clone --use-client-spec --dest="$git" //depot
+'
+
test_expect_success 'basic map' '
client_view "//depot/dir1/... //client/cli1/..." &&
files="cli1/file11 cli1/file12" &&
@@ -378,6 +384,393 @@ test_expect_success 'reinit depot' '
'
#
+# What happens when two files of the same name are overlayed together?
+# The last-listed file should take preference.
+#
+# //depot
+# - dir1
+# - file11
+# - file12
+# - filecollide
+# - dir2
+# - file21
+# - file22
+# - filecollide
+#
+test_expect_success 'overlay collision setup' '
+ client_view "//depot/... //client/..." &&
+ (
+ cd "$cli" &&
+ p4 sync &&
+ echo dir1/filecollide >dir1/filecollide &&
+ p4 add dir1/filecollide &&
+ p4 submit -d dir1/filecollide &&
+ echo dir2/filecollide >dir2/filecollide &&
+ p4 add dir2/filecollide &&
+ p4 submit -d dir2/filecollide
+ )
+'
+
+test_expect_success 'overlay collision 1 to 2' '
+ client_view "//depot/dir1/... //client/..." \
+ "+//depot/dir2/... //client/..." &&
+ files="file11 file12 file21 file22 filecollide" &&
+ echo dir2/filecollide >actual &&
+ client_verify $files &&
+ test_cmp actual "$cli"/filecollide &&
+ test_when_finished cleanup_git &&
+ "$GITP4" clone --use-client-spec --dest="$git" //depot &&
+ git_verify $files &&
+ test_cmp actual "$git"/filecollide
+'
+
+test_expect_failure 'overlay collision 2 to 1' '
+ client_view "//depot/dir2/... //client/..." \
+ "+//depot/dir1/... //client/..." &&
+ files="file11 file12 file21 file22 filecollide" &&
+ echo dir1/filecollide >actual &&
+ client_verify $files &&
+ test_cmp actual "$cli"/filecollide &&
+ test_when_finished cleanup_git &&
+ "$GITP4" clone --use-client-spec --dest="$git" //depot &&
+ git_verify $files &&
+ test_cmp actual "$git"/filecollide
+'
+
+test_expect_success 'overlay collision delete 2' '
+ client_view "//depot/... //client/..." &&
+ (
+ cd "$cli" &&
+ p4 sync &&
+ p4 delete dir2/filecollide &&
+ p4 submit -d "remove dir2/filecollide"
+ )
+'
+
+# no filecollide, got deleted with dir2
+test_expect_failure 'overlay collision 1 to 2, but 2 deleted' '
+ client_view "//depot/dir1/... //client/..." \
+ "+//depot/dir2/... //client/..." &&
+ files="file11 file12 file21 file22" &&
+ client_verify $files &&
+ test_when_finished cleanup_git &&
+ "$GITP4" clone --use-client-spec --dest="$git" //depot &&
+ git_verify $files
+'
+
+test_expect_success 'overlay collision update 1' '
+ client_view "//depot/dir1/... //client/dir1/..." &&
+ (
+ cd "$cli" &&
+ p4 sync &&
+ p4 open dir1/filecollide &&
+ echo dir1/filecollide update >dir1/filecollide &&
+ p4 submit -d "update dir1/filecollide"
+ )
+'
+
+# still no filecollide, dir2 still wins with the deletion even though the
+# change to dir1 is more recent
+test_expect_failure 'overlay collision 1 to 2, but 2 deleted, then 1 updated' '
+ client_view "//depot/dir1/... //client/..." \
+ "+//depot/dir2/... //client/..." &&
+ files="file11 file12 file21 file22" &&
+ client_verify $files &&
+ test_when_finished cleanup_git &&
+ "$GITP4" clone --use-client-spec --dest="$git" //depot &&
+ git_verify $files
+'
+
+test_expect_success 'overlay collision delete filecollides' '
+ client_view "//depot/... //client/..." &&
+ (
+ cd "$cli" &&
+ p4 sync &&
+ p4 delete dir1/filecollide dir2/filecollide &&
+ p4 submit -d "remove filecollides"
+ )
+'
+
+#
+# Overlays as part of sync, rather than initial checkout:
+# 1. add a file in dir1
+# 2. sync to include it
+# 3. add same file in dir2
+# 4. sync, make sure content switches as dir2 has priority
+# 5. add another file in dir1
+# 6. sync
+# 7. add/delete same file in dir2
+# 8. sync, make sure it disappears, again dir2 wins
+# 9. cleanup
+#
+# //depot
+# - dir1
+# - file11
+# - file12
+# - colA
+# - colB
+# - dir2
+# - file21
+# - file22
+# - colA
+# - colB
+#
+test_expect_success 'overlay sync: add colA in dir1' '
+ client_view "//depot/dir1/... //client/dir1/..." &&
+ (
+ cd "$cli" &&
+ p4 sync &&
+ echo dir1/colA >dir1/colA &&
+ p4 add dir1/colA &&
+ p4 submit -d dir1/colA
+ )
+'
+
+test_expect_success 'overlay sync: initial git checkout' '
+ client_view "//depot/dir1/... //client/..." \
+ "+//depot/dir2/... //client/..." &&
+ files="file11 file12 file21 file22 colA" &&
+ echo dir1/colA >actual &&
+ client_verify $files &&
+ test_cmp actual "$cli"/colA &&
+ "$GITP4" clone --use-client-spec --dest="$git" //depot &&
+ git_verify $files &&
+ test_cmp actual "$git"/colA
+'
+
+test_expect_success 'overlay sync: add colA in dir2' '
+ client_view "//depot/dir2/... //client/dir2/..." &&
+ (
+ cd "$cli" &&
+ p4 sync &&
+ echo dir2/colA >dir2/colA &&
+ p4 add dir2/colA &&
+ p4 submit -d dir2/colA
+ )
+'
+
+test_expect_success 'overlay sync: colA content switch' '
+ client_view "//depot/dir1/... //client/..." \
+ "+//depot/dir2/... //client/..." &&
+ files="file11 file12 file21 file22 colA" &&
+ echo dir2/colA >actual &&
+ client_verify $files &&
+ test_cmp actual "$cli"/colA &&
+ (
+ cd "$git" &&
+ "$GITP4" sync --use-client-spec &&
+ git merge --ff-only p4/master
+ ) &&
+ git_verify $files &&
+ test_cmp actual "$git"/colA
+'
+
+test_expect_success 'overlay sync: add colB in dir1' '
+ client_view "//depot/dir1/... //client/dir1/..." &&
+ (
+ cd "$cli" &&
+ p4 sync &&
+ echo dir1/colB >dir1/colB &&
+ p4 add dir1/colB &&
+ p4 submit -d dir1/colB
+ )
+'
+
+test_expect_success 'overlay sync: colB appears' '
+ client_view "//depot/dir1/... //client/..." \
+ "+//depot/dir2/... //client/..." &&
+ files="file11 file12 file21 file22 colA colB" &&
+ echo dir1/colB >actual &&
+ client_verify $files &&
+ test_cmp actual "$cli"/colB &&
+ (
+ cd "$git" &&
+ "$GITP4" sync --use-client-spec &&
+ git merge --ff-only p4/master
+ ) &&
+ git_verify $files &&
+ test_cmp actual "$git"/colB
+'
+
+test_expect_success 'overlay sync: add/delete colB in dir2' '
+ client_view "//depot/dir2/... //client/dir2/..." &&
+ (
+ cd "$cli" &&
+ p4 sync &&
+ echo dir2/colB >dir2/colB &&
+ p4 add dir2/colB &&
+ p4 submit -d dir2/colB &&
+ p4 delete dir2/colB &&
+ p4 submit -d "delete dir2/colB"
+ )
+'
+
+test_expect_success 'overlay sync: colB disappears' '
+ client_view "//depot/dir1/... //client/..." \
+ "+//depot/dir2/... //client/..." &&
+ files="file11 file12 file21 file22 colA" &&
+ client_verify $files &&
+ test_when_finished cleanup_git &&
+ (
+ cd "$git" &&
+ "$GITP4" sync --use-client-spec &&
+ git merge --ff-only p4/master
+ ) &&
+ git_verify $files
+'
+
+test_expect_success 'overlay sync: cleanup' '
+ client_view "//depot/... //client/..." &&
+ (
+ cd "$cli" &&
+ p4 sync &&
+ p4 delete dir1/colA dir2/colA dir1/colB &&
+ p4 submit -d "remove overlay sync files"
+ )
+'
+
+#
+# Overlay tests again, but swapped so dir1 has priority.
+# 1. add a file in dir1
+# 2. sync to include it
+# 3. add same file in dir2
+# 4. sync, make sure content does not switch
+# 5. add another file in dir1
+# 6. sync
+# 7. add/delete same file in dir2
+# 8. sync, make sure it is still there
+# 9. cleanup
+#
+# //depot
+# - dir1
+# - file11
+# - file12
+# - colA
+# - colB
+# - dir2
+# - file21
+# - file22
+# - colA
+# - colB
+#
+test_expect_success 'overlay sync swap: add colA in dir1' '
+ client_view "//depot/dir1/... //client/dir1/..." &&
+ (
+ cd "$cli" &&
+ p4 sync &&
+ echo dir1/colA >dir1/colA &&
+ p4 add dir1/colA &&
+ p4 submit -d dir1/colA
+ )
+'
+
+test_expect_success 'overlay sync swap: initial git checkout' '
+ client_view "//depot/dir2/... //client/..." \
+ "+//depot/dir1/... //client/..." &&
+ files="file11 file12 file21 file22 colA" &&
+ echo dir1/colA >actual &&
+ client_verify $files &&
+ test_cmp actual "$cli"/colA &&
+ "$GITP4" clone --use-client-spec --dest="$git" //depot &&
+ git_verify $files &&
+ test_cmp actual "$git"/colA
+'
+
+test_expect_success 'overlay sync swap: add colA in dir2' '
+ client_view "//depot/dir2/... //client/dir2/..." &&
+ (
+ cd "$cli" &&
+ p4 sync &&
+ echo dir2/colA >dir2/colA &&
+ p4 add dir2/colA &&
+ p4 submit -d dir2/colA
+ )
+'
+
+test_expect_failure 'overlay sync swap: colA no content switch' '
+ client_view "//depot/dir2/... //client/..." \
+ "+//depot/dir1/... //client/..." &&
+ files="file11 file12 file21 file22 colA" &&
+ echo dir1/colA >actual &&
+ client_verify $files &&
+ test_cmp actual "$cli"/colA &&
+ (
+ cd "$git" &&
+ "$GITP4" sync --use-client-spec &&
+ git merge --ff-only p4/master
+ ) &&
+ git_verify $files &&
+ test_cmp actual "$git"/colA
+'
+
+test_expect_success 'overlay sync swap: add colB in dir1' '
+ client_view "//depot/dir1/... //client/dir1/..." &&
+ (
+ cd "$cli" &&
+ p4 sync &&
+ echo dir1/colB >dir1/colB &&
+ p4 add dir1/colB &&
+ p4 submit -d dir1/colB
+ )
+'
+
+test_expect_success 'overlay sync swap: colB appears' '
+ client_view "//depot/dir2/... //client/..." \
+ "+//depot/dir1/... //client/..." &&
+ files="file11 file12 file21 file22 colA colB" &&
+ echo dir1/colB >actual &&
+ client_verify $files &&
+ test_cmp actual "$cli"/colB &&
+ (
+ cd "$git" &&
+ "$GITP4" sync --use-client-spec &&
+ git merge --ff-only p4/master
+ ) &&
+ git_verify $files &&
+ test_cmp actual "$git"/colB
+'
+
+test_expect_success 'overlay sync swap: add/delete colB in dir2' '
+ client_view "//depot/dir2/... //client/dir2/..." &&
+ (
+ cd "$cli" &&
+ p4 sync &&
+ echo dir2/colB >dir2/colB &&
+ p4 add dir2/colB &&
+ p4 submit -d dir2/colB &&
+ p4 delete dir2/colB &&
+ p4 submit -d "delete dir2/colB"
+ )
+'
+
+test_expect_failure 'overlay sync swap: colB no change' '
+ client_view "//depot/dir2/... //client/..." \
+ "+//depot/dir1/... //client/..." &&
+ files="file11 file12 file21 file22 colA colB" &&
+ echo dir1/colB >actual &&
+ client_verify $files &&
+ test_cmp actual "$cli"/colB &&
+ test_when_finished cleanup_git &&
+ (
+ cd "$git" &&
+ "$GITP4" sync --use-client-spec &&
+ git merge --ff-only p4/master
+ ) &&
+ git_verify $files &&
+ test_cmp actual "$cli"/colB
+'
+
+test_expect_success 'overlay sync swap: cleanup' '
+ client_view "//depot/... //client/..." &&
+ (
+ cd "$cli" &&
+ p4 sync &&
+ p4 delete dir1/colA dir2/colA dir1/colB &&
+ p4 submit -d "remove overlay sync files"
+ )
+'
+
+#
# Rename directories to test quoting in depot-side mappings
# //depot
# - "dir 1"
diff --git a/t/t9810-git-p4-rcs.sh b/t/t9810-git-p4-rcs.sh
new file mode 100755
index 0000000000..49dfde0616
--- /dev/null
+++ b/t/t9810-git-p4-rcs.sh
@@ -0,0 +1,388 @@
+#!/bin/sh
+
+test_description='git-p4 rcs keywords'
+
+. ./lib-git-p4.sh
+
+test_expect_success 'start p4d' '
+ start_p4d
+'
+
+#
+# Make one file with keyword lines at the top, and
+# enough plain text to be able to test modifications
+# far away from the keywords.
+#
+test_expect_success 'init depot' '
+ (
+ cd "$cli" &&
+ cat <<-\EOF >filek &&
+ $Id$
+ /* $Revision$ */
+ # $Change$
+ line4
+ line5
+ line6
+ line7
+ line8
+ EOF
+ cp filek fileko &&
+ sed -i "s/Revision/Revision: do not scrub me/" fileko
+ cp fileko file_text &&
+ sed -i "s/Id/Id: do not scrub me/" file_text
+ p4 add -t text+k filek &&
+ p4 submit -d "filek" &&
+ p4 add -t text+ko fileko &&
+ p4 submit -d "fileko" &&
+ p4 add -t text file_text &&
+ p4 submit -d "file_text"
+ )
+'
+
+#
+# Generate these in a function to make it easy to use single quote marks.
+#
+write_scrub_scripts () {
+ cat >"$TRASH_DIRECTORY/scrub_k.py" <<-\EOF &&
+ import re, sys
+ sys.stdout.write(re.sub(r'(?i)\$(Id|Header|Author|Date|DateTime|Change|File|Revision):[^$]*\$', r'$\1$', sys.stdin.read()))
+ EOF
+ cat >"$TRASH_DIRECTORY/scrub_ko.py" <<-\EOF
+ import re, sys
+ sys.stdout.write(re.sub(r'(?i)\$(Id|Header):[^$]*\$', r'$\1$', sys.stdin.read()))
+ EOF
+}
+
+test_expect_success 'scrub scripts' '
+ write_scrub_scripts
+'
+
+#
+# Compare $cli/file to its scrubbed version, should be different.
+# Compare scrubbed $cli/file to $git/file, should be same.
+#
+scrub_k_check () {
+ file="$1" &&
+ scrub="$TRASH_DIRECTORY/$file" &&
+ "$PYTHON_PATH" "$TRASH_DIRECTORY/scrub_k.py" <"$git/$file" >"$scrub" &&
+ ! test_cmp "$cli/$file" "$scrub" &&
+ test_cmp "$git/$file" "$scrub" &&
+ rm "$scrub"
+}
+scrub_ko_check () {
+ file="$1" &&
+ scrub="$TRASH_DIRECTORY/$file" &&
+ "$PYTHON_PATH" "$TRASH_DIRECTORY/scrub_ko.py" <"$git/$file" >"$scrub" &&
+ ! test_cmp "$cli/$file" "$scrub" &&
+ test_cmp "$git/$file" "$scrub" &&
+ rm "$scrub"
+}
+
+#
+# Modify far away from keywords. If no RCS lines show up
+# in the diff, there is no conflict.
+#
+test_expect_success 'edit far away from RCS lines' '
+ test_when_finished cleanup_git &&
+ "$GITP4" clone --dest="$git" //depot &&
+ (
+ cd "$git" &&
+ git config git-p4.skipSubmitEdit true &&
+ sed -i "s/^line7/line7 edit/" filek &&
+ git commit -m "filek line7 edit" filek &&
+ "$GITP4" submit &&
+ scrub_k_check filek
+ )
+'
+
+#
+# Modify near the keywords. This will require RCS scrubbing.
+#
+test_expect_success 'edit near RCS lines' '
+ test_when_finished cleanup_git &&
+ "$GITP4" clone --dest="$git" //depot &&
+ (
+ cd "$git" &&
+ git config git-p4.skipSubmitEdit true &&
+ git config git-p4.attemptRCSCleanup true &&
+ sed -i "s/^line4/line4 edit/" filek &&
+ git commit -m "filek line4 edit" filek &&
+ "$GITP4" submit &&
+ scrub_k_check filek
+ )
+'
+
+#
+# Modify the keywords themselves. This also will require RCS scrubbing.
+#
+test_expect_success 'edit keyword lines' '
+ test_when_finished cleanup_git &&
+ "$GITP4" clone --dest="$git" //depot &&
+ (
+ cd "$git" &&
+ git config git-p4.skipSubmitEdit true &&
+ git config git-p4.attemptRCSCleanup true &&
+ sed -i "/Revision/d" filek &&
+ git commit -m "filek remove Revision line" filek &&
+ "$GITP4" submit &&
+ scrub_k_check filek
+ )
+'
+
+#
+# Scrubbing text+ko files should not alter all keywords, just Id, Header.
+#
+test_expect_success 'scrub ko files differently' '
+ test_when_finished cleanup_git &&
+ "$GITP4" clone --dest="$git" //depot &&
+ (
+ cd "$git" &&
+ git config git-p4.skipSubmitEdit true &&
+ git config git-p4.attemptRCSCleanup true &&
+ sed -i "s/^line4/line4 edit/" fileko &&
+ git commit -m "fileko line4 edit" fileko &&
+ "$GITP4" submit &&
+ scrub_ko_check fileko &&
+ ! scrub_k_check fileko
+ )
+'
+
+# hack; git-p4 submit should do it on its own
+test_expect_success 'cleanup after failure' '
+ (
+ cd "$cli" &&
+ p4 revert ...
+ )
+'
+
+#
+# Do not scrub anything but +k or +ko files. Sneak a change into
+# the cli file so that submit will get a conflict. Make sure that
+# 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.
+#
+test_expect_success 'do not scrub plain text' '
+ test_when_finished cleanup_git &&
+ "$GITP4" clone --dest="$git" //depot &&
+ (
+ cd "$git" &&
+ git config git-p4.skipSubmitEdit true &&
+ git config git-p4.attemptRCSCleanup true &&
+ sed -i "s/^line4/line4 edit/" file_text &&
+ git commit -m "file_text line4 edit" file_text &&
+ (
+ cd "$cli" &&
+ p4 open file_text &&
+ sed -i "s/^line5/line5 p4 edit/" file_text &&
+ p4 submit -d "file5 p4 edit"
+ ) &&
+ ! "$GITP4" submit &&
+ (
+ # exepct something like:
+ # file_text - file(s) not opened on this client
+ # but not copious diff output
+ cd "$cli" &&
+ p4 diff file_text >wc &&
+ test_line_count = 1 wc
+ )
+ )
+'
+
+# hack; git-p4 submit should do it on its own
+test_expect_success 'cleanup after failure 2' '
+ (
+ cd "$cli" &&
+ p4 revert ...
+ )
+'
+
+create_kw_file () {
+ cat <<\EOF >"$1"
+/* A file
+ Id: $Id$
+ Revision: $Revision$
+ File: $File$
+ */
+int main(int argc, const char **argv) {
+ return 0;
+}
+EOF
+}
+
+test_expect_success 'add kwfile' '
+ (
+ cd "$cli" &&
+ echo file1 >file1 &&
+ p4 add file1 &&
+ p4 submit -d "file 1" &&
+ create_kw_file kwfile1.c &&
+ p4 add kwfile1.c &&
+ p4 submit -d "Add rcw kw file" kwfile1.c
+ )
+'
+
+p4_append_to_file () {
+ f="$1" &&
+ p4 edit -t ktext "$f" &&
+ echo "/* $(date) */" >>"$f" &&
+ p4 submit -d "appending a line in p4"
+}
+
+# Create some files with RCS keywords. If they get modified
+# elsewhere then the version number gets bumped which then
+# results in a merge conflict if we touch the RCS kw lines,
+# even though the change itself would otherwise apply cleanly.
+test_expect_success 'cope with rcs keyword expansion damage' '
+ test_when_finished cleanup_git &&
+ "$GITP4" clone --dest="$git" //depot &&
+ (
+ cd "$git" &&
+ git config git-p4.skipSubmitEdit true &&
+ git config git-p4.attemptRCSCleanup true &&
+ (cd ../cli && p4_append_to_file kwfile1.c) &&
+ old_lines=$(wc -l <kwfile1.c) &&
+ perl -n -i -e "print unless m/Revision:/" kwfile1.c &&
+ new_lines=$(wc -l <kwfile1.c) &&
+ test $new_lines = $(($old_lines - 1)) &&
+
+ git add kwfile1.c &&
+ git commit -m "Zap an RCS kw line" &&
+ "$GITP4" submit &&
+ "$GITP4" rebase &&
+ git diff p4/master &&
+ "$GITP4" commit &&
+ echo "try modifying in both" &&
+ cd "$cli" &&
+ p4 edit kwfile1.c &&
+ echo "line from p4" >>kwfile1.c &&
+ p4 submit -d "add a line in p4" kwfile1.c &&
+ cd "$git" &&
+ echo "line from git at the top" | cat - kwfile1.c >kwfile1.c.new &&
+ mv kwfile1.c.new kwfile1.c &&
+ git commit -m "Add line in git at the top" kwfile1.c &&
+ "$GITP4" rebase &&
+ "$GITP4" submit
+ )
+'
+
+test_expect_success 'cope with rcs keyword file deletion' '
+ test_when_finished cleanup_git &&
+ (
+ cd "$cli" &&
+ echo "\$Revision\$" >kwdelfile.c &&
+ p4 add -t ktext kwdelfile.c &&
+ p4 submit -d "Add file to be deleted" &&
+ cat kwdelfile.c &&
+ grep 1 kwdelfile.c
+ ) &&
+ "$GITP4" clone --dest="$git" //depot &&
+ (
+ cd "$git" &&
+ grep Revision kwdelfile.c &&
+ git rm -f kwdelfile.c &&
+ git commit -m "Delete a file containing RCS keywords" &&
+ git config git-p4.skipSubmitEdit true &&
+ git config git-p4.attemptRCSCleanup true &&
+ "$GITP4" submit
+ ) &&
+ (
+ cd "$cli" &&
+ p4 sync &&
+ ! test -f kwdelfile.c
+ )
+'
+
+# If you add keywords in git of the form $Header$ then everything should
+# work fine without any special handling.
+test_expect_success 'Add keywords in git which match the default p4 values' '
+ test_when_finished cleanup_git &&
+ "$GITP4" clone --dest="$git" //depot &&
+ (
+ cd "$git" &&
+ echo "NewKW: \$Revision\$" >>kwfile1.c &&
+ git add kwfile1.c &&
+ git commit -m "Adding RCS keywords in git" &&
+ git config git-p4.skipSubmitEdit true &&
+ git config git-p4.attemptRCSCleanup true &&
+ "$GITP4" submit
+ ) &&
+ (
+ cd "$cli" &&
+ p4 sync &&
+ test -f kwfile1.c &&
+ grep "NewKW.*Revision.*[0-9]" kwfile1.c
+
+ )
+'
+
+# If you add keywords in git of the form $Header:#1$ then things will fail
+# unless git-p4 takes steps to scrub the *git* commit.
+#
+test_expect_failure 'Add keywords in git which do not match the default p4 values' '
+ test_when_finished cleanup_git &&
+ "$GITP4" clone --dest="$git" //depot &&
+ (
+ cd "$git" &&
+ echo "NewKW2: \$Revision:1\$" >>kwfile1.c &&
+ git add kwfile1.c &&
+ git commit -m "Adding RCS keywords in git" &&
+ git config git-p4.skipSubmitEdit true &&
+ git config git-p4.attemptRCSCleanup true &&
+ "$GITP4" submit
+ ) &&
+ (
+ cd "$cli" &&
+ p4 sync &&
+ grep "NewKW2.*Revision.*[0-9]" kwfile1.c
+
+ )
+'
+
+# 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"
+ ) &&
+ "$GITP4" 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" | "$GITP4" submit) &&
+ git rebase --skip &&
+ ! test -f merge2.c
+ )
+'
+
+
+test_expect_success 'kill p4d' '
+ kill_p4d
+'
+
+test_done
diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh
new file mode 100644
index 0000000000..7b3b4bef30
--- /dev/null
+++ b/t/test-lib-functions.sh
@@ -0,0 +1,565 @@
+#!/bin/sh
+#
+# Copyright (c) 2005 Junio C Hamano
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see http://www.gnu.org/licenses/ .
+
+# The semantics of the editor variables are that of invoking
+# sh -c "$EDITOR \"$@\"" files ...
+#
+# If our trash directory contains shell metacharacters, they will be
+# interpreted if we just set $EDITOR directly, so do a little dance with
+# environment variables to work around this.
+#
+# In particular, quoting isn't enough, as the path may contain the same quote
+# that we're using.
+test_set_editor () {
+ FAKE_EDITOR="$1"
+ export FAKE_EDITOR
+ EDITOR='"$FAKE_EDITOR"'
+ export EDITOR
+}
+
+test_decode_color () {
+ awk '
+ function name(n) {
+ if (n == 0) return "RESET";
+ if (n == 1) return "BOLD";
+ if (n == 30) return "BLACK";
+ if (n == 31) return "RED";
+ if (n == 32) return "GREEN";
+ if (n == 33) return "YELLOW";
+ if (n == 34) return "BLUE";
+ if (n == 35) return "MAGENTA";
+ if (n == 36) return "CYAN";
+ if (n == 37) return "WHITE";
+ if (n == 40) return "BLACK";
+ if (n == 41) return "BRED";
+ if (n == 42) return "BGREEN";
+ if (n == 43) return "BYELLOW";
+ if (n == 44) return "BBLUE";
+ if (n == 45) return "BMAGENTA";
+ if (n == 46) return "BCYAN";
+ if (n == 47) return "BWHITE";
+ }
+ {
+ while (match($0, /\033\[[0-9;]*m/) != 0) {
+ printf "%s<", substr($0, 1, RSTART-1);
+ codes = substr($0, RSTART+2, RLENGTH-3);
+ if (length(codes) == 0)
+ printf "%s", name(0)
+ else {
+ n = split(codes, ary, ";");
+ sep = "";
+ for (i = 1; i <= n; i++) {
+ printf "%s%s", sep, name(ary[i]);
+ sep = ";"
+ }
+ }
+ printf ">";
+ $0 = substr($0, RSTART + RLENGTH, length($0) - RSTART - RLENGTH + 1);
+ }
+ print
+ }
+ '
+}
+
+nul_to_q () {
+ perl -pe 'y/\000/Q/'
+}
+
+q_to_nul () {
+ perl -pe 'y/Q/\000/'
+}
+
+q_to_cr () {
+ tr Q '\015'
+}
+
+q_to_tab () {
+ tr Q '\011'
+}
+
+append_cr () {
+ sed -e 's/$/Q/' | tr Q '\015'
+}
+
+remove_cr () {
+ tr '\015' Q | sed -e 's/Q$//'
+}
+
+# In some bourne shell implementations, the "unset" builtin returns
+# nonzero status when a variable to be unset was not set in the first
+# place.
+#
+# Use sane_unset when that should not be considered an error.
+
+sane_unset () {
+ unset "$@"
+ return 0
+}
+
+test_tick () {
+ if test -z "${test_tick+set}"
+ then
+ test_tick=1112911993
+ else
+ test_tick=$(($test_tick + 60))
+ fi
+ GIT_COMMITTER_DATE="$test_tick -0700"
+ GIT_AUTHOR_DATE="$test_tick -0700"
+ export GIT_COMMITTER_DATE GIT_AUTHOR_DATE
+}
+
+# Stop execution and start a shell. This is useful for debugging tests and
+# only makes sense together with "-v".
+#
+# Be sure to remove all invocations of this command before submitting.
+
+test_pause () {
+ if test "$verbose" = t; then
+ "$SHELL_PATH" <&6 >&3 2>&4
+ else
+ error >&5 "test_pause requires --verbose"
+ fi
+}
+
+# Call test_commit with the arguments "<message> [<file> [<contents>]]"
+#
+# This will commit a file with the given contents and the given commit
+# message. It will also add a tag with <message> as name.
+#
+# Both <file> and <contents> default to <message>.
+
+test_commit () {
+ file=${2:-"$1.t"}
+ echo "${3-$1}" > "$file" &&
+ git add "$file" &&
+ test_tick &&
+ git commit -m "$1" &&
+ git tag "$1"
+}
+
+# Call test_merge with the arguments "<message> <commit>", where <commit>
+# can be a tag pointing to the commit-to-merge.
+
+test_merge () {
+ test_tick &&
+ git merge -m "$1" "$2" &&
+ git tag "$1"
+}
+
+# This function helps systems where core.filemode=false is set.
+# Use it instead of plain 'chmod +x' to set or unset the executable bit
+# of a file in the working directory and add it to the index.
+
+test_chmod () {
+ chmod "$@" &&
+ git update-index --add "--chmod=$@"
+}
+
+# Unset a configuration variable, but don't fail if it doesn't exist.
+test_unconfig () {
+ git config --unset-all "$@"
+ config_status=$?
+ case "$config_status" in
+ 5) # ok, nothing to unset
+ config_status=0
+ ;;
+ esac
+ return $config_status
+}
+
+# Set git config, automatically unsetting it after the test is over.
+test_config () {
+ test_when_finished "test_unconfig '$1'" &&
+ git config "$@"
+}
+
+test_config_global () {
+ test_when_finished "test_unconfig --global '$1'" &&
+ git config --global "$@"
+}
+
+write_script () {
+ {
+ echo "#!${2-"$SHELL_PATH"}" &&
+ cat
+ } >"$1" &&
+ chmod +x "$1"
+}
+
+# Use test_set_prereq to tell that a particular prerequisite is available.
+# The prerequisite can later be checked for in two ways:
+#
+# - Explicitly using test_have_prereq.
+#
+# - Implicitly by specifying the prerequisite tag in the calls to
+# test_expect_{success,failure,code}.
+#
+# The single parameter is the prerequisite tag (a simple word, in all
+# capital letters by convention).
+
+test_set_prereq () {
+ satisfied="$satisfied$1 "
+}
+satisfied=" "
+
+test_have_prereq () {
+ # prerequisites can be concatenated with ','
+ save_IFS=$IFS
+ IFS=,
+ set -- $*
+ IFS=$save_IFS
+
+ total_prereq=0
+ ok_prereq=0
+ missing_prereq=
+
+ for prerequisite
+ do
+ total_prereq=$(($total_prereq + 1))
+ case $satisfied in
+ *" $prerequisite "*)
+ ok_prereq=$(($ok_prereq + 1))
+ ;;
+ *)
+ # Keep a list of missing prerequisites
+ if test -z "$missing_prereq"
+ then
+ missing_prereq=$prerequisite
+ else
+ missing_prereq="$prerequisite,$missing_prereq"
+ fi
+ esac
+ done
+
+ test $total_prereq = $ok_prereq
+}
+
+test_declared_prereq () {
+ case ",$test_prereq," in
+ *,$1,*)
+ return 0
+ ;;
+ esac
+ return 1
+}
+
+test_expect_failure () {
+ test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq=
+ test "$#" = 2 ||
+ error "bug in the test script: not 2 or 3 parameters to test-expect-failure"
+ export test_prereq
+ if ! test_skip "$@"
+ then
+ say >&3 "checking known breakage: $2"
+ if test_run_ "$2" expecting_failure
+ then
+ test_known_broken_ok_ "$1"
+ else
+ test_known_broken_failure_ "$1"
+ fi
+ fi
+ echo >&3 ""
+}
+
+test_expect_success () {
+ test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq=
+ test "$#" = 2 ||
+ error "bug in the test script: not 2 or 3 parameters to test-expect-success"
+ export test_prereq
+ if ! test_skip "$@"
+ then
+ say >&3 "expecting success: $2"
+ if test_run_ "$2"
+ then
+ test_ok_ "$1"
+ else
+ test_failure_ "$@"
+ fi
+ fi
+ echo >&3 ""
+}
+
+# test_external runs external test scripts that provide continuous
+# test output about their progress, and succeeds/fails on
+# zero/non-zero exit code. It outputs the test output on stdout even
+# in non-verbose mode, and announces the external script with "# run
+# <n>: ..." before running it. When providing relative paths, keep in
+# mind that all scripts run in "trash directory".
+# Usage: test_external description command arguments...
+# Example: test_external 'Perl API' perl ../path/to/test.pl
+test_external () {
+ test "$#" = 4 && { test_prereq=$1; shift; } || test_prereq=
+ test "$#" = 3 ||
+ error >&5 "bug in the test script: not 3 or 4 parameters to test_external"
+ descr="$1"
+ shift
+ export test_prereq
+ if ! test_skip "$descr" "$@"
+ then
+ # Announce the script to reduce confusion about the
+ # test output that follows.
+ say_color "" "# run $test_count: $descr ($*)"
+ # Export TEST_DIRECTORY, TRASH_DIRECTORY and GIT_TEST_LONG
+ # to be able to use them in script
+ export TEST_DIRECTORY TRASH_DIRECTORY GIT_TEST_LONG
+ # Run command; redirect its stderr to &4 as in
+ # test_run_, but keep its stdout on our stdout even in
+ # non-verbose mode.
+ "$@" 2>&4
+ if [ "$?" = 0 ]
+ then
+ if test $test_external_has_tap -eq 0; then
+ test_ok_ "$descr"
+ else
+ say_color "" "# test_external test $descr was ok"
+ test_success=$(($test_success + 1))
+ fi
+ else
+ if test $test_external_has_tap -eq 0; then
+ test_failure_ "$descr" "$@"
+ else
+ say_color error "# test_external test $descr failed: $@"
+ test_failure=$(($test_failure + 1))
+ fi
+ fi
+ fi
+}
+
+# Like test_external, but in addition tests that the command generated
+# no output on stderr.
+test_external_without_stderr () {
+ # The temporary file has no (and must have no) security
+ # implications.
+ tmp=${TMPDIR:-/tmp}
+ stderr="$tmp/git-external-stderr.$$.tmp"
+ test_external "$@" 4> "$stderr"
+ [ -f "$stderr" ] || error "Internal error: $stderr disappeared."
+ descr="no stderr: $1"
+ shift
+ say >&3 "# expecting no stderr from previous command"
+ if [ ! -s "$stderr" ]; then
+ rm "$stderr"
+
+ if test $test_external_has_tap -eq 0; then
+ test_ok_ "$descr"
+ else
+ say_color "" "# test_external_without_stderr test $descr was ok"
+ test_success=$(($test_success + 1))
+ fi
+ else
+ if [ "$verbose" = t ]; then
+ output=`echo; echo "# Stderr is:"; cat "$stderr"`
+ else
+ output=
+ fi
+ # rm first in case test_failure exits.
+ rm "$stderr"
+ if test $test_external_has_tap -eq 0; then
+ test_failure_ "$descr" "$@" "$output"
+ else
+ say_color error "# test_external_without_stderr test $descr failed: $@: $output"
+ test_failure=$(($test_failure + 1))
+ fi
+ fi
+}
+
+# debugging-friendly alternatives to "test [-f|-d|-e]"
+# The commands test the existence or non-existence of $1. $2 can be
+# given to provide a more precise diagnosis.
+test_path_is_file () {
+ if ! [ -f "$1" ]
+ then
+ echo "File $1 doesn't exist. $*"
+ false
+ fi
+}
+
+test_path_is_dir () {
+ if ! [ -d "$1" ]
+ then
+ echo "Directory $1 doesn't exist. $*"
+ false
+ fi
+}
+
+test_path_is_missing () {
+ if [ -e "$1" ]
+ then
+ echo "Path exists:"
+ ls -ld "$1"
+ if [ $# -ge 1 ]; then
+ echo "$*"
+ fi
+ false
+ fi
+}
+
+# test_line_count checks that a file has the number of lines it
+# ought to. For example:
+#
+# test_expect_success 'produce exactly one line of output' '
+# do something >output &&
+# test_line_count = 1 output
+# '
+#
+# is like "test $(wc -l <output) = 1" except that it passes the
+# output through when the number of lines is wrong.
+
+test_line_count () {
+ if test $# != 3
+ then
+ error "bug in the test script: not 3 parameters to test_line_count"
+ elif ! test $(wc -l <"$3") "$1" "$2"
+ then
+ echo "test_line_count: line count for $3 !$1 $2"
+ cat "$3"
+ return 1
+ fi
+}
+
+# This is not among top-level (test_expect_success | test_expect_failure)
+# but is a prefix that can be used in the test script, like:
+#
+# test_expect_success 'complain and die' '
+# do something &&
+# do something else &&
+# test_must_fail git checkout ../outerspace
+# '
+#
+# Writing this as "! git checkout ../outerspace" is wrong, because
+# the failure could be due to a segv. We want a controlled failure.
+
+test_must_fail () {
+ "$@"
+ exit_code=$?
+ if test $exit_code = 0; then
+ echo >&2 "test_must_fail: command succeeded: $*"
+ return 1
+ elif test $exit_code -gt 129 -a $exit_code -le 192; then
+ echo >&2 "test_must_fail: died by signal: $*"
+ return 1
+ elif test $exit_code = 127; then
+ echo >&2 "test_must_fail: command not found: $*"
+ return 1
+ fi
+ return 0
+}
+
+# Similar to test_must_fail, but tolerates success, too. This is
+# meant to be used in contexts like:
+#
+# test_expect_success 'some command works without configuration' '
+# test_might_fail git config --unset all.configuration &&
+# do something
+# '
+#
+# Writing "git config --unset all.configuration || :" would be wrong,
+# because we want to notice if it fails due to segv.
+
+test_might_fail () {
+ "$@"
+ exit_code=$?
+ if test $exit_code -gt 129 -a $exit_code -le 192; then
+ echo >&2 "test_might_fail: died by signal: $*"
+ return 1
+ elif test $exit_code = 127; then
+ echo >&2 "test_might_fail: command not found: $*"
+ return 1
+ fi
+ return 0
+}
+
+# Similar to test_must_fail and test_might_fail, but check that a
+# given command exited with a given exit code. Meant to be used as:
+#
+# test_expect_success 'Merge with d/f conflicts' '
+# test_expect_code 1 git merge "merge msg" B master
+# '
+
+test_expect_code () {
+ want_code=$1
+ shift
+ "$@"
+ exit_code=$?
+ if test $exit_code = $want_code
+ then
+ return 0
+ fi
+
+ echo >&2 "test_expect_code: command exited with $exit_code, we wanted $want_code $*"
+ return 1
+}
+
+# test_cmp is a helper function to compare actual and expected output.
+# You can use it like:
+#
+# test_expect_success 'foo works' '
+# echo expected >expected &&
+# foo >actual &&
+# test_cmp expected actual
+# '
+#
+# This could be written as either "cmp" or "diff -u", but:
+# - cmp's output is not nearly as easy to read as diff -u
+# - not all diff versions understand "-u"
+
+test_cmp() {
+ $GIT_TEST_CMP "$@"
+}
+
+# This function can be used to schedule some commands to be run
+# unconditionally at the end of the test to restore sanity:
+#
+# test_expect_success 'test core.capslock' '
+# git config core.capslock true &&
+# test_when_finished "git config --unset core.capslock" &&
+# hello world
+# '
+#
+# That would be roughly equivalent to
+#
+# test_expect_success 'test core.capslock' '
+# git config core.capslock true &&
+# hello world
+# git config --unset core.capslock
+# '
+#
+# except that the greeting and config --unset must both succeed for
+# the test to pass.
+#
+# Note that under --immediate mode, no clean-up is done to help diagnose
+# what went wrong.
+
+test_when_finished () {
+ test_cleanup="{ $*
+ } && (exit \"\$eval_ret\"); eval_ret=\$?; $test_cleanup"
+}
+
+# Most tests can use the created repository, but some may need to create more.
+# Usage: test_create_repo <directory>
+test_create_repo () {
+ test "$#" = 1 ||
+ error "bug in the test script: not 1 parameter to test-create-repo"
+ repo="$1"
+ mkdir -p "$repo"
+ (
+ cd "$repo" || error "Cannot setup test environment"
+ "$GIT_EXEC_PATH/git-init" "--template=$GIT_BUILD_DIR/templates/blt/" >&3 2>&4 ||
+ error "cannot run git init -- have you built things yet?"
+ mv .git/hooks .git/hooks-disabled
+ ) || exit
+}
diff --git a/t/test-lib.sh b/t/test-lib.sh
index c0d04c494a..9e2b71132a 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -46,7 +46,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 $(perl -e '
+unset VISUAL EMAIL LANGUAGE COLUMNS $(perl -e '
my @env = keys %ENV;
my $ok = join("|", qw(
TRACE
@@ -56,6 +56,7 @@ unset VISUAL EMAIL LANGUAGE $(perl -e '
.*_TEST
PROVE
VALGRIND
+ PERF_AGGREGATING_LATER
));
my @vars = grep(/^GIT_/ && !/^GIT_($ok)/o, @env);
print join("\n", @vars);
@@ -65,7 +66,8 @@ GIT_AUTHOR_NAME='A U Thor'
GIT_COMMITTER_EMAIL=committer@example.com
GIT_COMMITTER_NAME='C O Mitter'
GIT_MERGE_VERBOSITY=5
-export GIT_MERGE_VERBOSITY
+GIT_MERGE_AUTOEDIT=no
+export GIT_MERGE_VERBOSITY GIT_MERGE_AUTOEDIT
export GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME
export GIT_COMMITTER_EMAIL GIT_COMMITTER_NAME
export EDITOR
@@ -98,6 +100,8 @@ _z40=0000000000000000000000000000000000000000
LF='
'
+export _x05 _x40 _z40 LF
+
# Each test should start with something like this, after copyright notices:
#
# test_description='Description of this test...
@@ -223,235 +227,9 @@ die () {
GIT_EXIT_OK=
trap 'die' EXIT
-# The semantics of the editor variables are that of invoking
-# sh -c "$EDITOR \"$@\"" files ...
-#
-# If our trash directory contains shell metacharacters, they will be
-# interpreted if we just set $EDITOR directly, so do a little dance with
-# environment variables to work around this.
-#
-# In particular, quoting isn't enough, as the path may contain the same quote
-# that we're using.
-test_set_editor () {
- FAKE_EDITOR="$1"
- export FAKE_EDITOR
- EDITOR='"$FAKE_EDITOR"'
- export EDITOR
-}
-
-test_decode_color () {
- awk '
- function name(n) {
- if (n == 0) return "RESET";
- if (n == 1) return "BOLD";
- if (n == 30) return "BLACK";
- if (n == 31) return "RED";
- if (n == 32) return "GREEN";
- if (n == 33) return "YELLOW";
- if (n == 34) return "BLUE";
- if (n == 35) return "MAGENTA";
- if (n == 36) return "CYAN";
- if (n == 37) return "WHITE";
- if (n == 40) return "BLACK";
- if (n == 41) return "BRED";
- if (n == 42) return "BGREEN";
- if (n == 43) return "BYELLOW";
- if (n == 44) return "BBLUE";
- if (n == 45) return "BMAGENTA";
- if (n == 46) return "BCYAN";
- if (n == 47) return "BWHITE";
- }
- {
- while (match($0, /\033\[[0-9;]*m/) != 0) {
- printf "%s<", substr($0, 1, RSTART-1);
- codes = substr($0, RSTART+2, RLENGTH-3);
- if (length(codes) == 0)
- printf "%s", name(0)
- else {
- n = split(codes, ary, ";");
- sep = "";
- for (i = 1; i <= n; i++) {
- printf "%s%s", sep, name(ary[i]);
- sep = ";"
- }
- }
- printf ">";
- $0 = substr($0, RSTART + RLENGTH, length($0) - RSTART - RLENGTH + 1);
- }
- print
- }
- '
-}
-
-nul_to_q () {
- perl -pe 'y/\000/Q/'
-}
-
-q_to_nul () {
- perl -pe 'y/Q/\000/'
-}
-
-q_to_cr () {
- tr Q '\015'
-}
-
-q_to_tab () {
- tr Q '\011'
-}
-
-append_cr () {
- sed -e 's/$/Q/' | tr Q '\015'
-}
-
-remove_cr () {
- tr '\015' Q | sed -e 's/Q$//'
-}
-
-# In some bourne shell implementations, the "unset" builtin returns
-# nonzero status when a variable to be unset was not set in the first
-# place.
-#
-# Use sane_unset when that should not be considered an error.
-
-sane_unset () {
- unset "$@"
- return 0
-}
-
-test_tick () {
- if test -z "${test_tick+set}"
- then
- test_tick=1112911993
- else
- test_tick=$(($test_tick + 60))
- fi
- GIT_COMMITTER_DATE="$test_tick -0700"
- GIT_AUTHOR_DATE="$test_tick -0700"
- export GIT_COMMITTER_DATE GIT_AUTHOR_DATE
-}
-
-# Call test_commit with the arguments "<message> [<file> [<contents>]]"
-#
-# This will commit a file with the given contents and the given commit
-# message. It will also add a tag with <message> as name.
-#
-# Both <file> and <contents> default to <message>.
-
-test_commit () {
- file=${2:-"$1.t"}
- echo "${3-$1}" > "$file" &&
- git add "$file" &&
- test_tick &&
- git commit -m "$1" &&
- git tag "$1"
-}
-
-# Call test_merge with the arguments "<message> <commit>", where <commit>
-# can be a tag pointing to the commit-to-merge.
-
-test_merge () {
- test_tick &&
- git merge -m "$1" "$2" &&
- git tag "$1"
-}
-
-# This function helps systems where core.filemode=false is set.
-# Use it instead of plain 'chmod +x' to set or unset the executable bit
-# of a file in the working directory and add it to the index.
-
-test_chmod () {
- chmod "$@" &&
- git update-index --add "--chmod=$@"
-}
-
-# Unset a configuration variable, but don't fail if it doesn't exist.
-test_unconfig () {
- git config --unset-all "$@"
- config_status=$?
- case "$config_status" in
- 5) # ok, nothing to unset
- config_status=0
- ;;
- esac
- return $config_status
-}
-
-# Set git config, automatically unsetting it after the test is over.
-test_config () {
- test_when_finished "test_unconfig '$1'" &&
- git config "$@"
-}
-
-
-test_config_global () {
- test_when_finished "test_unconfig --global '$1'" &&
- git config --global "$@"
-}
-
-write_script () {
- {
- echo "#!${2-"$SHELL_PATH"}" &&
- cat
- } >"$1" &&
- chmod +x "$1"
-}
-
-# Use test_set_prereq to tell that a particular prerequisite is available.
-# The prerequisite can later be checked for in two ways:
-#
-# - Explicitly using test_have_prereq.
-#
-# - Implicitly by specifying the prerequisite tag in the calls to
-# test_expect_{success,failure,code}.
-#
-# The single parameter is the prerequisite tag (a simple word, in all
-# capital letters by convention).
-
-test_set_prereq () {
- satisfied="$satisfied$1 "
-}
-satisfied=" "
-
-test_have_prereq () {
- # prerequisites can be concatenated with ','
- save_IFS=$IFS
- IFS=,
- set -- $*
- IFS=$save_IFS
-
- total_prereq=0
- ok_prereq=0
- missing_prereq=
-
- for prerequisite
- do
- total_prereq=$(($total_prereq + 1))
- case $satisfied in
- *" $prerequisite "*)
- ok_prereq=$(($ok_prereq + 1))
- ;;
- *)
- # Keep a list of missing prerequisites
- if test -z "$missing_prereq"
- then
- missing_prereq=$prerequisite
- else
- missing_prereq="$prerequisite,$missing_prereq"
- fi
- esac
- done
-
- test $total_prereq = $ok_prereq
-}
-
-test_declared_prereq () {
- case ",$test_prereq," in
- *,$1,*)
- return 0
- ;;
- esac
- return 1
-}
+# 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
# You are not expected to call test_ok_ and test_failure_ directly, use
# the text_expect_* functions instead.
@@ -539,318 +317,16 @@ test_skip () {
esac
}
-test_expect_failure () {
- test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq=
- test "$#" = 2 ||
- error "bug in the test script: not 2 or 3 parameters to test-expect-failure"
- export test_prereq
- if ! test_skip "$@"
- then
- say >&3 "checking known breakage: $2"
- if test_run_ "$2" expecting_failure
- then
- test_known_broken_ok_ "$1"
- else
- test_known_broken_failure_ "$1"
- fi
- fi
- echo >&3 ""
-}
-
-test_expect_success () {
- test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq=
- test "$#" = 2 ||
- error "bug in the test script: not 2 or 3 parameters to test-expect-success"
- export test_prereq
- if ! test_skip "$@"
- then
- say >&3 "expecting success: $2"
- if test_run_ "$2"
- then
- test_ok_ "$1"
- else
- test_failure_ "$@"
- fi
- fi
- echo >&3 ""
-}
-
-# test_external runs external test scripts that provide continuous
-# test output about their progress, and succeeds/fails on
-# zero/non-zero exit code. It outputs the test output on stdout even
-# in non-verbose mode, and announces the external script with "# run
-# <n>: ..." before running it. When providing relative paths, keep in
-# mind that all scripts run in "trash directory".
-# Usage: test_external description command arguments...
-# Example: test_external 'Perl API' perl ../path/to/test.pl
-test_external () {
- test "$#" = 4 && { test_prereq=$1; shift; } || test_prereq=
- test "$#" = 3 ||
- error >&5 "bug in the test script: not 3 or 4 parameters to test_external"
- descr="$1"
- shift
- export test_prereq
- if ! test_skip "$descr" "$@"
- then
- # Announce the script to reduce confusion about the
- # test output that follows.
- say_color "" "# run $test_count: $descr ($*)"
- # Export TEST_DIRECTORY, TRASH_DIRECTORY and GIT_TEST_LONG
- # to be able to use them in script
- export TEST_DIRECTORY TRASH_DIRECTORY GIT_TEST_LONG
- # Run command; redirect its stderr to &4 as in
- # test_run_, but keep its stdout on our stdout even in
- # non-verbose mode.
- "$@" 2>&4
- if [ "$?" = 0 ]
- then
- if test $test_external_has_tap -eq 0; then
- test_ok_ "$descr"
- else
- say_color "" "# test_external test $descr was ok"
- test_success=$(($test_success + 1))
- fi
- else
- if test $test_external_has_tap -eq 0; then
- test_failure_ "$descr" "$@"
- else
- say_color error "# test_external test $descr failed: $@"
- test_failure=$(($test_failure + 1))
- fi
- fi
- fi
-}
-
-# Like test_external, but in addition tests that the command generated
-# no output on stderr.
-test_external_without_stderr () {
- # The temporary file has no (and must have no) security
- # implications.
- tmp=${TMPDIR:-/tmp}
- stderr="$tmp/git-external-stderr.$$.tmp"
- test_external "$@" 4> "$stderr"
- [ -f "$stderr" ] || error "Internal error: $stderr disappeared."
- descr="no stderr: $1"
- shift
- say >&3 "# expecting no stderr from previous command"
- if [ ! -s "$stderr" ]; then
- rm "$stderr"
-
- if test $test_external_has_tap -eq 0; then
- test_ok_ "$descr"
- else
- say_color "" "# test_external_without_stderr test $descr was ok"
- test_success=$(($test_success + 1))
- fi
- else
- if [ "$verbose" = t ]; then
- output=`echo; echo "# Stderr is:"; cat "$stderr"`
- else
- output=
- fi
- # rm first in case test_failure exits.
- rm "$stderr"
- if test $test_external_has_tap -eq 0; then
- test_failure_ "$descr" "$@" "$output"
- else
- say_color error "# test_external_without_stderr test $descr failed: $@: $output"
- test_failure=$(($test_failure + 1))
- fi
- fi
-}
-
-# debugging-friendly alternatives to "test [-f|-d|-e]"
-# The commands test the existence or non-existence of $1. $2 can be
-# given to provide a more precise diagnosis.
-test_path_is_file () {
- if ! [ -f "$1" ]
- then
- echo "File $1 doesn't exist. $*"
- false
- fi
-}
-
-test_path_is_dir () {
- if ! [ -d "$1" ]
- then
- echo "Directory $1 doesn't exist. $*"
- false
- fi
-}
-
-test_path_is_missing () {
- if [ -e "$1" ]
- then
- echo "Path exists:"
- ls -ld "$1"
- if [ $# -ge 1 ]; then
- echo "$*"
- fi
- false
- fi
-}
-
-# test_line_count checks that a file has the number of lines it
-# ought to. For example:
-#
-# test_expect_success 'produce exactly one line of output' '
-# do something >output &&
-# test_line_count = 1 output
-# '
-#
-# is like "test $(wc -l <output) = 1" except that it passes the
-# output through when the number of lines is wrong.
-
-test_line_count () {
- if test $# != 3
- then
- error "bug in the test script: not 3 parameters to test_line_count"
- elif ! test $(wc -l <"$3") "$1" "$2"
- then
- echo "test_line_count: line count for $3 !$1 $2"
- cat "$3"
- return 1
- fi
-}
-
-# This is not among top-level (test_expect_success | test_expect_failure)
-# but is a prefix that can be used in the test script, like:
-#
-# test_expect_success 'complain and die' '
-# do something &&
-# do something else &&
-# test_must_fail git checkout ../outerspace
-# '
-#
-# Writing this as "! git checkout ../outerspace" is wrong, because
-# the failure could be due to a segv. We want a controlled failure.
-
-test_must_fail () {
- "$@"
- exit_code=$?
- if test $exit_code = 0; then
- echo >&2 "test_must_fail: command succeeded: $*"
- return 1
- elif test $exit_code -gt 129 -a $exit_code -le 192; then
- echo >&2 "test_must_fail: died by signal: $*"
- return 1
- elif test $exit_code = 127; then
- echo >&2 "test_must_fail: command not found: $*"
- return 1
- fi
- return 0
-}
-
-# Similar to test_must_fail, but tolerates success, too. This is
-# meant to be used in contexts like:
-#
-# test_expect_success 'some command works without configuration' '
-# test_might_fail git config --unset all.configuration &&
-# do something
-# '
-#
-# Writing "git config --unset all.configuration || :" would be wrong,
-# because we want to notice if it fails due to segv.
-
-test_might_fail () {
- "$@"
- exit_code=$?
- if test $exit_code -gt 129 -a $exit_code -le 192; then
- echo >&2 "test_might_fail: died by signal: $*"
- return 1
- elif test $exit_code = 127; then
- echo >&2 "test_might_fail: command not found: $*"
- return 1
- fi
- return 0
-}
-
-# Similar to test_must_fail and test_might_fail, but check that a
-# given command exited with a given exit code. Meant to be used as:
-#
-# test_expect_success 'Merge with d/f conflicts' '
-# test_expect_code 1 git merge "merge msg" B master
-# '
-
-test_expect_code () {
- want_code=$1
- shift
- "$@"
- exit_code=$?
- if test $exit_code = $want_code
- then
- return 0
- fi
-
- echo >&2 "test_expect_code: command exited with $exit_code, we wanted $want_code $*"
- return 1
-}
-
-# test_cmp is a helper function to compare actual and expected output.
-# You can use it like:
-#
-# test_expect_success 'foo works' '
-# echo expected >expected &&
-# foo >actual &&
-# test_cmp expected actual
-# '
-#
-# This could be written as either "cmp" or "diff -u", but:
-# - cmp's output is not nearly as easy to read as diff -u
-# - not all diff versions understand "-u"
-
-test_cmp() {
- $GIT_TEST_CMP "$@"
-}
-
-# This function can be used to schedule some commands to be run
-# unconditionally at the end of the test to restore sanity:
-#
-# test_expect_success 'test core.capslock' '
-# git config core.capslock true &&
-# test_when_finished "git config --unset core.capslock" &&
-# hello world
-# '
-#
-# That would be roughly equivalent to
-#
-# test_expect_success 'test core.capslock' '
-# git config core.capslock true &&
-# hello world
-# git config --unset core.capslock
-# '
-#
-# except that the greeting and config --unset must both succeed for
-# the test to pass.
-#
-# Note that under --immediate mode, no clean-up is done to help diagnose
-# what went wrong.
-
-test_when_finished () {
- test_cleanup="{ $*
- } && (exit \"\$eval_ret\"); eval_ret=\$?; $test_cleanup"
-}
-
-# Most tests can use the created repository, but some may need to create more.
-# Usage: test_create_repo <directory>
-test_create_repo () {
- test "$#" = 1 ||
- error "bug in the test script: not 1 parameter to test-create-repo"
- repo="$1"
- mkdir -p "$repo"
- (
- cd "$repo" || error "Cannot setup test environment"
- "$GIT_EXEC_PATH/git-init" "--template=$GIT_BUILD_DIR/templates/blt/" >&3 2>&4 ||
- error "cannot run git init -- have you built things yet?"
- mv .git/hooks .git/hooks-disabled
- ) || exit
+# stub; perf-lib overrides it
+test_at_end_hook_ () {
+ :
}
test_done () {
GIT_EXIT_OK=t
if test -z "$HARNESS_ACTIVE"; then
- test_results_dir="$TEST_DIRECTORY/test-results"
+ test_results_dir="$TEST_OUTPUT_DIRECTORY/test-results"
mkdir -p "$test_results_dir"
test_results_path="$test_results_dir/${0%.sh}-$$.counts"
@@ -889,6 +365,8 @@ test_done () {
cd "$(dirname "$remove_trash")" &&
rm -rf "$(basename "$remove_trash")"
+ test_at_end_hook_
+
exit 0 ;;
*)
@@ -911,6 +389,12 @@ then
# 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"
@@ -1046,7 +530,7 @@ test="trash directory.$(basename "$0" .sh)"
test -n "$root" && test="$root/$test"
case "$test" in
/*) TRASH_DIRECTORY="$test" ;;
- *) TRASH_DIRECTORY="$TEST_DIRECTORY/$test" ;;
+ *) TRASH_DIRECTORY="$TEST_OUTPUT_DIRECTORY/$test" ;;
esac
test ! -z "$debug" || remove_trash=$TRASH_DIRECTORY
rm -fr "$test" || {
@@ -1058,7 +542,11 @@ rm -fr "$test" || {
HOME="$TRASH_DIRECTORY"
export HOME
-test_create_repo "$test"
+if test -z "$TEST_NO_CREATE_REPO"; then
+ test_create_repo "$test"
+else
+ mkdir -p "$test"
+fi
# Use -P to resolve symlinks in our working directory so that the cwd
# in subprocesses like git equals our $PWD (for pathname comparisons).
cd -P "$test" || exit 1
@@ -1127,6 +615,7 @@ case $(uname -s) in
;;
esac
+( COLUMNS=1 && test $COLUMNS = 1 ) && test_set_prereq COLUMNS_CAN_BE_1
test -z "$NO_PERL" && test_set_prereq PERL
test -z "$NO_PYTHON" && test_set_prereq PYTHON
test -n "$USE_LIBPCRE" && test_set_prereq LIBPCRE
diff --git a/tag.c b/tag.c
index 3aa186df62..78d272b863 100644
--- a/tag.c
+++ b/tag.c
@@ -24,6 +24,18 @@ struct object *deref_tag(struct object *o, const char *warn, int warnlen)
return o;
}
+struct object *deref_tag_noverify(struct object *o)
+{
+ while (o && o->type == OBJ_TAG) {
+ o = parse_object(o->sha1);
+ if (o && o->type == OBJ_TAG && ((struct tag *)o)->tagged)
+ o = ((struct tag *)o)->tagged;
+ else
+ o = NULL;
+ }
+ return o;
+}
+
struct tag *lookup_tag(const unsigned char *sha1)
{
struct object *obj = lookup_object(sha1);
diff --git a/tag.h b/tag.h
index 5ee88e6550..bc8a1e40f0 100644
--- a/tag.h
+++ b/tag.h
@@ -16,6 +16,7 @@ extern struct tag *lookup_tag(const unsigned char *sha1);
extern int parse_tag_buffer(struct tag *item, const void *data, unsigned long size);
extern int parse_tag(struct tag *item);
extern struct object *deref_tag(struct object *, const char *, int);
+extern struct object *deref_tag_noverify(struct object *);
extern size_t parse_signature(const char *buf, unsigned long size);
#endif /* TAG_H */
diff --git a/test-dump-cache-tree.c b/test-dump-cache-tree.c
index e6c292385f..a6ffdf39d5 100644
--- a/test-dump-cache-tree.c
+++ b/test-dump-cache-tree.c
@@ -59,6 +59,6 @@ int main(int ac, char **av)
struct cache_tree *another = cache_tree();
if (read_cache() < 0)
die("unable to read index file");
- cache_tree_update(another, active_cache, active_nr, 0, 1, 0);
+ cache_tree_update(another, active_cache, active_nr, WRITE_TREE_DRY_RUN);
return dump_cache_tree(active_cache_tree, another, "");
}
diff --git a/test-obj-pool.c b/test-obj-pool.c
deleted file mode 100644
index 5018863ef5..0000000000
--- a/test-obj-pool.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * test-obj-pool.c: code to exercise the svn importer's object pool
- */
-
-#include "cache.h"
-#include "vcs-svn/obj_pool.h"
-
-enum pool { POOL_ONE, POOL_TWO };
-obj_pool_gen(one, int, 1)
-obj_pool_gen(two, int, 4096)
-
-static uint32_t strtouint32(const char *s)
-{
- char *end;
- uintmax_t n = strtoumax(s, &end, 10);
- if (*s == '\0' || (*end != '\n' && *end != '\0'))
- die("invalid offset: %s", s);
- return (uint32_t) n;
-}
-
-static void handle_command(const char *command, enum pool pool, const char *arg)
-{
- switch (*command) {
- case 'a':
- if (!prefixcmp(command, "alloc ")) {
- uint32_t n = strtouint32(arg);
- printf("%"PRIu32"\n",
- pool == POOL_ONE ?
- one_alloc(n) : two_alloc(n));
- return;
- }
- case 'c':
- if (!prefixcmp(command, "commit ")) {
- pool == POOL_ONE ? one_commit() : two_commit();
- return;
- }
- if (!prefixcmp(command, "committed ")) {
- printf("%"PRIu32"\n",
- pool == POOL_ONE ?
- one_pool.committed : two_pool.committed);
- return;
- }
- case 'f':
- if (!prefixcmp(command, "free ")) {
- uint32_t n = strtouint32(arg);
- pool == POOL_ONE ? one_free(n) : two_free(n);
- return;
- }
- case 'n':
- if (!prefixcmp(command, "null ")) {
- printf("%"PRIu32"\n",
- pool == POOL_ONE ?
- one_offset(NULL) : two_offset(NULL));
- return;
- }
- case 'o':
- if (!prefixcmp(command, "offset ")) {
- uint32_t n = strtouint32(arg);
- printf("%"PRIu32"\n",
- pool == POOL_ONE ?
- one_offset(one_pointer(n)) :
- two_offset(two_pointer(n)));
- return;
- }
- case 'r':
- if (!prefixcmp(command, "reset ")) {
- pool == POOL_ONE ? one_reset() : two_reset();
- return;
- }
- case 's':
- if (!prefixcmp(command, "set ")) {
- uint32_t n = strtouint32(arg);
- if (pool == POOL_ONE)
- *one_pointer(n) = 1;
- else
- *two_pointer(n) = 1;
- return;
- }
- case 't':
- if (!prefixcmp(command, "test ")) {
- uint32_t n = strtouint32(arg);
- printf("%d\n", pool == POOL_ONE ?
- *one_pointer(n) : *two_pointer(n));
- return;
- }
- default:
- die("unrecognized command: %s", command);
- }
-}
-
-static void handle_line(const char *line)
-{
- const char *arg = strchr(line, ' ');
- enum pool pool;
-
- if (arg && !prefixcmp(arg + 1, "one"))
- pool = POOL_ONE;
- else if (arg && !prefixcmp(arg + 1, "two"))
- pool = POOL_TWO;
- else
- die("no pool specified: %s", line);
-
- handle_command(line, pool, arg + strlen("one "));
-}
-
-int main(int argc, char *argv[])
-{
- struct strbuf sb = STRBUF_INIT;
- if (argc != 1)
- usage("test-obj-str < script");
-
- while (strbuf_getline(&sb, stdin, '\n') != EOF)
- handle_line(sb.buf);
- strbuf_release(&sb);
- return 0;
-}
diff --git a/test-parse-options.c b/test-parse-options.c
index 36487c402b..3c9510a701 100644
--- a/test-parse-options.c
+++ b/test-parse-options.c
@@ -37,7 +37,11 @@ int main(int argc, const char **argv)
NULL
};
struct option options[] = {
- OPT_BOOLEAN('b', "boolean", &boolean, "get a boolean"),
+ OPT_BOOL(0, "yes", &boolean, "get a boolean"),
+ OPT_BOOL('D', "no-doubt", &boolean, "begins with 'no-'"),
+ { OPTION_SET_INT, 'B', "no-fear", &boolean, NULL,
+ "be brave", PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 },
+ OPT_COUNTUP('b', "boolean", &boolean, "increment by one"),
OPT_BIT('4', "or4", &boolean,
"bitwise-or boolean with ...0100", 4),
OPT_NEGBIT(0, "neg-or4", &boolean, "same as --no-or4", 4),
@@ -62,11 +66,11 @@ int main(int argc, const char **argv)
OPT_ARGUMENT("quux", "means --quux"),
OPT_NUMBER_CALLBACK(&integer, "set integer to NUM",
number_callback),
- { OPTION_BOOLEAN, '+', NULL, &boolean, NULL, "same as -b",
+ { OPTION_COUNTUP, '+', NULL, &boolean, NULL, "same as -b",
PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH },
- { OPTION_BOOLEAN, 0, "ambiguous", &ambiguous, NULL,
+ { OPTION_COUNTUP, 0, "ambiguous", &ambiguous, NULL,
"positive ambiguity", PARSE_OPT_NOARG | PARSE_OPT_NONEG },
- { OPTION_BOOLEAN, 0, "no-ambiguous", &ambiguous, NULL,
+ { OPTION_COUNTUP, 0, "no-ambiguous", &ambiguous, NULL,
"negative ambiguity", PARSE_OPT_NOARG | PARSE_OPT_NONEG },
OPT_GROUP("Standard options"),
OPT__ABBREV(&abbrev),
diff --git a/test-string-pool.c b/test-string-pool.c
deleted file mode 100644
index c5782e6bce..0000000000
--- a/test-string-pool.c
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * test-string-pool.c: code to exercise the svn importer's string pool
- */
-
-#include "git-compat-util.h"
-#include "vcs-svn/string_pool.h"
-
-int main(int argc, char *argv[])
-{
- const uint32_t unequal = pool_intern("does not equal");
- const uint32_t equal = pool_intern("equals");
- uint32_t buf[3];
- uint32_t n;
-
- if (argc != 2)
- usage("test-string-pool <string>,<string>");
-
- n = pool_tok_seq(3, buf, ",-", argv[1]);
- if (n >= 3)
- die("too many strings");
- if (n <= 1)
- die("too few strings");
-
- buf[2] = buf[1];
- buf[1] = (buf[0] == buf[2]) ? equal : unequal;
- pool_print_seq(3, buf, ' ', stdout);
- fputc('\n', stdout);
-
- pool_reset();
- return 0;
-}
diff --git a/test-subprocess.c b/test-subprocess.c
index 8926bc52a9..f2d4c0d22b 100644
--- a/test-subprocess.c
+++ b/test-subprocess.c
@@ -1,7 +1,7 @@
#include "cache.h"
#include "run-command.h"
-int main(int argc, char **argv)
+int main(int argc, const char **argv)
{
struct child_process cp;
int nogit = 0;
@@ -9,12 +9,12 @@ int main(int argc, char **argv)
setup_git_directory_gently(&nogit);
if (nogit)
die("No git repo found");
- if (!strcmp(argv[1], "--setup-work-tree")) {
+ if (argc > 1 && !strcmp(argv[1], "--setup-work-tree")) {
setup_work_tree();
argv++;
}
memset(&cp, 0, sizeof(cp));
cp.git_cmd = 1;
- cp.argv = (const char **)argv+1;
+ cp.argv = argv + 1;
return run_command(&cp);
}
diff --git a/test-svn-fe.c b/test-svn-fe.c
index b42ba789b1..332a5f711d 100644
--- a/test-svn-fe.c
+++ b/test-svn-fe.c
@@ -4,15 +4,51 @@
#include "git-compat-util.h"
#include "vcs-svn/svndump.h"
+#include "vcs-svn/svndiff.h"
+#include "vcs-svn/sliding_window.h"
+#include "vcs-svn/line_buffer.h"
-int main(int argc, char *argv[])
+static const char test_svnfe_usage[] =
+ "test-svn-fe (<dumpfile> | [-d] <preimage> <delta> <len>)";
+
+static int apply_delta(int argc, char *argv[])
{
- if (argc != 2)
- usage("test-svn-fe <file>");
- if (svndump_init(argv[1]))
+ struct line_buffer preimage = LINE_BUFFER_INIT;
+ struct line_buffer delta = LINE_BUFFER_INIT;
+ struct sliding_view preimage_view = SLIDING_VIEW_INIT(&preimage, -1);
+
+ if (argc != 5)
+ usage(test_svnfe_usage);
+
+ if (buffer_init(&preimage, argv[2]))
+ die_errno("cannot open preimage");
+ if (buffer_init(&delta, argv[3]))
+ die_errno("cannot open delta");
+ if (svndiff0_apply(&delta, (off_t) strtoull(argv[4], NULL, 0),
+ &preimage_view, stdout))
return 1;
- svndump_read(NULL);
- svndump_deinit();
- svndump_reset();
+ if (buffer_deinit(&preimage))
+ 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;
}
+
+int main(int argc, char *argv[])
+{
+ if (argc == 2) {
+ if (svndump_init(argv[1]))
+ return 1;
+ svndump_read(NULL);
+ svndump_deinit();
+ svndump_reset();
+ return 0;
+ }
+
+ if (argc >= 2 && !strcmp(argv[1], "-d"))
+ return apply_delta(argc, argv);
+ usage(test_svnfe_usage);
+}
diff --git a/test-treap.c b/test-treap.c
deleted file mode 100644
index 294d7ee273..0000000000
--- a/test-treap.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * test-treap.c: code to exercise the svn importer's treap structure
- */
-
-#include "cache.h"
-#include "vcs-svn/obj_pool.h"
-#include "vcs-svn/trp.h"
-
-struct int_node {
- uintmax_t n;
- struct trp_node children;
-};
-
-obj_pool_gen(node, struct int_node, 3)
-
-static int node_cmp(struct int_node *a, struct int_node *b)
-{
- return (a->n > b->n) - (a->n < b->n);
-}
-
-trp_gen(static, treap_, struct int_node, children, node, node_cmp)
-
-static void strtonode(struct int_node *item, const char *s)
-{
- char *end;
- item->n = strtoumax(s, &end, 10);
- if (*s == '\0' || (*end != '\n' && *end != '\0'))
- die("invalid integer: %s", s);
-}
-
-int main(int argc, char *argv[])
-{
- struct strbuf sb = STRBUF_INIT;
- struct trp_root root = { ~0U };
- uint32_t item;
-
- if (argc != 1)
- usage("test-treap < ints");
-
- while (strbuf_getline(&sb, stdin, '\n') != EOF) {
- struct int_node *node = node_pointer(node_alloc(1));
-
- item = node_offset(node);
- strtonode(node, sb.buf);
- node = treap_insert(&root, node_pointer(item));
- if (node_offset(node) != item)
- die("inserted %"PRIu32" in place of %"PRIu32"",
- node_offset(node), item);
- }
-
- item = node_offset(treap_first(&root));
- while (~item) {
- uint32_t next;
- struct int_node *tmp = node_pointer(node_alloc(1));
-
- tmp->n = node_pointer(item)->n;
- next = node_offset(treap_next(&root, node_pointer(item)));
-
- treap_remove(&root, node_pointer(item));
- item = node_offset(treap_nsearch(&root, tmp));
-
- if (item != next && (!~item || node_pointer(item)->n != tmp->n))
- die("found %"PRIuMAX" in place of %"PRIuMAX"",
- ~item ? node_pointer(item)->n : ~(uintmax_t) 0,
- ~next ? node_pointer(next)->n : ~(uintmax_t) 0);
- printf("%"PRIuMAX"\n", tmp->n);
- }
- node_reset();
- return 0;
-}
diff --git a/transport.c b/transport.c
index 401b8dd35c..2dfac700b6 100644
--- a/transport.c
+++ b/transport.c
@@ -721,6 +721,10 @@ void transport_print_push_status(const char *dest, struct ref *refs,
{
struct ref *ref;
int n = 0;
+ unsigned char head_sha1[20];
+ char *head;
+
+ head = resolve_refdup("HEAD", head_sha1, 1, NULL);
if (verbose) {
for (ref = refs; ref; ref = ref->next)
@@ -738,8 +742,13 @@ void transport_print_push_status(const char *dest, struct ref *refs,
ref->status != REF_STATUS_UPTODATE &&
ref->status != REF_STATUS_OK)
n += print_one_push_status(ref, dest, n, porcelain);
- if (ref->status == REF_STATUS_REJECT_NONFASTFORWARD)
- *nonfastforward = 1;
+ if (ref->status == REF_STATUS_REJECT_NONFASTFORWARD &&
+ *nonfastforward != NON_FF_HEAD) {
+ if (!strcmp(head, ref->name))
+ *nonfastforward = NON_FF_HEAD;
+ else
+ *nonfastforward = NON_FF_OTHER;
+ }
}
}
@@ -1032,6 +1041,8 @@ int transport_push(struct transport *transport,
match_flags |= MATCH_REFS_ALL;
if (flags & TRANSPORT_PUSH_MIRROR)
match_flags |= MATCH_REFS_MIRROR;
+ if (flags & TRANSPORT_PUSH_PRUNE)
+ match_flags |= MATCH_REFS_PRUNE;
if (match_push_refs(local_refs, &remote_refs,
refspec_nr, refspec, match_flags)) {
@@ -1152,7 +1163,7 @@ int transport_disconnect(struct transport *transport)
}
/*
- * Strip username (and password) from an url and return
+ * Strip username (and password) from a URL and return
* it in a newly allocated string.
*/
char *transport_anonymize_url(const char *url)
diff --git a/transport.h b/transport.h
index 059b3303e2..1631a35ea6 100644
--- a/transport.h
+++ b/transport.h
@@ -102,6 +102,7 @@ struct transport {
#define TRANSPORT_PUSH_PORCELAIN 16
#define TRANSPORT_PUSH_SET_UPSTREAM 32
#define TRANSPORT_RECURSE_SUBMODULES_CHECK 64
+#define TRANSPORT_PUSH_PRUNE 128
#define TRANSPORT_SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3)
@@ -137,6 +138,8 @@ int transport_set_option(struct transport *transport, const char *name,
void transport_set_verbosity(struct transport *transport, int verbosity,
int force_progress);
+#define NON_FF_HEAD 1
+#define NON_FF_OTHER 2
int transport_push(struct transport *connection,
int refspec_nr, const char **refspec, int flags,
int * nonfastforward);
diff --git a/unpack-trees.c b/unpack-trees.c
index 7c9ecf665d..f0ac24b9f5 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -102,21 +102,28 @@ void setup_unpack_trees_porcelain(struct unpack_trees_options *opts,
opts->unpack_rejects[i].strdup_strings = 1;
}
-static void add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
- unsigned int set, unsigned int clear)
+static void do_add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
+ unsigned int set, unsigned int clear)
{
- unsigned int size = ce_size(ce);
- struct cache_entry *new = xmalloc(size);
-
clear |= CE_HASHED | CE_UNHASHED;
if (set & CE_REMOVE)
set |= CE_WT_REMOVE;
+ ce->next = NULL;
+ ce->ce_flags = (ce->ce_flags & ~clear) | set;
+ add_index_entry(&o->result, ce,
+ ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
+}
+
+static void add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
+ unsigned int set, unsigned int clear)
+{
+ unsigned int size = ce_size(ce);
+ struct cache_entry *new = xmalloc(size);
+
memcpy(new, ce, size);
- new->next = NULL;
- new->ce_flags = (new->ce_flags & ~clear) | set;
- add_index_entry(&o->result, new, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
+ do_add_entry(o, new, set, clear);
}
/*
@@ -587,7 +594,7 @@ static int unpack_nondirectories(int n, unsigned long mask,
for (i = 0; i < n; i++)
if (src[i] && src[i] != o->df_conflict_entry)
- add_entry(o, src[i], 0, 0);
+ do_add_entry(o, src[i], 0, 0);
return 0;
}
@@ -772,7 +779,7 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str
if (unpack_nondirectories(n, mask, dirmask, src, names, info) < 0)
return -1;
- if (src[0]) {
+ if (o->merge && src[0]) {
if (ce_stage(src[0]))
mark_ce_used_same_name(src[0], o);
else
@@ -1202,7 +1209,7 @@ static int verify_uptodate_1(struct cache_entry *ce,
return 0;
/*
* NEEDSWORK: the current default policy is to allow
- * submodule to be out of sync wrt the supermodule
+ * submodule to be out of sync wrt the superproject
* index. This needs to be tightened later for
* submodules that are marked to be automatically
* checked out.
diff --git a/upload-pack.c b/upload-pack.c
index 0d11e21a68..bb08e2eb0d 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -724,11 +724,14 @@ static int send_ref(const char *refname, const unsigned char *sha1, int flag, vo
static const char *capabilities = "multi_ack thin-pack side-band"
" side-band-64k ofs-delta shallow no-progress"
" include-tag multi_ack_detailed";
- struct object *o = parse_object(sha1);
+ struct object *o = lookup_unknown_object(sha1);
const char *refname_nons = strip_namespace(refname);
- if (!o)
- die("git upload-pack: cannot find object %s:", sha1_to_hex(sha1));
+ 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));
+ }
if (capabilities)
packet_write(1, "%s %s%c%s%s\n", sha1_to_hex(sha1), refname_nons,
@@ -742,7 +745,7 @@ static int send_ref(const char *refname, const unsigned char *sha1, int flag, vo
nr_our_refs++;
}
if (o->type == OBJ_TAG) {
- o = deref_tag(o, refname, 0);
+ o = deref_tag_noverify(o);
if (o)
packet_write(1, "%s %s^{}\n", sha1_to_hex(o->sha1), refname_nons);
}
diff --git a/userdiff.c b/userdiff.c
index 76109da4bc..1e7184f7f0 100644
--- a/userdiff.c
+++ b/userdiff.c
@@ -210,14 +210,7 @@ static int parse_funcname(struct userdiff_funcname *f, const char *k,
if (git_config_string(&f->pattern, k, v) < 0)
return -1;
f->cflags = cflags;
- return 1;
-}
-
-static int parse_string(const char **d, const char *k, const char *v)
-{
- if (git_config_string(d, k, v) < 0)
- return -1;
- return 1;
+ return 0;
}
static int parse_tristate(int *b, const char *k, const char *v)
@@ -226,13 +219,13 @@ static int parse_tristate(int *b, const char *k, const char *v)
*b = -1;
else
*b = git_config_bool(k, v);
- return 1;
+ return 0;
}
static int parse_bool(int *b, const char *k, const char *v)
{
*b = git_config_bool(k, v);
- return 1;
+ return 0;
}
int userdiff_config(const char *k, const char *v)
@@ -246,13 +239,13 @@ int userdiff_config(const char *k, const char *v)
if ((drv = parse_driver(k, v, "binary")))
return parse_tristate(&drv->binary, k, v);
if ((drv = parse_driver(k, v, "command")))
- return parse_string(&drv->external, k, v);
+ return git_config_string(&drv->external, k, v);
if ((drv = parse_driver(k, v, "textconv")))
- return parse_string(&drv->textconv, k, v);
+ return git_config_string(&drv->textconv, k, v);
if ((drv = parse_driver(k, v, "cachetextconv")))
return parse_bool(&drv->textconv_want_cache, k, v);
if ((drv = parse_driver(k, v, "wordregex")))
- return parse_string(&drv->word_regex, k, v);
+ return git_config_string(&drv->word_regex, k, v);
return 0;
}
diff --git a/vcs-svn/LICENSE b/vcs-svn/LICENSE
index 0a5e3c43a0..eb91858b82 100644
--- a/vcs-svn/LICENSE
+++ b/vcs-svn/LICENSE
@@ -1,8 +1,7 @@
Copyright (C) 2010 David Barr <david.barr@cordelta.com>.
All rights reserved.
-Copyright (C) 2008 Jason Evans <jasone@canonware.com>.
-All rights reserved.
+Copyright (C) 2010 Jonathan Nieder <jrnieder@gmail.com>.
Copyright (C) 2005 Stefan Hegny, hydrografix Consulting GmbH,
Frankfurt/Main, Germany
diff --git a/vcs-svn/fast_export.c b/vcs-svn/fast_export.c
index 99ed70b88a..b823b8519c 100644
--- a/vcs-svn/fast_export.c
+++ b/vcs-svn/fast_export.c
@@ -4,34 +4,77 @@
*/
#include "git-compat-util.h"
+#include "strbuf.h"
+#include "quote.h"
#include "fast_export.h"
-#include "line_buffer.h"
#include "repo_tree.h"
-#include "string_pool.h"
+#include "strbuf.h"
+#include "svndiff.h"
+#include "sliding_window.h"
+#include "line_buffer.h"
#define MAX_GITSVN_LINE_LEN 4096
static uint32_t first_commit_done;
+static struct line_buffer postimage = LINE_BUFFER_INIT;
+static struct line_buffer report_buffer = LINE_BUFFER_INIT;
+
+/* NEEDSWORK: move to fast_export_init() */
+static int init_postimage(void)
+{
+ static int postimage_initialized;
+ if (postimage_initialized)
+ return 0;
+ postimage_initialized = 1;
+ return buffer_tmpfile_init(&postimage);
+}
+
+void fast_export_init(int fd)
+{
+ first_commit_done = 0;
+ if (buffer_fdinit(&report_buffer, fd))
+ die_errno("cannot read from file descriptor %d", fd);
+}
+
+void fast_export_deinit(void)
+{
+ if (buffer_deinit(&report_buffer))
+ die_errno("error closing fast-import feedback stream");
+}
+
+void fast_export_reset(void)
+{
+ buffer_reset(&report_buffer);
+}
-void fast_export_delete(uint32_t depth, uint32_t *path)
+void fast_export_delete(const char *path)
{
putchar('D');
putchar(' ');
- pool_print_seq(depth, path, '/', stdout);
+ quote_c_style(path, NULL, stdout, 0);
putchar('\n');
}
-void fast_export_modify(uint32_t depth, uint32_t *path, uint32_t mode,
- uint32_t mark)
+static void fast_export_truncate(const char *path, uint32_t mode)
+{
+ fast_export_modify(path, mode, "inline");
+ printf("data 0\n\n");
+}
+
+void fast_export_modify(const char *path, uint32_t mode, const char *dataref)
{
/* Mode must be 100644, 100755, 120000, or 160000. */
- printf("M %06"PRIo32" :%"PRIu32" ", mode, mark);
- pool_print_seq(depth, path, '/', stdout);
+ if (!dataref) {
+ fast_export_truncate(path, mode);
+ return;
+ }
+ printf("M %06"PRIo32" %s ", mode, dataref);
+ quote_c_style(path, NULL, stdout, 0);
putchar('\n');
}
static char gitsvnline[MAX_GITSVN_LINE_LEN];
-void fast_export_commit(uint32_t revision, const char *author,
+void fast_export_begin_commit(uint32_t revision, const char *author,
const struct strbuf *log,
const char *uuid, const char *url,
unsigned long timestamp)
@@ -47,6 +90,7 @@ void fast_export_commit(uint32_t revision, const char *author,
*gitsvnline = '\0';
}
printf("commit refs/heads/master\n");
+ printf("mark :%"PRIu32"\n", revision);
printf("committer %s <%s@%s> %ld +0000\n",
*author ? author : "nobody",
*author ? author : "nobody",
@@ -57,15 +101,44 @@ void fast_export_commit(uint32_t revision, const char *author,
printf("%s\n", gitsvnline);
if (!first_commit_done) {
if (revision > 1)
- printf("from refs/heads/master^0\n");
+ printf("from :%"PRIu32"\n", revision - 1);
first_commit_done = 1;
}
- repo_diff(revision - 1, revision);
- fputc('\n', stdout);
+}
+void fast_export_end_commit(uint32_t revision)
+{
printf("progress Imported commit %"PRIu32".\n\n", revision);
}
+static void ls_from_rev(uint32_t rev, const char *path)
+{
+ /* ls :5 path/to/old/file */
+ printf("ls :%"PRIu32" ", rev);
+ quote_c_style(path, NULL, stdout, 0);
+ putchar('\n');
+ fflush(stdout);
+}
+
+static void ls_from_active_commit(const char *path)
+{
+ /* ls "path/to/file" */
+ printf("ls \"");
+ quote_c_style(path, NULL, stdout, 1);
+ printf("\"\n");
+ fflush(stdout);
+}
+
+static const char *get_response_line(void)
+{
+ const char *line = buffer_read_line(&report_buffer);
+ if (line)
+ return line;
+ if (buffer_ferror(&report_buffer))
+ die_errno("error reading from fast-import");
+ die("unexpected end of fast-import feedback");
+}
+
static void die_short_read(struct line_buffer *input)
{
if (buffer_ferror(input))
@@ -73,16 +146,171 @@ static void die_short_read(struct line_buffer *input)
die("invalid dump: unexpected end of file");
}
-void fast_export_blob(uint32_t mode, uint32_t mark, uint32_t len, struct line_buffer *input)
+static int ends_with(const char *s, size_t len, const char *suffix)
{
+ const size_t suffixlen = strlen(suffix);
+ if (len < suffixlen)
+ return 0;
+ return !memcmp(s + len - suffixlen, suffix, suffixlen);
+}
+
+static int parse_cat_response_line(const char *header, off_t *len)
+{
+ size_t headerlen = strlen(header);
+ uintmax_t n;
+ const char *type;
+ const char *end;
+
+ if (ends_with(header, headerlen, " missing"))
+ return error("cat-blob reports missing blob: %s", header);
+ type = memmem(header, headerlen, " blob ", strlen(" blob "));
+ if (!type)
+ return error("cat-blob header has wrong object type: %s", header);
+ n = strtoumax(type + strlen(" blob "), (char **) &end, 10);
+ if (end == type + strlen(" blob "))
+ return error("cat-blob header does not contain length: %s", header);
+ if (memchr(type + strlen(" blob "), '-', end - type - strlen(" blob ")))
+ return error("cat-blob header contains negative length: %s", header);
+ if (n == UINTMAX_MAX || n > maximum_signed_value_of_type(off_t))
+ return error("blob too large for current definition of off_t");
+ *len = n;
+ if (*end)
+ return error("cat-blob header contains garbage after length: %s", header);
+ return 0;
+}
+
+static void check_preimage_overflow(off_t a, off_t b)
+{
+ if (signed_add_overflows(a, b))
+ die("blob too large for current definition of off_t");
+}
+
+static long apply_delta(off_t len, struct line_buffer *input,
+ const char *old_data, uint32_t old_mode)
+{
+ long ret;
+ struct sliding_view preimage = SLIDING_VIEW_INIT(&report_buffer, 0);
+ FILE *out;
+
+ if (init_postimage() || !(out = buffer_tmpfile_rewind(&postimage)))
+ die("cannot open temporary file for blob retrieval");
+ if (old_data) {
+ const char *response;
+ printf("cat-blob %s\n", old_data);
+ fflush(stdout);
+ response = get_response_line();
+ if (parse_cat_response_line(response, &preimage.max_off))
+ die("invalid cat-blob response: %s", response);
+ check_preimage_overflow(preimage.max_off, 1);
+ }
+ if (old_mode == REPO_MODE_LNK) {
+ strbuf_addstr(&preimage.buf, "link ");
+ check_preimage_overflow(preimage.max_off, strlen("link "));
+ preimage.max_off += strlen("link ");
+ check_preimage_overflow(preimage.max_off, 1);
+ }
+ if (svndiff0_apply(input, len, &preimage, out))
+ die("cannot apply delta");
+ if (old_data) {
+ /* Read the remainder of preimage and trailing newline. */
+ assert(!signed_add_overflows(preimage.max_off, 1));
+ preimage.max_off++; /* room for newline */
+ if (move_window(&preimage, preimage.max_off - 1, 1))
+ die("cannot seek to end of input");
+ if (preimage.buf.buf[0] != '\n')
+ die("missing newline after cat-blob response");
+ }
+ ret = buffer_tmpfile_prepare_to_read(&postimage);
+ if (ret < 0)
+ die("cannot read temporary file for blob retrieval");
+ strbuf_release(&preimage.buf);
+ return ret;
+}
+
+void fast_export_data(uint32_t mode, off_t len, struct line_buffer *input)
+{
+ assert(len >= 0);
if (mode == REPO_MODE_LNK) {
/* svn symlink blobs start with "link " */
+ if (len < 5)
+ die("invalid dump: symlink too short for \"link\" prefix");
len -= 5;
if (buffer_skip_bytes(input, 5) != 5)
die_short_read(input);
}
- printf("blob\nmark :%"PRIu32"\ndata %"PRIu32"\n", mark, len);
+ printf("data %"PRIuMAX"\n", (uintmax_t) len);
if (buffer_copy_bytes(input, len) != len)
die_short_read(input);
fputc('\n', stdout);
}
+
+static int parse_ls_response(const char *response, uint32_t *mode,
+ struct strbuf *dataref)
+{
+ const char *tab;
+ const char *response_end;
+
+ assert(response);
+ response_end = response + strlen(response);
+
+ if (*response == 'm') { /* Missing. */
+ errno = ENOENT;
+ return -1;
+ }
+
+ /* Mode. */
+ if (response_end - response < strlen("100644") ||
+ response[strlen("100644")] != ' ')
+ die("invalid ls response: missing mode: %s", response);
+ *mode = 0;
+ for (; *response != ' '; response++) {
+ char ch = *response;
+ if (ch < '0' || ch > '7')
+ die("invalid ls response: mode is not octal: %s", response);
+ *mode *= 8;
+ *mode += ch - '0';
+ }
+
+ /* ' blob ' or ' tree ' */
+ if (response_end - response < strlen(" blob ") ||
+ (response[1] != 'b' && response[1] != 't'))
+ die("unexpected ls response: not a tree or blob: %s", response);
+ response += strlen(" blob ");
+
+ /* Dataref. */
+ tab = memchr(response, '\t', response_end - response);
+ if (!tab)
+ die("invalid ls response: missing tab: %s", response);
+ strbuf_add(dataref, response, tab - response);
+ return 0;
+}
+
+int fast_export_ls_rev(uint32_t rev, const char *path,
+ uint32_t *mode, struct strbuf *dataref)
+{
+ ls_from_rev(rev, path);
+ return parse_ls_response(get_response_line(), mode, dataref);
+}
+
+int fast_export_ls(const char *path, uint32_t *mode, struct strbuf *dataref)
+{
+ ls_from_active_commit(path);
+ return parse_ls_response(get_response_line(), mode, dataref);
+}
+
+void fast_export_blob_delta(uint32_t mode,
+ uint32_t old_mode, const char *old_data,
+ off_t len, struct line_buffer *input)
+{
+ long postimage_len;
+
+ assert(len >= 0);
+ postimage_len = apply_delta(len, input, old_data, old_mode);
+ if (mode == REPO_MODE_LNK) {
+ buffer_skip_bytes(&postimage, strlen("link "));
+ postimage_len -= strlen("link ");
+ }
+ printf("data %ld\n", postimage_len);
+ buffer_copy_bytes(&postimage, postimage_len);
+ fputc('\n', stdout);
+}
diff --git a/vcs-svn/fast_export.h b/vcs-svn/fast_export.h
index 33a8fe996f..aa629f54ff 100644
--- a/vcs-svn/fast_export.h
+++ b/vcs-svn/fast_export.h
@@ -1,16 +1,28 @@
#ifndef FAST_EXPORT_H_
#define FAST_EXPORT_H_
-#include "line_buffer.h"
struct strbuf;
+struct line_buffer;
-void fast_export_delete(uint32_t depth, uint32_t *path);
-void fast_export_modify(uint32_t depth, uint32_t *path, uint32_t mode,
- uint32_t mark);
-void fast_export_commit(uint32_t revision, const char *author,
+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_begin_commit(uint32_t revision, const char *author,
const struct strbuf *log, const char *uuid,
const char *url, unsigned long timestamp);
-void fast_export_blob(uint32_t mode, uint32_t mark, uint32_t len,
- struct line_buffer *input);
+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_blob_delta(uint32_t mode,
+ uint32_t old_mode, const char *old_data,
+ off_t len, struct line_buffer *input);
+
+/* If there is no such file at that rev, returns -1, errno == ENOENT. */
+int fast_export_ls_rev(uint32_t rev, const char *path,
+ uint32_t *mode_out, struct strbuf *dataref_out);
+int fast_export_ls(const char *path,
+ uint32_t *mode_out, struct strbuf *dataref_out);
#endif
diff --git a/vcs-svn/line_buffer.c b/vcs-svn/line_buffer.c
index c39038723e..01fcb842f1 100644
--- a/vcs-svn/line_buffer.c
+++ b/vcs-svn/line_buffer.c
@@ -91,10 +91,10 @@ char *buffer_read_line(struct line_buffer *buf)
return buf->line_buffer;
}
-void buffer_read_binary(struct line_buffer *buf,
- struct strbuf *sb, uint32_t size)
+size_t buffer_read_binary(struct line_buffer *buf,
+ struct strbuf *sb, size_t size)
{
- strbuf_fread(sb, size, buf->infile);
+ return strbuf_fread(sb, size, buf->infile);
}
off_t buffer_copy_bytes(struct line_buffer *buf, off_t nbytes)
diff --git a/vcs-svn/line_buffer.h b/vcs-svn/line_buffer.h
index d0b22dda76..8901f214ba 100644
--- a/vcs-svn/line_buffer.h
+++ b/vcs-svn/line_buffer.h
@@ -23,7 +23,7 @@ long buffer_tmpfile_prepare_to_read(struct line_buffer *buf);
int buffer_ferror(struct line_buffer *buf);
char *buffer_read_line(struct line_buffer *buf);
int buffer_read_char(struct line_buffer *buf);
-void buffer_read_binary(struct line_buffer *buf, struct strbuf *sb, uint32_t len);
+size_t buffer_read_binary(struct line_buffer *buf, struct strbuf *sb, size_t len);
/* Returns number of bytes read (not necessarily written). */
off_t buffer_copy_bytes(struct line_buffer *buf, off_t len);
off_t buffer_skip_bytes(struct line_buffer *buf, off_t len);
diff --git a/vcs-svn/obj_pool.h b/vcs-svn/obj_pool.h
deleted file mode 100644
index deb6eb8135..0000000000
--- a/vcs-svn/obj_pool.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Licensed under a two-clause BSD-style license.
- * See LICENSE for details.
- */
-
-#ifndef OBJ_POOL_H_
-#define OBJ_POOL_H_
-
-#include "git-compat-util.h"
-
-#define MAYBE_UNUSED __attribute__((__unused__))
-
-#define obj_pool_gen(pre, obj_t, initial_capacity) \
-static struct { \
- uint32_t committed; \
- uint32_t size; \
- uint32_t capacity; \
- obj_t *base; \
-} pre##_pool = {0, 0, 0, NULL}; \
-static MAYBE_UNUSED uint32_t pre##_alloc(uint32_t count) \
-{ \
- uint32_t offset; \
- if (pre##_pool.size + count > pre##_pool.capacity) { \
- while (pre##_pool.size + count > pre##_pool.capacity) \
- if (pre##_pool.capacity) \
- pre##_pool.capacity *= 2; \
- else \
- pre##_pool.capacity = initial_capacity; \
- pre##_pool.base = realloc(pre##_pool.base, \
- pre##_pool.capacity * sizeof(obj_t)); \
- } \
- offset = pre##_pool.size; \
- pre##_pool.size += count; \
- return offset; \
-} \
-static MAYBE_UNUSED void pre##_free(uint32_t count) \
-{ \
- pre##_pool.size -= count; \
-} \
-static MAYBE_UNUSED uint32_t pre##_offset(obj_t *obj) \
-{ \
- return obj == NULL ? ~0 : obj - pre##_pool.base; \
-} \
-static MAYBE_UNUSED obj_t *pre##_pointer(uint32_t offset) \
-{ \
- return offset >= pre##_pool.size ? NULL : &pre##_pool.base[offset]; \
-} \
-static MAYBE_UNUSED void pre##_commit(void) \
-{ \
- pre##_pool.committed = pre##_pool.size; \
-} \
-static MAYBE_UNUSED void pre##_reset(void) \
-{ \
- free(pre##_pool.base); \
- pre##_pool.base = NULL; \
- pre##_pool.size = 0; \
- pre##_pool.capacity = 0; \
- pre##_pool.committed = 0; \
-}
-
-#endif
diff --git a/vcs-svn/repo_tree.c b/vcs-svn/repo_tree.c
index c3f198d29a..67d27f0b6c 100644
--- a/vcs-svn/repo_tree.c
+++ b/vcs-svn/repo_tree.c
@@ -4,323 +4,45 @@
*/
#include "git-compat-util.h"
-
-#include "string_pool.h"
+#include "strbuf.h"
#include "repo_tree.h"
-#include "obj_pool.h"
#include "fast_export.h"
-#include "trp.h"
-
-struct repo_dirent {
- uint32_t name_offset;
- struct trp_node children;
- uint32_t mode;
- uint32_t content_offset;
-};
-
-struct repo_dir {
- struct trp_root entries;
-};
-
-struct repo_commit {
- uint32_t root_dir_offset;
-};
-
-/* Memory pools for commit, dir and dirent */
-obj_pool_gen(commit, struct repo_commit, 4096)
-obj_pool_gen(dir, struct repo_dir, 4096)
-obj_pool_gen(dent, struct repo_dirent, 4096)
-
-static uint32_t active_commit;
-static uint32_t mark;
-
-static int repo_dirent_name_cmp(const void *a, const void *b);
-
-/* Treap for directory entries */
-trp_gen(static, dent_, struct repo_dirent, children, dent, repo_dirent_name_cmp)
-
-uint32_t next_blob_mark(void)
+const char *repo_read_path(const char *path, uint32_t *mode_out)
{
- return mark++;
-}
+ int err;
+ static struct strbuf buf = STRBUF_INIT;
-static struct repo_dir *repo_commit_root_dir(struct repo_commit *commit)
-{
- return dir_pointer(commit->root_dir_offset);
-}
-
-static struct repo_dirent *repo_first_dirent(struct repo_dir *dir)
-{
- return dent_first(&dir->entries);
-}
-
-static int repo_dirent_name_cmp(const void *a, const void *b)
-{
- const struct repo_dirent *dent1 = a, *dent2 = b;
- uint32_t a_offset = dent1->name_offset;
- uint32_t b_offset = dent2->name_offset;
- return (a_offset > b_offset) - (a_offset < b_offset);
-}
-
-static int repo_dirent_is_dir(struct repo_dirent *dent)
-{
- return dent != NULL && dent->mode == REPO_MODE_DIR;
-}
-
-static struct repo_dir *repo_dir_from_dirent(struct repo_dirent *dent)
-{
- if (!repo_dirent_is_dir(dent))
+ strbuf_reset(&buf);
+ err = fast_export_ls(path, mode_out, &buf);
+ if (err) {
+ if (errno != ENOENT)
+ die_errno("BUG: unexpected fast_export_ls error");
+ /* Treat missing paths as directories. */
+ *mode_out = REPO_MODE_DIR;
return NULL;
- return dir_pointer(dent->content_offset);
-}
-
-static struct repo_dir *repo_clone_dir(struct repo_dir *orig_dir)
-{
- uint32_t orig_o, new_o;
- orig_o = dir_offset(orig_dir);
- if (orig_o >= dir_pool.committed)
- return orig_dir;
- new_o = dir_alloc(1);
- orig_dir = dir_pointer(orig_o);
- *dir_pointer(new_o) = *orig_dir;
- return dir_pointer(new_o);
-}
-
-static struct repo_dirent *repo_read_dirent(uint32_t revision,
- const uint32_t *path)
-{
- uint32_t name = 0;
- struct repo_dirent *key = dent_pointer(dent_alloc(1));
- struct repo_dir *dir = NULL;
- struct repo_dirent *dent = NULL;
- dir = repo_commit_root_dir(commit_pointer(revision));
- while (~(name = *path++)) {
- key->name_offset = name;
- dent = dent_search(&dir->entries, key);
- if (dent == NULL || !repo_dirent_is_dir(dent))
- break;
- dir = repo_dir_from_dirent(dent);
}
- dent_free(1);
- return dent;
+ return buf.buf;
}
-static void repo_write_dirent(const uint32_t *path, uint32_t mode,
- uint32_t content_offset, uint32_t del)
+void repo_copy(uint32_t revision, const char *src, const char *dst)
{
- uint32_t name, revision, dir_o = ~0U, parent_dir_o = ~0U;
- struct repo_dir *dir;
- struct repo_dirent *key;
- struct repo_dirent *dent = NULL;
- revision = active_commit;
- dir = repo_commit_root_dir(commit_pointer(revision));
- dir = repo_clone_dir(dir);
- commit_pointer(revision)->root_dir_offset = dir_offset(dir);
- while (~(name = *path++)) {
- parent_dir_o = dir_offset(dir);
-
- key = dent_pointer(dent_alloc(1));
- key->name_offset = name;
-
- dent = dent_search(&dir->entries, key);
- if (dent == NULL)
- dent = key;
- else
- dent_free(1);
-
- if (dent == key) {
- dent->mode = REPO_MODE_DIR;
- dent->content_offset = 0;
- dent = dent_insert(&dir->entries, dent);
- }
-
- if (dent_offset(dent) < dent_pool.committed) {
- dir_o = repo_dirent_is_dir(dent) ?
- dent->content_offset : ~0;
- dent_remove(&dir->entries, dent);
- dent = dent_pointer(dent_alloc(1));
- dent->name_offset = name;
- dent->mode = REPO_MODE_DIR;
- dent->content_offset = dir_o;
- dent = dent_insert(&dir->entries, dent);
- }
-
- dir = repo_dir_from_dirent(dent);
- dir = repo_clone_dir(dir);
- dent->content_offset = dir_offset(dir);
- }
- if (dent == NULL)
+ int err;
+ uint32_t mode;
+ static struct strbuf data = STRBUF_INIT;
+
+ strbuf_reset(&data);
+ err = fast_export_ls_rev(revision, src, &mode, &data);
+ if (err) {
+ if (errno != ENOENT)
+ die_errno("BUG: unexpected fast_export_ls_rev error");
+ fast_export_delete(dst);
return;
- dent->mode = mode;
- dent->content_offset = content_offset;
- if (del && ~parent_dir_o)
- dent_remove(&dir_pointer(parent_dir_o)->entries, dent);
-}
-
-uint32_t repo_read_path(const uint32_t *path)
-{
- uint32_t content_offset = 0;
- struct repo_dirent *dent = repo_read_dirent(active_commit, path);
- if (dent != NULL)
- content_offset = dent->content_offset;
- return content_offset;
-}
-
-uint32_t repo_read_mode(const uint32_t *path)
-{
- struct repo_dirent *dent = repo_read_dirent(active_commit, path);
- if (dent == NULL)
- die("invalid dump: path to be modified is missing");
- return dent->mode;
-}
-
-void repo_copy(uint32_t revision, const uint32_t *src, const uint32_t *dst)
-{
- uint32_t mode = 0, content_offset = 0;
- struct repo_dirent *src_dent;
- src_dent = repo_read_dirent(revision, src);
- if (src_dent != NULL) {
- mode = src_dent->mode;
- content_offset = src_dent->content_offset;
- repo_write_dirent(dst, mode, content_offset, 0);
- }
-}
-
-void repo_add(uint32_t *path, uint32_t mode, uint32_t blob_mark)
-{
- repo_write_dirent(path, mode, blob_mark, 0);
-}
-
-void repo_delete(uint32_t *path)
-{
- repo_write_dirent(path, 0, 0, 1);
-}
-
-static void repo_git_add_r(uint32_t depth, uint32_t *path, struct repo_dir *dir);
-
-static void repo_git_add(uint32_t depth, uint32_t *path, struct repo_dirent *dent)
-{
- if (repo_dirent_is_dir(dent))
- repo_git_add_r(depth, path, repo_dir_from_dirent(dent));
- else
- fast_export_modify(depth, path,
- dent->mode, dent->content_offset);
-}
-
-static void repo_git_add_r(uint32_t depth, uint32_t *path, struct repo_dir *dir)
-{
- struct repo_dirent *de = repo_first_dirent(dir);
- while (de) {
- path[depth] = de->name_offset;
- repo_git_add(depth + 1, path, de);
- de = dent_next(&dir->entries, de);
- }
-}
-
-static void repo_diff_r(uint32_t depth, uint32_t *path, struct repo_dir *dir1,
- struct repo_dir *dir2)
-{
- struct repo_dirent *de1, *de2;
- de1 = repo_first_dirent(dir1);
- de2 = repo_first_dirent(dir2);
-
- while (de1 && de2) {
- if (de1->name_offset < de2->name_offset) {
- path[depth] = de1->name_offset;
- fast_export_delete(depth + 1, path);
- de1 = dent_next(&dir1->entries, de1);
- continue;
- }
- if (de1->name_offset > de2->name_offset) {
- path[depth] = de2->name_offset;
- repo_git_add(depth + 1, path, de2);
- de2 = dent_next(&dir2->entries, de2);
- continue;
- }
- path[depth] = de1->name_offset;
-
- if (de1->mode == de2->mode &&
- de1->content_offset == de2->content_offset) {
- ; /* No change. */
- } else if (repo_dirent_is_dir(de1) && repo_dirent_is_dir(de2)) {
- repo_diff_r(depth + 1, path,
- repo_dir_from_dirent(de1),
- repo_dir_from_dirent(de2));
- } else if (!repo_dirent_is_dir(de1) && !repo_dirent_is_dir(de2)) {
- repo_git_add(depth + 1, path, de2);
- } else {
- fast_export_delete(depth + 1, path);
- repo_git_add(depth + 1, path, de2);
- }
- de1 = dent_next(&dir1->entries, de1);
- de2 = dent_next(&dir2->entries, de2);
- }
- while (de1) {
- path[depth] = de1->name_offset;
- fast_export_delete(depth + 1, path);
- de1 = dent_next(&dir1->entries, de1);
- }
- while (de2) {
- path[depth] = de2->name_offset;
- repo_git_add(depth + 1, path, de2);
- de2 = dent_next(&dir2->entries, de2);
- }
-}
-
-static uint32_t path_stack[REPO_MAX_PATH_DEPTH];
-
-void repo_diff(uint32_t r1, uint32_t r2)
-{
- repo_diff_r(0,
- path_stack,
- repo_commit_root_dir(commit_pointer(r1)),
- repo_commit_root_dir(commit_pointer(r2)));
-}
-
-void repo_commit(uint32_t revision, const char *author,
- const struct strbuf *log, const char *uuid, const char *url,
- unsigned long timestamp)
-{
- fast_export_commit(revision, author, log, uuid, url, timestamp);
- dent_commit();
- dir_commit();
- active_commit = commit_alloc(1);
- commit_pointer(active_commit)->root_dir_offset =
- commit_pointer(active_commit - 1)->root_dir_offset;
-}
-
-static void mark_init(void)
-{
- uint32_t i;
- mark = 0;
- for (i = 0; i < dent_pool.size; i++)
- if (!repo_dirent_is_dir(dent_pointer(i)) &&
- dent_pointer(i)->content_offset > mark)
- mark = dent_pointer(i)->content_offset;
- mark++;
-}
-
-void repo_init(void)
-{
- mark_init();
- if (commit_pool.size == 0) {
- /* Create empty tree for commit 0. */
- commit_alloc(1);
- commit_pointer(0)->root_dir_offset = dir_alloc(1);
- dir_pointer(0)->entries.trp_root = ~0;
- dir_commit();
}
- /* Preallocate next commit, ready for changes. */
- active_commit = commit_alloc(1);
- commit_pointer(active_commit)->root_dir_offset =
- commit_pointer(active_commit - 1)->root_dir_offset;
+ fast_export_modify(dst, mode, data.buf);
}
-void repo_reset(void)
+void repo_delete(const char *path)
{
- pool_reset();
- commit_reset();
- dir_reset();
- dent_reset();
+ fast_export_delete(path);
}
diff --git a/vcs-svn/repo_tree.h b/vcs-svn/repo_tree.h
index 37bde2e374..889c6a3c95 100644
--- a/vcs-svn/repo_tree.h
+++ b/vcs-svn/repo_tree.h
@@ -8,15 +8,11 @@ struct strbuf;
#define REPO_MODE_EXE 0100755
#define REPO_MODE_LNK 0120000
-#define REPO_MAX_PATH_LEN 4096
-#define REPO_MAX_PATH_DEPTH 1000
-
uint32_t next_blob_mark(void);
-void repo_copy(uint32_t revision, const uint32_t *src, const uint32_t *dst);
-void repo_add(uint32_t *path, uint32_t mode, uint32_t blob_mark);
-uint32_t repo_read_path(const uint32_t *path);
-uint32_t repo_read_mode(const uint32_t *path);
-void repo_delete(uint32_t *path);
+void repo_copy(uint32_t revision, const char *src, const char *dst);
+void repo_add(const char *path, uint32_t mode, uint32_t blob_mark);
+const char *repo_read_path(const char *path, uint32_t *mode_out);
+void repo_delete(const char *path);
void repo_commit(uint32_t revision, const char *author,
const struct strbuf *log, const char *uuid, const char *url,
long unsigned timestamp);
diff --git a/vcs-svn/sliding_window.c b/vcs-svn/sliding_window.c
new file mode 100644
index 0000000000..ec2707c9c4
--- /dev/null
+++ b/vcs-svn/sliding_window.c
@@ -0,0 +1,79 @@
+/*
+ * Licensed under a two-clause BSD-style license.
+ * See LICENSE for details.
+ */
+
+#include "git-compat-util.h"
+#include "sliding_window.h"
+#include "line_buffer.h"
+#include "strbuf.h"
+
+static int input_error(struct line_buffer *file)
+{
+ if (!buffer_ferror(file))
+ return error("delta preimage ends early");
+ return error("cannot read delta preimage: %s", strerror(errno));
+}
+
+static int skip_or_whine(struct line_buffer *file, off_t gap)
+{
+ if (buffer_skip_bytes(file, gap) != gap)
+ return input_error(file);
+ return 0;
+}
+
+static int read_to_fill_or_whine(struct line_buffer *file,
+ struct strbuf *buf, size_t width)
+{
+ buffer_read_binary(file, buf, width - buf->len);
+ if (buf->len != width)
+ return input_error(file);
+ return 0;
+}
+
+static int check_offset_overflow(off_t offset, uintmax_t len)
+{
+ if (len > maximum_signed_value_of_type(off_t))
+ return error("unrepresentable length in delta: "
+ "%"PRIuMAX" > OFF_MAX", len);
+ if (signed_add_overflows(offset, (off_t) len))
+ return error("unrepresentable offset in delta: "
+ "%"PRIuMAX" + %"PRIuMAX" > OFF_MAX",
+ (uintmax_t) offset, len);
+ return 0;
+}
+
+int move_window(struct sliding_view *view, off_t off, size_t width)
+{
+ off_t file_offset;
+ assert(view);
+ assert(view->width <= view->buf.len);
+ assert(!check_offset_overflow(view->off, view->buf.len));
+
+ if (check_offset_overflow(off, 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)
+ return error("delta preimage ends early");
+
+ file_offset = view->off + view->buf.len;
+ if (off < file_offset) {
+ /* Move the overlapping region into place. */
+ strbuf_remove(&view->buf, 0, off - view->off);
+ } else {
+ /* Seek ahead to skip the gap. */
+ if (skip_or_whine(view->file, off - file_offset))
+ return -1;
+ strbuf_setlen(&view->buf, 0);
+ }
+
+ if (view->buf.len > width)
+ ; /* Already read. */
+ else if (read_to_fill_or_whine(view->file, &view->buf, width))
+ return -1;
+
+ view->off = off;
+ view->width = width;
+ return 0;
+}
diff --git a/vcs-svn/sliding_window.h b/vcs-svn/sliding_window.h
new file mode 100644
index 0000000000..b43a825cba
--- /dev/null
+++ b/vcs-svn/sliding_window.h
@@ -0,0 +1,18 @@
+#ifndef SLIDING_WINDOW_H_
+#define SLIDING_WINDOW_H_
+
+#include "strbuf.h"
+
+struct sliding_view {
+ struct line_buffer *file;
+ off_t off;
+ size_t width;
+ off_t max_off; /* -1 means unlimited */
+ struct strbuf buf;
+};
+
+#define SLIDING_VIEW_INIT(input, len) { (input), 0, 0, (len), STRBUF_INIT }
+
+extern int move_window(struct sliding_view *view, off_t off, size_t width);
+
+#endif
diff --git a/vcs-svn/string_pool.c b/vcs-svn/string_pool.c
deleted file mode 100644
index 1b63b19a38..0000000000
--- a/vcs-svn/string_pool.c
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Licensed under a two-clause BSD-style license.
- * See LICENSE for details.
- */
-
-#include "git-compat-util.h"
-#include "trp.h"
-#include "obj_pool.h"
-#include "string_pool.h"
-
-static struct trp_root tree = { ~0U };
-
-struct node {
- uint32_t offset;
- struct trp_node children;
-};
-
-/* Two memory pools: one for struct node, and another for strings */
-obj_pool_gen(node, struct node, 4096)
-obj_pool_gen(string, char, 4096)
-
-static char *node_value(struct node *node)
-{
- return node ? string_pointer(node->offset) : NULL;
-}
-
-static int node_cmp(struct node *a, struct node *b)
-{
- return strcmp(node_value(a), node_value(b));
-}
-
-/* Build a Treap from the node structure (a trp_node w/ offset) */
-trp_gen(static, tree_, struct node, children, node, node_cmp)
-
-const char *pool_fetch(uint32_t entry)
-{
- return node_value(node_pointer(entry));
-}
-
-uint32_t pool_intern(const char *key)
-{
- /* Canonicalize key */
- struct node *match = NULL, *node;
- uint32_t key_len;
- if (key == NULL)
- return ~0;
- key_len = strlen(key) + 1;
- node = node_pointer(node_alloc(1));
- node->offset = string_alloc(key_len);
- strcpy(node_value(node), key);
- match = tree_search(&tree, node);
- if (!match) {
- tree_insert(&tree, node);
- } else {
- node_free(1);
- string_free(key_len);
- node = match;
- }
- return node_offset(node);
-}
-
-uint32_t pool_tok_r(char *str, const char *delim, char **saveptr)
-{
- char *token = strtok_r(str, delim, saveptr);
- return token ? pool_intern(token) : ~0;
-}
-
-void pool_print_seq(uint32_t len, uint32_t *seq, char delim, FILE *stream)
-{
- uint32_t i;
- for (i = 0; i < len && ~seq[i]; i++) {
- fputs(pool_fetch(seq[i]), stream);
- if (i < len - 1 && ~seq[i + 1])
- fputc(delim, stream);
- }
-}
-
-uint32_t pool_tok_seq(uint32_t sz, uint32_t *seq, const char *delim, char *str)
-{
- char *context = NULL;
- uint32_t token = ~0U;
- uint32_t length;
-
- if (sz == 0)
- return ~0;
- if (str)
- token = pool_tok_r(str, delim, &context);
- for (length = 0; length < sz; length++) {
- seq[length] = token;
- if (token == ~0)
- return length;
- token = pool_tok_r(NULL, delim, &context);
- }
- seq[sz - 1] = ~0;
- return sz;
-}
-
-void pool_reset(void)
-{
- node_reset();
- string_reset();
-}
diff --git a/vcs-svn/string_pool.h b/vcs-svn/string_pool.h
deleted file mode 100644
index 222fb66e68..0000000000
--- a/vcs-svn/string_pool.h
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef STRING_POOL_H_
-#define STRING_POOL_H_
-
-uint32_t pool_intern(const char *key);
-const char *pool_fetch(uint32_t entry);
-uint32_t pool_tok_r(char *str, const char *delim, char **saveptr);
-void pool_print_seq(uint32_t len, uint32_t *seq, char delim, FILE *stream);
-uint32_t pool_tok_seq(uint32_t sz, uint32_t *seq, const char *delim, char *str);
-void pool_reset(void);
-
-#endif
diff --git a/vcs-svn/string_pool.txt b/vcs-svn/string_pool.txt
deleted file mode 100644
index 1b41f15628..0000000000
--- a/vcs-svn/string_pool.txt
+++ /dev/null
@@ -1,43 +0,0 @@
-string_pool API
-===============
-
-The string_pool API provides facilities for replacing strings
-with integer keys that can be more easily compared and stored.
-The facilities are designed so that one could teach Git without
-too much trouble to store the information needed for these keys to
-remain valid over multiple executions.
-
-Functions
----------
-
-pool_intern::
- Include a string in the string pool and get its key.
- If that string is already in the pool, retrieves its
- existing key.
-
-pool_fetch::
- Retrieve the string associated to a given key.
-
-pool_tok_r::
- Extract the key of the next token from a string.
- Interface mimics strtok_r.
-
-pool_print_seq::
- Print a sequence of strings named by key to a file, using the
- specified delimiter to separate them.
-
- If NULL (key ~0) appears in the sequence, the sequence ends
- early.
-
-pool_tok_seq::
- Split a string into tokens, storing the keys of segments
- into a caller-provided array.
-
- Unless sz is 0, the array will always be ~0-terminated.
- If there is not enough room for all the tokens, the
- array holds as many tokens as fit in the entries before
- the terminating ~0. Return value is the index after the
- last token, or sz if the tokens did not fit.
-
-pool_reset::
- Deallocate storage for the string pool.
diff --git a/vcs-svn/svndiff.c b/vcs-svn/svndiff.c
new file mode 100644
index 0000000000..1647c1a780
--- /dev/null
+++ b/vcs-svn/svndiff.c
@@ -0,0 +1,308 @@
+/*
+ * Licensed under a two-clause BSD-style license.
+ * See LICENSE for details.
+ */
+
+#include "git-compat-util.h"
+#include "sliding_window.h"
+#include "line_buffer.h"
+#include "svndiff.h"
+
+/*
+ * svndiff0 applier
+ *
+ * See http://svn.apache.org/repos/asf/subversion/trunk/notes/svndiff.
+ *
+ * svndiff0 ::= 'SVN\0' window*
+ * window ::= int int int int int instructions inline_data;
+ * instructions ::= instruction*;
+ * instruction ::= view_selector int int
+ * | copyfrom_data int
+ * | packed_view_selector int
+ * | packed_copyfrom_data
+ * ;
+ * view_selector ::= copyfrom_source
+ * | copyfrom_target
+ * ;
+ * copyfrom_source ::= # binary 00 000000;
+ * copyfrom_target ::= # binary 01 000000;
+ * copyfrom_data ::= # binary 10 000000;
+ * packed_view_selector ::= # view_selector OR-ed with 6 bit value;
+ * packed_copyfrom_data ::= # copyfrom_data OR-ed with 6 bit value;
+ * int ::= highdigit* lowdigit;
+ * highdigit ::= # binary 1000 0000 OR-ed with 7 bit value;
+ * lowdigit ::= # 7 bit value;
+ */
+
+#define INSN_MASK 0xc0
+#define INSN_COPYFROM_SOURCE 0x00
+#define INSN_COPYFROM_TARGET 0x40
+#define INSN_COPYFROM_DATA 0x80
+#define OPERAND_MASK 0x3f
+
+#define VLI_CONTINUE 0x80
+#define VLI_DIGIT_MASK 0x7f
+#define VLI_BITS_PER_DIGIT 7
+
+struct window {
+ struct sliding_view *in;
+ struct strbuf out;
+ struct strbuf instructions;
+ struct strbuf data;
+};
+
+#define WINDOW_INIT(w) { (w), STRBUF_INIT, STRBUF_INIT, STRBUF_INIT }
+
+static void window_release(struct window *ctx)
+{
+ strbuf_release(&ctx->out);
+ strbuf_release(&ctx->instructions);
+ strbuf_release(&ctx->data);
+}
+
+static int write_strbuf(struct strbuf *sb, FILE *out)
+{
+ if (fwrite(sb->buf, 1, sb->len, out) == sb->len) /* Success. */
+ return 0;
+ return error("cannot write delta postimage: %s", strerror(errno));
+}
+
+static int error_short_read(struct line_buffer *input)
+{
+ if (buffer_ferror(input))
+ return error("error reading delta: %s", strerror(errno));
+ return error("invalid delta: unexpected end of file");
+}
+
+static int read_chunk(struct line_buffer *delta, off_t *delta_len,
+ struct strbuf *buf, size_t len)
+{
+ strbuf_reset(buf);
+ if (len > *delta_len ||
+ buffer_read_binary(delta, buf, len) != len)
+ return error_short_read(delta);
+ *delta_len -= buf->len;
+ return 0;
+}
+
+static int read_magic(struct line_buffer *in, off_t *len)
+{
+ static const char magic[] = {'S', 'V', 'N', '\0'};
+ struct strbuf sb = STRBUF_INIT;
+
+ if (read_chunk(in, len, &sb, sizeof(magic))) {
+ strbuf_release(&sb);
+ return -1;
+ }
+ if (memcmp(sb.buf, magic, sizeof(magic))) {
+ strbuf_release(&sb);
+ return error("invalid delta: unrecognized file type");
+ }
+ strbuf_release(&sb);
+ return 0;
+}
+
+static int read_int(struct line_buffer *in, uintmax_t *result, off_t *len)
+{
+ uintmax_t rv = 0;
+ off_t sz;
+ for (sz = *len; sz; sz--) {
+ const int ch = buffer_read_char(in);
+ if (ch == EOF)
+ break;
+
+ rv <<= VLI_BITS_PER_DIGIT;
+ rv += (ch & VLI_DIGIT_MASK);
+ if (ch & VLI_CONTINUE)
+ continue;
+
+ *result = rv;
+ *len = sz - 1;
+ return 0;
+ }
+ return error_short_read(in);
+}
+
+static int parse_int(const char **buf, size_t *result, const char *end)
+{
+ size_t rv = 0;
+ const char *pos;
+ for (pos = *buf; pos != end; pos++) {
+ unsigned char ch = *pos;
+
+ rv <<= VLI_BITS_PER_DIGIT;
+ rv += (ch & VLI_DIGIT_MASK);
+ if (ch & VLI_CONTINUE)
+ continue;
+
+ *result = rv;
+ *buf = pos + 1;
+ return 0;
+ }
+ return error("invalid delta: unexpected end of instructions section");
+}
+
+static int read_offset(struct line_buffer *in, off_t *result, off_t *len)
+{
+ uintmax_t val;
+ if (read_int(in, &val, len))
+ return -1;
+ if (val > maximum_signed_value_of_type(off_t))
+ return error("unrepresentable offset in delta: %"PRIuMAX"", val);
+ *result = val;
+ return 0;
+}
+
+static int read_length(struct line_buffer *in, size_t *result, off_t *len)
+{
+ uintmax_t val;
+ if (read_int(in, &val, len))
+ return -1;
+ if (val > SIZE_MAX)
+ return error("unrepresentable length in delta: %"PRIuMAX"", val);
+ *result = val;
+ return 0;
+}
+
+static int copyfrom_source(struct window *ctx, const char **instructions,
+ size_t nbytes, const char *insns_end)
+{
+ size_t offset;
+ if (parse_int(instructions, &offset, insns_end))
+ return -1;
+ if (unsigned_add_overflows(offset, nbytes) ||
+ offset + nbytes > ctx->in->width)
+ return error("invalid delta: copies source data outside view");
+ strbuf_add(&ctx->out, ctx->in->buf.buf + offset, nbytes);
+ return 0;
+}
+
+static int copyfrom_target(struct window *ctx, const char **instructions,
+ size_t nbytes, const char *instructions_end)
+{
+ size_t offset;
+ if (parse_int(instructions, &offset, instructions_end))
+ return -1;
+ if (offset >= ctx->out.len)
+ return error("invalid delta: copies from the future");
+ for (; nbytes > 0; nbytes--)
+ strbuf_addch(&ctx->out, ctx->out.buf[offset++]);
+ return 0;
+}
+
+static int copyfrom_data(struct window *ctx, size_t *data_pos, size_t nbytes)
+{
+ const size_t pos = *data_pos;
+ if (unsigned_add_overflows(pos, nbytes) ||
+ pos + nbytes > ctx->data.len)
+ return error("invalid delta: copies unavailable inline data");
+ strbuf_add(&ctx->out, ctx->data.buf + pos, nbytes);
+ *data_pos += nbytes;
+ return 0;
+}
+
+static int parse_first_operand(const char **buf, size_t *out, const char *end)
+{
+ size_t result = (unsigned char) *(*buf)++ & OPERAND_MASK;
+ if (result) { /* immediate operand */
+ *out = result;
+ return 0;
+ }
+ return parse_int(buf, out, end);
+}
+
+static int execute_one_instruction(struct window *ctx,
+ const char **instructions, size_t *data_pos)
+{
+ unsigned int instruction;
+ const char *insns_end = ctx->instructions.buf + ctx->instructions.len;
+ size_t nbytes;
+ assert(ctx);
+ assert(instructions && *instructions);
+ assert(data_pos);
+
+ instruction = (unsigned char) **instructions;
+ if (parse_first_operand(instructions, &nbytes, insns_end))
+ return -1;
+ switch (instruction & INSN_MASK) {
+ case INSN_COPYFROM_SOURCE:
+ return copyfrom_source(ctx, instructions, nbytes, insns_end);
+ case INSN_COPYFROM_TARGET:
+ return copyfrom_target(ctx, instructions, nbytes, insns_end);
+ case INSN_COPYFROM_DATA:
+ return copyfrom_data(ctx, data_pos, nbytes);
+ default:
+ return error("invalid delta: unrecognized instruction");
+ }
+}
+
+static int apply_window_in_core(struct window *ctx)
+{
+ const char *instructions;
+ size_t data_pos = 0;
+
+ /*
+ * Fill ctx->out.buf using data from the source, target,
+ * and inline data views.
+ */
+ for (instructions = ctx->instructions.buf;
+ instructions != ctx->instructions.buf + ctx->instructions.len;
+ )
+ if (execute_one_instruction(ctx, &instructions, &data_pos))
+ return -1;
+ if (data_pos != ctx->data.len)
+ return error("invalid delta: does not copy all inline data");
+ return 0;
+}
+
+static int apply_one_window(struct line_buffer *delta, off_t *delta_len,
+ struct sliding_view *preimage, FILE *out)
+{
+ struct window ctx = WINDOW_INIT(preimage);
+ size_t out_len;
+ size_t instructions_len;
+ size_t data_len;
+ assert(delta_len);
+
+ /* "source view" offset and length already handled; */
+ if (read_length(delta, &out_len, delta_len) ||
+ read_length(delta, &instructions_len, delta_len) ||
+ read_length(delta, &data_len, delta_len) ||
+ read_chunk(delta, delta_len, &ctx.instructions, instructions_len) ||
+ read_chunk(delta, delta_len, &ctx.data, data_len))
+ goto error_out;
+ strbuf_grow(&ctx.out, out_len);
+ if (apply_window_in_core(&ctx))
+ goto error_out;
+ if (ctx.out.len != out_len) {
+ error("invalid delta: incorrect postimage length");
+ goto error_out;
+ }
+ if (write_strbuf(&ctx.out, out))
+ goto error_out;
+ window_release(&ctx);
+ return 0;
+error_out:
+ window_release(&ctx);
+ return -1;
+}
+
+int svndiff0_apply(struct line_buffer *delta, off_t delta_len,
+ struct sliding_view *preimage, FILE *postimage)
+{
+ assert(delta && preimage && postimage);
+
+ if (read_magic(delta, &delta_len))
+ return -1;
+ while (delta_len) { /* For each window: */
+ off_t pre_off = pre_off; /* stupid GCC... */
+ size_t pre_len;
+
+ if (read_offset(delta, &pre_off, &delta_len) ||
+ read_length(delta, &pre_len, &delta_len) ||
+ move_window(preimage, pre_off, pre_len) ||
+ apply_one_window(delta, &delta_len, preimage, postimage))
+ return -1;
+ }
+ return 0;
+}
diff --git a/vcs-svn/svndiff.h b/vcs-svn/svndiff.h
new file mode 100644
index 0000000000..74eb464bab
--- /dev/null
+++ b/vcs-svn/svndiff.h
@@ -0,0 +1,10 @@
+#ifndef SVNDIFF_H_
+#define SVNDIFF_H_
+
+struct line_buffer;
+struct sliding_view;
+
+extern int svndiff0_apply(struct line_buffer *delta, off_t delta_len,
+ struct sliding_view *preimage, FILE *postimage);
+
+#endif
diff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c
index bc792223b2..644fdc71ba 100644
--- a/vcs-svn/svndump.c
+++ b/vcs-svn/svndump.c
@@ -11,7 +11,6 @@
#include "repo_tree.h"
#include "fast_export.h"
#include "line_buffer.h"
-#include "string_pool.h"
#include "strbuf.h"
#include "svndump.h"
@@ -21,15 +20,19 @@
*/
#define constcmp(s, ref) memcmp(s, ref, sizeof(ref) - 1)
+#define REPORT_FILENO 3
+
#define NODEACT_REPLACE 4
#define NODEACT_DELETE 3
#define NODEACT_ADD 2
#define NODEACT_CHANGE 1
#define NODEACT_UNKNOWN 0
-#define DUMP_CTX 0
-#define REV_CTX 1
-#define NODE_CTX 2
+/* States: */
+#define DUMP_CTX 0 /* dump metadata */
+#define REV_CTX 1 /* revision metadata */
+#define NODE_CTX 2 /* node metadata */
+#define INTERNODE_CTX 3 /* between nodes */
#define LENGTH_UNKNOWN (~0)
#define DATE_RFC2822_LEN 31
@@ -37,8 +40,9 @@
static struct line_buffer input = LINE_BUFFER_INIT;
static struct {
- uint32_t action, propLength, textLength, srcRev, type;
- uint32_t src[REPO_MAX_PATH_DEPTH], dst[REPO_MAX_PATH_DEPTH];
+ uint32_t action, propLength, srcRev, type;
+ off_t text_length;
+ struct strbuf src, dst;
uint32_t text_delta, prop_delta;
} node_ctx;
@@ -58,10 +62,12 @@ static void reset_node_ctx(char *fname)
node_ctx.type = 0;
node_ctx.action = NODEACT_UNKNOWN;
node_ctx.propLength = LENGTH_UNKNOWN;
- node_ctx.textLength = LENGTH_UNKNOWN;
- node_ctx.src[0] = ~0;
+ node_ctx.text_length = -1;
+ strbuf_reset(&node_ctx.src);
node_ctx.srcRev = 0;
- pool_tok_seq(REPO_MAX_PATH_DEPTH, node_ctx.dst, "/", fname);
+ strbuf_reset(&node_ctx.dst);
+ if (fname)
+ strbuf_addstr(&node_ctx.dst, fname);
node_ctx.text_delta = 0;
node_ctx.prop_delta = 0;
}
@@ -202,28 +208,32 @@ static void read_props(void)
static void handle_node(void)
{
- uint32_t mark = 0;
const uint32_t type = node_ctx.type;
const int have_props = node_ctx.propLength != LENGTH_UNKNOWN;
- const int have_text = node_ctx.textLength != LENGTH_UNKNOWN;
+ const int have_text = node_ctx.text_length != -1;
+ /*
+ * Old text for this node:
+ * NULL - directory or bug
+ * empty_blob - empty
+ * "<dataref>" - data retrievable from fast-import
+ */
+ static const char *const empty_blob = "::empty::";
+ const char *old_data = NULL;
+ uint32_t old_mode = REPO_MODE_BLB;
- if (node_ctx.text_delta)
- die("text deltas not supported");
- if (have_text)
- mark = next_blob_mark();
if (node_ctx.action == NODEACT_DELETE) {
if (have_text || have_props || node_ctx.srcRev)
die("invalid dump: deletion node has "
"copyfrom info, text, or properties");
- repo_delete(node_ctx.dst);
+ repo_delete(node_ctx.dst.buf);
return;
}
if (node_ctx.action == NODEACT_REPLACE) {
- repo_delete(node_ctx.dst);
+ repo_delete(node_ctx.dst.buf);
node_ctx.action = NODEACT_ADD;
}
if (node_ctx.srcRev) {
- repo_copy(node_ctx.srcRev, node_ctx.src, node_ctx.dst);
+ repo_copy(node_ctx.srcRev, node_ctx.src.buf, node_ctx.dst.buf);
if (node_ctx.action == NODEACT_ADD)
node_ctx.action = NODEACT_CHANGE;
}
@@ -231,23 +241,27 @@ static void handle_node(void)
die("invalid dump: directories cannot have text attached");
/*
- * Decide on the new content (mark) and mode (node_ctx.type).
+ * Find old content (old_data) and decide on the new mode.
*/
- if (node_ctx.action == NODEACT_CHANGE && !~*node_ctx.dst) {
+ if (node_ctx.action == NODEACT_CHANGE && !*node_ctx.dst.buf) {
if (type != REPO_MODE_DIR)
die("invalid dump: root of tree is not a regular file");
+ old_data = NULL;
} else if (node_ctx.action == NODEACT_CHANGE) {
uint32_t mode;
- if (!have_text)
- mark = repo_read_path(node_ctx.dst);
- mode = repo_read_mode(node_ctx.dst);
+ old_data = repo_read_path(node_ctx.dst.buf, &mode);
if (mode == REPO_MODE_DIR && type != REPO_MODE_DIR)
die("invalid dump: cannot modify a directory into a file");
if (mode != REPO_MODE_DIR && type == REPO_MODE_DIR)
die("invalid dump: cannot modify a file into a directory");
node_ctx.type = mode;
+ old_mode = mode;
} else if (node_ctx.action == NODEACT_ADD) {
- if (!have_text && type != REPO_MODE_DIR)
+ if (type == REPO_MODE_DIR)
+ old_data = NULL;
+ else if (have_text)
+ old_data = empty_blob;
+ else
die("invalid dump: adds node without text");
} else {
die("invalid dump: Node-path block lacks Node-action");
@@ -266,18 +280,39 @@ static void handle_node(void)
/*
* Save the result.
*/
- repo_add(node_ctx.dst, node_ctx.type, mark);
- if (have_text)
- fast_export_blob(node_ctx.type, mark,
- node_ctx.textLength, &input);
+ if (type == REPO_MODE_DIR) /* directories are not tracked. */
+ return;
+ assert(old_data);
+ if (old_data == empty_blob)
+ /* For the fast_export_* functions, NULL means empty. */
+ old_data = NULL;
+ if (!have_text) {
+ fast_export_modify(node_ctx.dst.buf, node_ctx.type, old_data);
+ return;
+ }
+ if (!node_ctx.text_delta) {
+ fast_export_modify(node_ctx.dst.buf, node_ctx.type, "inline");
+ fast_export_data(node_ctx.type, node_ctx.text_length, &input);
+ return;
+ }
+ fast_export_modify(node_ctx.dst.buf, node_ctx.type, "inline");
+ fast_export_blob_delta(node_ctx.type, old_mode, old_data,
+ node_ctx.text_length, &input);
}
-static void handle_revision(void)
+static void begin_revision(void)
+{
+ 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);
+}
+
+static void end_revision(void)
{
if (rev_ctx.revision)
- repo_commit(rev_ctx.revision, rev_ctx.author.buf,
- &rev_ctx.log, dump_ctx.uuid.buf, dump_ctx.url.buf,
- rev_ctx.timestamp);
+ fast_export_end_commit(rev_ctx.revision);
}
void svndump_read(const char *url)
@@ -318,8 +353,10 @@ void svndump_read(const char *url)
continue;
if (active_ctx == NODE_CTX)
handle_node();
+ if (active_ctx == REV_CTX)
+ begin_revision();
if (active_ctx != DUMP_CTX)
- handle_revision();
+ end_revision();
active_ctx = REV_CTX;
reset_rev_ctx(atoi(val));
break;
@@ -329,6 +366,8 @@ void svndump_read(const char *url)
if (!constcmp(t + strlen("Node-"), "path")) {
if (active_ctx == NODE_CTX)
handle_node();
+ if (active_ctx == REV_CTX)
+ begin_revision();
active_ctx = NODE_CTX;
reset_node_ctx(val);
break;
@@ -361,7 +400,8 @@ void svndump_read(const char *url)
case sizeof("Node-copyfrom-path"):
if (constcmp(t, "Node-copyfrom-path"))
continue;
- pool_tok_seq(REPO_MAX_PATH_DEPTH, node_ctx.src, "/", val);
+ strbuf_reset(&node_ctx.src);
+ strbuf_addstr(&node_ctx.src, val);
break;
case sizeof("Node-copyfrom-rev"):
if (constcmp(t, "Node-copyfrom-rev"))
@@ -370,7 +410,15 @@ void svndump_read(const char *url)
break;
case sizeof("Text-content-length"):
if (!constcmp(t, "Text-content-length")) {
- node_ctx.textLength = atoi(val);
+ char *end;
+ uintmax_t textlen;
+
+ textlen = 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))
+ die("unrepresentable length in dump: %s", val);
+ node_ctx.text_length = (off_t) textlen;
break;
}
if (constcmp(t, "Prop-content-length"))
@@ -399,7 +447,7 @@ void svndump_read(const char *url)
read_props();
} else if (active_ctx == NODE_CTX) {
handle_node();
- active_ctx = REV_CTX;
+ active_ctx = INTERNODE_CTX;
} else {
fprintf(stderr, "Unexpected content length header: %"PRIu32"\n", len);
if (buffer_skip_bytes(&input, len) != len)
@@ -411,19 +459,23 @@ void svndump_read(const char *url)
die_short_read();
if (active_ctx == NODE_CTX)
handle_node();
+ if (active_ctx == REV_CTX)
+ begin_revision();
if (active_ctx != DUMP_CTX)
- handle_revision();
+ end_revision();
}
int svndump_init(const char *filename)
{
if (buffer_init(&input, filename))
return error("cannot open %s: %s", filename, strerror(errno));
- repo_init();
+ fast_export_init(REPORT_FILENO);
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(&node_ctx.src, 4096);
+ strbuf_init(&node_ctx.dst, 4096);
reset_dump_ctx(NULL);
reset_rev_ctx(0);
reset_node_ctx(NULL);
@@ -432,11 +484,13 @@ int svndump_init(const char *filename)
void svndump_deinit(void)
{
- repo_reset();
+ fast_export_deinit();
reset_dump_ctx(NULL);
reset_rev_ctx(0);
reset_node_ctx(NULL);
strbuf_release(&rev_ctx.log);
+ strbuf_release(&node_ctx.src);
+ strbuf_release(&node_ctx.dst);
if (buffer_deinit(&input))
fprintf(stderr, "Input error\n");
if (ferror(stdout))
@@ -445,8 +499,8 @@ void svndump_deinit(void)
void svndump_reset(void)
{
+ fast_export_reset();
buffer_reset(&input);
- repo_reset();
strbuf_release(&dump_ctx.uuid);
strbuf_release(&dump_ctx.url);
strbuf_release(&rev_ctx.log);
diff --git a/vcs-svn/trp.h b/vcs-svn/trp.h
deleted file mode 100644
index c32b9184e9..0000000000
--- a/vcs-svn/trp.h
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * C macro implementation of treaps.
- *
- * Usage:
- * #include <stdint.h>
- * #include "trp.h"
- * trp_gen(...)
- *
- * Licensed under a two-clause BSD-style license.
- * See LICENSE for details.
- */
-
-#ifndef TRP_H_
-#define TRP_H_
-
-#define MAYBE_UNUSED __attribute__((__unused__))
-
-/* Node structure. */
-struct trp_node {
- uint32_t trpn_left;
- uint32_t trpn_right;
-};
-
-/* Root structure. */
-struct trp_root {
- uint32_t trp_root;
-};
-
-/* Pointer/Offset conversion. */
-#define trpn_pointer(a_base, a_offset) (a_base##_pointer(a_offset))
-#define trpn_offset(a_base, a_pointer) (a_base##_offset(a_pointer))
-#define trpn_modify(a_base, a_offset) \
- do { \
- if ((a_offset) < a_base##_pool.committed) { \
- uint32_t old_offset = (a_offset);\
- (a_offset) = a_base##_alloc(1); \
- *trpn_pointer(a_base, a_offset) = \
- *trpn_pointer(a_base, old_offset); \
- } \
- } while (0)
-
-/* Left accessors. */
-#define trp_left_get(a_base, a_field, a_node) \
- (trpn_pointer(a_base, a_node)->a_field.trpn_left)
-#define trp_left_set(a_base, a_field, a_node, a_left) \
- do { \
- trpn_modify(a_base, a_node); \
- trp_left_get(a_base, a_field, a_node) = (a_left); \
- } while (0)
-
-/* Right accessors. */
-#define trp_right_get(a_base, a_field, a_node) \
- (trpn_pointer(a_base, a_node)->a_field.trpn_right)
-#define trp_right_set(a_base, a_field, a_node, a_right) \
- do { \
- trpn_modify(a_base, a_node); \
- trp_right_get(a_base, a_field, a_node) = (a_right); \
- } while (0)
-
-/*
- * Fibonacci hash function.
- * The multiplier is the nearest prime to (2^32 times (√5 - 1)/2).
- * See Knuth §6.4: volume 3, 3rd ed, p518.
- */
-#define trpn_hash(a_node) (uint32_t) (2654435761u * (a_node))
-
-/* Priority accessors. */
-#define trp_prio_get(a_node) trpn_hash(a_node)
-
-/* Node initializer. */
-#define trp_node_new(a_base, a_field, a_node) \
- do { \
- trp_left_set(a_base, a_field, (a_node), ~0); \
- trp_right_set(a_base, a_field, (a_node), ~0); \
- } while (0)
-
-/* Internal utility macros. */
-#define trpn_first(a_base, a_field, a_root, r_node) \
- do { \
- (r_node) = (a_root); \
- if ((r_node) == ~0) \
- return NULL; \
- while (~trp_left_get(a_base, a_field, (r_node))) \
- (r_node) = trp_left_get(a_base, a_field, (r_node)); \
- } while (0)
-
-#define trpn_rotate_left(a_base, a_field, a_node, r_node) \
- do { \
- (r_node) = trp_right_get(a_base, a_field, (a_node)); \
- trp_right_set(a_base, a_field, (a_node), \
- trp_left_get(a_base, a_field, (r_node))); \
- trp_left_set(a_base, a_field, (r_node), (a_node)); \
- } while (0)
-
-#define trpn_rotate_right(a_base, a_field, a_node, r_node) \
- do { \
- (r_node) = trp_left_get(a_base, a_field, (a_node)); \
- trp_left_set(a_base, a_field, (a_node), \
- trp_right_get(a_base, a_field, (r_node))); \
- trp_right_set(a_base, a_field, (r_node), (a_node)); \
- } while (0)
-
-#define trp_gen(a_attr, a_pre, a_type, a_field, a_base, a_cmp) \
-a_attr a_type MAYBE_UNUSED *a_pre##first(struct trp_root *treap) \
-{ \
- uint32_t ret; \
- trpn_first(a_base, a_field, treap->trp_root, ret); \
- return trpn_pointer(a_base, ret); \
-} \
-a_attr a_type MAYBE_UNUSED *a_pre##next(struct trp_root *treap, a_type *node) \
-{ \
- uint32_t ret; \
- uint32_t offset = trpn_offset(a_base, node); \
- if (~trp_right_get(a_base, a_field, offset)) { \
- trpn_first(a_base, a_field, \
- trp_right_get(a_base, a_field, offset), ret); \
- } else { \
- uint32_t tnode = treap->trp_root; \
- ret = ~0; \
- while (1) { \
- int cmp = (a_cmp)(trpn_pointer(a_base, offset), \
- trpn_pointer(a_base, tnode)); \
- if (cmp < 0) { \
- ret = tnode; \
- tnode = trp_left_get(a_base, a_field, tnode); \
- } else if (cmp > 0) { \
- tnode = trp_right_get(a_base, a_field, tnode); \
- } else { \
- break; \
- } \
- } \
- } \
- return trpn_pointer(a_base, ret); \
-} \
-a_attr a_type MAYBE_UNUSED *a_pre##search(struct trp_root *treap, a_type *key) \
-{ \
- int cmp; \
- uint32_t ret = treap->trp_root; \
- while (~ret && (cmp = (a_cmp)(key, trpn_pointer(a_base, ret)))) { \
- if (cmp < 0) { \
- ret = trp_left_get(a_base, a_field, ret); \
- } else { \
- ret = trp_right_get(a_base, a_field, ret); \
- } \
- } \
- return trpn_pointer(a_base, ret); \
-} \
-a_attr a_type MAYBE_UNUSED *a_pre##nsearch(struct trp_root *treap, a_type *key) \
-{ \
- int cmp; \
- uint32_t ret = treap->trp_root; \
- while (~ret && (cmp = (a_cmp)(key, trpn_pointer(a_base, ret)))) { \
- if (cmp < 0) { \
- if (!~trp_left_get(a_base, a_field, ret)) \
- break; \
- ret = trp_left_get(a_base, a_field, ret); \
- } else { \
- ret = trp_right_get(a_base, a_field, ret); \
- } \
- } \
- return trpn_pointer(a_base, ret); \
-} \
-a_attr uint32_t MAYBE_UNUSED a_pre##insert_recurse(uint32_t cur_node, uint32_t ins_node) \
-{ \
- if (cur_node == ~0) { \
- return ins_node; \
- } else { \
- uint32_t ret; \
- int cmp = (a_cmp)(trpn_pointer(a_base, ins_node), \
- trpn_pointer(a_base, cur_node)); \
- if (cmp < 0) { \
- uint32_t left = a_pre##insert_recurse( \
- trp_left_get(a_base, a_field, cur_node), ins_node); \
- trp_left_set(a_base, a_field, cur_node, left); \
- if (trp_prio_get(left) < trp_prio_get(cur_node)) \
- trpn_rotate_right(a_base, a_field, cur_node, ret); \
- else \
- ret = cur_node; \
- } else { \
- uint32_t right = a_pre##insert_recurse( \
- trp_right_get(a_base, a_field, cur_node), ins_node); \
- trp_right_set(a_base, a_field, cur_node, right); \
- if (trp_prio_get(right) < trp_prio_get(cur_node)) \
- trpn_rotate_left(a_base, a_field, cur_node, ret); \
- else \
- ret = cur_node; \
- } \
- return ret; \
- } \
-} \
-a_attr a_type *MAYBE_UNUSED a_pre##insert(struct trp_root *treap, a_type *node) \
-{ \
- uint32_t offset = trpn_offset(a_base, node); \
- trp_node_new(a_base, a_field, offset); \
- treap->trp_root = a_pre##insert_recurse(treap->trp_root, offset); \
- return trpn_pointer(a_base, offset); \
-} \
-a_attr uint32_t MAYBE_UNUSED a_pre##remove_recurse(uint32_t cur_node, uint32_t rem_node) \
-{ \
- int cmp = a_cmp(trpn_pointer(a_base, rem_node), \
- trpn_pointer(a_base, cur_node)); \
- if (cmp == 0) { \
- uint32_t ret; \
- uint32_t left = trp_left_get(a_base, a_field, cur_node); \
- uint32_t right = trp_right_get(a_base, a_field, cur_node); \
- if (left == ~0) { \
- if (right == ~0) \
- return ~0; \
- } else if (right == ~0 || trp_prio_get(left) < trp_prio_get(right)) { \
- trpn_rotate_right(a_base, a_field, cur_node, ret); \
- right = a_pre##remove_recurse(cur_node, rem_node); \
- trp_right_set(a_base, a_field, ret, right); \
- return ret; \
- } \
- trpn_rotate_left(a_base, a_field, cur_node, ret); \
- left = a_pre##remove_recurse(cur_node, rem_node); \
- trp_left_set(a_base, a_field, ret, left); \
- return ret; \
- } else if (cmp < 0) { \
- uint32_t left = a_pre##remove_recurse( \
- trp_left_get(a_base, a_field, cur_node), rem_node); \
- trp_left_set(a_base, a_field, cur_node, left); \
- return cur_node; \
- } else { \
- uint32_t right = a_pre##remove_recurse( \
- trp_right_get(a_base, a_field, cur_node), rem_node); \
- trp_right_set(a_base, a_field, cur_node, right); \
- return cur_node; \
- } \
-} \
-a_attr void MAYBE_UNUSED a_pre##remove(struct trp_root *treap, a_type *node) \
-{ \
- treap->trp_root = a_pre##remove_recurse(treap->trp_root, \
- trpn_offset(a_base, node)); \
-} \
-
-#endif
diff --git a/vcs-svn/trp.txt b/vcs-svn/trp.txt
deleted file mode 100644
index 177ebca335..0000000000
--- a/vcs-svn/trp.txt
+++ /dev/null
@@ -1,109 +0,0 @@
-Motivation
-==========
-
-Treaps provide a memory-efficient binary search tree structure.
-Insertion/deletion/search are about as about as fast in the average
-case as red-black trees and the chances of worst-case behavior are
-vanishingly small, thanks to (pseudo-)randomness. The bad worst-case
-behavior is a small price to pay, given that treaps are much simpler
-to implement.
-
-API
-===
-
-The trp API generates a data structure and functions to handle a
-large growing set of objects stored in a pool.
-
-The caller:
-
-. Specifies parameters for the generated functions with the
- trp_gen(static, foo_, ...) macro.
-
-. Allocates a `struct trp_root` variable and sets it to {~0}.
-
-. Adds new nodes to the set using `foo_insert`. Any pointers
- to existing nodes cannot be relied upon any more, so the caller
- might retrieve them anew with `foo_pointer`.
-
-. Can find a specific item in the set using `foo_search`.
-
-. Can iterate over items in the set using `foo_first` and `foo_next`.
-
-. Can remove an item from the set using `foo_remove`.
-
-Example:
-
-----
-struct ex_node {
- const char *s;
- struct trp_node ex_link;
-};
-static struct trp_root ex_base = {~0};
-obj_pool_gen(ex, struct ex_node, 4096);
-trp_gen(static, ex_, struct ex_node, ex_link, ex, strcmp)
-struct ex_node *item;
-
-item = ex_pointer(ex_alloc(1));
-item->s = "hello";
-ex_insert(&ex_base, item);
-item = ex_pointer(ex_alloc(1));
-item->s = "goodbye";
-ex_insert(&ex_base, item);
-for (item = ex_first(&ex_base); item; item = ex_next(&ex_base, item))
- printf("%s\n", item->s);
-----
-
-Functions
----------
-
-trp_gen(attr, foo_, node_type, link_field, pool, cmp)::
-
- Generate a type-specific treap implementation.
-+
-. The storage class for generated functions will be 'attr' (e.g., `static`).
-. Generated function names are prefixed with 'foo_' (e.g., `treap_`).
-. Treap nodes will be of type 'node_type' (e.g., `struct treap_node`).
- This type must be a struct with at least one `struct trp_node` field
- to point to its children.
-. The field used to access child nodes will be 'link_field'.
-. All treap nodes must lie in the 'pool' object pool.
-. Treap nodes must be totally ordered by the 'cmp' relation, with the
- following prototype:
-+
-int (*cmp)(node_type \*a, node_type \*b)
-+
-and returning a value less than, equal to, or greater than zero
-according to the result of comparison.
-
-node_type {asterisk}foo_insert(struct trp_root *treap, node_type \*node)::
-
- Insert node into treap. If inserted multiple times,
- a node will appear in the treap multiple times.
-+
-The return value is the address of the node within the treap,
-which might differ from `node` if `pool_alloc` had to call
-`realloc` to expand the pool.
-
-void foo_remove(struct trp_root *treap, node_type \*node)::
-
- Remove node from treap. Caller must ensure node is
- present in treap before using this function.
-
-node_type *foo_search(struct trp_root \*treap, node_type \*key)::
-
- Search for a node that matches key. If no match is found,
- result is NULL.
-
-node_type *foo_nsearch(struct trp_root \*treap, node_type \*key)::
-
- Like `foo_search`, but if the key is missing return what
- would be key's successor, were key in treap (NULL if no
- successor).
-
-node_type *foo_first(struct trp_root \*treap)::
-
- Find the first item from the treap, in sorted order.
-
-node_type *foo_next(struct trp_root \*treap, node_type \*node)::
-
- Find the next item.
diff --git a/wt-status.c b/wt-status.c
index 9ffc535f1a..bc268ceda0 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -777,7 +777,7 @@ void wt_status_print(struct wt_status *s)
}
}
-static void wt_shortstatus_unmerged(int null_termination, struct string_list_item *it,
+static void wt_shortstatus_unmerged(struct string_list_item *it,
struct wt_status *s)
{
struct wt_status_change_data *d = it->util;
@@ -793,7 +793,7 @@ static void wt_shortstatus_unmerged(int null_termination, struct string_list_ite
case 7: how = "UU"; break; /* both modified */
}
color_fprintf(s->fp, color(WT_STATUS_UNMERGED, s), "%s", how);
- if (null_termination) {
+ if (s->null_termination) {
fprintf(stdout, " %s%c", it->string, 0);
} else {
struct strbuf onebuf = STRBUF_INIT;
@@ -804,7 +804,7 @@ static void wt_shortstatus_unmerged(int null_termination, struct string_list_ite
}
}
-static void wt_shortstatus_status(int null_termination, struct string_list_item *it,
+static void wt_shortstatus_status(struct string_list_item *it,
struct wt_status *s)
{
struct wt_status_change_data *d = it->util;
@@ -818,7 +818,7 @@ static void wt_shortstatus_status(int null_termination, struct string_list_item
else
putchar(' ');
putchar(' ');
- if (null_termination) {
+ if (s->null_termination) {
fprintf(stdout, "%s%c", it->string, 0);
if (d->head_path)
fprintf(stdout, "%s%c", d->head_path, 0);
@@ -846,10 +846,10 @@ static void wt_shortstatus_status(int null_termination, struct string_list_item
}
}
-static void wt_shortstatus_other(int null_termination, struct string_list_item *it,
+static void wt_shortstatus_other(struct string_list_item *it,
struct wt_status *s, const char *sign)
{
- if (null_termination) {
+ if (s->null_termination) {
fprintf(stdout, "%s %s%c", sign, it->string, 0);
} else {
struct strbuf onebuf = STRBUF_INIT;
@@ -889,8 +889,8 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)
if (s->is_initial)
color_fprintf(s->fp, header_color, _("Initial commit on "));
if (!stat_tracking_info(branch, &num_ours, &num_theirs)) {
- color_fprintf_ln(s->fp, branch_color_local,
- "%s", branch_name);
+ color_fprintf(s->fp, branch_color_local, "%s", branch_name);
+ fputc(s->null_termination ? '\0' : '\n', s->fp);
return;
}
@@ -914,14 +914,15 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)
color_fprintf(s->fp, branch_color_remote, "%d", num_theirs);
}
- color_fprintf_ln(s->fp, header_color, "]");
+ color_fprintf(s->fp, header_color, "]");
+ fputc(s->null_termination ? '\0' : '\n', s->fp);
}
-void wt_shortstatus_print(struct wt_status *s, int null_termination, int show_branch)
+void wt_shortstatus_print(struct wt_status *s)
{
int i;
- if (show_branch)
+ if (s->show_branch)
wt_shortstatus_print_tracking(s);
for (i = 0; i < s->change.nr; i++) {
@@ -931,28 +932,28 @@ void wt_shortstatus_print(struct wt_status *s, int null_termination, int show_br
it = &(s->change.items[i]);
d = it->util;
if (d->stagemask)
- wt_shortstatus_unmerged(null_termination, it, s);
+ wt_shortstatus_unmerged(it, s);
else
- wt_shortstatus_status(null_termination, it, s);
+ wt_shortstatus_status(it, s);
}
for (i = 0; i < s->untracked.nr; i++) {
struct string_list_item *it;
it = &(s->untracked.items[i]);
- wt_shortstatus_other(null_termination, it, s, "??");
+ wt_shortstatus_other(it, s, "??");
}
for (i = 0; i < s->ignored.nr; i++) {
struct string_list_item *it;
it = &(s->ignored.items[i]);
- wt_shortstatus_other(null_termination, it, s, "!!");
+ wt_shortstatus_other(it, s, "!!");
}
}
-void wt_porcelain_print(struct wt_status *s, int null_termination)
+void wt_porcelain_print(struct wt_status *s)
{
s->use_color = 0;
s->relative_paths = 0;
s->prefix = NULL;
- wt_shortstatus_print(s, null_termination, 0);
+ wt_shortstatus_print(s);
}
diff --git a/wt-status.h b/wt-status.h
index 682b4c8f7d..ab3c7cc8a1 100644
--- a/wt-status.h
+++ b/wt-status.h
@@ -56,6 +56,8 @@ struct wt_status {
enum untracked_status_type show_untracked_files;
const char *ignore_submodule_arg;
char color_palette[WT_STATUS_MAXSLOT][COLOR_MAXLEN];
+ int null_termination;
+ int show_branch;
/* These are computed during processing of the individual sections */
int commitable;
@@ -72,8 +74,8 @@ void wt_status_prepare(struct wt_status *s);
void wt_status_print(struct wt_status *s);
void wt_status_collect(struct wt_status *s);
-void wt_shortstatus_print(struct wt_status *s, int null_termination, int show_branch);
-void wt_porcelain_print(struct wt_status *s, int null_termination);
+void wt_shortstatus_print(struct wt_status *s);
+void wt_porcelain_print(struct wt_status *s);
void status_printf_ln(struct wt_status *s, const char *color, const char *fmt, ...)
;
diff --git a/xdiff/xdiff.h b/xdiff/xdiff.h
index 00d36c3ac7..09215afe6e 100644
--- a/xdiff/xdiff.h
+++ b/xdiff/xdiff.h
@@ -32,14 +32,12 @@ extern "C" {
#define XDF_IGNORE_WHITESPACE (1 << 2)
#define XDF_IGNORE_WHITESPACE_CHANGE (1 << 3)
#define XDF_IGNORE_WHITESPACE_AT_EOL (1 << 4)
-#define XDF_PATIENCE_DIFF (1 << 5)
-#define XDF_HISTOGRAM_DIFF (1 << 6)
#define XDF_WHITESPACE_FLAGS (XDF_IGNORE_WHITESPACE | XDF_IGNORE_WHITESPACE_CHANGE | XDF_IGNORE_WHITESPACE_AT_EOL)
-#define XDL_PATCH_NORMAL '-'
-#define XDL_PATCH_REVERSE '+'
-#define XDL_PATCH_MODEMASK ((1 << 8) - 1)
-#define XDL_PATCH_IGNOREBSPACE (1 << 8)
+#define XDF_PATIENCE_DIFF (1 << 5)
+#define XDF_HISTOGRAM_DIFF (1 << 6)
+#define XDF_DIFF_ALGORITHM_MASK (XDF_PATIENCE_DIFF | XDF_HISTOGRAM_DIFF)
+#define XDF_DIFF_ALG(x) ((x) & XDF_DIFF_ALGORITHM_MASK)
#define XDL_EMIT_FUNCNAMES (1 << 0)
#define XDL_EMIT_COMMON (1 << 1)
diff --git a/xdiff/xdiffi.c b/xdiff/xdiffi.c
index 75a3922750..bc889e8789 100644
--- a/xdiff/xdiffi.c
+++ b/xdiff/xdiffi.c
@@ -328,10 +328,10 @@ int xdl_do_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
xdalgoenv_t xenv;
diffdata_t dd1, dd2;
- if (xpp->flags & XDF_PATIENCE_DIFF)
+ if (XDF_DIFF_ALG(xpp->flags) == XDF_PATIENCE_DIFF)
return xdl_do_patience_diff(mf1, mf2, xpp, xe);
- if (xpp->flags & XDF_HISTOGRAM_DIFF)
+ if (XDF_DIFF_ALG(xpp->flags) == XDF_HISTOGRAM_DIFF)
return xdl_do_histogram_diff(mf1, mf2, xpp, xe);
if (xdl_prepare_env(mf1, mf2, xpp, xe) < 0) {
diff --git a/xdiff/xemit.c b/xdiff/xemit.c
index 2e669c3e25..d11dbf9f13 100644
--- a/xdiff/xemit.c
+++ b/xdiff/xemit.c
@@ -87,7 +87,7 @@ static long def_ff(const char *rec, long len, char *buf, long sz, void *priv)
static int xdl_emit_common(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
xdemitconf_t const *xecfg) {
- xdfile_t *xdf = &xe->xdf1;
+ xdfile_t *xdf = &xe->xdf2;
const char *rchg = xdf->rchg;
long ix;
@@ -204,8 +204,8 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
/*
* Emit pre-context.
*/
- for (; s1 < xch->i1; s1++)
- if (xdl_emit_record(&xe->xdf1, s1, " ", ecb) < 0)
+ for (; s2 < xch->i2; s2++)
+ if (xdl_emit_record(&xe->xdf2, s2, " ", ecb) < 0)
return -1;
for (s1 = xch->i1, s2 = xch->i2;; xch = xch->next) {
@@ -213,7 +213,7 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
* Merge previous with current change atom.
*/
for (; s1 < xch->i1 && s2 < xch->i2; s1++, s2++)
- if (xdl_emit_record(&xe->xdf1, s1, " ", ecb) < 0)
+ if (xdl_emit_record(&xe->xdf2, s2, " ", ecb) < 0)
return -1;
/*
@@ -239,8 +239,8 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
/*
* Emit post-context.
*/
- for (s1 = xche->i1 + xche->chg1; s1 < e1; s1++)
- if (xdl_emit_record(&xe->xdf1, s1, " ", ecb) < 0)
+ for (s2 = xche->i2 + xche->chg2; s2 < e2; s2++)
+ if (xdl_emit_record(&xe->xdf2, s2, " ", ecb) < 0)
return -1;
}
diff --git a/xdiff/xhistogram.c b/xdiff/xhistogram.c
index 18f6f997c3..bf99787c3e 100644
--- a/xdiff/xhistogram.c
+++ b/xdiff/xhistogram.c
@@ -252,7 +252,7 @@ static int fall_back_to_classic_diff(struct histindex *index,
int line1, int count1, int line2, int count2)
{
xpparam_t xpp;
- xpp.flags = index->xpp->flags & ~XDF_HISTOGRAM_DIFF;
+ xpp.flags = index->xpp->flags & ~XDF_DIFF_ALGORITHM_MASK;
return xdl_fall_back_diff(index->env, &xpp,
line1, count1, line2, count2);
diff --git a/xdiff/xpatience.c b/xdiff/xpatience.c
index fdd7d0263f..04e1a1ab2a 100644
--- a/xdiff/xpatience.c
+++ b/xdiff/xpatience.c
@@ -288,7 +288,7 @@ static int fall_back_to_classic_diff(struct hashmap *map,
int line1, int count1, int line2, int count2)
{
xpparam_t xpp;
- xpp.flags = map->xpp->flags & ~XDF_PATIENCE_DIFF;
+ xpp.flags = map->xpp->flags & ~XDF_DIFF_ALGORITHM_MASK;
return xdl_fall_back_diff(map->env, &xpp,
line1, count1, line2, count2);
diff --git a/xdiff/xprepare.c b/xdiff/xprepare.c
index e419f4f726..63a22c630e 100644
--- a/xdiff/xprepare.c
+++ b/xdiff/xprepare.c
@@ -181,7 +181,7 @@ static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_
if (!(recs = (xrecord_t **) xdl_malloc(narec * sizeof(xrecord_t *))))
goto abort;
- if (xpp->flags & XDF_HISTOGRAM_DIFF)
+ if (XDF_DIFF_ALG(xpp->flags) == XDF_HISTOGRAM_DIFF)
hbits = hsize = 0;
else {
hbits = xdl_hashbits((unsigned int) narec);
@@ -209,8 +209,8 @@ static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_
crec->ha = hav;
recs[nrec++] = crec;
- if (!(xpp->flags & XDF_HISTOGRAM_DIFF) &&
- xdl_classify_record(pass, cf, rhash, hbits, crec) < 0)
+ if ((XDF_DIFF_ALG(xpp->flags) != XDF_HISTOGRAM_DIFF) &&
+ xdl_classify_record(pass, cf, rhash, hbits, crec) < 0)
goto abort;
}
}
@@ -273,16 +273,15 @@ int xdl_prepare_env(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
* (nrecs) will be updated correctly anyway by
* xdl_prepare_ctx().
*/
- sample = xpp->flags & XDF_HISTOGRAM_DIFF ? XDL_GUESS_NLINES2 : XDL_GUESS_NLINES1;
+ sample = (XDF_DIFF_ALG(xpp->flags) == XDF_HISTOGRAM_DIFF
+ ? XDL_GUESS_NLINES2 : XDL_GUESS_NLINES1);
enl1 = xdl_guess_lines(mf1, sample) + 1;
enl2 = xdl_guess_lines(mf2, sample) + 1;
- if (!(xpp->flags & XDF_HISTOGRAM_DIFF) &&
- xdl_init_classifier(&cf, enl1 + enl2 + 1, xpp->flags) < 0) {
-
+ if (XDF_DIFF_ALG(xpp->flags) != XDF_HISTOGRAM_DIFF &&
+ xdl_init_classifier(&cf, enl1 + enl2 + 1, xpp->flags) < 0)
return -1;
- }
if (xdl_prepare_ctx(1, mf1, enl1, xpp, &cf, &xe->xdf1) < 0) {
@@ -296,9 +295,9 @@ int xdl_prepare_env(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
return -1;
}
- if (!(xpp->flags & XDF_PATIENCE_DIFF) &&
- !(xpp->flags & XDF_HISTOGRAM_DIFF) &&
- xdl_optimize_ctxs(&cf, &xe->xdf1, &xe->xdf2) < 0) {
+ if ((XDF_DIFF_ALG(xpp->flags) != XDF_PATIENCE_DIFF) &&
+ (XDF_DIFF_ALG(xpp->flags) != XDF_HISTOGRAM_DIFF) &&
+ xdl_optimize_ctxs(&cf, &xe->xdf1, &xe->xdf2) < 0) {
xdl_free_ctx(&xe->xdf2);
xdl_free_ctx(&xe->xdf1);