summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore6
-rw-r--r--.mailmap9
-rw-r--r--Documentation/Makefile26
-rw-r--r--Documentation/RelNotes/1.7.12.1.txt134
-rw-r--r--Documentation/RelNotes/1.7.12.2.txt40
-rw-r--r--Documentation/RelNotes/1.7.12.3.txt34
-rw-r--r--Documentation/RelNotes/1.7.12.txt136
-rw-r--r--Documentation/RelNotes/1.8.0.txt257
-rw-r--r--Documentation/config.txt55
-rw-r--r--Documentation/fetch-options.txt3
-rw-r--r--Documentation/git-add.txt2
-rw-r--r--Documentation/git-apply.txt11
-rw-r--r--Documentation/git-blame.txt6
-rw-r--r--Documentation/git-branch.txt18
-rw-r--r--Documentation/git-cherry-pick.txt5
-rw-r--r--Documentation/git-clean.txt4
-rw-r--r--Documentation/git-clone.txt34
-rw-r--r--Documentation/git-commit.txt6
-rw-r--r--Documentation/git-config.txt17
-rw-r--r--Documentation/git-credential-cache--daemon.txt2
-rw-r--r--Documentation/git-credential-cache.txt2
-rw-r--r--Documentation/git-credential-store.txt2
-rw-r--r--Documentation/git-credential.txt154
-rw-r--r--Documentation/git-daemon.txt16
-rw-r--r--Documentation/git-difftool.txt8
-rw-r--r--Documentation/git-fast-import.txt8
-rw-r--r--Documentation/git-filter-branch.txt19
-rw-r--r--Documentation/git-for-each-ref.txt7
-rw-r--r--Documentation/git-format-patch.txt11
-rw-r--r--Documentation/git-grep.txt10
-rw-r--r--Documentation/git-log.txt6
-rw-r--r--Documentation/git-ls-remote.txt5
-rw-r--r--Documentation/git-merge-base.txt28
-rw-r--r--Documentation/git-mergetool.txt3
-rw-r--r--Documentation/git-p4.txt34
-rw-r--r--Documentation/git-push.txt10
-rw-r--r--Documentation/git-rebase.txt57
-rw-r--r--Documentation/git-remote.txt3
-rw-r--r--Documentation/git-rev-parse.txt6
-rw-r--r--Documentation/git-shortlog.txt3
-rw-r--r--Documentation/git-submodule.txt1
-rw-r--r--Documentation/git.txt68
-rw-r--r--Documentation/gitattributes.txt11
-rw-r--r--Documentation/gitcore-tutorial.txt9
-rw-r--r--Documentation/gitignore.txt28
-rw-r--r--Documentation/gittutorial.txt8
-rw-r--r--Documentation/merge-strategies.txt3
-rw-r--r--Documentation/pretty-formats.txt3
-rw-r--r--Documentation/pretty-options.txt4
-rw-r--r--Documentation/rev-list-options.txt47
-rw-r--r--Documentation/revisions.txt2
-rw-r--r--Documentation/technical/api-argv-array.txt4
-rw-r--r--Documentation/technical/api-credentials.txt39
-rw-r--r--Documentation/technical/api-sha1-array.txt3
-rw-r--r--Documentation/technical/api-string-list.txt75
-rw-r--r--Documentation/technical/pack-protocol.txt6
-rw-r--r--Documentation/user-manual.txt9
-rwxr-xr-xGIT-VERSION-GEN2
-rw-r--r--Makefile429
l---------RelNotes2
-rw-r--r--abspath.c9
-rw-r--r--archive-zip.c49
-rw-r--r--archive.c38
-rw-r--r--argv-array.c11
-rw-r--r--argv-array.h1
-rw-r--r--attr.c12
-rw-r--r--bisect.c2
-rw-r--r--branch.c38
-rw-r--r--builtin.h4
-rw-r--r--builtin/add.c29
-rw-r--r--builtin/apply.c565
-rw-r--r--builtin/archive.c12
-rw-r--r--builtin/bisect--helper.c6
-rw-r--r--builtin/blame.c138
-rw-r--r--builtin/branch.c150
-rw-r--r--builtin/cat-file.c22
-rw-r--r--builtin/check-attr.c12
-rw-r--r--builtin/checkout-index.c24
-rw-r--r--builtin/checkout.c315
-rw-r--r--builtin/clean.c18
-rw-r--r--builtin/clone.c133
-rw-r--r--builtin/column.c16
-rw-r--r--builtin/commit-tree.c4
-rw-r--r--builtin/commit.c182
-rw-r--r--builtin/config.c91
-rw-r--r--builtin/count-objects.c4
-rw-r--r--builtin/credential.c31
-rw-r--r--builtin/describe.c28
-rw-r--r--builtin/fast-export.c28
-rw-r--r--builtin/fetch-pack.c189
-rw-r--r--builtin/fetch.c116
-rw-r--r--builtin/fmt-merge-msg.c16
-rw-r--r--builtin/for-each-ref.c18
-rw-r--r--builtin/fsck.c24
-rw-r--r--builtin/gc.c16
-rw-r--r--builtin/grep.c206
-rw-r--r--builtin/hash-object.c16
-rw-r--r--builtin/help.c35
-rw-r--r--builtin/index-pack.c220
-rw-r--r--builtin/init-db.c19
-rw-r--r--builtin/log.c108
-rw-r--r--builtin/ls-files.c54
-rw-r--r--builtin/ls-remote.c2
-rw-r--r--builtin/ls-tree.c22
-rw-r--r--builtin/mailinfo.c48
-rw-r--r--builtin/merge-base.c34
-rw-r--r--builtin/merge-file.c20
-rw-r--r--builtin/merge.c48
-rw-r--r--builtin/mktree.c8
-rw-r--r--builtin/mv.c10
-rw-r--r--builtin/name-rev.c22
-rw-r--r--builtin/notes.c127
-rw-r--r--builtin/pack-objects.c139
-rw-r--r--builtin/pack-refs.c6
-rw-r--r--builtin/prune-packed.c6
-rw-r--r--builtin/prune.c15
-rw-r--r--builtin/push.c63
-rw-r--r--builtin/read-tree.c38
-rw-r--r--builtin/receive-pack.c49
-rw-r--r--builtin/reflog.c6
-rw-r--r--builtin/remote.c86
-rw-r--r--builtin/replace.c12
-rw-r--r--builtin/rerere.c4
-rw-r--r--builtin/reset.c30
-rw-r--r--builtin/rev-parse.c32
-rw-r--r--builtin/revert.c40
-rw-r--r--builtin/rm.c14
-rw-r--r--builtin/send-pack.c15
-rw-r--r--builtin/shortlog.c14
-rw-r--r--builtin/show-branch.c42
-rw-r--r--builtin/show-ref.c28
-rw-r--r--builtin/symbolic-ref.c8
-rw-r--r--builtin/tag.c56
-rw-r--r--builtin/update-index.c65
-rw-r--r--builtin/update-ref.c10
-rw-r--r--builtin/update-server-info.c4
-rw-r--r--builtin/verify-pack.c6
-rw-r--r--builtin/verify-tag.c4
-rw-r--r--builtin/write-tree.c10
-rw-r--r--cache.h59
-rw-r--r--command-list.txt4
-rw-r--r--commit.c313
-rw-r--r--commit.h3
-rw-r--r--compat/mkdir.c24
-rw-r--r--compat/poll/poll.c (renamed from compat/win32/poll.c)14
-rw-r--r--compat/poll/poll.h (renamed from compat/win32/poll.h)0
-rw-r--r--compat/precompose_utf8.c184
-rw-r--r--compat/precompose_utf8.h45
-rw-r--r--config.c34
-rw-r--r--config.mak.in50
-rw-r--r--configure.ac210
-rw-r--r--connect.c63
-rw-r--r--[-rwxr-xr-x]contrib/completion/git-completion.bash277
-rw-r--r--contrib/completion/git-prompt.sh290
-rw-r--r--contrib/credential/gnome-keyring/.gitignore1
-rw-r--r--contrib/credential/gnome-keyring/Makefile24
-rw-r--r--contrib/credential/gnome-keyring/git-credential-gnome-keyring.c445
-rw-r--r--contrib/credential/wincred/Makefile14
-rw-r--r--contrib/credential/wincred/git-credential-wincred.c357
-rw-r--r--contrib/examples/builtin-fetch--tool.c2
-rwxr-xr-xcontrib/git-jump/git-jump4
-rw-r--r--contrib/mw-to-git/Makefile47
-rwxr-xr-xcontrib/mw-to-git/git-remote-mediawiki777
-rw-r--r--contrib/mw-to-git/t/.gitignore4
-rw-r--r--contrib/mw-to-git/t/Makefile31
-rw-r--r--contrib/mw-to-git/t/README124
-rwxr-xr-xcontrib/mw-to-git/t/install-wiki.sh45
-rw-r--r--contrib/mw-to-git/t/install-wiki/.gitignore1
-rw-r--r--contrib/mw-to-git/t/install-wiki/LocalSettings.php129
-rw-r--r--contrib/mw-to-git/t/install-wiki/db_install.php120
-rw-r--r--contrib/mw-to-git/t/push-pull-tests.sh144
-rwxr-xr-xcontrib/mw-to-git/t/t9360-mw-to-git-clone.sh257
-rwxr-xr-xcontrib/mw-to-git/t/t9361-mw-to-git-push-pull.sh24
-rwxr-xr-xcontrib/mw-to-git/t/t9362-mw-to-git-utf8.sh321
-rwxr-xr-xcontrib/mw-to-git/t/t9363-mw-to-git-export-import.sh198
-rwxr-xr-xcontrib/mw-to-git/t/t9364-pull-by-rev.sh17
-rwxr-xr-xcontrib/mw-to-git/t/test-gitmw-lib.sh435
-rwxr-xr-xcontrib/mw-to-git/t/test-gitmw.pl225
-rw-r--r--contrib/mw-to-git/t/test.config35
-rw-r--r--credential.c4
-rw-r--r--credential.h1
-rw-r--r--daemon.c77
-rw-r--r--diff.c12
-rw-r--r--diff.h1
-rw-r--r--dir.c154
-rw-r--r--dir.h2
-rw-r--r--environment.c1
-rw-r--r--fast-import.c2
-rw-r--r--fetch-pack.h20
-rw-r--r--gettext.c15
-rw-r--r--gettext.h7
-rwxr-xr-xgit-am.sh72
-rw-r--r--git-compat-util.h48
-rwxr-xr-xgit-cvsimport.perl33
-rwxr-xr-xgit-difftool.perl306
-rw-r--r--git-mergetool--lib.sh42
-rwxr-xr-xgit-p4.py570
-rw-r--r--git-rebase--am.sh2
-rw-r--r--git-rebase--interactive.sh141
-rw-r--r--git-rebase--merge.sh2
-rwxr-xr-xgit-rebase.sh132
-rwxr-xr-xgit-send-email.perl18
-rwxr-xr-xgit-submodule.sh79
-rwxr-xr-xgit-svn.perl3292
-rw-r--r--git.c3
-rwxr-xr-xgitk-git/gitk5
-rwxr-xr-xgitweb/gitweb.perl33
-rw-r--r--graph.c32
-rw-r--r--graph.h27
-rw-r--r--grep.c131
-rw-r--r--grep.h22
-rw-r--r--help.c15
-rw-r--r--http-push.c3
-rw-r--r--http-walker.c4
-rw-r--r--http.c6
-rw-r--r--ident.c4
-rw-r--r--ll-merge.c32
-rw-r--r--merge-recursive.c160
-rw-r--r--mergetools/codecompare25
-rw-r--r--mergetools/defaults28
-rw-r--r--notes-merge.c6
-rw-r--r--notes.c14
-rw-r--r--notes.h14
-rw-r--r--parse-options.c1
-rw-r--r--parse-options.h2
-rw-r--r--path.c69
-rw-r--r--perl/.gitignore1
-rw-r--r--perl/Git/IndexInfo.pm33
-rw-r--r--perl/Git/SVN.pm2394
-rw-r--r--perl/Git/SVN/Editor.pm25
-rw-r--r--perl/Git/SVN/Fetcher.pm3
-rw-r--r--perl/Git/SVN/GlobSpec.pm61
-rw-r--r--perl/Git/SVN/Log.pm395
-rw-r--r--perl/Git/SVN/Migration.pm258
-rw-r--r--perl/Git/SVN/Ra.pm94
-rw-r--r--perl/Git/SVN/Utils.pm232
-rw-r--r--perl/Makefile25
-rw-r--r--perl/Makefile.PL35
-rw-r--r--pkt-line.c32
-rw-r--r--pkt-line.h1
-rw-r--r--po/TEAMS3
-rw-r--r--po/de.po1801
-rw-r--r--po/git.pot5313
-rw-r--r--po/sv.po5576
-rw-r--r--po/vi.po2615
-rw-r--r--po/zh_CN.po5757
-rw-r--r--read-cache.c71
-rw-r--r--remote-curl.c27
-rw-r--r--rerere.c14
-rw-r--r--rerere.h1
-rw-r--r--revision.c134
-rw-r--r--revision.h11
-rw-r--r--run-command.c13
-rw-r--r--sequencer.c76
-rw-r--r--sequencer.h8
-rw-r--r--setup.c8
-rw-r--r--sha1-array.c2
-rw-r--r--sha1-array.h1
-rw-r--r--sha1_file.c26
-rw-r--r--sha1_name.c494
-rw-r--r--strbuf.c13
-rw-r--r--strbuf.h4
-rw-r--r--string-list.c127
-rw-r--r--string-list.h71
-rw-r--r--submodule.c43
-rw-r--r--submodule.h3
-rw-r--r--symlinks.c7
-rw-r--r--t/Git-SVN/00compile.t14
-rw-r--r--t/Git-SVN/Utils/add_path_to_url.t27
-rw-r--r--t/Git-SVN/Utils/can_compress.t11
-rw-r--r--t/Git-SVN/Utils/canonicalize_url.t26
-rw-r--r--t/Git-SVN/Utils/collapse_dotdot.t23
-rw-r--r--t/Git-SVN/Utils/fatal.t34
-rw-r--r--t/Git-SVN/Utils/join_paths.t32
-rw-r--r--t/README9
-rw-r--r--t/lib-bash.sh18
-rwxr-xr-xt/lib-credential.sh43
-rw-r--r--t/lib-git-p4.sh84
-rw-r--r--t/lib-httpd.sh4
-rw-r--r--t/lib-httpd/apache.conf5
-rw-r--r--t/perf/.gitignore5
-rw-r--r--t/perf/perf-lib.sh1
-rwxr-xr-xt/t0000-basic.sh28
-rwxr-xr-xt/t0003-attributes.sh10
-rwxr-xr-xt/t0006-date.sh2
-rwxr-xr-xt/t0040-parse-options.sh34
-rwxr-xr-xt/t0050-filesystem.sh64
-rwxr-xr-xt/t0060-path-utils.sh59
-rwxr-xr-xt/t0063-string-list.sh121
-rwxr-xr-xt/t0201-gettext-fallbacks.sh8
-rwxr-xr-xt/t0300-credentials.sh14
-rwxr-xr-xt/t1050-large.sh17
-rwxr-xr-xt/t1100-commit-tree-options.sh1
-rwxr-xr-xt/t1300-repo-config.sh2
-rwxr-xr-xt/t1304-default-acl.sh19
-rwxr-xr-xt/t1306-xdg-files.sh197
-rwxr-xr-xt/t1450-fsck.sh4
-rwxr-xr-xt/t1502-rev-parse-parseopt.sh2
-rwxr-xr-xt/t1512-rev-parse-disambiguation.sh264
-rwxr-xr-xt/t2006-checkout-index-basic.sh4
-rwxr-xr-xt/t2107-update-index-basic.sh4
-rwxr-xr-xt/t3004-ls-files-basic.sh4
-rwxr-xr-xt/t3200-branch.sh74
-rwxr-xr-xt/t3300-funny-names.sh24
-rwxr-xr-xt/t3400-rebase.sh8
-rwxr-xr-xt/t3404-rebase-interactive.sh185
-rwxr-xr-xt/t3405-rebase-malformed.sh32
-rwxr-xr-xt/t3406-rebase-message.sh9
-rwxr-xr-xt/t3412-rebase-root.sh7
-rwxr-xr-xt/t3501-revert-cherry-pick.sh4
-rwxr-xr-xt/t3505-cherry-pick-empty.sh5
-rwxr-xr-xt/t3507-cherry-pick-conflict.sh32
-rwxr-xr-xt/t3508-cherry-pick-many-commits.sh15
-rwxr-xr-xt/t3510-cherry-pick-sequence.sh6
-rwxr-xr-xt/t3902-quoted.sh31
-rwxr-xr-xt/t3903-stash.sh2
-rwxr-xr-xt/t3910-mac-os-precompose.sh153
-rwxr-xr-xt/t4006-diff-mode.sh8
-rwxr-xr-xt/t4012-diff-binary.sh94
-rwxr-xr-xt/t4016-diff-quote.sh20
-rwxr-xr-xt/t4018-diff-funcname.sh2
-rwxr-xr-xt/t4034-diff-words.sh1
-rw-r--r--t/t4034/ada/expect27
-rw-r--r--t/t4034/ada/post13
-rw-r--r--t/t4034/ada/pre13
-rwxr-xr-xt/t4108-apply-threeway.sh157
-rwxr-xr-xt/t4117-apply-reject.sh8
-rwxr-xr-xt/t4120-apply-popt.sh4
-rwxr-xr-xt/t4133-apply-filenames.sh4
-rwxr-xr-xt/t4200-rerere.sh4
-rwxr-xr-xt/t4202-log.sh12
-rwxr-xr-xt/t4205-log-pretty-formats.sh4
-rwxr-xr-xt/t5100-mailinfo.sh2
-rw-r--r--t/t5100/info00175
-rw-r--r--t/t5100/msg00172
-rw-r--r--t/t5100/patch00176
-rw-r--r--t/t5100/sample.mbox16
-rwxr-xr-xt/t5300-pack-object.sh7
-rwxr-xr-xt/t5400-send-pack.sh3
-rwxr-xr-xt/t5500-fetch-pack.sh47
-rwxr-xr-xt/t5504-fetch-receive-strict.sh2
-rwxr-xr-xt/t5505-remote.sh32
-rwxr-xr-xt/t5512-ls-remote.sh16
-rwxr-xr-xt/t5514-fetch-multiple.sh30
-rwxr-xr-xt/t5530-upload-pack-error.sh4
-rwxr-xr-xt/t5540-http-push.sh2
-rwxr-xr-xt/t5541-http-push.sh5
-rwxr-xr-xt/t5551-http-fetch.sh15
-rwxr-xr-xt/t5701-clone-local.sh10
-rwxr-xr-xt/t5709-clone-refspec.sh156
-rwxr-xr-xt/t6022-merge-rename.sh16
-rwxr-xr-xt/t6037-merge-ours-theirs.sh14
-rwxr-xr-xt/t6042-merge-rename-corner-cases.sh2
-rwxr-xr-xt/t6500-gc.sh4
-rwxr-xr-xt/t7060-wtstatus.sh96
-rwxr-xr-xt/t7400-submodule-basic.sh153
-rwxr-xr-xt/t7403-submodule-sync.sh90
-rwxr-xr-xt/t7409-submodule-detached-worktree.sh78
-rwxr-xr-xt/t7502-commit.sh75
-rwxr-xr-xt/t7508-status.sh2
-rwxr-xr-xt/t7512-status-help.sh649
-rwxr-xr-xt/t7600-merge.sh2
-rwxr-xr-xt/t7610-mergetool.sh13
-rwxr-xr-xt/t7800-difftool.sh11
-rwxr-xr-xt/t7810-grep.sh313
-rwxr-xr-xt/t8004-blame-with-conflicts.sh2
-rwxr-xr-xt/t9107-git-svn-migrate.sh6
-rwxr-xr-xt/t9118-git-svn-funky-branch-names.sh9
-rwxr-xr-xt/t9154-git-svn-fancy-glob.sh9
-rwxr-xr-xt/t9163-git-svn-reset-clears-caches.sh78
-rwxr-xr-xt/t9164-git-svn-dcommit-concurrent.sh216
-rwxr-xr-xt/t9165-git-svn-fetch-merge-branch-of-branch.sh60
-rwxr-xr-xt/t9166-git-svn-fetch-merge-branch-of-branch2.sh53
-rwxr-xr-xt/t9800-git-p4-basic.sh421
-rwxr-xr-xt/t9801-git-p4-branch.sh77
-rwxr-xr-xt/t9805-git-p4-skip-submit-edit.sh11
-rwxr-xr-xt/t9806-git-p4-options.sh17
-rwxr-xr-xt/t9807-git-p4-submit.sh220
-rwxr-xr-xt/t9808-git-p4-chdir.sh4
-rwxr-xr-xt/t9809-git-p4-client-view.sh17
-rwxr-xr-xt/t9810-git-p4-rcs.sh58
-rwxr-xr-xt/t9812-git-p4-wildcards.sh147
-rwxr-xr-xt/t9813-git-p4-preserve-users.sh153
-rwxr-xr-xt/t9814-git-p4-rename.sh206
-rwxr-xr-xt/t9815-git-p4-submit-fail.sh429
-rwxr-xr-xt/t9902-completion.sh74
-rwxr-xr-xt/t9903-bash-prompt.sh456
-rw-r--r--t/test-lib-functions.sh69
-rw-r--r--t/test-lib.sh181
-rw-r--r--test-credential.c38
-rw-r--r--test-line-buffer.c1
-rw-r--r--test-string-list.c123
-rw-r--r--test-svn-fe.c2
-rw-r--r--trace.c2
-rw-r--r--transport-helper.c15
-rw-r--r--transport.c12
-rw-r--r--transport.h1
-rw-r--r--tree.c7
-rw-r--r--unpack-trees.c5
-rw-r--r--upload-pack.c7
-rw-r--r--userdiff.c9
-rw-r--r--utf8.c26
-rw-r--r--utf8.h1
-rw-r--r--vcs-svn/fast_export.c11
-rw-r--r--vcs-svn/fast_export.h1
-rw-r--r--vcs-svn/line_buffer.c4
-rw-r--r--vcs-svn/line_buffer.h1
-rw-r--r--vcs-svn/sliding_window.c2
-rw-r--r--vcs-svn/svndiff.c15
-rw-r--r--vcs-svn/svndump.c37
-rw-r--r--version.c38
-rw-r--r--version.h9
-rw-r--r--wrapper.c13
-rw-r--r--wt-status.c296
-rw-r--r--wt-status.h12
415 files changed, 38584 insertions, 12037 deletions
diff --git a/.gitignore b/.gitignore
index f1acd3e..a188a82 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,9 @@
/GIT-CFLAGS
/GIT-LDFLAGS
/GIT-GUI-VARS
+/GIT-PREFIX
+/GIT-SCRIPT-DEFINES
+/GIT-USER-AGENT
/GIT-VERSION-FILE
/bin-wrappers/
/git
@@ -31,6 +34,7 @@
/git-commit-tree
/git-config
/git-count-objects
+/git-credential
/git-credential-cache
/git-credential-cache--daemon
/git-credential-store
@@ -172,7 +176,6 @@
/gitweb/static/gitweb.js
/gitweb/static/gitweb.min.*
/test-chmtime
-/test-credential
/test-ctype
/test-date
/test-delta
@@ -191,6 +194,7 @@
/test-run-command
/test-sha1
/test-sigchain
+/test-string-list
/test-subprocess
/test-svn-fe
/common-cmds.h
diff --git a/.mailmap b/.mailmap
index 6303782..bcf4f87 100644
--- a/.mailmap
+++ b/.mailmap
@@ -18,6 +18,7 @@ David KÃ¥gedal <davidk@lysator.liu.se>
David S. Miller <davem@davemloft.net>
Deskin Miller <deskinm@umich.edu>
Dirk Süsserott <newsletter@dirk.my1.cc>
+Erik Faye-Lund <kusmabite@gmail.com> <kusmabite@googlemail.com>
Fredrik Kuivinen <freku045@student.liu.se>
H. Peter Anvin <hpa@bonde.sc.orionmulti.com>
H. Peter Anvin <hpa@tazenda.sc.orionmulti.com>
@@ -26,6 +27,9 @@ Horst H. von Brand <vonbrand@inf.utfsm.cl>
İsmail Dönmez <ismail@pardus.org.tr>
Jay Soffian <jaysoffian+git@gmail.com>
Joachim Berdal Haga <cjhaga@fys.uio.no>
+Johannes Sixt <j6t@kdbg.org> <johannes.sixt@telecom.at>
+Johannes Sixt <j6t@kdbg.org> <j.sixt@viscovery.net>
+Johannes Sixt <j6t@kdbg.org> <J.Sixt@eudaptics.com>
Jon Loeliger <jdl@freescale.com>
Jon Seymour <jon@blackcubes.dyndns.org>
Jonathan Nieder <jrnieder@uchicago.edu>
@@ -43,6 +47,7 @@ Lars Doelle <lars.doelle@on-line.de>
Li Hong <leehong@pku.edu.cn>
Lukas Sandström <lukass@etek.chalmers.se>
Martin Langhoff <martin@laptop.org>
+Martin von Zweigbergk <martinvonz@gmail.com> <martin.von.zweigbergk@gmail.com>
Michael Coleman <tutufan@gmail.com>
Michael J Gruber <git@drmicha.warpmail.net> <michaeljgruber+gmane@fastmail.fm>
Michael W. Olson <mwolson@gnu.org>
@@ -51,7 +56,10 @@ Nanako Shiraishi <nanako3@bluebottle.com>
Nanako Shiraishi <nanako3@lavabit.com>
Nguyá»…n Thái Ngá»c Duy <pclouds@gmail.com>
<nico@fluxnic.net> <nico@cam.org>
+Peter Krefting <peter@softwolves.pp.se> <peter@svarten.intern.softwolves.pp.se>
+Peter Krefting <peter@softwolves.pp.se> <peter@softwolves.pp.se>
Philippe Bruhat <book@cpan.org>
+Ralf Thielow <ralf.thielow@gmail.com> <ralf.thielow@googlemail.com>
Ramsay Allan Jones <ramsay@ramsay1.demon.co.uk>
René Scharfe <rene.scharfe@lsrfire.ath.cx>
Robert Fitzsimons <robfitz@273k.net>
@@ -61,6 +69,7 @@ Sean Estabrooks <seanlkml@sympatico.ca>
Shawn O. Pearce <spearce@spearce.org>
Steven Grimm <koreth@midwinter.com>
Theodore Ts'o <tytso@mit.edu>
+Thomas Rast <trast@inf.ethz.ch> <trast@student.ethz.ch>
Tony Luck <tony.luck@intel.com>
Uwe Kleine-König <Uwe_Zeisberger@digi.com>
Uwe Kleine-König <Uwe.Kleine-Koenig@digi.com>
diff --git a/Documentation/Makefile b/Documentation/Makefile
index 5d76a84..267dfe1 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -44,9 +44,10 @@ man5dir=$(mandir)/man5
man7dir=$(mandir)/man7
# DESTDIR=
-ASCIIDOC=asciidoc
+ASCIIDOC = asciidoc
ASCIIDOC_EXTRA =
MANPAGE_XSL = manpage-normal.xsl
+XMLTO = xmlto
XMLTO_EXTRA =
INSTALL?=install
RM ?= rm -f
@@ -66,12 +67,6 @@ endif
-include ../config.mak
#
-# For asciidoc ...
-# -7.1.2, set ASCIIDOC7
-# 8.0-, no extra settings are needed
-#
-
-#
# For docbook-xsl ...
# -1.68.1, no extra settings are needed?
# 1.69.0, set ASCIIDOC_ROFF?
@@ -81,9 +76,6 @@ endif
# 1.73.0-, no extra settings are needed
#
-ifndef ASCIIDOC7
-ASCIIDOC_EXTRA += -a asciidoc7compatible
-endif
ifdef DOCBOOK_XSL_172
ASCIIDOC_EXTRA += -a git-asciidoc-no-roff
MANPAGE_XSL = manpage-1.72.xsl
@@ -134,15 +126,6 @@ DEFAULT_EDITOR_SQ = $(subst ','\'',$(DEFAULT_EDITOR))
ASCIIDOC_EXTRA += -a 'git-default-editor=$(DEFAULT_EDITOR_SQ)'
endif
-#
-# Please note that there is a minor bug in asciidoc.
-# The version after 6.0.3 _will_ include the patch found here:
-# http://marc.theaimsgroup.com/?l=git&m=111558757202243&w=2
-#
-# Until that version is released you may have to apply the patch
-# yourself - yes, all 6 characters of it!
-#
-
QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir
QUIET_SUBDIR1 =
@@ -263,7 +246,7 @@ manpage-base-url.xsl: manpage-base-url.xsl.in
%.1 %.5 %.7 : %.xml manpage-base-url.xsl
$(QUIET_XMLTO)$(RM) $@ && \
- xmlto -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $<
+ $(XMLTO) -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $<
%.xml : %.txt
$(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
@@ -362,4 +345,7 @@ require-htmlrepo::
quick-install-html: require-htmlrepo
'$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(HTML_REPO) $(DESTDIR)$(htmldir)
+print-man1:
+ @for i in $(MAN1_TXT); do echo $$i; done
+
.PHONY: FORCE
diff --git a/Documentation/RelNotes/1.7.12.1.txt b/Documentation/RelNotes/1.7.12.1.txt
new file mode 100644
index 0000000..b8f04af
--- /dev/null
+++ b/Documentation/RelNotes/1.7.12.1.txt
@@ -0,0 +1,134 @@
+Git 1.7.12.1 Release Notes
+==========================
+
+Fixes since v1.7.12
+-------------------
+
+ * "git apply -p0" did not parse pathnames on "diff --git" line
+ correctly. This caused patches that had pathnames in no other
+ places to be mistakenly rejected (most notably, binary patch that
+ does not rename nor change mode). Textual patches, renames or mode
+ changes have preimage and postimage pathnames in different places
+ in a form that can be parsed unambiguously and did not suffer from
+ this problem.
+
+ * "git cherry-pick A C B" used to replay changes in A and then B and
+ then C if these three commits had committer timestamps in that
+ order, which is not what the user who said "A C B" naturally
+ expects.
+
+ * "git commit --amend" let the user edit the log message and then
+ died when the human-readable committer name was given
+ insufficiently by getpwent(3).
+
+ * Some capabilities were asked by fetch-pack even when upload-pack
+ did not advertise that they are available. fetch-pack has been
+ fixed not to do so.
+
+ * "git diff" had a confusion between taking data from a path in the
+ working tree and taking data from an object that happens to have
+ name 0{40} recorded in a tree.
+
+ * "git for-each-ref" did not correctly support more than one --sort
+ option.
+
+ * "git log .." errored out saying it is both rev range and a path
+ when there is no disambiguating "--" is on the command line.
+ Update the command line parser to interpret ".." as a path in such
+ a case.
+
+ * The "--topo-order", "--date-order" (and the lack of either means
+ the default order) options to "rev-list" and "log" family of
+ commands were poorly described in the documentation.
+
+ * "git prune" without "-v" used to warn about leftover temporary
+ files (which is an indication of an earlier aborted operation).
+
+ * Pushing to smart HTTP server with recent Git fails without having
+ the username in the URL to force authentication, if the server is
+ configured to allow GET anonymously, while requiring authentication
+ for POST.
+
+ * The reflog entries left by "git rebase" and "git rebase -i" were
+ inconsistent (the interactive one gave an abbreviated object name).
+
+ * When "git push" triggered the automatic gc on the receiving end, a
+ message from "git prune" that said it was removing cruft leaked to
+ the standard output, breaking the communication protocol.
+
+ * "git show --quiet" ought to be a synonym for "git show -s", but
+ wasn't.
+
+ * "git show --format='%ci'" did not give timestamp correctly for
+ commits created without human readable name on "committer" line.
+
+ * "git send-email" did not unquote encoded words that appear on the
+ header correctly, and lost "_" from strings.
+
+ * The interactive prompt "git send-email" gives was error prone. It
+ asked "What e-mail address do you want to use?" with the address it
+ guessed (correctly) the user would want to use in its prompt,
+ tempting the user to say "y". But the response was taken as "No,
+ please use 'y' as the e-mail address instead", which is most
+ certainly not what the user meant.
+
+ * "gitweb" when used with PATH_INFO failed to notice directories with
+ SP (and other characters that need URL-style quoting) in them.
+
+ * When the user gives an argument that can be taken as both a
+ revision name and a pathname without disambiguating with "--", we
+ used to give a help message "Use '--' to separate". The message
+ has been clarified to show where that '--' goes on the command
+ line.
+
+ * When the user exports a non-default IFS without HT, scripts that
+ rely on being able to parse "ls-files -s | while read a b c..."
+ started to fail. Protect them from such a misconfiguration.
+
+ * The attribute system may be asked for a path that itself or its
+ leading directories no longer exists in the working tree, and it is
+ fine if we cannot open .gitattribute file in such a case. Failure
+ to open per-directory .gitattributes with error status other than
+ ENOENT and ENOTDIR should be diagnosed, but it wasn't.
+
+ * After "gitk" showed the contents of a tag, neither "Reread
+ references" nor "Reload" did not update what is shown as the
+ contents of it, when the user overwrote the tag with "git tag -f".
+
+ * "ciabot" script (in contrib/) has been updated with extensive
+ documentation.
+
+ * "git-jump" script (in contrib/) did not work well when
+ diff.noprefix or diff.mnemonicprefix is in effect.
+
+ * Older parts of the documentation described as if having a regular
+ file in .git/refs/ hierarchy were the only way to have branches and
+ tags, which is not true for quite some time.
+
+ * A utility shell function test_seq has been added as a replacement
+ for the 'seq' utility found on some platforms.
+
+ * Compatibility wrapper to learn the maximum number of file
+ descriptors we can open around sysconf(_SC_OPEN_MAX) and
+ getrlimit(RLIMIT_NO_FILE) has been introduced for portability.
+
+ * We used curl_easy_strerror() without checking version of cURL,
+ breaking the build for versions before curl 7.12.0.
+
+ * Code to work around MacOS X UTF-8 gotcha has been cleaned up.
+
+ * Fallback 'getpass' implementation made unportable use of stdio API.
+
+ * The "--rebase" option to "git pull" can be abbreviated to "-r",
+ but we didn't document it.
+
+ * It was generally understood that "--long-option"s to many of our
+ subcommands can be abbreviated to the unique prefix, but it was not
+ easy to find it described for new readers of the documentation set.
+
+ * The synopsis said "checkout [-B branch]" to make it clear the
+ branch name is a parameter to the option, but the heading for the
+ option description was "-B::", not "-B branch::", making the
+ documentation misleading.
+
+Also contains numerous documentation updates.
diff --git a/Documentation/RelNotes/1.7.12.2.txt b/Documentation/RelNotes/1.7.12.2.txt
new file mode 100644
index 0000000..6925574
--- /dev/null
+++ b/Documentation/RelNotes/1.7.12.2.txt
@@ -0,0 +1,40 @@
+Git 1.7.12.2 Release Notes
+==========================
+
+Fixes since v1.7.12.1
+---------------------
+
+ * When "git am" is fed an input that has multiple "Content-type: ..."
+ header, it did not grok charset= attribute correctly.
+
+ * Even during a conflicted merge, "git blame $path" always meant to
+ blame uncommitted changes to the "working tree" version; make it
+ more useful by showing cleanly merged parts as coming from the other
+ branch that is being merged.
+
+ * "git blame MAKEFILE" run in a history that has "Makefile" but not
+ "MAKEFILE" should say "No such file MAKEFILE in HEAD", but got
+ confused on a case insensitive filesystem and failed to do so.
+
+ * "git fetch --all", when passed "--no-tags", did not honor the
+ "--no-tags" option while fetching from individual remotes (the same
+ issue existed with "--tags", but combination "--all --tags" makes
+ much less sense than "--all --no-tags").
+
+ * "git log/diff/format-patch --stat" showed the "N line(s) added"
+ comment in user's locale and caused careless submitters to send
+ patches with such a line in them to projects whose project language
+ is not their language, mildly irritating others. Localization to
+ the line has been disabled for now.
+
+ * "git log --all-match --grep=A --grep=B" ought to show commits that
+ mention both A and B, but when these three options are used with
+ --author or --committer, it showed commits that mention either A or
+ B (or both) instead.
+
+ * The subcommand to remove the definition of a remote in "git remote"
+ was named "rm" even though all other subcommands were spelled out.
+ Introduce "git remote remove" to remove confusion, and keep "rm" as
+ a backward compatible synonym.
+
+Also contains a handful of documentation updates.
diff --git a/Documentation/RelNotes/1.7.12.3.txt b/Documentation/RelNotes/1.7.12.3.txt
new file mode 100644
index 0000000..ecda427
--- /dev/null
+++ b/Documentation/RelNotes/1.7.12.3.txt
@@ -0,0 +1,34 @@
+Git 1.7.12.3 Release Notes
+==========================
+
+Fixes since v1.7.12.2
+---------------------
+
+ * "git am" mishandled a patch attached as application/octet-stream
+ (e.g. not text/*); Content-Transfer-Encoding (e.g. base64) was not
+ honored correctly.
+
+ * It was unclear in the documentation for "git blame" that it is
+ unnecessary for users to use the "--follow" option.
+
+ * A repository created with "git clone --single" had its fetch
+ refspecs set up just like a clone without "--single", leading the
+ subsequent "git fetch" to slurp all the other branches, defeating
+ the whole point of specifying "only this branch".
+
+ * "git fetch" over http had an old workaround for an unlikely server
+ misconfiguration; it turns out that this hurts debuggability of the
+ configuration in general, and has been reverted.
+
+ * "git fetch" over http advertised that it supports "deflate", which
+ is much less common, and did not advertise the more common "gzip" on
+ its Accept-Encoding header.
+
+ * "git receive-pack" (the counterpart to "git push") did not give
+ progress output while processing objects it received to the puser
+ when run over the smart-http protocol.
+
+ * "git status" honored the ignore=dirty settings in .gitmodules but
+ "git commit" didn't.
+
+Also contains a handful of documentation updates.
diff --git a/Documentation/RelNotes/1.7.12.txt b/Documentation/RelNotes/1.7.12.txt
new file mode 100644
index 0000000..010d8c7
--- /dev/null
+++ b/Documentation/RelNotes/1.7.12.txt
@@ -0,0 +1,136 @@
+Git v1.7.12 Release Notes
+=========================
+
+Updates since v1.7.11
+---------------------
+
+UI, Workflows & Features
+
+ * Git can be told to normalize pathnames it read from readdir(3) and
+ all arguments it got from the command line into precomposed UTF-8
+ (assuming that they come as decomposed UTF-8), in order to work
+ around issues on Mac OS.
+
+ I think there still are other places that need conversion
+ (e.g. paths that are read from stdin for some commands), but this
+ should be a good first step in the right direction.
+
+ * Per-user $HOME/.gitconfig file can optionally be stored in
+ $HOME/.config/git/config instead, which is in line with XDG.
+
+ * The value of core.attributesfile and core.excludesfile default to
+ $HOME/.config/git/attributes and $HOME/.config/git/ignore respectively
+ when these files exist.
+
+ * Logic to disambiguate abbreviated object names have been taught to
+ take advantage of object types that are expected in the context,
+ e.g. XXXXXX in the "git describe" output v1.2.3-gXXXXXX must be a
+ commit object, not a blob nor a tree. This will help us prolong
+ the lifetime of abbreviated object names.
+
+ * "git apply" learned to wiggle the base version and perform three-way
+ merge when a patch does not exactly apply to the version you have.
+
+ * Scripted Porcelain writers now have access to the credential API via
+ the "git credential" plumbing command.
+
+ * "git help" used to always default to "man" format even on platforms
+ where "man" viewer is not widely available.
+
+ * "git clone --local $path" started its life as an experiment to
+ optionally use link/copy when cloning a repository on the disk, but
+ we didn't deprecate it after we made the option a no-op to always
+ use the optimization. The command learned "--no-local" option to
+ turn this off, as a more explicit alternative over use of file://
+ URL.
+
+ * "git fetch" and friends used to say "remote side hung up
+ unexpectedly" when they failed to get response they expect from the
+ other side, but one common reason why they don't get expected
+ response is that the remote repository does not exist or cannot be
+ read. The error message in this case was updated to give better
+ hints to the user.
+
+ * "git help -w $cmd" can show HTML version of documentation for
+ "git-$cmd" by setting help.htmlpath to somewhere other than the
+ default location where the build procedure installs them locally;
+ the variable can even point at a http:// URL.
+
+ * "git rebase [-i] --root $tip" can now be used to rewrite all the
+ history leading to "$tip" down to the root commit.
+
+ * "git rebase -i" learned "-x <cmd>" to insert "exec <cmd>" after
+ each commit in the resulting history.
+
+ * "git status" gives finer classification to various states of paths
+ in conflicted state and offer advice messages in its output.
+
+ * "git submodule" learned to deal with nested submodule structure
+ where a module is contained within a module whose origin is
+ specified as a relative URL to its superproject's origin.
+
+ * A rather heavy-ish "git completion" script has been split to create
+ a separate "git prompting" script, to help lazy-autoloading of the
+ completion part while making prompting part always available.
+
+ * "gitweb" pays attention to various forms of credits that are
+ similar to "Signed-off-by:" lines in the commit objects and
+ highlights them accordingly.
+
+
+Foreign Interface
+
+ * "mediawiki" remote helper (in contrib/) learned to handle file
+ attachments.
+
+ * "git p4" now uses "Jobs:" and "p4 move" when appropriate.
+
+ * vcs-svn has been updated to clean-up compilation, lift 32-bit
+ limitations, etc.
+
+
+Performance, Internal Implementation, etc. (please report possible regressions)
+
+ * Some tests showed false failures caused by a bug in ecryptofs.
+
+ * We no longer use AsciiDoc7 syntax in our documentation and favor a
+ more modern style.
+
+ * "git am --rebasing" codepath was taught to grab authorship, log
+ message and the patch text directly out of existing commits. This
+ will help rebasing commits that have confusing "diff" output in
+ their log messages.
+
+ * "git index-pack" and "git pack-objects" use streaming API to read
+ from the object store to avoid having to hold a large blob object
+ in-core while they are doing their thing.
+
+ * Code to match paths with exclude patterns learned to avoid calling
+ fnmatch() by comparing fixed leading substring literally when
+ possible.
+
+ * "git log -n 1 -- rarely-touched-path" was spending unnecessary
+ cycles after showing the first change to find the next one, only to
+ discard it.
+
+ * "git svn" got a large-looking code reorganization at the last
+ minute before the code freeze.
+
+
+Also contains minor documentation updates and code clean-ups.
+
+
+Fixes since v1.7.11
+-------------------
+
+Unless otherwise noted, all the fixes since v1.7.11 in the maintenance
+releases are contained in this release (see release notes to them for
+details).
+
+ * "git submodule add" was confused when the superproject did not have
+ its repository in its usual place in the working tree and GIT_DIR
+ and GIT_WORK_TREE was used to access it.
+
+ * "git commit --amend" let the user edit the log message and then died
+ when the human-readable committer name was given insufficiently by
+ getpwent(3).
diff --git a/Documentation/RelNotes/1.8.0.txt b/Documentation/RelNotes/1.8.0.txt
new file mode 100644
index 0000000..6a6f323
--- /dev/null
+++ b/Documentation/RelNotes/1.8.0.txt
@@ -0,0 +1,257 @@
+Git v1.8.0 Release Notes
+========================
+
+Backward compatibility notes
+----------------------------
+
+In the next major release, we will change the behavior of the "git
+push" command. When "git push [$there]" does not say what to push, we
+have used the traditional "matching" semantics so far (all your branches were
+sent to the remote as long as there already are branches of the same
+name over there). We will now use the "simple" semantics, that pushes the
+current branch to the branch with the same name only when the current
+branch is set to integrate with that remote branch. There is a user
+preference configuration variable "push.default" to change this, and
+"git push" will warn about the upcoming change until you set this
+variable.
+
+"git branch --set-upstream" is deprecated and may be removed in a
+relatively distant future. "git branch [-u|--set-upstream-to]" has
+been introduced with a saner order of arguments.
+
+
+Updates since v1.7.12
+---------------------
+
+UI, Workflows & Features
+
+ * A credential helper for Win32 to allow access to the keychain of
+ the logged-in user has been added.
+
+ * An initial port to HP NonStop.
+
+ * A credential helper to allow access to the Gnome keyring has been
+ added.
+
+ * When "git am" sanitizes the "Subject:" line, we strip the prefix from
+ "Re: subject" and also from a less common "re: subject", but left
+ the even less common "RE: subject" intact. We strip that now, too.
+
+ * It was tempting to say "git branch --set-upstream origin/master",
+ but that tells Git to arrange the local branch "origin/master" to
+ integrate with the currently checked out branch, which is highly
+ unlikely what the user meant. The option is deprecated; use the
+ new "--set-upstream-to" (with a short-and-sweet "-u") option
+ instead.
+
+ * "git cherry-pick" learned the "--allow-empty-message" option to
+ allow it to replay a commit without any log message.
+
+ * After "git cherry-pick -s" gave control back to the user asking
+ help to resolve conflicts, concluding "git commit" used to need to
+ be run with "-s" if the user wants to sign it off; now the command
+ leaves the sign-off line in the log template.
+
+ * "git daemon" learned the "--access-hook" option to allow an
+ external command to decline service based on the client address,
+ repository path, etc.
+
+ * "git difftool --dir-diff" learned to use symbolic links to prepare
+ a temporary copy of the working tree when available.
+
+ * "git grep" learned to use a non-standard pattern type by default if
+ a configuration variable tells it to.
+
+ * "git log -g" learned the "--grep-reflog=<pattern>" option to limit
+ its output to commits with a reflog message that matches the given
+ pattern.
+
+ * "git merge-base" learned the "--is-ancestor A B" option to tell if A is
+ an ancestor of B. The result is indicated by its exit status code.
+
+ * "git mergetool" now allows users to override the actual command used
+ with the mergetool.$name.cmd configuration variable even for built-in
+ mergetool backends.
+
+ * The "-Xours" backend option to "git merge -s recursive" now takes
+ effect even on binary files.
+
+ * "git rebase -i" learned the "--edit-todo" option to open an editor
+ to edit the instruction sheet.
+
+
+Foreign Interface
+
+ * "git svn" has been updated to work with SVN 1.7.
+
+ * "git p4" learned the "--conflicts" option to specify what to do when
+ encountering a conflict during "p4 submit".
+
+
+Performance, Internal Implementation, etc. (please report possible regressions)
+
+ * Git ships with a fall-back regexp implementation for platforms with
+ buggy regexp library, but it was easy for people to keep using their
+ platform regexp by mistake. A new test has been added to check this.
+
+ * The "check-docs" build target has been updated and greatly
+ simplified.
+
+ * The test suite is run under MALLOC_CHECK_ when running with a glibc
+ that supports the feature.
+
+ * The documentation in the TeXinfo format was using indented output
+ for materials meant to be examples that are better typeset in
+ monospace.
+
+ * Compatibility wrapper around some mkdir(2) implementations that
+ reject parameters with trailing slash has been introduced.
+
+ * Compatibility wrapper for systems that lack usable setitimer() has
+ been added.
+
+ * The option parsing of "git checkout" had error checking, dwim and
+ defaulting missing options, all mixed in the code, and issuing an
+ appropriate error message with useful context was getting harder.
+ The code has been reorganized to allow giving a proper diagnosis
+ when the user says "git checkout -b -t foo bar" (e.g. "-t" is not a
+ good name for a branch).
+
+ * Many internal uses of a "git merge-base" equivalent were only to see
+ if one commit fast-forwards to the other, which did not need the
+ full set of merge bases to be computed. They have been updated to
+ use less expensive checks.
+
+ * The heuristics to detect and silently convert latin1 to utf8 when
+ we were told to use utf-8 in the log message has been transplanted
+ from "mailinfo" to "commit" and "commit-tree".
+
+ * Messages given by "git <subcommand> -h" from many subcommands have
+ been marked for translation.
+
+
+Also contains minor documentation updates and code clean-ups.
+
+
+Fixes since v1.7.12
+-------------------
+
+Unless otherwise noted, all the fixes since v1.7.12 in the
+maintenance track are contained in this release (see release notes
+to them for details).
+
+ * The attribute system may be asked for a path that itself or its
+ leading directories no longer exists in the working tree, and it is
+ fine if we cannot open .gitattribute file in such a case. Failure
+ to open per-directory .gitattributes with error status other than
+ ENOENT and ENOTDIR should be diagnosed, but it wasn't.
+
+ * When looking for $HOME/.gitconfig etc., it is OK if we cannot read
+ them because they do not exist, but we did not diagnose existing
+ files that we cannot read.
+
+ * When "git am" is fed an input that has multiple "Content-type: ..."
+ header, it did not grok charset= attribute correctly.
+
+ * "git am" mishandled a patch attached as application/octet-stream
+ (e.g. not text/*); Content-Transfer-Encoding (e.g. base64) was not
+ honored correctly.
+
+ * "git blame MAKEFILE" run in a history that has "Makefile" but not
+ "MAKEFILE" should say "No such file MAKEFILE in HEAD", but got
+ confused on a case insensitive filesystem and failed to do so.
+
+ * Even during a conflicted merge, "git blame $path" always meant to
+ blame uncommitted changes to the "working tree" version; make it
+ more useful by showing cleanly merged parts as coming from the other
+ branch that is being merged.
+
+ * It was unclear in the documentation for "git blame" that it is
+ unnecessary for users to use the "--follow" option.
+
+ * Output from "git branch -v" contains "(no branch)" that could be
+ localized, but the code to align it along with the names of
+ branches was counting in bytes, not in display columns.
+
+ * "git cherry-pick A C B" used to replay changes in A and then B and
+ then C if these three commits had committer timestamps in that
+ order, which is not what the user who said "A C B" naturally
+ expects.
+
+ * A repository created with "git clone --single" had its fetch
+ refspecs set up just like a clone without "--single", leading the
+ subsequent "git fetch" to slurp all the other branches, defeating
+ the whole point of specifying "only this branch".
+
+ * Documentation talked about "first line of commit log" when it meant
+ the title of the commit. The description was clarified by defining
+ how the title is decided and rewording the casual mention of "first
+ line" to "title".
+
+ * "git cvsimport" did not thoroughly cleanse tag names that it
+ inferred from the names of the tags it obtained from CVS, which
+ caused "git tag" to barf and stop the import in the middle.
+
+ * Earlier we made the diffstat summary line that shows the number of
+ lines added/deleted localizable, but it was found irritating having
+ to see them in various languages on a list whose discussion language
+ is English, and this change has been reverted.
+
+ * "git fetch --all", when passed "--no-tags", did not honor the
+ "--no-tags" option while fetching from individual remotes (the same
+ issue existed with "--tags", but the combination "--all --tags" makes
+ much less sense than "--all --no-tags").
+
+ * "git fetch" over http had an old workaround for an unlikely server
+ misconfiguration; it turns out that this hurts debuggability of the
+ configuration in general, and has been reverted.
+
+ * "git fetch" over http advertised that it supports "deflate", which
+ is much less common, and did not advertise the more common "gzip" on
+ its Accept-Encoding header.
+
+ * "git gc --auto" notified the user that auto-packing has triggered
+ even under the "--quiet" option.
+
+ * After "gitk" showed the contents of a tag, neither "Reread
+ references" nor "Reload" updated what is shown as the
+ contents of it when the user overwrote the tag with "git tag -f".
+
+ * "git log --all-match --grep=A --grep=B" ought to show commits that
+ mention both A and B, but when these three options are used with
+ --author or --committer, it showed commits that mention either A or
+ B (or both) instead.
+
+ * "git p4", when "--use-client-spec" and "--detect-branches" are used
+ together, misdetected branches.
+
+ * "git receive-pack" (the counterpart to "git push") did not give
+ progress output while processing objects it received to the puser
+ when run over the smart-http protocol.
+
+ * When you misspell the command name you give to the "exec" action in
+ the "git rebase -i" instruction sheet you were told that 'rebase' is not a
+ git subcommand from "git rebase --continue".
+
+ * The subcommand in "git remote" to remove a defined remote was
+ "rm" and the command did not take a fully-spelled "remove".
+
+ * The interactive prompt that "git send-email" gives was error prone. It
+ asked "What e-mail address do you want to use?" with the address it
+ guessed (correctly) the user would want to use in its prompt,
+ tempting the user to say "y". But the response was taken as "No,
+ please use 'y' as the e-mail address instead", which is most
+ certainly not what the user meant.
+
+ * "git show --format='%ci'" did not give the timestamp correctly for
+ commits created without human readable name on the "committer" line.
+
+ * "git show --quiet" ought to be a synonym for "git show -s", but
+ wasn't.
+
+ * "git submodule frotz" was not diagnosed as "frotz" being an unknown
+ subcommand to "git submodule"; the user instead got a complaint
+ that "git submodule status" was run with an unknown path "frotz".
+
+ * "git status" honored the ignore=dirty settings in .gitmodules but
+ "git commit" didn't.
diff --git a/Documentation/config.txt b/Documentation/config.txt
index b49feb5..11f320b 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -159,9 +159,10 @@ advice.*::
specified a refspec that isn't your current branch) and
it resulted in a non-fast-forward error.
statusHints::
- Directions on how to stage/unstage/add shown in the
- output of linkgit:git-status[1] and the template shown
- when writing commit messages.
+ Show directions on how to proceed from the current
+ state in the output of linkgit:git-status[1] and in
+ the template shown when writing commit messages in
+ linkgit:git-commit[1].
commitBeforeMerge::
Advice shown when linkgit:git-merge[1] refuses to
merge to avoid overwriting local changes.
@@ -213,6 +214,15 @@ The default is false, except linkgit:git-clone[1] or linkgit:git-init[1]
will probe and set core.ignorecase true if appropriate when the repository
is created.
+core.precomposeunicode::
+ This option is only used by Mac OS implementation of git.
+ When core.precomposeunicode=true, git reverts the unicode decomposition
+ of filenames done by Mac OS. This is useful when sharing a repository
+ between Mac OS and Linux or Windows.
+ (Git for Windows 1.7.10 or higher is needed, or git under cygwin 1.7).
+ When false, file names are handled fully transparent by git,
+ which is backward compatible with older versions of git.
+
core.trustctime::
If false, the ctime differences between the index and the
working tree are ignored; useful when the inode change time
@@ -486,7 +496,9 @@ core.excludesfile::
'.git/info/exclude', git looks into this file for patterns
of files which are not meant to be tracked. "`~/`" is expanded
to the value of `$HOME` and "`~user/`" to the specified user's
- home directory. See linkgit:gitignore[5].
+ home directory. Its default value is $XDG_CONFIG_HOME/git/ignore.
+ If $XDG_CONFIG_HOME is either not set or empty, $HOME/.config/git/ignore
+ is used instead. See linkgit:gitignore[5].
core.askpass::
Some commands (e.g. svn and http interfaces) that interactively
@@ -501,7 +513,9 @@ core.attributesfile::
In addition to '.gitattributes' (per-directory) and
'.git/info/attributes', git looks into this file for attributes
(see linkgit:gitattributes[5]). Path expansions are made the same
- way as for `core.excludesfile`.
+ way as for `core.excludesfile`. Its default value is
+ $XDG_CONFIG_HOME/git/attributes. If $XDG_CONFIG_HOME is either not
+ set or empty, $HOME/.config/git/attributes is used instead.
core.editor::
Commands such as `commit` and `tag` that lets you edit
@@ -545,8 +559,9 @@ core.whitespace::
* `space-before-tab` treats a space character that appears immediately
before a tab character in the initial indent part of the line as an
error (enabled by default).
-* `indent-with-non-tab` treats a line that is indented with 8 or more
- space characters as an error (not enabled by default).
+* `indent-with-non-tab` treats a line that is indented with space
+ characters instead of the equivalent tabs as an error (not enabled by
+ default).
* `tab-in-indent` treats a tab character in the initial indent part of
the line as an error (not enabled by default).
* `blank-at-eof` treats blank lines added at the end of file as an error
@@ -883,7 +898,7 @@ column.ui::
make equal size columns
--
+
- This option defaults to 'never'.
+This option defaults to 'never'.
column.branch::
Specify whether to output branch listing in `git branch` in columns.
@@ -1196,8 +1211,16 @@ gitweb.snapshot::
grep.lineNumber::
If set to true, enable '-n' option by default.
+grep.patternType::
+ Set the default matching behavior. Using a value of 'basic', 'extended',
+ 'fixed', or 'perl' will enable the '--basic-regexp', '--extended-regexp',
+ '--fixed-strings', or '--perl-regexp' option accordingly, while the
+ value 'default' will return to the default matching behavior.
+
grep.extendedRegexp::
- If set to true, enable '--extended-regexp' option by default.
+ If set to true, enable '--extended-regexp' option by default. This
+ option is ignored when the 'grep.patternType' option is set to a value
+ other than 'default'.
gpg.program::
Use this custom program instead of "gpg" found on $PATH when
@@ -1723,6 +1746,7 @@ push.default::
no refspec is implied by any of the options given on the command
line. Possible values are:
+
+--
* `nothing` - do not push anything.
* `matching` - push all branches having the same name in both ends.
This is for those who prepare all the branches into a publishable
@@ -1742,12 +1766,13 @@ push.default::
option and is well-suited for beginners. It will become the default
in Git 2.0.
* `current` - push the current branch to a branch of the same name.
- +
- The `simple`, `current` and `upstream` modes are for those who want to
- push out a single branch after finishing work, even when the other
- branches are not yet ready to be pushed out. If you are working with
- other people to push into the same shared repository, you would want
- to use one of these.
+--
++
+The `simple`, `current` and `upstream` modes are for those who want to
+push out a single branch after finishing work, even when the other
+branches are not yet ready to be pushed out. If you are working with
+other people to push into the same shared repository, you would want
+to use one of these.
rebase.stat::
Whether to show a diffstat of what changed upstream since the last
diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt
index 39d326a..b4d6476 100644
--- a/Documentation/fetch-options.txt
+++ b/Documentation/fetch-options.txt
@@ -10,7 +10,8 @@
--depth=<depth>::
Deepen the history of a 'shallow' repository created by
`git clone` with `--depth=<depth>` option (see linkgit:git-clone[1])
- by the specified number of commits.
+ to the specified number of commits from the tip of each remote
+ branch history. Tags for the deepened commits are not fetched.
ifndef::git-pull[]
--dry-run::
diff --git a/Documentation/git-add.txt b/Documentation/git-add.txt
index 9c1d395..fd9e36b 100644
--- a/Documentation/git-add.txt
+++ b/Documentation/git-add.txt
@@ -155,7 +155,7 @@ Configuration
The optional configuration variable `core.excludesfile` indicates a path to a
file containing patterns of file names to exclude from git-add, similar to
$GIT_DIR/info/exclude. Patterns in the exclude file are used in addition to
-those in info/exclude. See linkgit:gitrepository-layout[5].
+those in info/exclude. See linkgit:gitignore[5].
EXAMPLES
diff --git a/Documentation/git-apply.txt b/Documentation/git-apply.txt
index afd2c9a..634b84e 100644
--- a/Documentation/git-apply.txt
+++ b/Documentation/git-apply.txt
@@ -9,7 +9,7 @@ git-apply - Apply a patch to files and/or to the index
SYNOPSIS
--------
[verse]
-'git apply' [--stat] [--numstat] [--summary] [--check] [--index]
+'git apply' [--stat] [--numstat] [--summary] [--check] [--index] [--3way]
[--apply] [--no-add] [--build-fake-ancestor=<file>] [-R | --reverse]
[--allow-binary-replacement | --binary] [--reject] [-z]
[-p<n>] [-C<n>] [--inaccurate-eof] [--recount] [--cached]
@@ -72,6 +72,15 @@ OPTIONS
cached data, apply the patch, and store the result in the index
without using the working tree. This implies `--index`.
+-3::
+--3way::
+ When the patch does not apply cleanly, fall back on 3-way merge if
+ the patch records the identity of blobs it is supposed to apply to,
+ and we have those blobs available locally, possibly leaving the
+ conflict markers in the files in the working tree for the user to
+ resolve. This option implies the `--index` option, and is incompatible
+ with the `--reject` and the `--cached` options.
+
--build-fake-ancestor=<file>::
Newer 'git diff' output has embedded 'index information'
for each blob to help identify the original version that
diff --git a/Documentation/git-blame.txt b/Documentation/git-blame.txt
index 7ee9236..e44173f 100644
--- a/Documentation/git-blame.txt
+++ b/Documentation/git-blame.txt
@@ -20,6 +20,12 @@ last modified the line. Optionally, start annotating from the given revision.
The command can also limit the range of lines annotated.
+The origin of lines is automatically followed across whole-file
+renames (currently there is no option to turn the rename-following
+off). To follow lines moved from one file to another, or to follow
+lines that were copied and pasted from another file, etc., see the
+`-C` and `-M` options.
+
The report does not tell you anything about lines which have been deleted or
replaced; you need to use a tool such as 'git diff' or the "pickaxe"
interface briefly mentioned in the following paragraph.
diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index 47235be..45a225e 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -13,6 +13,8 @@ SYNOPSIS
[--column[=<options>] | --no-column]
[(--merged | --no-merged | --contains) [<commit>]] [<pattern>...]
'git branch' [--set-upstream | --track | --no-track] [-l] [-f] <branchname> [<start-point>]
+'git branch' (--set-upstream-to=<upstream> | -u <upstream>) [<branchname>]
+'git branch' --unset-upstream [<branchname>]
'git branch' (-m | -M) [<oldbranch>] <newbranch>
'git branch' (-d | -D) [-r] <branchname>...
'git branch' --edit-description [<branchname>]
@@ -48,7 +50,7 @@ branch so that 'git pull' will appropriately merge from
the remote-tracking branch. This behavior may be changed via the global
`branch.autosetupmerge` configuration flag. That setting can be
overridden by using the `--track` and `--no-track` options, and
-changed later using `git branch --set-upstream`.
+changed later using `git branch --set-upstream-to`.
With a `-m` or `-M` option, <oldbranch> will be renamed to <newbranch>.
If <oldbranch> had a corresponding reflog, it is renamed to match
@@ -129,11 +131,13 @@ This option is only applicable in non-verbose mode.
use `git branch --list <pattern>` to list matching branches.
-v::
+-vv::
--verbose::
When in list mode,
show sha1 and commit subject line for each head, along with
relationship to upstream branch (if any). If given twice, print
- the name of the upstream branch, as well.
+ the name of the upstream branch, as well (see also `git remote
+ show <remote>`).
-q::
--quiet::
@@ -173,6 +177,16 @@ start-point is either a local or remote-tracking branch.
like `--track` would when creating the branch, except that where
branch points to is not changed.
+-u <upstream>::
+--set-upstream-to=<upstream>::
+ Set up <branchname>'s tracking information so <upstream> is
+ considered <branchname>'s upstream branch. If no <branchname>
+ is specified, then it defaults to the current branch.
+
+--unset-upstream::
+ Remove the upstream information for <branchname>. If no branch
+ is specified it defaults to the current branch.
+
--edit-description::
Open an editor and edit the text to explain what the branch is
for, to be used by various other commands (e.g. `request-pull`).
diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index 0e170a5..c205d23 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -118,6 +118,11 @@ effect to your index in a row.
previous commit are dropped. To force the inclusion of those commits
use `--keep-redundant-commits`.
+--allow-empty-message::
+ By default, cherry-picking a commit with an empty message will fail.
+ This option overrides that behaviour, allowing commits with empty
+ messages to be cherry picked.
+
--keep-redundant-commits::
If a commit being cherry picked duplicates a commit already in the
current history, it will become empty. By default these
diff --git a/Documentation/git-clean.txt b/Documentation/git-clean.txt
index 79fb984..9f42c0d 100644
--- a/Documentation/git-clean.txt
+++ b/Documentation/git-clean.txt
@@ -63,6 +63,10 @@ OPTIONS
Remove only files ignored by git. This may be useful to rebuild
everything from scratch, but keep manually created files.
+SEE ALSO
+--------
+linkgit:gitignore[5]
+
GIT
---
Part of the linkgit:git[1] suite
diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt
index 6e22522..6d98ef3 100644
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.txt
@@ -29,7 +29,8 @@ currently active branch.
After the clone, a plain `git fetch` without arguments will update
all the remote-tracking branches, and a `git pull` without
arguments will in addition merge the remote master branch into the
-current master branch, if any.
+current master branch, if any (this is untrue when "--single-branch"
+is given; see below).
This default configuration is achieved by creating references to
the remote branch heads under `refs/remotes/origin` and
@@ -46,13 +47,18 @@ OPTIONS
mechanism and clones the repository by making a copy of
HEAD and everything under objects and refs directories.
The files under `.git/objects/` directory are hardlinked
- to save space when possible. This is now the default when
- the source repository is specified with `/path/to/repo`
- syntax, so it essentially is a no-op option. To force
- copying instead of hardlinking (which may be desirable
- if you are trying to make a back-up of your repository),
- but still avoid the usual "git aware" transport
- mechanism, `--no-hardlinks` can be used.
+ to save space when possible.
++
+If the repository is specified as a local path (e.g., `/path/to/repo`),
+this is the default, and --local is essentially a no-op. If the
+repository is specified as a URL, then this flag is ignored (and we
+never use the local optimizations). Specifying `--no-local` will
+override the default when `/path/to/repo` is given, using the regular
+git transport instead.
++
+To force copying instead of hardlinking (which may be desirable if you
+are trying to make a back-up of your repository), but still avoid the
+usual "git aware" transport mechanism, `--no-hardlinks` can be used.
--no-hardlinks::
Optimize the cloning process from a repository on a
@@ -147,9 +153,10 @@ objects from the source repository into a pack in the cloned repository.
-b <name>::
Instead of pointing the newly created HEAD to the branch pointed
to by the cloned repository's HEAD, point to `<name>` branch
- instead. `--branch` can also take tags and treat them like
- detached HEAD. In a non-bare repository, this is the branch
- that will be checked out.
+ instead. In a non-bare repository, this is the branch that will
+ be checked out.
+ `--branch` can also take tags and detaches the HEAD at that commit
+ in the resulting repository.
--upload-pack <upload-pack>::
-u <upload-pack>::
@@ -188,6 +195,11 @@ objects from the source repository into a pack in the cloned repository.
clone with the `--depth` option, this is the default, unless
`--no-single-branch` is given to fetch the histories near the
tips of all branches.
+ Further fetches into the resulting repository will only update the
+ remote tracking branch for the branch this option was used for the
+ initial cloning. If the HEAD at the remote did not point at any
+ branch when `--single-branch` clone was made, no remote tracking
+ branch is created.
--recursive::
--recurse-submodules::
diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt
index 4622297..9594ac8 100644
--- a/Documentation/git-commit.txt
+++ b/Documentation/git-commit.txt
@@ -389,8 +389,10 @@ DISCUSSION
Though not required, it's a good idea to begin the commit message
with a single short (less than 50 character) line summarizing the
change, followed by a blank line and then a more thorough description.
-Tools that turn commits into email, for example, use the first line
-on the Subject: line and the rest of the commit in the body.
+The text up to the first blank line in a commit message is treated
+as the commit title, and that title is used throughout git.
+For example, linkgit:git-format-patch[1] turns a commit into email, and it uses
+the title on the Subject line and the rest of the commit in the body.
include::i18n.txt[]
diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt
index 21b8f61..eaea079 100644
--- a/Documentation/git-config.txt
+++ b/Documentation/git-config.txt
@@ -97,10 +97,11 @@ OPTIONS
--global::
For writing options: write to global ~/.gitconfig file rather than
- the repository .git/config.
+ the repository .git/config, write to $XDG_CONFIG_HOME/git/config file
+ if this file exists and the ~/.gitconfig file doesn't.
+
-For reading options: read only from global ~/.gitconfig rather than
-from all available files.
+For reading options: read only from global ~/.gitconfig and from
+$XDG_CONFIG_HOME/git/config rather than from all available files.
+
See also <<FILES>>.
@@ -194,7 +195,7 @@ See also <<FILES>>.
FILES
-----
-If not set explicitly with '--file', there are three files where
+If not set explicitly with '--file', there are four files where
'git config' will search for configuration options:
$GIT_DIR/config::
@@ -204,6 +205,14 @@ $GIT_DIR/config::
User-specific configuration file. Also called "global"
configuration file.
+$XDG_CONFIG_HOME/git/config::
+ Second user-specific configuration file. If $XDG_CONFIG_HOME is not set
+ or empty, $HOME/.config/git/config will be used. Any single-valued
+ variable set in this file will be overwritten by whatever is in
+ ~/.gitconfig. It is a good idea not to create this file if
+ you sometimes use older versions of Git, as support for this
+ file was added fairly recently.
+
$(prefix)/etc/gitconfig::
System-wide configuration file.
diff --git a/Documentation/git-credential-cache--daemon.txt b/Documentation/git-credential-cache--daemon.txt
index 11edc5a..d15db42 100644
--- a/Documentation/git-credential-cache--daemon.txt
+++ b/Documentation/git-credential-cache--daemon.txt
@@ -3,7 +3,7 @@ git-credential-cache--daemon(1)
NAME
----
-git-credential-cache--daemon - temporarily store user credentials in memory
+git-credential-cache--daemon - Temporarily store user credentials in memory
SYNOPSIS
--------
diff --git a/Documentation/git-credential-cache.txt b/Documentation/git-credential-cache.txt
index f3d09c5..eeff5fa 100644
--- a/Documentation/git-credential-cache.txt
+++ b/Documentation/git-credential-cache.txt
@@ -3,7 +3,7 @@ git-credential-cache(1)
NAME
----
-git-credential-cache - helper to temporarily store passwords in memory
+git-credential-cache - Helper to temporarily store passwords in memory
SYNOPSIS
--------
diff --git a/Documentation/git-credential-store.txt b/Documentation/git-credential-store.txt
index 3109346..b27c03c 100644
--- a/Documentation/git-credential-store.txt
+++ b/Documentation/git-credential-store.txt
@@ -3,7 +3,7 @@ git-credential-store(1)
NAME
----
-git-credential-store - helper to store credentials on disk
+git-credential-store - Helper to store credentials on disk
SYNOPSIS
--------
diff --git a/Documentation/git-credential.txt b/Documentation/git-credential.txt
new file mode 100644
index 0000000..810e957
--- /dev/null
+++ b/Documentation/git-credential.txt
@@ -0,0 +1,154 @@
+git-credential(1)
+=================
+
+NAME
+----
+git-credential - Retrieve and store user credentials
+
+SYNOPSIS
+--------
+------------------
+git credential <fill|approve|reject>
+------------------
+
+DESCRIPTION
+-----------
+
+Git has an internal interface for storing and retrieving credentials
+from system-specific helpers, as well as prompting the user for
+usernames and passwords. The git-credential command exposes this
+interface to scripts which may want to retrieve, store, or prompt for
+credentials in the same manner as git. The design of this scriptable
+interface models the internal C API; see
+link:technical/api-credentials.txt[the git credential API] for more
+background on the concepts.
+
+git-credential takes an "action" option on the command-line (one of
+`fill`, `approve`, or `reject`) and reads a credential description
+on stdin (see <<IOFMT,INPUT/OUTPUT FORMAT>>).
+
+If the action is `fill`, git-credential will attempt to add "username"
+and "password" attributes to the description by reading config files,
+by contacting any configured credential helpers, or by prompting the
+user. The username and password attributes of the credential
+description are then printed to stdout together with the attributes
+already provided.
+
+If the action is `approve`, git-credential will send the description
+to any configured credential helpers, which may store the credential
+for later use.
+
+If the action is `reject`, git-credential will send the description to
+any configured credential helpers, which may erase any stored
+credential matching the description.
+
+If the action is `approve` or `reject`, no output should be emitted.
+
+TYPICAL USE OF GIT CREDENTIAL
+-----------------------------
+
+An application using git-credential will typically use `git
+credential` following these steps:
+
+ 1. Generate a credential description based on the context.
++
+For example, if we want a password for
+`https://example.com/foo.git`, we might generate the following
+credential description (don't forget the blank line at the end; it
+tells `git credential` that the application finished feeding all the
+infomation it has):
+
+ protocol=https
+ host=example.com
+ path=foo.git
+
+ 2. Ask git-credential to give us a username and password for this
+ description. This is done by running `git credential fill`,
+ feeding the description from step (1) to its standard input. The complete
+ credential description (including the credential per se, i.e. the
+ login and password) will be produced on standard output, like:
+
+ protocol=https
+ host=example.com
+ username=bob
+ password=secr3t
++
+In most cases, this means the attributes given in the input will be
+repeated in the output, but git may also modify the credential
+description, for example by removing the `path` attribute when the
+protocol is HTTP(s) and `credential.useHttpPath` is false.
++
+If the `git credential` knew about the password, this step may
+not have involved the user actually typing this password (the
+user may have typed a password to unlock the keychain instead,
+or no user interaction was done if the keychain was already
+unlocked) before it returned `password=secr3t`.
+
+ 3. Use the credential (e.g., access the URL with the username and
+ password from step (2)), and see if it's accepted.
+
+ 4. Report on the success or failure of the password. If the
+ credential allowed the operation to complete successfully, then
+ it can be marked with an "approve" action to tell `git
+ credential` to reuse it in its next invocation. If the credential
+ was rejected during the operation, use the "reject" action so
+ that `git credential` will ask for a new password in its next
+ invocation. In either case, `git credential` should be fed with
+ the credential description obtained from step (2) (which also
+ contain the ones provided in step (1)).
+
+[[IOFMT]]
+INPUT/OUTPUT FORMAT
+-------------------
+
+`git credential` reads and/or writes (depending on the action used)
+credential information in its standard input/output. This information
+can correspond either to keys for which `git credential` will obtain
+the login/password information (e.g. host, protocol, path), or to the
+actual credential data to be obtained (login/password).
+
+The credential is split into a set of named attributes, with one
+attribute per line. Each attribute is
+specified by a key-value pair, separated by an `=` (equals) sign,
+followed by a newline. The key may contain any bytes except `=`,
+newline, or NUL. The value may contain any bytes except newline or NUL.
+In both cases, all bytes are treated as-is (i.e., there is no quoting,
+and one cannot transmit a value with newline or NUL in it). The list of
+attributes is terminated by a blank line or end-of-file.
+Git understands the following attributes:
+
+`protocol`::
+
+ The protocol over which the credential will be used (e.g.,
+ `https`).
+
+`host`::
+
+ The remote hostname for a network credential.
+
+`path`::
+
+ The path with which the credential will be used. E.g., for
+ accessing a remote https repository, this will be the
+ repository's path on the server.
+
+`username`::
+
+ The credential's username, if we already have one (e.g., from a
+ URL, from the user, or from a previously run helper).
+
+`password`::
+
+ The credential's password, if we are asking it to be stored.
+
+`url`::
+
+ When this special attribute is read by `git credential`, the
+ value is parsed as a URL and treated as if its constituent parts
+ were read (e.g., `url=https://example.com` would behave as if
+ `protocol=https` and `host=example.com` had been provided). This
+ can help callers avoid parsing URLs themselves. Note that any
+ components which are missing from the URL (e.g., there is no
+ username in the example above) will be set to empty; if you want
+ to provide a URL and override some attributes, provide the URL
+ attribute first, followed by any overrides.
diff --git a/Documentation/git-daemon.txt b/Documentation/git-daemon.txt
index e8f7577..7e5098a 100644
--- a/Documentation/git-daemon.txt
+++ b/Documentation/git-daemon.txt
@@ -16,6 +16,7 @@ SYNOPSIS
[--reuseaddr] [--detach] [--pid-file=<file>]
[--enable=<service>] [--disable=<service>]
[--allow-override=<service>] [--forbid-override=<service>]
+ [--access-hook=<path>]
[--inetd | [--listen=<host_or_ipaddr>] [--port=<n>] [--user=<user> [--group=<group>]]
[<directory>...]
@@ -171,6 +172,21 @@ the facility of inet daemon to achieve the same before spawning
errors are not enabled, all errors report "access denied" to the
client. The default is --no-informative-errors.
+--access-hook=<path>::
+ Every time a client connects, first run an external command
+ specified by the <path> with service name (e.g. "upload-pack"),
+ path to the repository, hostname (%H), canonical hostname
+ (%CH), ip address (%IP), and tcp port (%P) as its command line
+ arguments. The external command can decide to decline the
+ service by exiting with a non-zero status (or to allow it by
+ exiting with a zero status). It can also look at the $REMOTE_ADDR
+ and $REMOTE_PORT environment variables to learn about the
+ requestor when making this decision.
++
+The external command can optionally write a single line to its
+standard output to be sent to the requestor as an error message when
+it declines the service.
+
<directory>::
A directory to add to the whitelist of allowed directories. Unless
--strict-paths is specified this will also include subdirectories
diff --git a/Documentation/git-difftool.txt b/Documentation/git-difftool.txt
index 31fc2e3..73ca702 100644
--- a/Documentation/git-difftool.txt
+++ b/Documentation/git-difftool.txt
@@ -69,6 +69,14 @@ with custom merge tool commands and has the same value as `$MERGED`.
--tool-help::
Print a list of diff tools that may be used with `--tool`.
+--symlinks::
+--no-symlinks::
+ 'git difftool''s default behavior is create symlinks to the
+ working tree when run in `--dir-diff` mode.
++
+ Specifying `--no-symlinks` instructs 'git difftool' to create
+ copies instead. `--no-symlinks` is the default on Windows.
+
-x <command>::
--extcmd=<command>::
Specify a custom command for viewing diffs.
diff --git a/Documentation/git-fast-import.txt b/Documentation/git-fast-import.txt
index 2620d28..6603a7a 100644
--- a/Documentation/git-fast-import.txt
+++ b/Documentation/git-fast-import.txt
@@ -39,6 +39,10 @@ OPTIONS
See ``Date Formats'' below for details about which formats
are supported, and their syntax.
+-- done::
+ Terminate with error if there is no 'done' command at the
+ end of the stream.
+
--force::
Force updating modified existing branches, even if doing
so would cause commits to be lost (as the new commit does
@@ -1047,7 +1051,9 @@ done::
Error out if the stream ends without a 'done' command.
Without this feature, errors causing the frontend to end
abruptly at a convenient point in the stream can go
- undetected.
+ undetected. This may occur, for example, if an import
+ front end dies in mid-operation without emitting SIGTERM
+ or SIGKILL at its subordinate git fast-import instance.
`option`
~~~~~~~~
diff --git a/Documentation/git-filter-branch.txt b/Documentation/git-filter-branch.txt
index 15e7ac8..e2301f5 100644
--- a/Documentation/git-filter-branch.txt
+++ b/Documentation/git-filter-branch.txt
@@ -304,6 +304,11 @@ committed a merge between P1 and P2, it will be propagated properly
and all children of the merge will become merge commits with P1,P2
as their parents instead of the merge commit.
+*NOTE* the changes introduced by the commits, and which are not reverted
+by subsequent commits, will still be in the rewritten branch. If you want
+to throw out _changes_ together with the commits, you should use the
+interactive mode of 'git rebase'.
+
You can rewrite the commit log messages using `--msg-filter`. For
example, 'git svn-id' strings in a repository created by 'git svn' can
be removed this way:
@@ -314,11 +319,6 @@ git filter-branch --msg-filter '
'
-------------------------------------------------------
-To restrict rewriting to only part of the history, specify a revision
-range in addition to the new branch name. The new branch name will
-point to the top-most revision that a 'git rev-list' of this range
-will print.
-
If you need to add 'Acked-by' lines to, say, the last 10 commits (none
of which is a merge), use this command:
@@ -329,11 +329,10 @@ git filter-branch --msg-filter '
' HEAD~10..HEAD
--------------------------------------------------------
-*NOTE* the changes introduced by the commits, and which are not reverted
-by subsequent commits, will still be in the rewritten branch. If you want
-to throw out _changes_ together with the commits, you should use the
-interactive mode of 'git rebase'.
-
+To restrict rewriting to only part of the history, specify a revision
+range in addition to the new branch name. The new branch name will
+point to the top-most revision that a 'git rev-list' of this range
+will print.
Consider this history:
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index c872b88..db55a4e 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -102,9 +102,10 @@ Fields that have name-email-date tuple as its value (`author`,
and `date` to extract the named component.
The complete message in a commit and tag object is `contents`.
-Its first line is `contents:subject`, the remaining lines
-are `contents:body` and the optional GPG signature
-is `contents:signature`.
+Its first line is `contents:subject`, where subject is the concatenation
+of all lines of the commit message up to the first blank line. The next
+line is 'contents:body', where body is all of the lines after the first
+blank line. Finally, the optional GPG signature is `contents:signature`.
For sorting purposes, fields with numeric values sort in numeric
order (`objectsize`, `authordate`, `committerdate`, `taggerdate`).
diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt
index 04c7346..6d43f56 100644
--- a/Documentation/git-format-patch.txt
+++ b/Documentation/git-format-patch.txt
@@ -58,10 +58,13 @@ output, unless the `--stdout` option is specified.
If `-o` is specified, output files are created in <dir>. Otherwise
they are created in the current working directory.
-By default, the subject of a single patch is "[PATCH] First Line" and
-the subject when multiple patches are output is "[PATCH n/m] First
-Line". To force 1/1 to be added for a single patch, use `-n`. To omit
-patch numbers from the subject, use `-N`.
+By default, the subject of a single patch is "[PATCH] " followed by
+the concatenation of lines from the commit message up to the first blank
+line (see the DISCUSSION section of linkgit:git-commit[1]).
+
+When multiple patches are output, the subject prefix will instead be
+"[PATCH n/m] ". To force 1/1 to be added for a single patch, use `-n`.
+To omit patch numbers from the subject, use `-N`.
If given `--thread`, `git-format-patch` will generate `In-Reply-To` and
`References` headers to make the second and subsequent patch mails appear
diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt
index 3bec036..cfecf84 100644
--- a/Documentation/git-grep.txt
+++ b/Documentation/git-grep.txt
@@ -42,8 +42,16 @@ CONFIGURATION
grep.lineNumber::
If set to true, enable '-n' option by default.
+grep.patternType::
+ Set the default matching behavior. Using a value of 'basic', 'extended',
+ 'fixed', or 'perl' will enable the '--basic-regexp', '--extended-regexp',
+ '--fixed-strings', or '--perl-regexp' option accordingly, while the
+ value 'default' will return to the default matching behavior.
+
grep.extendedRegexp::
- If set to true, enable '--extended-regexp' option by default.
+ If set to true, enable '--extended-regexp' option by default. This
+ option is ignored when the 'grep.patternType' option is set to a value
+ other than 'default'.
OPTIONS
diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt
index 1f90620..585dac4 100644
--- a/Documentation/git-log.txt
+++ b/Documentation/git-log.txt
@@ -24,10 +24,6 @@ each commit introduces are shown.
OPTIONS
-------
--<n>::
- Limits the number of commits to show.
- Note that this is a commit limiting option, see below.
-
<since>..<until>::
Show only commits between the named two commits. When
either <since> or <until> is omitted, it defaults to
@@ -137,6 +133,8 @@ Examples
This makes sense only when following a strict policy of merging all
topic branches when staying on a single integration branch.
+`git log -3`::
+ Limits the number of commits to show to 3.
Discussion
----------
diff --git a/Documentation/git-ls-remote.txt b/Documentation/git-ls-remote.txt
index 7a9b86a..774de5e 100644
--- a/Documentation/git-ls-remote.txt
+++ b/Documentation/git-ls-remote.txt
@@ -42,6 +42,11 @@ OPTIONS
it successfully talked with the remote repository, whether it
found any matching refs.
+--get-url::
+ Expand the URL of the given remote repository taking into account any
+ "url.<base>.insteadOf" config setting (See linkgit:git-config[1]) and
+ exit without talking to the remote.
+
<repository>::
Location of the repository. The shorthand defined in
$GIT_DIR/branches/ can be used. Use "." (dot) to list references in
diff --git a/Documentation/git-merge-base.txt b/Documentation/git-merge-base.txt
index b295bf8..87842e3 100644
--- a/Documentation/git-merge-base.txt
+++ b/Documentation/git-merge-base.txt
@@ -11,6 +11,7 @@ SYNOPSIS
[verse]
'git merge-base' [-a|--all] <commit> <commit>...
'git merge-base' [-a|--all] --octopus <commit>...
+'git merge-base' --is-ancestor <commit> <commit>
'git merge-base' --independent <commit>...
DESCRIPTION
@@ -50,6 +51,12 @@ from linkgit:git-show-branch[1] when used with the `--merge-base` option.
from any other. This mimics the behavior of 'git show-branch
--independent'.
+--is-ancestor::
+ Check if the first <commit> is an ancestor of the second <commit>,
+ and exit with status 0 if true, or with status 1 if not.
+ Errors are signaled by a non-zero status that is not 1.
+
+
OPTIONS
-------
-a::
@@ -110,6 +117,27 @@ both '1' and '2' are merge-bases of A and B. Neither one is better than
the other (both are 'best' merge bases). When the `--all` option is not given,
it is unspecified which best one is output.
+A common idiom to check "fast-forward-ness" between two commits A
+and B is (or at least used to be) to compute the merge base between
+A and B, and check if it is the same as A, in which case, A is an
+ancestor of B. You will see this idiom used often in older scripts.
+
+ A=$(git rev-parse --verify A)
+ if test "$A" = "$(git merge-base A B)"
+ then
+ ... A is an ancestor of B ...
+ fi
+
+In modern git, you can say this in a more direct way:
+
+ if git merge-base --is-ancestor A B
+ then
+ ... A is an ancestor of B ...
+ fi
+
+instead.
+
+
See also
--------
linkgit:git-rev-list[1],
diff --git a/Documentation/git-mergetool.txt b/Documentation/git-mergetool.txt
index d7207bd..6b563c5 100644
--- a/Documentation/git-mergetool.txt
+++ b/Documentation/git-mergetool.txt
@@ -64,6 +64,9 @@ variable `mergetool.<tool>.trustExitCode` can be set to `true`.
Otherwise, 'git mergetool' will prompt the user to indicate the
success of the resolution after the custom tool has exited.
+--tool-help::
+ Print a list of merge tools that may be used with `--tool`.
+
-y::
--no-prompt::
Don't prompt before each invocation of the merge resolution
diff --git a/Documentation/git-p4.txt b/Documentation/git-p4.txt
index fe1f49b..beff622 100644
--- a/Documentation/git-p4.txt
+++ b/Documentation/git-p4.txt
@@ -163,7 +163,7 @@ All commands except clone accept these options.
--git-dir <dir>::
Set the 'GIT_DIR' environment variable. See linkgit:git[1].
---verbose::
+--verbose, -v::
Provide more progress information.
Sync options
@@ -255,7 +255,7 @@ These options can be used to modify 'git p4 submit' behavior.
p4. By default, this is the most recent p4 commit reachable
from 'HEAD'.
--M[<n>]::
+-M::
Detect renames. See linkgit:git-diff[1]. Renames will be
represented in p4 using explicit 'move' operations. There
is no corresponding option to detect copies, but there are
@@ -269,6 +269,24 @@ These options can be used to modify 'git p4 submit' behavior.
Export tags from git as p4 labels. Tags found in git are applied
to the perforce working directory.
+--dry-run, -n::
+ Show just what commits would be submitted to p4; do not change
+ state in git or p4.
+
+--prepare-p4-only::
+ Apply a commit to the p4 workspace, opening, adding and deleting
+ files in p4 as for a normal submit operation. Do not issue the
+ final "p4 submit", but instead print a message about how to
+ submit manually or revert. This option always stops after the
+ first (oldest) commit. Git tags are not exported to p4.
+
+--conflict=(ask|skip|quit)::
+ Conflicts can occur when applying a commit to p4. When this
+ happens, the default behavior ("ask") is to prompt whether to
+ skip this commit and continue, or quit. This option can be used
+ to bypass the prompt, causing conflicting commits to be automatically
+ skipped, or to quit trying to apply commits, without prompting.
+
Rebase options
~~~~~~~~~~~~~~
These options can be used to modify 'git p4 rebase' behavior.
@@ -465,13 +483,15 @@ git-p4.useClientSpec::
Submit variables
~~~~~~~~~~~~~~~~
git-p4.detectRenames::
- Detect renames. See linkgit:git-diff[1].
+ Detect renames. See linkgit:git-diff[1]. This can be true,
+ false, or a score as expected by 'git diff -M'.
git-p4.detectCopies::
- Detect copies. See linkgit:git-diff[1].
+ Detect copies. See linkgit:git-diff[1]. This can be true,
+ false, or a score as expected by 'git diff -C'.
git-p4.detectCopiesHarder::
- Detect copies harder. See linkgit:git-diff[1].
+ Detect copies harder. See linkgit:git-diff[1]. A boolean.
git-p4.preserveUser::
On submit, re-author changes to reflect the git author,
@@ -517,6 +537,10 @@ git-p4.labelExportRegexp::
Only p4 labels matching this regular expression will be exported. The
default value is '[a-zA-Z0-9_\-.]+$'.
+git-p4.conflict::
+ Specify submit behavior when a conflict with p4 is found, as per
+ --conflict. The default behavior is 'ask'.
+
IMPLEMENTATION DETAILS
----------------------
* Changesets from p4 are imported using git fast-import.
diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt
index cb97cc1..22d2580 100644
--- a/Documentation/git-push.txt
+++ b/Documentation/git-push.txt
@@ -37,7 +37,9 @@ OPTIONS[[OPTIONS]]
`+`, followed by the source ref <src>, followed
by a colon `:`, followed by the destination ref <dst>.
It is used to specify with what <src> object the <dst> ref
- in the remote repository is to be updated.
+ in the remote repository is to be updated. If not specified,
+ the behavior of the command is controlled by the `push.default`
+ configuration variable.
+
The <src> is often the name of the branch you would want to push, but
it can be any arbitrary "SHA-1 expression", such as `master~4` or
@@ -65,7 +67,8 @@ directs git to push "matching" branches: for every branch that exists on
the local side, the remote side is updated if a branch of the same name
already exists on the remote side. This is the default operation mode
if no explicit refspec is found (that is neither on the command line
-nor in any Push line of the corresponding remotes file---see below).
+nor in any Push line of the corresponding remotes file---see below) and
+no `push.default` configuration variable is set.
--all::
Instead of naming each ref to push, specifies that all
@@ -357,7 +360,8 @@ Examples
`git push origin :`.
+
The default behavior of this command when no <refspec> is given can be
-configured by setting the `push` option of the remote.
+configured by setting the `push` option of the remote, or the `push.default`
+configuration variable.
+
For example, to default to pushing only the current branch to `origin`
use `git config remote.origin.push HEAD`. Any valid <refspec> (like
diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index feb51a6..da067ec 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -8,11 +8,11 @@ git-rebase - Forward-port local commits to the updated upstream head
SYNOPSIS
--------
[verse]
-'git rebase' [-i | --interactive] [options] [--onto <newbase>]
+'git rebase' [-i | --interactive] [options] [--exec <cmd>] [--onto <newbase>]
[<upstream>] [<branch>]
-'git rebase' [-i | --interactive] [options] --onto <newbase>
+'git rebase' [-i | --interactive] [options] [--exec <cmd>] [--onto <newbase>]
--root [<branch>]
-'git rebase' --continue | --skip | --abort
+'git rebase' --continue | --skip | --abort | --edit-todo
DESCRIPTION
-----------
@@ -210,7 +210,7 @@ rebase.autosquash::
OPTIONS
-------
-<newbase>::
+--onto <newbase>::
Starting point at which to create the new commits. If the
--onto option is not specified, the starting point is
<upstream>. May be any valid commit, and not just an
@@ -245,6 +245,9 @@ leave out at most one of A and B, in which case it defaults to HEAD.
--skip::
Restart the rebasing process by skipping the current patch.
+--edit-todo::
+ Edit the todo list during an interactive rebase.
+
-m::
--merge::
Use merging strategies to rebase. When the recursive (default) merge
@@ -344,14 +347,36 @@ This uses the `--interactive` machinery internally, but combining it
with the `--interactive` option explicitly is generally not a good
idea unless you know what you are doing (see BUGS below).
+-x <cmd>::
+--exec <cmd>::
+ Append "exec <cmd>" after each line creating a commit in the
+ final history. <cmd> will be interpreted as one or more shell
+ commands.
++
+This option can only be used with the `--interactive` option
+(see INTERACTIVE MODE below).
++
+You may execute several commands by either using one instance of `--exec`
+with several commands:
++
+ git rebase -i --exec "cmd1 && cmd2 && ..."
++
+or by giving more than one `--exec`:
++
+ git rebase -i --exec "cmd1" --exec "cmd2" --exec ...
++
+If `--autosquash` is used, "exec" lines will not be appended for
+the intermediate commits, and will only appear at the end of each
+squash/fixup series.
--root::
Rebase all commits reachable from <branch>, instead of
limiting them with an <upstream>. This allows you to rebase
- the root commit(s) on a branch. Must be used with --onto, and
+ the root commit(s) on a branch. When used with --onto, it
will skip changes already contained in <newbase> (instead of
- <upstream>). When used together with --preserve-merges, 'all'
- root commits will be rewritten to have <newbase> as parent
+ <upstream>) whereas without --onto it will operate on every change.
+ When used together with both --onto and --preserve-merges,
+ 'all' root commits will be rewritten to have <newbase> as parent
instead.
--autosquash::
@@ -521,6 +546,24 @@ in `$SHELL`, or the default shell if `$SHELL` is not set), so you can
use shell features (like "cd", ">", ";" ...). The command is run from
the root of the working tree.
+----------------------------------
+$ git rebase -i --exec "make test"
+----------------------------------
+
+This command lets you check that intermediate commits are compilable.
+The todo list becomes like that:
+
+--------------------
+pick 5928aea one
+exec make test
+pick 04d0fda two
+exec make test
+pick ba46169 three
+exec make test
+pick f4593f9 four
+exec make test
+--------------------
+
SPLITTING COMMITS
-----------------
diff --git a/Documentation/git-remote.txt b/Documentation/git-remote.txt
index a308f4c..e8c396b 100644
--- a/Documentation/git-remote.txt
+++ b/Documentation/git-remote.txt
@@ -12,7 +12,7 @@ SYNOPSIS
'git remote' [-v | --verbose]
'git remote add' [-t <branch>] [-m <master>] [-f] [--tags|--no-tags] [--mirror=<fetch|push>] <name> <url>
'git remote rename' <old> <new>
-'git remote rm' <name>
+'git remote remove' <name>
'git remote set-head' <name> (-a | -d | <branch>)
'git remote set-branches' [--add] <name> <branch>...
'git remote set-url' [--push] <name> <newurl> [<oldurl>]
@@ -85,6 +85,7 @@ In case <old> and <new> are the same, and <old> is a file under
`$GIT_DIR/remotes` or `$GIT_DIR/branches`, the remote is converted to
the configuration file format.
+'remove'::
'rm'::
Remove the remote named <name>. All remote-tracking branches and
diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt
index 4cc3e95..3c63561 100644
--- a/Documentation/git-rev-parse.txt
+++ b/Documentation/git-rev-parse.txt
@@ -101,6 +101,12 @@ OPTIONS
The option core.warnAmbiguousRefs is used to select the strict
abbreviation mode.
+--disambiguate=<prefix>::
+ Show every object whose name begins with the given prefix.
+ The <prefix> must be at least 4 hexadecimal digits long to
+ avoid listing each and every object in the repository by
+ mistake.
+
--all::
Show all refs found in `refs/`.
diff --git a/Documentation/git-shortlog.txt b/Documentation/git-shortlog.txt
index 01d8417..afeb4cd 100644
--- a/Documentation/git-shortlog.txt
+++ b/Documentation/git-shortlog.txt
@@ -14,8 +14,7 @@ git log --pretty=short | 'git shortlog' [-h] [-n] [-s] [-e] [-w]
DESCRIPTION
-----------
Summarizes 'git log' output in a format suitable for inclusion
-in release announcements. Each commit will be grouped by author and
-the first line of the commit message will be shown.
+in release announcements. Each commit will be grouped by author and title.
Additionally, "[PATCH]" will be stripped from the commit description.
diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
index 2de7bf0..b4683bb 100644
--- a/Documentation/git-submodule.txt
+++ b/Documentation/git-submodule.txt
@@ -112,7 +112,6 @@ status::
initialized, `+` if the currently checked out submodule commit
does not match the SHA-1 found in the index of the containing
repository and `U` if the submodule has merge conflicts.
- This command is the default command for 'git submodule'.
+
If `--recursive` is specified, this command will recurse into nested
submodules, and show their status as well.
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 65c37c4..d1d227a 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -22,18 +22,17 @@ unusually rich command set that provides both high-level operations
and full access to internals.
See linkgit:gittutorial[7] to get started, then see
-link:everyday.html[Everyday Git] for a useful minimum set of commands, and
-"man git-commandname" for documentation of each command. CVS users may
-also want to read linkgit:gitcvs-migration[7]. See
-the link:user-manual.html[Git User's Manual] for a more in-depth
-introduction.
+link:everyday.html[Everyday Git] for a useful minimum set of
+commands. The link:user-manual.html[Git User's Manual] has a more
+in-depth introduction.
-The '<command>' is either a name of a Git command (see below) or an alias
-as defined in the configuration file (see linkgit:git-config[1]).
+After you mastered the basic concepts, you can come back to this
+page to learn what commands git offers. You can learn more about
+individual git commands with "git help command". linkgit:gitcli[7]
+manual page gives you an overview of the command line command syntax.
-Formatted and hyperlinked version of the latest git
-documentation can be viewed at
-`http://www.kernel.org/pub/software/scm/git/docs/`.
+Formatted and hyperlinked version of the latest git documentation
+can be viewed at `http://git-htmldocs.googlecode.com/git/git.html`.
ifdef::stalenotes[]
[NOTE]
@@ -44,6 +43,14 @@ 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.12.3/git.html[documentation for release 1.7.12.3]
+
+* release notes for
+ link:RelNotes/1.7.12.3.txt[1.7.12.3],
+ link:RelNotes/1.7.12.2.txt[1.7.12.2],
+ link:RelNotes/1.7.12.1.txt[1.7.12.1],
+ link:RelNotes/1.7.12.txt[1.7.12].
+
* link:v1.7.11.7/git.html[documentation for release 1.7.11.7]
* release notes for
@@ -408,24 +415,6 @@ help ...`.
linkgit:git-replace[1] for more information.
-FURTHER DOCUMENTATION
----------------------
-
-See the references above to get started using git. The following is
-probably more detail than necessary for a first-time user.
-
-The link:user-manual.html#git-concepts[git concepts chapter of the
-user-manual] and linkgit:gitcore-tutorial[7] both provide
-introductions to the underlying git architecture.
-
-See linkgit:gitworkflows[7] for an overview of recommended workflows.
-
-See also the link:howto-index.html[howto] documents for some useful
-examples.
-
-The internals are documented in the
-link:technical/api-index.html[GIT API documentation].
-
GIT COMMANDS
------------
@@ -845,6 +834,29 @@ The index is also capable of storing multiple entries (called "stages")
for a given pathname. These stages are used to hold the various
unmerged version of a file when a merge is in progress.
+FURTHER DOCUMENTATION
+---------------------
+
+See the references in the "description" section to get started
+using git. The following is probably more detail than necessary
+for a first-time user.
+
+The link:user-manual.html#git-concepts[git concepts chapter of the
+user-manual] and linkgit:gitcore-tutorial[7] both provide
+introductions to the underlying git architecture.
+
+See linkgit:gitworkflows[7] for an overview of recommended workflows.
+
+See also the link:howto-index.html[howto] documents for some useful
+examples.
+
+The internals are documented in the
+link:technical/api-index.html[GIT API documentation].
+
+Users migrating from CVS may also want to
+read linkgit:gitcvs-migration[7].
+
+
Authors
-------
Git was started by Linus Torvalds, and is currently maintained by Junio
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index 80120ea..ba02d4d 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -66,6 +66,11 @@ is from the path in question, the lower its precedence). Finally
global and system-wide files are considered (they have the lowest
precedence).
+When the `.gitattributes` file is missing from the work tree, the
+path in the index is used as a fall-back. During checkout process,
+`.gitattributes` in the index is used and then the file in the
+working tree is used as a fall-back.
+
If you wish to affect only a single repository (i.e., to assign
attributes to files that are particular to
one user's workflow for that repository), then
@@ -75,6 +80,8 @@ repositories (i.e., attributes of interest to all users) should go into
`.gitattributes` files. Attributes that should affect all repositories
for a single user should be placed in a file specified by the
`core.attributesfile` configuration option (see linkgit:git-config[1]).
+Its default value is $XDG_CONFIG_HOME/git/attributes. If $XDG_CONFIG_HOME
+is either not set or empty, $HOME/.config/git/attributes is used instead.
Attributes for all users on a system should be placed in the
`$(prefix)/etc/gitattributes` file.
@@ -509,6 +516,8 @@ configuration file (you still need to enable this with the
attribute mechanism, via `.gitattributes`). The following built in
patterns are available:
+- `ada` suitable for source code in the Ada language.
+
- `bibtex` suitable for files with BibTeX coded references.
- `cpp` suitable for source code in the C and C++ languages.
@@ -925,7 +934,7 @@ file at the toplevel (i.e. not in any subdirectory). The built-in
macro attribute "binary" is equivalent to:
------------
-[attr]binary -diff -text
+[attr]binary -diff -merge -text
------------
diff --git a/Documentation/gitcore-tutorial.txt b/Documentation/gitcore-tutorial.txt
index 9d89336..5325c5a 100644
--- a/Documentation/gitcore-tutorial.txt
+++ b/Documentation/gitcore-tutorial.txt
@@ -956,12 +956,11 @@ $ git show-branch --topo-order --more=1 master mybranch
------------------------------------------------
The first two lines indicate that it is showing the two branches
-and the first line of the commit log message from their
-top-of-the-tree commits, you are currently on `master` branch
-(notice the asterisk `*` character), and the first column for
-the later output lines is used to show commits contained in the
+with the titles of their top-of-the-tree commits, you are currently on
+`master` branch (notice the asterisk `*` character), and the first
+column for the later output lines is used to show commits contained in the
`master` branch, and the second column for the `mybranch`
-branch. Three commits are shown along with their log messages.
+branch. Three commits are shown along with their titles.
All of them have non blank characters in the first column (`*`
shows an ordinary commit on the current branch, `-` is a merge commit), which
means they are now part of the `master` branch. Only the "Some
diff --git a/Documentation/gitignore.txt b/Documentation/gitignore.txt
index 2e7328b..96639e0 100644
--- a/Documentation/gitignore.txt
+++ b/Documentation/gitignore.txt
@@ -41,16 +41,24 @@ precedence, the last matching pattern decides the outcome):
variable 'core.excludesfile'.
Which file to place a pattern in depends on how the pattern is meant to
-be used. Patterns which should be version-controlled and distributed to
-other repositories via clone (i.e., files that all developers will want
-to ignore) should go into a `.gitignore` file. Patterns which are
-specific to a particular repository but which do not need to be shared
-with other related repositories (e.g., auxiliary files that live inside
-the repository but are specific to one user's workflow) should go into
-the `$GIT_DIR/info/exclude` file. Patterns which a user wants git to
-ignore in all situations (e.g., backup or temporary files generated by
-the user's editor of choice) generally go into a file specified by
-`core.excludesfile` in the user's `~/.gitconfig`.
+be used.
+
+ * Patterns which should be version-controlled and distributed to
+ other repositories via clone (i.e., files that all developers will want
+ to ignore) should go into a `.gitignore` file.
+
+ * Patterns which are
+ specific to a particular repository but which do not need to be shared
+ with other related repositories (e.g., auxiliary files that live inside
+ the repository but are specific to one user's workflow) should go into
+ the `$GIT_DIR/info/exclude` file.
+
+ * Patterns which a user wants git to
+ ignore in all situations (e.g., backup or temporary files generated by
+ the user's editor of choice) generally go into a file specified by
+ `core.excludesfile` in the user's `~/.gitconfig`. Its default value is
+ $XDG_CONFIG_HOME/git/ignore. If $XDG_CONFIG_HOME is either not set or
+ empty, $HOME/.config/git/ignore is used instead.
The underlying git plumbing tools, such as
'git ls-files' and 'git read-tree', read
diff --git a/Documentation/gittutorial.txt b/Documentation/gittutorial.txt
index dee0505..f1cb6f3 100644
--- a/Documentation/gittutorial.txt
+++ b/Documentation/gittutorial.txt
@@ -139,9 +139,11 @@ them to the index, and commit, all in one step.
A note on commit messages: Though not required, it's a good idea to
begin the commit message with a single short (less than 50 character)
line summarizing the change, followed by a blank line and then a more
-thorough description. Tools that turn commits into email, for
-example, use the first line on the Subject: line and the rest of the
-commit in the body.
+thorough description. The text up to the first blank line in a commit
+message is treated as the commit title, and that title is used
+throughout git. For example, linkgit:git-format-patch[1] turns a
+commit into email, and it uses the title on the Subject line and the
+rest of the commit in the body.
Git tracks content not files
----------------------------
diff --git a/Documentation/merge-strategies.txt b/Documentation/merge-strategies.txt
index 595a3cf..66db802 100644
--- a/Documentation/merge-strategies.txt
+++ b/Documentation/merge-strategies.txt
@@ -32,13 +32,14 @@ ours;;
This option forces conflicting hunks to be auto-resolved cleanly by
favoring 'our' version. Changes from the other tree that do not
conflict with our side are reflected to the merge result.
+ For a binary file, the entire contents are taken from our side.
+
This should not be confused with the 'ours' merge strategy, which does not
even look at what the other tree contains at all. It discards everything
the other tree did, declaring 'our' history contains all that happened in it.
theirs;;
- This is opposite of 'ours'.
+ This is the opposite of 'ours'.
patience;;
With this option, 'merge-recursive' spends a little extra time
diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
index e3d8a83..d9edded 100644
--- a/Documentation/pretty-formats.txt
+++ b/Documentation/pretty-formats.txt
@@ -130,6 +130,9 @@ The placeholders are:
- '%b': body
- '%B': raw body (unwrapped subject and body)
- '%N': commit notes
+- '%GG': raw verification message from GPG for a signed commit
+- '%G?': show either "G" for Good or "B" for Bad for a signed commit
+- '%GS': show the name of the signer for a signed commit
- '%gD': reflog selector, e.g., `refs/stash@{1}`
- '%gd': shortened reflog selector, e.g., `stash@{1}`
- '%gn': reflog identity name
diff --git a/Documentation/pretty-options.txt b/Documentation/pretty-options.txt
index 2a3dc86..5e49942 100644
--- a/Documentation/pretty-options.txt
+++ b/Documentation/pretty-options.txt
@@ -66,3 +66,7 @@ being displayed. Examples: "--notes=foo" will show only notes from
--[no-]standard-notes::
These options are deprecated. Use the above --notes/--no-notes
options instead.
+
+--show-signature::
+ Check the validity of a signed commit object by passing the signature
+ to `gpg --verify` and show the output.
diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt
index def1340..ee49743 100644
--- a/Documentation/rev-list-options.txt
+++ b/Documentation/rev-list-options.txt
@@ -3,12 +3,20 @@ Commit Limiting
Besides specifying a range of commits that should be listed using the
special notations explained in the description, additional commit
-limiting may be applied. Note that they are applied before commit
-ordering and formatting options, such as '--reverse'.
+limiting may be applied.
+
+Using more options generally further limits the output (e.g.
+`--since=<date1>` limits to commits newer than `<date1>`, and using it
+with `--grep=<pattern>` further limits to commits whose log message
+has a line that matches `<pattern>`), unless otherwise noted.
+
+Note that these are applied before commit
+ordering and formatting options, such as `--reverse`.
--
--n 'number'::
+-<number>::
+-n <number>::
--max-count=<number>::
Limit the number of commits to output.
@@ -38,16 +46,33 @@ endif::git-rev-list[]
--committer=<pattern>::
Limit the commits output to ones with author/committer
- header lines that match the specified pattern (regular expression).
+ header lines that match the specified pattern (regular
+ expression). With more than one `--author=<pattern>`,
+ commits whose author matches any of the given patterns are
+ chosen (similarly for multiple `--committer=<pattern>`).
+
+--grep-reflog=<pattern>::
+
+ Limit the commits output to ones with reflog entries that
+ match the specified pattern (regular expression). With
+ more than one `--grep-reflog`, commits whose reflog message
+ matches any of the given patterns are chosen. It is an
+ error to use this option unless `--walk-reflogs` is in use.
--grep=<pattern>::
Limit the commits output to ones with log message that
- matches the specified pattern (regular expression).
+ matches the specified pattern (regular expression). With
+ more than one `--grep=<pattern>`, commits whose message
+ matches any of the given patterns are chosen (but see
+ `--all-match`).
++
+When `--show-notes` is in effect, the message from the notes as
+if it is part of the log message.
--all-match::
Limit the commits output to ones that match all given --grep,
- --author and --committer instead of ones that match at least one.
+ instead of ones that match at least one.
-i::
--regexp-ignore-case::
@@ -636,10 +661,14 @@ These options are mostly targeted for packing of git repositories.
Only useful with '--objects'; print the object IDs that are not
in packs.
---no-walk::
+--no-walk[=(sorted|unsorted)]::
- Only show the given revs, but do not traverse their ancestors.
- This has no effect if a range is specified.
+ Only show the given commits, but do not traverse their ancestors.
+ This has no effect if a range is specified. If the argument
+ "unsorted" is given, the commits are show in the order they were
+ given on the command line. Otherwise (if "sorted" or no argument
+ was given), the commits are show in reverse chronological order
+ by commit time.
--do-walk::
diff --git a/Documentation/revisions.txt b/Documentation/revisions.txt
index 69d996b..991fcd8 100644
--- a/Documentation/revisions.txt
+++ b/Documentation/revisions.txt
@@ -55,6 +55,8 @@ when you run `git cherry-pick`.
+
Note that any of the 'refs/*' cases above may come either from
the '$GIT_DIR/refs' directory or from the '$GIT_DIR/packed-refs' file.
+While the ref name encoding is unspecified, UTF-8 is prefered as
+some output processing may assume ref names in UTF-8.
'<refname>@\{<date>\}', e.g. 'master@\{yesterday\}', 'HEAD@\{5 minutes ago\}'::
A ref followed by the suffix '@' with a date specification
diff --git a/Documentation/technical/api-argv-array.txt b/Documentation/technical/api-argv-array.txt
index 1b7d8f1..1a79781 100644
--- a/Documentation/technical/api-argv-array.txt
+++ b/Documentation/technical/api-argv-array.txt
@@ -46,6 +46,10 @@ Functions
Format a string and push it onto the end of the array. This is a
convenience wrapper combining `strbuf_addf` and `argv_array_push`.
+`argv_array_pop`::
+ Remove the final element from the array. If there are no
+ elements in the array, do nothing.
+
`argv_array_clear`::
Free all memory associated with the array and return it to the
initial, empty state.
diff --git a/Documentation/technical/api-credentials.txt b/Documentation/technical/api-credentials.txt
index adb6f0c..5977b58 100644
--- a/Documentation/technical/api-credentials.txt
+++ b/Documentation/technical/api-credentials.txt
@@ -241,42 +241,9 @@ appended to its command line, which is one of:
Remove a matching credential, if any, from the helper's storage.
The details of the credential will be provided on the helper's stdin
-stream. The credential is split into a set of named attributes.
-Attributes are provided to the helper, one per line. Each attribute is
-specified by a key-value pair, separated by an `=` (equals) sign,
-followed by a newline. The key may contain any bytes except `=`,
-newline, or NUL. The value may contain any bytes except newline or NUL.
-In both cases, all bytes are treated as-is (i.e., there is no quoting,
-and one cannot transmit a value with newline or NUL in it). The list of
-attributes is terminated by a blank line or end-of-file.
-
-Git will send the following attributes (but may not send all of
-them for a given credential; for example, a `host` attribute makes no
-sense when dealing with a non-network protocol):
-
-`protocol`::
-
- The protocol over which the credential will be used (e.g.,
- `https`).
-
-`host`::
-
- The remote hostname for a network credential.
-
-`path`::
-
- The path with which the credential will be used. E.g., for
- accessing a remote https repository, this will be the
- repository's path on the server.
-
-`username`::
-
- The credential's username, if we already have one (e.g., from a
- URL, from the user, or from a previously run helper).
-
-`password`::
-
- The credential's password, if we are asking it to be stored.
+stream. The exact format is the same as the input/output format of the
+`git credential` plumbing command (see the section `INPUT/OUTPUT
+FORMAT` in linkgit:git-credential[7] for a detailed specification).
For a `get` operation, the helper should produce a list of attributes
on stdout in the same format. A helper is free to produce a subset, or
diff --git a/Documentation/technical/api-sha1-array.txt b/Documentation/technical/api-sha1-array.txt
index 4a4bae8..45d1c51 100644
--- a/Documentation/technical/api-sha1-array.txt
+++ b/Documentation/technical/api-sha1-array.txt
@@ -25,9 +25,6 @@ Functions
the array (but note that some operations below may lose this
ordering).
-`sha1_array_sort`::
- Sort the elements in the array.
-
`sha1_array_lookup`::
Perform a binary search of the array for a specific sha1.
If found, returns the offset (in number of elements) of the
diff --git a/Documentation/technical/api-string-list.txt b/Documentation/technical/api-string-list.txt
index 5a0c14f..94d7a2b 100644
--- a/Documentation/technical/api-string-list.txt
+++ b/Documentation/technical/api-string-list.txt
@@ -1,8 +1,9 @@
string-list API
===============
-The string_list API offers a data structure and functions to handle sorted
-and unsorted string lists.
+The string_list API offers a data structure and functions to handle
+sorted and unsorted string lists. A "sorted" list is one whose
+entries are sorted by string value in `strcmp()` order.
The 'string_list' struct used to be called 'path_list', but was renamed
because it is not specific to paths.
@@ -20,8 +21,9 @@ If you need something advanced, you can manually malloc() the `items`
member (you need this if you add things later) and you should set the
`nr` and `alloc` members in that case, too.
-. Adds new items to the list, using `string_list_append` or
- `string_list_insert`.
+. Adds new items to the list, using `string_list_append`,
+ `string_list_append_nodup`, `string_list_insert`,
+ `string_list_split`, and/or `string_list_split_in_place`.
. Can check if a string is in the list using `string_list_has_string` or
`unsorted_string_list_has_string` and get it from the list using
@@ -29,18 +31,23 @@ member (you need this if you add things later) and you should set the
. Can sort an unsorted list using `sort_string_list`.
+. Can remove duplicate items from a sorted list using
+ `string_list_remove_duplicates`.
+
. Can remove individual items of an unsorted list using
`unsorted_string_list_delete_item`.
+. Can remove items not matching a criterion from a sorted or unsorted
+ list using `filter_string_list`.
+
. Finally it should free the list using `string_list_clear`.
Example:
----
-struct string_list list;
+struct string_list list = STRING_LIST_INIT_NODUP;
int i;
-memset(&list, 0, sizeof(struct string_list));
string_list_append(&list, "foo");
string_list_append(&list, "bar");
for (i = 0; i < list.nr; i++)
@@ -60,6 +67,22 @@ Functions
* General ones (works with sorted and unsorted lists as well)
+`filter_string_list`::
+
+ Apply a function to each item in a list, retaining only the
+ items for which the function returns true. If free_util is
+ true, call free() on the util members of any items that have
+ to be deleted. Preserve the order of the items that are
+ retained.
+
+`string_list_longest_prefix`::
+
+ Return the longest string within a string_list that is a
+ prefix (in the sense of prefixcmp()) of the specified string,
+ or NULL if no such prefix exists. This function does not
+ require the string_list to be sorted (it does a linear
+ search).
+
`print_string_list`::
Dump a string_list to stdout, useful mainly for debugging purposes. It
@@ -96,15 +119,32 @@ write `string_list_insert(...)->util = ...;`.
Look up a given string in the string_list, returning the containing
string_list_item. If the string is not found, NULL is returned.
+`string_list_remove_duplicates`::
+
+ Remove all but the first of consecutive entries that have the
+ same string value. If free_util is true, call free() on the
+ util members of any items that have to be deleted.
+
* Functions for unsorted lists only
`string_list_append`::
- Append a new string to the end of the string_list.
+ Append a new string to the end of the string_list. If
+ `strdup_string` is set, then the string argument is copied;
+ otherwise the new `string_list_entry` refers to the input
+ string.
+
+`string_list_append_nodup`::
+
+ Append a new string to the end of the string_list. The new
+ `string_list_entry` always refers to the input string, even if
+ `strdup_string` is set. This function can be used to hand
+ ownership of a malloc()ed string to a `string_list` that has
+ `strdup_string` set.
`sort_string_list`::
- Make an unsorted list sorted.
+ Sort the list's entries by string value in `strcmp()` order.
`unsorted_string_list_has_string`::
@@ -124,6 +164,25 @@ counterpart for sorted lists, which performs a binary search.
is set. The third parameter controls if the `util` pointer of the
items should be freed or not.
+`string_list_split`::
+`string_list_split_in_place`::
+
+ Split a string into substrings on a delimiter character and
+ append the substrings to a `string_list`. If `maxsplit` is
+ non-negative, then split at most `maxsplit` times. Return the
+ number of substrings appended to the list.
++
+`string_list_split` requires a `string_list` that has `strdup_strings`
+set to true; it leaves the input string untouched and makes copies of
+the substrings in newly-allocated memory.
+`string_list_split_in_place` requires a `string_list` that has
+`strdup_strings` set to false; it splits the input string in place,
+overwriting the delimiter characters with NULs and creating new
+string_list_items that point into the original string (the original
+string must therefore not be modified or freed while the `string_list`
+is in use).
+
+
Data structures
---------------
diff --git a/Documentation/technical/pack-protocol.txt b/Documentation/technical/pack-protocol.txt
index 49cdc57..d51e20f 100644
--- a/Documentation/technical/pack-protocol.txt
+++ b/Documentation/technical/pack-protocol.txt
@@ -259,8 +259,10 @@ a positive depth, this step is skipped.
----
If the client has requested a positive depth, the server will compute
-the set of commits which are no deeper than the desired depth, starting
-at the client's wants. The server writes 'shallow' lines for each
+the set of commits which are no deeper than the desired depth. The set
+of commits start at the client's wants.
+
+The server writes 'shallow' lines for each
commit whose parents will not be sent as a result. The server writes
an 'unshallow' line for each commit which the client has indicated is
shallow, but is no longer shallow at the currently requested depth
diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt
index 03d95dc..85651b5 100644
--- a/Documentation/user-manual.txt
+++ b/Documentation/user-manual.txt
@@ -1136,9 +1136,12 @@ Creating good commit messages
Though not required, it's a good idea to begin the commit message
with a single short (less than 50 character) line summarizing the
change, followed by a blank line and then a more thorough
-description. Tools that turn commits into email, for example, use
-the first line on the Subject line and the rest of the commit in the
-body.
+description. The text up to the first blank line in a commit
+message is treated as the commit title, and that title is used
+throughout git. For example, linkgit:git-format-patch[1] turns a
+commit into email, and it uses the title on the Subject line and the
+rest of the commit in the body.
+
[[ignoring-files]]
Ignoring files
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index 28f1290..88e4c21 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v1.7.11.7
+DEF_VER=v1.8.0-rc1
LF='
'
diff --git a/Makefile b/Makefile
index 13293d3..f69979e 100644
--- a/Makefile
+++ b/Makefile
@@ -90,6 +90,8 @@ all::
#
# Define NO_MKDTEMP if you don't have mkdtemp in the C library.
#
+# Define MKDIR_WO_TRAILING_SLASH if your mkdir() can't deal with trailing slash.
+#
# Define NO_MKSTEMPS if you don't have mkstemps in the C library.
#
# Define NO_STRTOK_R if you don't have strtok_r in the C library.
@@ -143,6 +145,12 @@ all::
#
# Define NEEDS_LIBICONV if linking with libc is not enough (Darwin).
#
+# Define NEEDS_LIBINTL_BEFORE_LIBICONV if you need libintl before libiconv.
+#
+# Define NO_INTPTR_T if you don't have intptr_t nor uintptr_t.
+#
+# Define NO_UINTMAX_T if you don't have uintmax_t.
+#
# Define NEEDS_SOCKET if linking with libc is not enough (SunOS,
# Patrick Mauritz).
#
@@ -152,11 +160,21 @@ all::
#
# Define NO_MMAP if you want to avoid mmap.
#
+# Define NO_SYS_POLL_H if you don't have sys/poll.h.
+#
+# Define NO_POLL if you do not have or don't want to use poll().
+# This also implies NO_SYS_POLL_H.
+#
# Define NO_PTHREADS if you do not have or do not want to use Pthreads.
#
# Define NO_PREAD if you have a problem with pread() system call (e.g.
# cygwin1.dll before v1.5.22).
#
+# Define NO_SETITIMER if you don't have setitimer()
+#
+# Define NO_STRUCT_ITIMERVAL if you don't have struct itimerval
+# This also implies NO_SETITIMER
+#
# Define NO_THREAD_SAFE_PREAD if your pread() implementation is not
# thread-safe. (e.g. compat/pread.c or cygwin)
#
@@ -205,8 +223,6 @@ all::
# Define NO_ST_BLOCKS_IN_STRUCT_STAT if your platform does not have st_blocks
# field that counts the on-disk footprint in 512-byte blocks.
#
-# Define ASCIIDOC7 if you want to format documentation with AsciiDoc 7
-#
# Define DOCBOOK_XSL_172 if you want to format man pages with DocBook XSL v1.72
# (not v1.73 or v1.71).
#
@@ -298,6 +314,13 @@ all::
# the diff algorithm. It gives a nice speedup if your processor has
# fast unaligned word loads. Does NOT work on big-endian systems!
# Enabled by default on x86_64.
+#
+# Define GIT_USER_AGENT if you want to change how git identifies itself during
+# network interactions. The default is "git/$(GIT_VERSION)".
+#
+# Define DEFAULT_HELP_FORMAT to "man", "info" or "html"
+# (defaults to "man") if you want to have a different default when
+# "git help" is called without a parameter specifying the format.
GIT-VERSION-FILE: FORCE
@$(SHELL_PATH) ./GIT-VERSION-GEN
@@ -391,12 +414,9 @@ BUILTIN_OBJS =
BUILT_INS =
COMPAT_CFLAGS =
COMPAT_OBJS =
-XDIFF_H =
XDIFF_OBJS =
-VCSSVN_H =
VCSSVN_OBJS =
-VCSSVN_TEST_OBJS =
-MISC_H =
+GENERATED_H =
EXTRA_CPPFLAGS =
LIB_H =
LIB_OBJS =
@@ -482,7 +502,6 @@ X =
PROGRAMS += $(patsubst %.o,git-%$X,$(PROGRAM_OBJS))
TEST_PROGRAMS_NEED_X += test-chmtime
-TEST_PROGRAMS_NEED_X += test-credential
TEST_PROGRAMS_NEED_X += test-ctype
TEST_PROGRAMS_NEED_X += test-date
TEST_PROGRAMS_NEED_X += test-delta
@@ -501,6 +520,7 @@ TEST_PROGRAMS_NEED_X += test-run-command
TEST_PROGRAMS_NEED_X += test-scrap-cache-tree
TEST_PROGRAMS_NEED_X += test-sha1
TEST_PROGRAMS_NEED_X += test-sigchain
+TEST_PROGRAMS_NEED_X += test-string-list
TEST_PROGRAMS_NEED_X += test-subprocess
TEST_PROGRAMS_NEED_X += test-svn-fe
@@ -558,54 +578,47 @@ LIB_FILE=libgit.a
XDIFF_LIB=xdiff/lib.a
VCSSVN_LIB=vcs-svn/lib.a
-XDIFF_H += xdiff/xinclude.h
-XDIFF_H += xdiff/xmacros.h
-XDIFF_H += xdiff/xdiff.h
-XDIFF_H += xdiff/xtypes.h
-XDIFF_H += xdiff/xutils.h
-XDIFF_H += xdiff/xprepare.h
-XDIFF_H += xdiff/xdiffi.h
-XDIFF_H += xdiff/xemit.h
-
-VCSSVN_H += vcs-svn/line_buffer.h
-VCSSVN_H += vcs-svn/sliding_window.h
-VCSSVN_H += vcs-svn/repo_tree.h
-VCSSVN_H += vcs-svn/fast_export.h
-VCSSVN_H += vcs-svn/svndiff.h
-VCSSVN_H += vcs-svn/svndump.h
-
-MISC_H += bisect.h
-MISC_H += branch.h
-MISC_H += bundle.h
-MISC_H += common-cmds.h
-MISC_H += fetch-pack.h
-MISC_H += reachable.h
-MISC_H += send-pack.h
-MISC_H += shortlog.h
-MISC_H += tar.h
-MISC_H += thread-utils.h
-MISC_H += url.h
-MISC_H += walker.h
-MISC_H += wt-status.h
+LIB_H += xdiff/xinclude.h
+LIB_H += xdiff/xmacros.h
+LIB_H += xdiff/xdiff.h
+LIB_H += xdiff/xtypes.h
+LIB_H += xdiff/xutils.h
+LIB_H += xdiff/xprepare.h
+LIB_H += xdiff/xdiffi.h
+LIB_H += xdiff/xemit.h
+
+LIB_H += vcs-svn/line_buffer.h
+LIB_H += vcs-svn/sliding_window.h
+LIB_H += vcs-svn/repo_tree.h
+LIB_H += vcs-svn/fast_export.h
+LIB_H += vcs-svn/svndiff.h
+LIB_H += vcs-svn/svndump.h
+
+GENERATED_H += common-cmds.h
LIB_H += advice.h
LIB_H += archive.h
LIB_H += argv-array.h
LIB_H += attr.h
+LIB_H += bisect.h
LIB_H += blob.h
+LIB_H += branch.h
LIB_H += builtin.h
LIB_H += bulk-checkin.h
-LIB_H += cache.h
+LIB_H += bundle.h
LIB_H += cache-tree.h
+LIB_H += cache.h
LIB_H += color.h
+LIB_H += column.h
LIB_H += commit.h
LIB_H += compat/bswap.h
LIB_H += compat/cygwin.h
LIB_H += compat/mingw.h
LIB_H += compat/obstack.h
+LIB_H += compat/poll/poll.h
+LIB_H += compat/precompose_utf8.h
LIB_H += compat/terminal.h
LIB_H += compat/win32/dirent.h
-LIB_H += compat/win32/poll.h
LIB_H += compat/win32/pthread.h
LIB_H += compat/win32/syslog.h
LIB_H += connected.h
@@ -618,6 +631,7 @@ LIB_H += diff.h
LIB_H += diffcore.h
LIB_H += dir.h
LIB_H += exec_cmd.h
+LIB_H += fetch-pack.h
LIB_H += fmt-merge-msg.h
LIB_H += fsck.h
LIB_H += gettext.h
@@ -627,6 +641,7 @@ LIB_H += graph.h
LIB_H += grep.h
LIB_H += hash.h
LIB_H += help.h
+LIB_H += http.h
LIB_H += kwset.h
LIB_H += levenshtein.h
LIB_H += list-objects.h
@@ -636,19 +651,20 @@ LIB_H += mailmap.h
LIB_H += merge-file.h
LIB_H += merge-recursive.h
LIB_H += mergesort.h
-LIB_H += notes.h
LIB_H += notes-cache.h
LIB_H += notes-merge.h
+LIB_H += notes.h
LIB_H += object.h
-LIB_H += pack.h
LIB_H += pack-refs.h
LIB_H += pack-revindex.h
+LIB_H += pack.h
LIB_H += parse-options.h
LIB_H += patch-ids.h
LIB_H += pkt-line.h
LIB_H += progress.h
LIB_H += prompt.h
LIB_H += quote.h
+LIB_H += reachable.h
LIB_H += reflog-walk.h
LIB_H += refs.h
LIB_H += remote.h
@@ -656,9 +672,11 @@ LIB_H += rerere.h
LIB_H += resolve-undo.h
LIB_H += revision.h
LIB_H += run-command.h
+LIB_H += send-pack.h
LIB_H += sequencer.h
LIB_H += sha1-array.h
LIB_H += sha1-lookup.h
+LIB_H += shortlog.h
LIB_H += sideband.h
LIB_H += sigchain.h
LIB_H += strbuf.h
@@ -666,14 +684,18 @@ LIB_H += streaming.h
LIB_H += string-list.h
LIB_H += submodule.h
LIB_H += tag.h
+LIB_H += tar.h
LIB_H += thread-utils.h
LIB_H += transport.h
-LIB_H += tree.h
LIB_H += tree-walk.h
+LIB_H += tree.h
LIB_H += unpack-trees.h
+LIB_H += url.h
LIB_H += userdiff.h
LIB_H += utf8.h
LIB_H += varint.h
+LIB_H += walker.h
+LIB_H += wt-status.h
LIB_H += xdiff-interface.h
LIB_H += xdiff/xdiff.h
@@ -802,6 +824,7 @@ LIB_OBJS += usage.o
LIB_OBJS += userdiff.o
LIB_OBJS += utf8.o
LIB_OBJS += varint.o
+LIB_OBJS += version.o
LIB_OBJS += walker.o
LIB_OBJS += wrapper.o
LIB_OBJS += write_or_die.o
@@ -830,6 +853,7 @@ BUILTIN_OBJS += builtin/commit-tree.o
BUILTIN_OBJS += builtin/commit.o
BUILTIN_OBJS += builtin/config.o
BUILTIN_OBJS += builtin/count-objects.o
+BUILTIN_OBJS += builtin/credential.o
BUILTIN_OBJS += builtin/describe.o
BUILTIN_OBJS += builtin/diff-files.o
BUILTIN_OBJS += builtin/diff-index.o
@@ -907,6 +931,8 @@ BUILTIN_OBJS += builtin/write-tree.o
GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
EXTLIBS =
+GIT_USER_AGENT = git/$(GIT_VERSION)
+
#
# Platform specific tweaks
#
@@ -993,6 +1019,8 @@ ifeq ($(uname_S),Darwin)
NO_MEMMEM = YesPlease
USE_ST_TIMESPEC = YesPlease
HAVE_DEV_TTY = YesPlease
+ COMPAT_OBJS += compat/precompose_utf8.o
+ BASIC_CFLAGS += -DPRECOMPOSE_UNICODE
endif
ifeq ($(uname_S),SunOS)
NEEDS_SOCKET = YesPlease
@@ -1208,7 +1236,7 @@ ifeq ($(uname_S),Windows)
NO_PREAD = YesPlease
NEEDS_CRYPTO_WITH_SSL = YesPlease
NO_LIBGEN_H = YesPlease
- NO_SYS_POLL_H = YesPlease
+ NO_POLL = YesPlease
NO_SYMLINK_HEAD = YesPlease
NO_IPV6 = YesPlease
NO_UNIX_SOCKETS = YesPlease
@@ -1241,6 +1269,7 @@ ifeq ($(uname_S),Windows)
BLK_SHA1 = YesPlease
NO_POSIX_GOODIES = UnfortunatelyYes
NATIVE_CRLF = YesPlease
+ DEFAULT_HELP_FORMAT = html
CC = compat/vcbuild/scripts/clink.pl
AR = compat/vcbuild/scripts/lib.pl
@@ -1248,7 +1277,7 @@ ifeq ($(uname_S),Windows)
BASIC_CFLAGS = -nologo -I. -I../zlib -Icompat/vcbuild -Icompat/vcbuild/include -DWIN32 -D_CONSOLE -DHAVE_STRING_H -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE
COMPAT_OBJS = compat/msvc.o compat/winansi.o \
compat/win32/pthread.o compat/win32/syslog.o \
- compat/win32/poll.o compat/win32/dirent.o
+ compat/win32/dirent.o
COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/regex -Icompat/win32 -DSTRIP_EXTENSION=\".exe\"
BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRT.lib
EXTLIBS = user32.lib advapi32.lib shell32.lib wininet.lib ws2_32.lib
@@ -1298,12 +1327,67 @@ ifeq ($(uname_S),Minix)
NO_CURL =
NO_EXPAT =
endif
+ifeq ($(uname_S),NONSTOP_KERNEL)
+ # Needs some C99 features, "inline" is just one of them.
+ # INLINE='' would just replace one set of warnings with another and
+ # still not compile in c89 mode, due to non-const array initializations.
+ CC = cc -c99
+ # Disable all optimization, seems to result in bad code, with -O or -O2
+ # or even -O1 (default), /usr/local/libexec/git-core/git-pack-objects
+ # abends on "git push". Needs more investigation.
+ CFLAGS = -g -O0
+ # We'd want it to be here.
+ prefix = /usr/local
+ # Our's are in ${prefix}/bin (perl might also be in /usr/bin/perl).
+ PERL_PATH = ${prefix}/bin/perl
+ PYTHON_PATH = ${prefix}/bin/python
+
+ # As detected by './configure'.
+ # Missdetected, hence commented out, see below.
+ #NO_CURL = YesPlease
+ # Added manually, see above.
+ NEEDS_SSL_WITH_CURL = YesPlease
+ HAVE_LIBCHARSET_H = YesPlease
+ NEEDS_LIBICONV = YesPlease
+ NEEDS_LIBINTL_BEFORE_LIBICONV = YesPlease
+ NO_SYS_SELECT_H = UnfortunatelyYes
+ NO_D_TYPE_IN_DIRENT = YesPlease
+ NO_HSTRERROR = YesPlease
+ NO_STRCASESTR = YesPlease
+ NO_FNMATCH_CASEFOLD = YesPlease
+ NO_MEMMEM = YesPlease
+ NO_STRLCPY = YesPlease
+ NO_SETENV = YesPlease
+ NO_UNSETENV = YesPlease
+ NO_MKDTEMP = YesPlease
+ NO_MKSTEMPS = YesPlease
+ # Currently libiconv-1.9.1.
+ OLD_ICONV = UnfortunatelyYes
+ NO_REGEX = YesPlease
+ NO_PTHREADS = UnfortunatelyYes
+
+ # Not detected (nor checked for) by './configure'.
+ # We don't have SA_RESTART on NonStop, unfortunalety.
+ COMPAT_CFLAGS += -DSA_RESTART=0
+ # Apparently needed in compat/fnmatch/fnmatch.c.
+ COMPAT_CFLAGS += -DHAVE_STRING_H=1
+ NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
+ NO_NSEC = YesPlease
+ NO_PREAD = YesPlease
+ NO_MMAP = YesPlease
+ NO_POLL = YesPlease
+ NO_INTPTR_T = UnfortunatelyYes
+ # Bug report 10-120822-4477 submitted to HP NonStop development.
+ MKDIR_WO_TRAILING_SLASH = YesPlease
+ # RFE 10-120912-4693 submitted to HP NonStop development.
+ NO_SETITIMER = UnfortunatelyYes
+endif
ifneq (,$(findstring MINGW,$(uname_S)))
pathsep = ;
NO_PREAD = YesPlease
NEEDS_CRYPTO_WITH_SSL = YesPlease
NO_LIBGEN_H = YesPlease
- NO_SYS_POLL_H = YesPlease
+ NO_POLL = YesPlease
NO_SYMLINK_HEAD = YesPlease
NO_UNIX_SOCKETS = YesPlease
NO_SETENV = YesPlease
@@ -1338,7 +1422,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
COMPAT_OBJS += compat/mingw.o compat/winansi.o \
compat/win32/pthread.o compat/win32/syslog.o \
- compat/win32/poll.o compat/win32/dirent.o
+ compat/win32/dirent.o
EXTLIBS += -lws2_32
PTHREAD_LIBS =
X = .exe
@@ -1534,6 +1618,9 @@ ifdef NEEDS_LIBICONV
else
ICONV_LINK =
endif
+ ifdef NEEDS_LIBINTL_BEFORE_LIBICONV
+ ICONV_LINK += -lintl
+ endif
EXTLIBS += $(ICONV_LINK) -liconv
endif
ifdef NEEDS_LIBGEN
@@ -1592,6 +1679,11 @@ ifdef NO_GETTEXT
BASIC_CFLAGS += -DNO_GETTEXT
USE_GETTEXT_SCHEME ?= fallthrough
endif
+ifdef NO_POLL
+ NO_SYS_POLL_H = YesPlease
+ COMPAT_CFLAGS += -DNO_POLL -Icompat/poll
+ COMPAT_OBJS += compat/poll/poll.o
+endif
ifdef NO_STRCASESTR
COMPAT_CFLAGS += -DNO_STRCASESTR
COMPAT_OBJS += compat/strcasestr.o
@@ -1630,6 +1722,10 @@ ifdef NO_MKDTEMP
COMPAT_CFLAGS += -DNO_MKDTEMP
COMPAT_OBJS += compat/mkdtemp.o
endif
+ifdef MKDIR_WO_TRAILING_SLASH
+ COMPAT_CFLAGS += -DMKDIR_WO_TRAILING_SLASH
+ COMPAT_OBJS += compat/mkdir.o
+endif
ifdef NO_MKSTEMPS
COMPAT_CFLAGS += -DNO_MKSTEMPS
endif
@@ -1661,6 +1757,13 @@ endif
ifdef OBJECT_CREATION_USES_RENAMES
COMPAT_CFLAGS += -DOBJECT_CREATION_MODE=1
endif
+ifdef NO_STRUCT_ITIMERVAL
+ COMPAT_CFLAGS += -DNO_STRUCT_ITIMERVAL
+ NO_SETITIMER=YesPlease
+endif
+ifdef NO_SETITIMER
+ COMPAT_CFLAGS += -DNO_SETITIMER
+endif
ifdef NO_PREAD
COMPAT_CFLAGS += -DNO_PREAD
COMPAT_OBJS += compat/pread.o
@@ -1678,6 +1781,9 @@ endif
ifdef NO_IPV6
BASIC_CFLAGS += -DNO_IPV6
endif
+ifdef NO_INTPTR_T
+ COMPAT_CFLAGS += -DNO_INTPTR_T
+endif
ifdef NO_UINTMAX_T
BASIC_CFLAGS += -Duintmax_t=uint32_t
endif
@@ -1843,10 +1949,6 @@ ifndef V
endif
endif
-ifdef ASCIIDOC7
- export ASCIIDOC7
-endif
-
ifdef NO_INSTALL_HARDLINKS
export NO_INSTALL_HARDLINKS
endif
@@ -1924,6 +2026,18 @@ SHELL_PATH_CQ_SQ = $(subst ','\'',$(SHELL_PATH_CQ))
BASIC_CFLAGS += -DSHELL_PATH='$(SHELL_PATH_CQ_SQ)'
endif
+GIT_USER_AGENT_SQ = $(subst ','\'',$(GIT_USER_AGENT))
+GIT_USER_AGENT_CQ = "$(subst ",\",$(subst \,\\,$(GIT_USER_AGENT)))"
+GIT_USER_AGENT_CQ_SQ = $(subst ','\'',$(GIT_USER_AGENT_CQ))
+GIT-USER-AGENT: FORCE
+ @if test x'$(GIT_USER_AGENT_SQ)' != x"`cat GIT-USER-AGENT 2>/dev/null`"; then \
+ echo '$(GIT_USER_AGENT_SQ)' >GIT-USER-AGENT; \
+ fi
+
+ifdef DEFAULT_HELP_FORMAT
+BASIC_CFLAGS += -DDEFAULT_HELP_FORMAT='"$(DEFAULT_HELP_FORMAT)"'
+endif
+
ALL_CFLAGS += $(BASIC_CFLAGS)
ALL_LDFLAGS += $(BASIC_LDFLAGS)
@@ -1970,8 +2084,41 @@ shell_compatibility_test: please_set_SHELL_PATH_to_a_more_modern_shell
strip: $(PROGRAMS) git$X
$(STRIP) $(STRIP_OPTS) $(PROGRAMS) git$X
-git.o: common-cmds.h
-git.sp git.s git.o: EXTRA_CPPFLAGS = -DGIT_VERSION='"$(GIT_VERSION)"' \
+### Target-specific flags and dependencies
+
+# The generic compilation pattern rule and automatically
+# computed header dependencies (falling back to a dependency on
+# LIB_H) are enough to describe how most targets should be built,
+# but some targets are special enough to need something a little
+# different.
+#
+# - When a source file "foo.c" #includes a generated header file,
+# we need to list that dependency for the "foo.o" target.
+#
+# We also list it from other targets that are built from foo.c
+# like "foo.sp" and "foo.s", even though that is easy to forget
+# to do because the generated header is already present around
+# after a regular build attempt.
+#
+# - Some code depends on configuration kept in makefile
+# variables. The target-specific variable EXTRA_CPPFLAGS can
+# be used to convey that information to the C preprocessor
+# using -D options.
+#
+# The "foo.o" target should have a corresponding dependency on
+# a file that changes when the value of the makefile variable
+# changes. For example, targets making use of the
+# $(GIT_VERSION) variable depend on GIT-VERSION-FILE.
+#
+# Technically the ".sp" and ".s" targets do not need this
+# dependency because they are force-built, but they get the
+# same dependency for consistency. This way, you do not have to
+# know how each target is implemented. And it means the
+# dependencies here will not need to change if the force-build
+# details change some day.
+
+git.sp git.s git.o: GIT-PREFIX
+git.sp git.s git.o: EXTRA_CPPFLAGS = \
'-DGIT_HTML_PATH="$(htmldir_SQ)"' \
'-DGIT_MAN_PATH="$(mandir_SQ)"' \
'-DGIT_INFO_PATH="$(infodir_SQ)"'
@@ -1980,14 +2127,19 @@ git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ git.o \
$(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS)
-help.sp help.o: common-cmds.h
+help.sp help.s help.o: common-cmds.h
-builtin/help.sp builtin/help.o: common-cmds.h
+builtin/help.sp builtin/help.s builtin/help.o: common-cmds.h GIT-PREFIX
builtin/help.sp builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \
'-DGIT_HTML_PATH="$(htmldir_SQ)"' \
'-DGIT_MAN_PATH="$(mandir_SQ)"' \
'-DGIT_INFO_PATH="$(infodir_SQ)"'
+version.sp version.s version.o: GIT-VERSION-FILE GIT-USER-AGENT
+version.sp version.s version.o: EXTRA_CPPFLAGS = \
+ '-DGIT_VERSION="$(GIT_VERSION)"' \
+ '-DGIT_USER_AGENT=$(GIT_USER_AGENT_CQ_SQ)'
+
$(BUILT_INS): git$X
$(QUIET_BUILT_IN)$(RM) $@ && \
ln git$X $@ 2>/dev/null || \
@@ -1999,35 +2151,54 @@ common-cmds.h: ./generate-cmdlist.sh command-list.txt
common-cmds.h: $(wildcard Documentation/git-*.txt)
$(QUIET_GEN)./generate-cmdlist.sh > $@+ && mv $@+ $@
+SCRIPT_DEFINES = $(SHELL_PATH_SQ):$(DIFF_SQ):$(GIT_VERSION):\
+ $(localedir_SQ):$(NO_CURL):$(USE_GETTEXT_SCHEME):$(SANE_TOOL_PATH_SQ):\
+ $(gitwebdir_SQ):$(PERL_PATH_SQ)
define cmd_munge_script
$(RM) $@ $@+ && \
sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
-e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \
-e 's|@@DIFF@@|$(DIFF_SQ)|' \
- -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
-e 's|@@LOCALEDIR@@|$(localedir_SQ)|g' \
-e 's/@@NO_CURL@@/$(NO_CURL)/g' \
-e 's/@@USE_GETTEXT_SCHEME@@/$(USE_GETTEXT_SCHEME)/g' \
-e $(BROKEN_PATH_FIX) \
+ -e 's|@@GITWEBDIR@@|$(gitwebdir_SQ)|g' \
+ -e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \
$@.sh >$@+
endef
-$(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh
+GIT-SCRIPT-DEFINES: FORCE
+ @FLAGS='$(SCRIPT_DEFINES)'; \
+ if test x"$$FLAGS" != x"`cat $@ 2>/dev/null`" ; then \
+ echo 1>&2 " * new script parameters"; \
+ echo "$$FLAGS" >$@; \
+ fi
+
+
+$(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh GIT-SCRIPT-DEFINES
$(QUIET_GEN)$(cmd_munge_script) && \
chmod +x $@+ && \
mv $@+ $@
-$(SCRIPT_LIB) : % : %.sh
+$(SCRIPT_LIB) : % : %.sh GIT-SCRIPT-DEFINES
$(QUIET_GEN)$(cmd_munge_script) && \
mv $@+ $@
ifndef NO_PERL
$(patsubst %.perl,%,$(SCRIPT_PERL)): perl/perl.mak
-perl/perl.mak: GIT-CFLAGS perl/Makefile perl/Makefile.PL
+perl/perl.mak: perl/PM.stamp
+
+perl/PM.stamp: FORCE
+ $(QUIET_GEN)$(FIND) perl -type f -name '*.pm' | sort >$@+ && \
+ { cmp $@+ $@ >/dev/null 2>/dev/null || mv $@+ $@; } && \
+ $(RM) $@+
+
+perl/perl.mak: GIT-CFLAGS GIT-PREFIX perl/Makefile perl/Makefile.PL
$(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' $(@F)
-$(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl
+$(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl GIT-VERSION-FILE
$(QUIET_GEN)$(RM) $@ $@+ && \
INSTLIBDIR=`MAKEFLAGS= $(MAKE) -C perl -s --no-print-directory instlibdir` && \
sed -e '1{' \
@@ -2047,14 +2218,8 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl
gitweb:
$(QUIET_SUBDIR0)gitweb $(QUIET_SUBDIR1) all
-git-instaweb: git-instaweb.sh gitweb
- $(QUIET_GEN)$(RM) $@ $@+ && \
- sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
- -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
- -e 's/@@NO_CURL@@/$(NO_CURL)/g' \
- -e 's|@@GITWEBDIR@@|$(gitwebdir_SQ)|g' \
- -e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \
- $@.sh > $@+ && \
+git-instaweb: git-instaweb.sh gitweb GIT-SCRIPT-DEFINES
+ $(QUIET_GEN)$(cmd_munge_script) && \
chmod +x $@+ && \
mv $@+ $@
else # NO_PERL
@@ -2068,7 +2233,7 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)) git-instaweb: % : unimplemented.sh
endif # NO_PERL
ifndef NO_PYTHON
-$(patsubst %.py,%,$(SCRIPT_PYTHON)): GIT-CFLAGS
+$(patsubst %.py,%,$(SCRIPT_PYTHON)): GIT-CFLAGS GIT-PREFIX
$(patsubst %.py,%,$(SCRIPT_PYTHON)): % : %.py
$(QUIET_GEN)$(RM) $@ $@+ && \
INSTLIBDIR=`MAKEFLAGS= $(MAKE) -C git_remote_helpers -s \
@@ -2090,24 +2255,23 @@ $(patsubst %.py,%,$(SCRIPT_PYTHON)): % : unimplemented.sh
mv $@+ $@
endif # NO_PYTHON
-configure: configure.ac
+configure: configure.ac GIT-VERSION-FILE
$(QUIET_GEN)$(RM) $@ $<+ && \
sed -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
$< > $<+ && \
autoconf -o $@ $<+ && \
$(RM) $<+
-# These can record GIT_VERSION
-git.o git.spec http.o \
- $(patsubst %.sh,%,$(SCRIPT_SH)) \
- $(patsubst %.perl,%,$(SCRIPT_PERL)) \
- : GIT-VERSION-FILE
-
-TEST_OBJS := $(patsubst test-%$X,test-%.o,$(TEST_PROGRAMS))
-GIT_OBJS := $(LIB_OBJS) $(BUILTIN_OBJS) $(PROGRAM_OBJS) $(TEST_OBJS) \
- git.o
-ifndef NO_CURL
- GIT_OBJS += http.o http-walker.o remote-curl.o
+ifdef AUTOCONFIGURED
+config.status: configure
+ $(QUIET_GEN)if test -f config.status; then \
+ ./config.status --recheck; \
+ else \
+ ./configure; \
+ fi
+reconfigure config.mak.autogen: config.status
+ $(QUIET_GEN)./config.status
+.PHONY: reconfigure # This is a convenience target.
endif
XDIFF_OBJS += xdiff/xdiffi.o
@@ -2125,9 +2289,14 @@ VCSSVN_OBJS += vcs-svn/fast_export.o
VCSSVN_OBJS += vcs-svn/svndiff.o
VCSSVN_OBJS += vcs-svn/svndump.o
-VCSSVN_TEST_OBJS += test-line-buffer.o
-
-OBJECTS := $(GIT_OBJS) $(XDIFF_OBJS) $(VCSSVN_OBJS)
+TEST_OBJS := $(patsubst test-%$X,test-%.o,$(TEST_PROGRAMS))
+OBJECTS := $(LIB_OBJS) $(BUILTIN_OBJS) $(PROGRAM_OBJS) $(TEST_OBJS) \
+ $(XDIFF_OBJS) \
+ $(VCSSVN_OBJS) \
+ git.o
+ifndef NO_CURL
+ OBJECTS += http.o http-walker.o remote-curl.o
+endif
dep_files := $(foreach f,$(OBJECTS),$(dir $f).depend/$(notdir $f).d)
dep_dirs := $(addsuffix .depend,$(sort $(dir $(OBJECTS))))
@@ -2226,51 +2395,32 @@ else
# Dependencies on automatically generated headers such as common-cmds.h
# should _not_ be included here, since they are necessary even when
# building an object for the first time.
-#
-# XXX. Please check occasionally that these include all dependencies
-# gcc detects!
-
-$(GIT_OBJS): $(LIB_H)
-builtin/branch.o builtin/checkout.o builtin/clone.o builtin/reset.o branch.o transport.o: branch.h
-builtin/bundle.o bundle.o transport.o: bundle.h
-builtin/bisect--helper.o builtin/rev-list.o bisect.o: bisect.h
-builtin/clone.o builtin/fetch-pack.o transport.o: fetch-pack.h
-builtin/index-pack.o builtin/grep.o builtin/pack-objects.o transport-helper.o thread-utils.o: thread-utils.h
-builtin/send-pack.o transport.o: send-pack.h
-builtin/log.o builtin/shortlog.o: shortlog.h
-builtin/prune.o builtin/reflog.o reachable.o: reachable.h
-builtin/commit.o builtin/revert.o wt-status.o: wt-status.h
-builtin/tar-tree.o archive-tar.o: tar.h
-connect.o transport.o url.o http-backend.o: url.h
-builtin/branch.o builtin/commit.o builtin/tag.o column.o help.o pager.o: column.h
-http-fetch.o http-walker.o remote-curl.o transport.o walker.o: walker.h
-http.o http-walker.o http-push.o http-fetch.o remote-curl.o: http.h url.h
-xdiff-interface.o $(XDIFF_OBJS): $(XDIFF_H)
-
-$(VCSSVN_OBJS) $(VCSSVN_TEST_OBJS): $(LIB_H) $(VCSSVN_H)
+$(OBJECTS): $(LIB_H)
endif
+exec_cmd.sp exec_cmd.s exec_cmd.o: GIT-PREFIX
exec_cmd.sp exec_cmd.s exec_cmd.o: EXTRA_CPPFLAGS = \
'-DGIT_EXEC_PATH="$(gitexecdir_SQ)"' \
'-DBINDIR="$(bindir_relative_SQ)"' \
'-DPREFIX="$(prefix_SQ)"'
+builtin/init-db.sp builtin/init-db.s builtin/init-db.o: GIT-PREFIX
builtin/init-db.sp builtin/init-db.s builtin/init-db.o: EXTRA_CPPFLAGS = \
-DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"'
+config.sp config.s config.o: GIT-PREFIX
config.sp config.s config.o: EXTRA_CPPFLAGS = \
-DETC_GITCONFIG='"$(ETC_GITCONFIG_SQ)"'
+attr.sp attr.s attr.o: GIT-PREFIX
attr.sp attr.s attr.o: EXTRA_CPPFLAGS = \
-DETC_GITATTRIBUTES='"$(ETC_GITATTRIBUTES_SQ)"'
+gettext.sp gettext.s gettext.o: GIT-PREFIX
gettext.sp gettext.s gettext.o: EXTRA_CPPFLAGS = \
-DGIT_LOCALE_PATH='"$(localedir_SQ)"'
-http.sp http.s http.o: EXTRA_CPPFLAGS = \
- -DGIT_HTTP_USER_AGENT='"git/$(GIT_VERSION)"'
-
ifdef NO_EXPAT
http-walker.sp http-walker.s http-walker.o: EXTRA_CPPFLAGS = -DNO_EXPAT
endif
@@ -2342,9 +2492,10 @@ XGETTEXT_FLAGS = \
--from-code=UTF-8
XGETTEXT_FLAGS_C = $(XGETTEXT_FLAGS) --language=C \
--keyword=_ --keyword=N_ --keyword="Q_:1,2"
-XGETTEXT_FLAGS_SH = $(XGETTEXT_FLAGS) --language=Shell
+XGETTEXT_FLAGS_SH = $(XGETTEXT_FLAGS) --language=Shell \
+ --keyword=gettextln --keyword=eval_gettextln
XGETTEXT_FLAGS_PERL = $(XGETTEXT_FLAGS) --keyword=__ --language=Perl
-LOCALIZED_C := $(C_OBJ:o=c) $(LIB_H) $(XDIFF_H) $(VCSSVN_H) $(MISC_H)
+LOCALIZED_C := $(C_OBJ:o=c) $(LIB_H) $(GENERATED_H)
LOCALIZED_SH := $(SCRIPT_SH)
LOCALIZED_PERL := $(SCRIPT_PERL)
@@ -2391,14 +2542,22 @@ cscope:
$(FIND_SOURCE_FILES) | xargs cscope -b
### Detect prefix changes
-TRACK_CFLAGS = $(CC):$(subst ','\'',$(ALL_CFLAGS)):\
- $(bindir_SQ):$(gitexecdir_SQ):$(template_dir_SQ):$(prefix_SQ):\
- $(localedir_SQ):$(USE_GETTEXT_SCHEME)
+TRACK_PREFIX = $(bindir_SQ):$(gitexecdir_SQ):$(template_dir_SQ):$(prefix_SQ):\
+ $(localedir_SQ)
+
+GIT-PREFIX: FORCE
+ @FLAGS='$(TRACK_PREFIX)'; \
+ if test x"$$FLAGS" != x"`cat GIT-PREFIX 2>/dev/null`" ; then \
+ echo 1>&2 " * new prefix flags"; \
+ echo "$$FLAGS" >GIT-PREFIX; \
+ fi
+
+TRACK_CFLAGS = $(CC):$(subst ','\'',$(ALL_CFLAGS)):$(USE_GETTEXT_SCHEME)
GIT-CFLAGS: FORCE
@FLAGS='$(TRACK_CFLAGS)'; \
if test x"$$FLAGS" != x"`cat GIT-CFLAGS 2>/dev/null`" ; then \
- echo 1>&2 " * new build flags or prefix"; \
+ echo 1>&2 " * new build flags"; \
echo "$$FLAGS" >GIT-CFLAGS; \
fi
@@ -2477,6 +2636,7 @@ bin-wrappers/%: wrap-for-bin.sh
# with that.
export NO_SVN_TESTS
+export TEST_NO_MALLOC_CHECK
### Testing rules
@@ -2650,7 +2810,7 @@ quick-install-html:
### Maintainer's dist rules
-git.spec: git.spec.in
+git.spec: git.spec.in GIT-VERSION-FILE
sed -e 's/@@VERSION@@/$(GIT_VERSION)/g' < $< > $@+
mv $@+ $@
@@ -2700,6 +2860,9 @@ dist-doc:
distclean: clean
$(RM) configure
+ $(RM) config.log config.status config.cache
+ $(RM) config.mak.autogen config.mak.append
+ $(RM) -r autom4te.cache
profile-clean:
$(RM) $(addsuffix *.gcda,$(addprefix $(PROFILE_DIR)/, $(object_dirs)))
@@ -2714,8 +2877,6 @@ clean: profile-clean
$(RM) -r $(dep_dirs)
$(RM) -r po/build/
$(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h $(ETAGS_TARGET) tags cscope*
- $(RM) -r autom4te.cache
- $(RM) config.log config.mak.autogen config.mak.append config.status config.cache
$(RM) -r $(GIT_TARNAME) .doc-tmp-dir
$(RM) $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz
$(RM) $(htmldocs).tar.gz $(manpages).tar.gz
@@ -2734,6 +2895,7 @@ ifndef NO_TCLTK
$(MAKE) -C git-gui clean
endif
$(RM) GIT-VERSION-FILE GIT-CFLAGS GIT-LDFLAGS GIT-GUI-VARS GIT-BUILD-OPTIONS
+ $(RM) GIT-USER-AGENT GIT-PREFIX GIT-SCRIPT-DEFINES
.PHONY: all install profile-clean clean strip
.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
@@ -2741,8 +2903,13 @@ endif
### Check documentation
#
+ALL_COMMANDS = $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS)
+ALL_COMMANDS += git
+ALL_COMMANDS += gitk
+ALL_COMMANDS += gitweb
+ALL_COMMANDS += git-gui git-citool
check-docs::
- @(for v in $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) git gitk; \
+ @(for v in $(ALL_COMMANDS); \
do \
case "$$v" in \
git-merge-octopus | git-merge-ours | git-merge-recursive | \
@@ -2764,35 +2931,13 @@ check-docs::
sed -e '/^#/d' \
-e 's/[ ].*//' \
-e 's/^/listed /' command-list.txt; \
- ls -1 Documentation/git*txt | \
+ $(MAKE) -C Documentation print-man1 | \
+ grep '\.txt$$' | \
sed -e 's|Documentation/|documented |' \
-e 's/\.txt//'; \
) | while read how cmd; \
do \
- case "$$how,$$cmd" in \
- *,git-citool | \
- *,git-gui | \
- *,git-help | \
- documented,gitattributes | \
- documented,gitignore | \
- documented,gitmodules | \
- documented,gitcli | \
- documented,git-tools | \
- documented,gitcore-tutorial | \
- documented,gitcvs-migration | \
- documented,gitdiffcore | \
- documented,gitglossary | \
- documented,githooks | \
- documented,gitrepository-layout | \
- documented,gitrevisions | \
- documented,gittutorial | \
- documented,gittutorial-2 | \
- documented,git-bisect-lk2009 | \
- documented,git-remote-helpers | \
- documented,gitworkflows | \
- sentinel,not,matching,is,ok ) continue ;; \
- esac; \
- case " $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) git gitk " in \
+ case " $(ALL_COMMANDS) " in \
*" $$cmd "*) ;; \
*) echo "removed but $$how: $$cmd" ;; \
esac; \
diff --git a/RelNotes b/RelNotes
index 6205f6c..2484b38 120000
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/1.7.11.7.txt \ No newline at end of file
+Documentation/RelNotes/1.8.0.txt \ No newline at end of file
diff --git a/abspath.c b/abspath.c
index f04ac18..05f2d79 100644
--- a/abspath.c
+++ b/abspath.c
@@ -35,6 +35,9 @@ const char *real_path(const char *path)
if (path == buf || path == next_buf)
return path;
+ if (!*path)
+ die("The empty string is not a valid path");
+
if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)
die ("Too long path: %.*s", 60, path);
@@ -42,8 +45,8 @@ const char *real_path(const char *path)
if (!is_directory(buf)) {
char *last_slash = find_last_dir_sep(buf);
if (last_slash) {
- *last_slash = '\0';
last_elem = xstrdup(last_slash + 1);
+ last_slash[1] = '\0';
} else {
last_elem = xstrdup(buf);
*buf = '\0';
@@ -123,7 +126,9 @@ const char *absolute_path(const char *path)
{
static char buf[PATH_MAX + 1];
- if (is_absolute_path(path)) {
+ if (!*path) {
+ die("The empty string is not a valid path");
+ } else if (is_absolute_path(path)) {
if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)
die("Too long path: %.*s", 60, path);
} else {
diff --git a/archive-zip.c b/archive-zip.c
index f5af81f..55f66b4 100644
--- a/archive-zip.c
+++ b/archive-zip.c
@@ -4,6 +4,7 @@
#include "cache.h"
#include "archive.h"
#include "streaming.h"
+#include "utf8.h"
static int zip_date;
static int zip_time;
@@ -16,7 +17,8 @@ static unsigned int zip_dir_offset;
static unsigned int zip_dir_entries;
#define ZIP_DIRECTORY_MIN_SIZE (1024 * 1024)
-#define ZIP_STREAM (8)
+#define ZIP_STREAM (1 << 3)
+#define ZIP_UTF8 (1 << 11)
struct zip_local_header {
unsigned char magic[4];
@@ -74,6 +76,14 @@ struct zip_dir_trailer {
unsigned char _end[1];
};
+struct zip_extra_mtime {
+ unsigned char magic[2];
+ unsigned char extra_size[2];
+ unsigned char flags[1];
+ unsigned char mtime[4];
+ unsigned char _end[1];
+};
+
/*
* On ARM, padding is added at the end of the struct, so a simple
* sizeof(struct ...) reports two bytes more than the payload size
@@ -83,6 +93,9 @@ struct zip_dir_trailer {
#define ZIP_DATA_DESC_SIZE offsetof(struct zip_data_desc, _end)
#define ZIP_DIR_HEADER_SIZE offsetof(struct zip_dir_header, _end)
#define ZIP_DIR_TRAILER_SIZE offsetof(struct zip_dir_trailer, _end)
+#define ZIP_EXTRA_MTIME_SIZE offsetof(struct zip_extra_mtime, _end)
+#define ZIP_EXTRA_MTIME_PAYLOAD_SIZE \
+ (ZIP_EXTRA_MTIME_SIZE - offsetof(struct zip_extra_mtime, flags))
static void copy_le16(unsigned char *dest, unsigned int n)
{
@@ -164,6 +177,17 @@ static void set_zip_header_data_desc(struct zip_local_header *header,
copy_le32(header->size, size);
}
+static int has_only_ascii(const char *s)
+{
+ for (;;) {
+ int c = *s++;
+ if (c == '\0')
+ return 1;
+ if (!isascii(c))
+ return 0;
+ }
+}
+
#define STREAM_BUFFER_SIZE (1024 * 16)
static int write_zip_entry(struct archiver_args *args,
@@ -173,6 +197,7 @@ static int write_zip_entry(struct archiver_args *args,
{
struct zip_local_header header;
struct zip_dir_header dirent;
+ struct zip_extra_mtime extra;
unsigned long attr2;
unsigned long compressed_size;
unsigned long crc;
@@ -187,6 +212,13 @@ static int write_zip_entry(struct archiver_args *args,
crc = crc32(0, NULL, 0);
+ if (!has_only_ascii(path)) {
+ if (is_utf8(path))
+ flags |= ZIP_UTF8;
+ else
+ warning("Path is not valid UTF-8: %s", path);
+ }
+
if (pathlen > 0xffff) {
return error("path too long (%d chars, SHA1: %s): %s",
(int)pathlen, sha1_to_hex(sha1), path);
@@ -246,8 +278,13 @@ static int write_zip_entry(struct archiver_args *args,
}
}
+ copy_le16(extra.magic, 0x5455);
+ copy_le16(extra.extra_size, ZIP_EXTRA_MTIME_PAYLOAD_SIZE);
+ extra.flags[0] = 1; /* just mtime */
+ copy_le32(extra.mtime, args->time);
+
/* make sure we have enough free space in the dictionary */
- direntsize = ZIP_DIR_HEADER_SIZE + pathlen;
+ direntsize = ZIP_DIR_HEADER_SIZE + pathlen + ZIP_EXTRA_MTIME_SIZE;
while (zip_dir_size < zip_dir_offset + direntsize) {
zip_dir_size += ZIP_DIRECTORY_MIN_SIZE;
zip_dir = xrealloc(zip_dir, zip_dir_size);
@@ -263,7 +300,7 @@ static int write_zip_entry(struct archiver_args *args,
copy_le16(dirent.mdate, zip_date);
set_zip_dir_data_desc(&dirent, size, compressed_size, crc);
copy_le16(dirent.filename_length, pathlen);
- copy_le16(dirent.extra_length, 0);
+ copy_le16(dirent.extra_length, ZIP_EXTRA_MTIME_SIZE);
copy_le16(dirent.comment_length, 0);
copy_le16(dirent.disk, 0);
copy_le16(dirent.attr1, 0);
@@ -281,11 +318,13 @@ static int write_zip_entry(struct archiver_args *args,
else
set_zip_header_data_desc(&header, size, compressed_size, crc);
copy_le16(header.filename_length, pathlen);
- copy_le16(header.extra_length, 0);
+ copy_le16(header.extra_length, ZIP_EXTRA_MTIME_SIZE);
write_or_die(1, &header, ZIP_LOCAL_HEADER_SIZE);
zip_offset += ZIP_LOCAL_HEADER_SIZE;
write_or_die(1, path, pathlen);
zip_offset += pathlen;
+ write_or_die(1, &extra, ZIP_EXTRA_MTIME_SIZE);
+ zip_offset += ZIP_EXTRA_MTIME_SIZE;
if (stream && method == 0) {
unsigned char buf[STREAM_BUFFER_SIZE];
ssize_t readlen;
@@ -382,6 +421,8 @@ static int write_zip_entry(struct archiver_args *args,
zip_dir_offset += ZIP_DIR_HEADER_SIZE;
memcpy(zip_dir + zip_dir_offset, path, pathlen);
zip_dir_offset += pathlen;
+ memcpy(zip_dir + zip_dir_offset, &extra, ZIP_EXTRA_MTIME_SIZE);
+ zip_dir_offset += ZIP_EXTRA_MTIME_SIZE;
zip_dir_entries++;
return 0;
diff --git a/archive.c b/archive.c
index a484433..4666404 100644
--- a/archive.c
+++ b/archive.c
@@ -7,10 +7,10 @@
#include "unpack-trees.h"
static char const * const archive_usage[] = {
- "git archive [options] <tree-ish> [<path>...]",
- "git archive --list",
- "git archive --remote <repo> [--exec <cmd>] [options] <tree-ish> [<path>...]",
- "git archive --remote <repo> [--exec <cmd>] --list",
+ N_("git archive [options] <tree-ish> [<path>...]"),
+ N_("git archive --list"),
+ N_("git archive --remote <repo> [--exec <cmd>] [options] <tree-ish> [<path>...]"),
+ N_("git archive --remote <repo> [--exec <cmd>] --list"),
NULL
};
@@ -319,16 +319,16 @@ static int parse_archive_args(int argc, const char **argv,
int worktree_attributes = 0;
struct option opts[] = {
OPT_GROUP(""),
- OPT_STRING(0, "format", &format, "fmt", "archive format"),
- OPT_STRING(0, "prefix", &base, "prefix",
- "prepend prefix to each pathname in the archive"),
- OPT_STRING('o', "output", &output, "file",
- "write the archive to this file"),
+ OPT_STRING(0, "format", &format, N_("fmt"), N_("archive format")),
+ OPT_STRING(0, "prefix", &base, N_("prefix"),
+ N_("prepend prefix to each pathname in the archive")),
+ OPT_STRING('o', "output", &output, N_("file"),
+ N_("write the archive to this file")),
OPT_BOOL(0, "worktree-attributes", &worktree_attributes,
- "read .gitattributes in working directory"),
- OPT__VERBOSE(&verbose, "report archived files on stderr"),
- OPT__COMPR('0', &compression_level, "store only", 0),
- OPT__COMPR('1', &compression_level, "compress faster", 1),
+ N_("read .gitattributes in working directory")),
+ OPT__VERBOSE(&verbose, N_("report archived files on stderr")),
+ OPT__COMPR('0', &compression_level, N_("store only"), 0),
+ OPT__COMPR('1', &compression_level, N_("compress faster"), 1),
OPT__COMPR_HIDDEN('2', &compression_level, 2),
OPT__COMPR_HIDDEN('3', &compression_level, 3),
OPT__COMPR_HIDDEN('4', &compression_level, 4),
@@ -336,15 +336,15 @@ static int parse_archive_args(int argc, const char **argv,
OPT__COMPR_HIDDEN('6', &compression_level, 6),
OPT__COMPR_HIDDEN('7', &compression_level, 7),
OPT__COMPR_HIDDEN('8', &compression_level, 8),
- OPT__COMPR('9', &compression_level, "compress better", 9),
+ OPT__COMPR('9', &compression_level, N_("compress better"), 9),
OPT_GROUP(""),
OPT_BOOL('l', "list", &list,
- "list supported archive formats"),
+ N_("list supported archive formats")),
OPT_GROUP(""),
- OPT_STRING(0, "remote", &remote, "repo",
- "retrieve the archive from remote repository <repo>"),
- OPT_STRING(0, "exec", &exec, "cmd",
- "path to the remote git-upload-archive command"),
+ OPT_STRING(0, "remote", &remote, N_("repo"),
+ N_("retrieve the archive from remote repository <repo>")),
+ OPT_STRING(0, "exec", &exec, N_("command"),
+ N_("path to the remote git-upload-archive command")),
OPT_END()
};
diff --git a/argv-array.c b/argv-array.c
index 0b5f889..256741d 100644
--- a/argv-array.c
+++ b/argv-array.c
@@ -49,12 +49,21 @@ void argv_array_pushl(struct argv_array *array, ...)
va_end(ap);
}
+void argv_array_pop(struct argv_array *array)
+{
+ if (!array->argc)
+ return;
+ free((char *)array->argv[array->argc - 1]);
+ array->argv[array->argc - 1] = NULL;
+ array->argc--;
+}
+
void argv_array_clear(struct argv_array *array)
{
if (array->argv != empty_argv) {
int i;
for (i = 0; i < array->argc; i++)
- free((char **)array->argv[i]);
+ free((char *)array->argv[i]);
free(array->argv);
}
argv_array_init(array);
diff --git a/argv-array.h b/argv-array.h
index b93a69c..f4b9866 100644
--- a/argv-array.h
+++ b/argv-array.h
@@ -16,6 +16,7 @@ void argv_array_push(struct argv_array *, const char *);
__attribute__((format (printf,2,3)))
void argv_array_pushf(struct argv_array *, const char *fmt, ...);
void argv_array_pushl(struct argv_array *, ...);
+void argv_array_pop(struct argv_array *);
void argv_array_clear(struct argv_array *);
#endif /* ARGV_ARRAY_H */
diff --git a/attr.c b/attr.c
index 303751f..887a9ae 100644
--- a/attr.c
+++ b/attr.c
@@ -306,7 +306,7 @@ static void free_attr_elem(struct attr_stack *e)
}
static const char *builtin_attr[] = {
- "[attr]binary -diff -text",
+ "[attr]binary -diff -merge -text",
NULL,
};
@@ -352,8 +352,11 @@ static struct attr_stack *read_attr_from_file(const char *path, int macro_ok)
char buf[2048];
int lineno = 0;
- if (!fp)
+ if (!fp) {
+ if (errno != ENOENT && errno != ENOTDIR)
+ warn_on_inaccessible(path);
return NULL;
+ }
res = xcalloc(1, sizeof(*res));
while (fgets(buf, sizeof(buf), fp))
handle_attr_line(res, buf, path, ++lineno, macro_ok);
@@ -497,6 +500,7 @@ static int git_attr_system(void)
static void bootstrap_attr_stack(void)
{
struct attr_stack *elem;
+ char *xdg_attributes_file;
if (attr_stack)
return;
@@ -515,6 +519,10 @@ static void bootstrap_attr_stack(void)
}
}
+ if (!git_attributes_file) {
+ home_config_paths(NULL, &xdg_attributes_file, "attributes");
+ git_attributes_file = xdg_attributes_file;
+ }
if (git_attributes_file) {
elem = read_attr_from_file(git_attributes_file, 1);
if (elem) {
diff --git a/bisect.c b/bisect.c
index 48acf73..1aad49b 100644
--- a/bisect.c
+++ b/bisect.c
@@ -833,7 +833,7 @@ static int check_ancestors(const char *prefix)
*/
static void check_good_are_ancestors_of_bad(const char *prefix, int no_checkout)
{
- char *filename = xstrdup(git_path("BISECT_ANCESTORS_OK"));
+ char *filename = git_pathdup("BISECT_ANCESTORS_OK");
struct stat st;
int fd;
diff --git a/branch.c b/branch.c
index eccdaf9..2bef1e7 100644
--- a/branch.c
+++ b/branch.c
@@ -74,25 +74,33 @@ void install_branch_config(int flag, const char *local, const char *origin, cons
strbuf_addf(&key, "branch.%s.rebase", local);
git_config_set(key.buf, "true");
}
+ strbuf_release(&key);
if (flag & BRANCH_CONFIG_VERBOSE) {
- strbuf_reset(&key);
-
- strbuf_addstr(&key, origin ? "remote" : "local");
-
- /* Are we tracking a proper "branch"? */
- if (remote_is_branch) {
- strbuf_addf(&key, " branch %s", shortname);
- if (origin)
- strbuf_addf(&key, " from %s", origin);
- }
+ if (remote_is_branch && origin)
+ printf(rebasing ?
+ "Branch %s set up to track remote branch %s from %s by rebasing.\n" :
+ "Branch %s set up to track remote branch %s from %s.\n",
+ local, shortname, origin);
+ else if (remote_is_branch && !origin)
+ printf(rebasing ?
+ "Branch %s set up to track local branch %s by rebasing.\n" :
+ "Branch %s set up to track local branch %s.\n",
+ local, shortname);
+ else if (!remote_is_branch && origin)
+ printf(rebasing ?
+ "Branch %s set up to track remote ref %s by rebasing.\n" :
+ "Branch %s set up to track remote ref %s.\n",
+ local, remote);
+ else if (!remote_is_branch && !origin)
+ printf(rebasing ?
+ "Branch %s set up to track local ref %s by rebasing.\n" :
+ "Branch %s set up to track local ref %s.\n",
+ local, remote);
else
- strbuf_addf(&key, " ref %s", remote);
- printf("Branch %s set up to track %s%s.\n",
- local, key.buf,
- rebasing ? " by rebasing" : "");
+ die("BUG: impossible combination of %d and %p",
+ remote_is_branch, origin);
}
- strbuf_release(&key);
}
/*
diff --git a/builtin.h b/builtin.h
index dffb34e..95116b8 100644
--- a/builtin.h
+++ b/builtin.h
@@ -9,7 +9,6 @@
#define DEFAULT_MERGE_LOG_LEN 20
-extern const char git_version_string[];
extern const char git_usage_string[];
extern const char git_more_info_string[];
@@ -22,7 +21,6 @@ struct fmt_merge_msg_opts {
extern int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
struct fmt_merge_msg_opts *);
-extern void commit_notes(struct notes_tree *t, const char *msg);
struct notes_rewrite_cfg {
struct notes_tree **trees;
@@ -34,7 +32,6 @@ struct notes_rewrite_cfg {
int mode_from_env;
};
-combine_notes_fn parse_combine_notes_fn(const char *v);
struct notes_rewrite_cfg *init_copy_notes_for_rewrite(const char *cmd);
int copy_note_for_rewrite(struct notes_rewrite_cfg *c,
const unsigned char *from_obj, const unsigned char *to_obj);
@@ -68,6 +65,7 @@ extern int cmd_commit(int argc, const char **argv, const char *prefix);
extern int cmd_commit_tree(int argc, const char **argv, const char *prefix);
extern int cmd_config(int argc, const char **argv, const char *prefix);
extern int cmd_count_objects(int argc, const char **argv, const char *prefix);
+extern int cmd_credential(int argc, const char **argv, const char *prefix);
extern int cmd_describe(int argc, const char **argv, const char *prefix);
extern int cmd_diff_files(int argc, const char **argv, const char *prefix);
extern int cmd_diff_index(int argc, const char **argv, const char *prefix);
diff --git a/builtin/add.c b/builtin/add.c
index 89dce56..e664100 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -16,7 +16,7 @@
#include "bulk-checkin.h"
static const char * const builtin_add_usage[] = {
- "git add [options] [--] <filepattern>...",
+ N_("git add [options] [--] <filepattern>..."),
NULL
};
static int patch_interactive, add_interactive, edit_interactive;
@@ -260,7 +260,7 @@ int interactive_add(int argc, const char **argv, const char *prefix, int patch)
static int edit_patch(int argc, const char **argv, const char *prefix)
{
- char *file = xstrdup(git_path("ADD_EDIT.patch"));
+ char *file = git_pathdup("ADD_EDIT.patch");
const char *apply_argv[] = { "apply", "--recount", "--cached",
NULL, NULL };
struct child_process child;
@@ -303,6 +303,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix)
die (_("Could not apply '%s'"), file);
unlink(file);
+ free(file);
return 0;
}
@@ -315,19 +316,19 @@ static int verbose = 0, show_only = 0, ignored_too = 0, refresh_only = 0;
static int ignore_add_errors, addremove, intent_to_add, ignore_missing = 0;
static struct option builtin_add_options[] = {
- OPT__DRY_RUN(&show_only, "dry run"),
- OPT__VERBOSE(&verbose, "be verbose"),
+ OPT__DRY_RUN(&show_only, N_("dry run")),
+ OPT__VERBOSE(&verbose, N_("be verbose")),
OPT_GROUP(""),
- OPT_BOOLEAN('i', "interactive", &add_interactive, "interactive picking"),
- OPT_BOOLEAN('p', "patch", &patch_interactive, "select hunks interactively"),
- OPT_BOOLEAN('e', "edit", &edit_interactive, "edit current diff and apply"),
- OPT__FORCE(&ignored_too, "allow adding otherwise ignored files"),
- OPT_BOOLEAN('u', "update", &take_worktree_changes, "update tracked files"),
- OPT_BOOLEAN('N', "intent-to-add", &intent_to_add, "record only the fact that the path will be added later"),
- OPT_BOOLEAN('A', "all", &addremove, "add changes from all tracked and untracked files"),
- OPT_BOOLEAN( 0 , "refresh", &refresh_only, "don't add, only refresh the index"),
- OPT_BOOLEAN( 0 , "ignore-errors", &ignore_add_errors, "just skip files which cannot be added because of errors"),
- OPT_BOOLEAN( 0 , "ignore-missing", &ignore_missing, "check if - even missing - files are ignored in dry run"),
+ OPT_BOOLEAN('i', "interactive", &add_interactive, N_("interactive picking")),
+ OPT_BOOLEAN('p', "patch", &patch_interactive, N_("select hunks interactively")),
+ OPT_BOOLEAN('e', "edit", &edit_interactive, N_("edit current diff and apply")),
+ OPT__FORCE(&ignored_too, N_("allow adding otherwise ignored files")),
+ OPT_BOOLEAN('u', "update", &take_worktree_changes, N_("update tracked files")),
+ OPT_BOOLEAN('N', "intent-to-add", &intent_to_add, N_("record only the fact that the path will be added later")),
+ OPT_BOOLEAN('A', "all", &addremove, N_("add changes from all tracked and untracked files")),
+ OPT_BOOLEAN( 0 , "refresh", &refresh_only, N_("don't add, only refresh the index")),
+ OPT_BOOLEAN( 0 , "ignore-errors", &ignore_add_errors, N_("just skip files which cannot be added because of errors")),
+ OPT_BOOLEAN( 0 , "ignore-missing", &ignore_missing, N_("check if - even missing - files are ignored in dry run")),
OPT_END(),
};
diff --git a/builtin/apply.c b/builtin/apply.c
index d2180b0..156b3ce 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -16,6 +16,9 @@
#include "dir.h"
#include "diff.h"
#include "parse-options.h"
+#include "xdiff-interface.h"
+#include "ll-merge.h"
+#include "rerere.h"
/*
* --check turns on checking that the working tree matches the
@@ -46,6 +49,7 @@ static int apply_with_reject;
static int apply_verbosely;
static int allow_overlap;
static int no_add;
+static int threeway;
static const char *fake_ancestor;
static int line_termination = '\n';
static unsigned int p_context = UINT_MAX;
@@ -192,12 +196,17 @@ struct patch {
unsigned int is_copy:1;
unsigned int is_rename:1;
unsigned int recount:1;
+ unsigned int conflicted_threeway:1;
+ unsigned int direct_to_threeway:1;
struct fragment *fragments;
char *result;
size_t resultsize;
char old_sha1_prefix[41];
char new_sha1_prefix[41];
struct patch *next;
+
+ /* three-way fallback result */
+ unsigned char threeway_stage[3][20];
};
static void free_fragment_list(struct fragment *list)
@@ -370,8 +379,8 @@ static void prepare_image(struct image *image, char *buf, size_t len,
static void clear_image(struct image *image)
{
free(image->buf);
- image->buf = NULL;
- image->len = 0;
+ free(image->line_allocated);
+ memset(image, 0, sizeof(*image));
}
/* fmt must contain _one_ %s and no other substitution */
@@ -2954,20 +2963,17 @@ static int apply_fragments(struct image *img, struct patch *patch)
return 0;
}
-static int read_file_or_gitlink(struct cache_entry *ce, struct strbuf *buf)
+static int read_blob_object(struct strbuf *buf, const unsigned char *sha1, unsigned mode)
{
- if (!ce)
- return 0;
-
- if (S_ISGITLINK(ce->ce_mode)) {
+ if (S_ISGITLINK(mode)) {
strbuf_grow(buf, 100);
- strbuf_addf(buf, "Subproject commit %s\n", sha1_to_hex(ce->sha1));
+ strbuf_addf(buf, "Subproject commit %s\n", sha1_to_hex(sha1));
} else {
enum object_type type;
unsigned long sz;
char *result;
- result = read_sha1_file(ce->sha1, &type, &sz);
+ result = read_sha1_file(sha1, &type, &sz);
if (!result)
return -1;
/* XXX read_sha1_file NUL-terminates */
@@ -2976,6 +2982,13 @@ static int read_file_or_gitlink(struct cache_entry *ce, struct strbuf *buf)
return 0;
}
+static int read_file_or_gitlink(struct cache_entry *ce, struct strbuf *buf)
+{
+ if (!ce)
+ return 0;
+ return read_blob_object(buf, ce->sha1, ce->ce_mode);
+}
+
static struct patch *in_fn_table(const char *name)
{
struct string_list_item *item;
@@ -2994,9 +3007,15 @@ static struct patch *in_fn_table(const char *name)
* item->util in the filename table records the status of the path.
* Usually it points at a patch (whose result records the contents
* of it after applying it), but it could be PATH_WAS_DELETED for a
- * path that a previously applied patch has already removed.
+ * path that a previously applied patch has already removed, or
+ * PATH_TO_BE_DELETED for a path that a later patch would remove.
+ *
+ * The latter is needed to deal with a case where two paths A and B
+ * are swapped by first renaming A to B and then renaming B to A;
+ * moving A to B should not be prevented due to presense of B as we
+ * will remove it in a later patch.
*/
- #define PATH_TO_BE_DELETED ((struct patch *) -2)
+#define PATH_TO_BE_DELETED ((struct patch *) -2)
#define PATH_WAS_DELETED ((struct patch *) -1)
static int to_be_deleted(struct patch *patch)
@@ -3048,127 +3067,324 @@ static void prepare_fn_table(struct patch *patch)
}
}
-static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce)
+static int checkout_target(struct cache_entry *ce, struct stat *st)
+{
+ struct checkout costate;
+
+ memset(&costate, 0, sizeof(costate));
+ costate.base_dir = "";
+ costate.refresh_cache = 1;
+ if (checkout_entry(ce, &costate, NULL) || lstat(ce->name, st))
+ return error(_("cannot checkout %s"), ce->name);
+ return 0;
+}
+
+static struct patch *previous_patch(struct patch *patch, int *gone)
+{
+ struct patch *previous;
+
+ *gone = 0;
+ if (patch->is_copy || patch->is_rename)
+ return NULL; /* "git" patches do not depend on the order */
+
+ previous = in_fn_table(patch->old_name);
+ if (!previous)
+ return NULL;
+
+ if (to_be_deleted(previous))
+ return NULL; /* the deletion hasn't happened yet */
+
+ if (was_deleted(previous))
+ *gone = 1;
+
+ return previous;
+}
+
+static int verify_index_match(struct cache_entry *ce, struct stat *st)
+{
+ if (S_ISGITLINK(ce->ce_mode)) {
+ if (!S_ISDIR(st->st_mode))
+ return -1;
+ return 0;
+ }
+ return ce_match_stat(ce, st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);
+}
+
+#define SUBMODULE_PATCH_WITHOUT_INDEX 1
+
+static int load_patch_target(struct strbuf *buf,
+ struct cache_entry *ce,
+ struct stat *st,
+ const char *name,
+ unsigned expected_mode)
+{
+ if (cached) {
+ if (read_file_or_gitlink(ce, buf))
+ return error(_("read of %s failed"), name);
+ } else if (name) {
+ if (S_ISGITLINK(expected_mode)) {
+ if (ce)
+ return read_file_or_gitlink(ce, buf);
+ else
+ return SUBMODULE_PATCH_WITHOUT_INDEX;
+ } else {
+ if (read_old_data(st, name, buf))
+ return error(_("read of %s failed"), name);
+ }
+ }
+ return 0;
+}
+
+/*
+ * We are about to apply "patch"; populate the "image" with the
+ * current version we have, from the working tree or from the index,
+ * depending on the situation e.g. --cached/--index. If we are
+ * applying a non-git patch that incrementally updates the tree,
+ * we read from the result of a previous diff.
+ */
+static int load_preimage(struct image *image,
+ struct patch *patch, struct stat *st, struct cache_entry *ce)
{
struct strbuf buf = STRBUF_INIT;
- struct image image;
size_t len;
char *img;
- struct patch *tpatch;
+ struct patch *previous;
+ int status;
- if (!(patch->is_copy || patch->is_rename) &&
- (tpatch = in_fn_table(patch->old_name)) != NULL && !to_be_deleted(tpatch)) {
- if (was_deleted(tpatch)) {
- return error(_("patch %s has been renamed/deleted"),
- patch->old_name);
- }
+ previous = previous_patch(patch, &status);
+ if (status)
+ return error(_("path %s has been renamed/deleted"),
+ patch->old_name);
+ if (previous) {
/* We have a patched copy in memory; use that. */
- strbuf_add(&buf, tpatch->result, tpatch->resultsize);
- } else if (cached) {
- if (read_file_or_gitlink(ce, &buf))
+ strbuf_add(&buf, previous->result, previous->resultsize);
+ } else {
+ status = load_patch_target(&buf, ce, st,
+ patch->old_name, patch->old_mode);
+ if (status < 0)
+ return status;
+ else if (status == SUBMODULE_PATCH_WITHOUT_INDEX) {
+ /*
+ * There is no way to apply subproject
+ * patch without looking at the index.
+ * NEEDSWORK: shouldn't this be flagged
+ * as an error???
+ */
+ free_fragment_list(patch->fragments);
+ patch->fragments = NULL;
+ } else if (status) {
return error(_("read of %s failed"), patch->old_name);
- } else if (patch->old_name) {
- if (S_ISGITLINK(patch->old_mode)) {
- if (ce) {
- read_file_or_gitlink(ce, &buf);
- } else {
- /*
- * There is no way to apply subproject
- * patch without looking at the index.
- * NEEDSWORK: shouldn't this be flagged
- * as an error???
- */
- free_fragment_list(patch->fragments);
- patch->fragments = NULL;
- }
- } else {
- if (read_old_data(st, patch->old_name, &buf))
- return error(_("read of %s failed"), patch->old_name);
}
}
img = strbuf_detach(&buf, &len);
- prepare_image(&image, img, len, !patch->is_binary);
+ prepare_image(image, img, len, !patch->is_binary);
+ return 0;
+}
- if (apply_fragments(&image, patch) < 0)
- return -1; /* note with --reject this succeeds. */
- patch->result = image.buf;
- patch->resultsize = image.len;
- add_to_fn_table(patch);
- free(image.line_allocated);
+static int three_way_merge(struct image *image,
+ char *path,
+ const unsigned char *base,
+ const unsigned char *ours,
+ const unsigned char *theirs)
+{
+ mmfile_t base_file, our_file, their_file;
+ mmbuffer_t result = { NULL };
+ int status;
- if (0 < patch->is_delete && patch->resultsize)
- return error(_("removal patch leaves file contents"));
+ read_mmblob(&base_file, base);
+ read_mmblob(&our_file, ours);
+ read_mmblob(&their_file, theirs);
+ status = ll_merge(&result, path,
+ &base_file, "base",
+ &our_file, "ours",
+ &their_file, "theirs", NULL);
+ free(base_file.ptr);
+ free(our_file.ptr);
+ free(their_file.ptr);
+ if (status < 0 || !result.ptr) {
+ free(result.ptr);
+ return -1;
+ }
+ clear_image(image);
+ image->buf = result.ptr;
+ image->len = result.size;
+ return status;
+}
+
+/*
+ * When directly falling back to add/add three-way merge, we read from
+ * the current contents of the new_name. In no cases other than that
+ * this function will be called.
+ */
+static int load_current(struct image *image, struct patch *patch)
+{
+ struct strbuf buf = STRBUF_INIT;
+ int status, pos;
+ size_t len;
+ char *img;
+ struct stat st;
+ struct cache_entry *ce;
+ char *name = patch->new_name;
+ unsigned mode = patch->new_mode;
+
+ if (!patch->is_new)
+ die("BUG: patch to %s is not a creation", patch->old_name);
+
+ pos = cache_name_pos(name, strlen(name));
+ if (pos < 0)
+ return error(_("%s: does not exist in index"), name);
+ ce = active_cache[pos];
+ if (lstat(name, &st)) {
+ if (errno != ENOENT)
+ return error(_("%s: %s"), name, strerror(errno));
+ if (checkout_target(ce, &st))
+ return -1;
+ }
+ if (verify_index_match(ce, &st))
+ return error(_("%s: does not match index"), name);
+
+ status = load_patch_target(&buf, ce, &st, name, mode);
+ if (status < 0)
+ return status;
+ else if (status)
+ return -1;
+ img = strbuf_detach(&buf, &len);
+ prepare_image(image, img, len, !patch->is_binary);
return 0;
}
-static int check_to_create_blob(const char *new_name, int ok_if_exists)
+static int try_threeway(struct image *image, struct patch *patch,
+ struct stat *st, struct cache_entry *ce)
{
- struct stat nst;
- if (!lstat(new_name, &nst)) {
- if (S_ISDIR(nst.st_mode) || ok_if_exists)
- return 0;
- /*
- * A leading component of new_name might be a symlink
- * that is going to be removed with this patch, but
- * still pointing at somewhere that has the path.
- * In such a case, path "new_name" does not exist as
- * far as git is concerned.
- */
- if (has_symlink_leading_path(new_name, strlen(new_name)))
- return 0;
+ unsigned char pre_sha1[20], post_sha1[20], our_sha1[20];
+ struct strbuf buf = STRBUF_INIT;
+ size_t len;
+ int status;
+ char *img;
+ struct image tmp_image;
+
+ /* No point falling back to 3-way merge in these cases */
+ if (patch->is_delete ||
+ S_ISGITLINK(patch->old_mode) || S_ISGITLINK(patch->new_mode))
+ return -1;
- return error(_("%s: already exists in working directory"), new_name);
+ /* Preimage the patch was prepared for */
+ if (patch->is_new)
+ write_sha1_file("", 0, blob_type, pre_sha1);
+ else if (get_sha1(patch->old_sha1_prefix, pre_sha1) ||
+ read_blob_object(&buf, pre_sha1, patch->old_mode))
+ return error("repository lacks the necessary blob to fall back on 3-way merge.");
+
+ fprintf(stderr, "Falling back to three-way merge...\n");
+
+ img = strbuf_detach(&buf, &len);
+ prepare_image(&tmp_image, img, len, 1);
+ /* Apply the patch to get the post image */
+ if (apply_fragments(&tmp_image, patch) < 0) {
+ clear_image(&tmp_image);
+ return -1;
+ }
+ /* post_sha1[] is theirs */
+ write_sha1_file(tmp_image.buf, tmp_image.len, blob_type, post_sha1);
+ clear_image(&tmp_image);
+
+ /* our_sha1[] is ours */
+ if (patch->is_new) {
+ if (load_current(&tmp_image, patch))
+ return error("cannot read the current contents of '%s'",
+ patch->new_name);
+ } else {
+ if (load_preimage(&tmp_image, patch, st, ce))
+ return error("cannot read the current contents of '%s'",
+ patch->old_name);
+ }
+ write_sha1_file(tmp_image.buf, tmp_image.len, blob_type, our_sha1);
+ clear_image(&tmp_image);
+
+ /* in-core three-way merge between post and our using pre as base */
+ status = three_way_merge(image, patch->new_name,
+ pre_sha1, our_sha1, post_sha1);
+ if (status < 0) {
+ fprintf(stderr, "Failed to fall back on three-way merge...\n");
+ return status;
+ }
+
+ if (status) {
+ patch->conflicted_threeway = 1;
+ if (patch->is_new)
+ hashclr(patch->threeway_stage[0]);
+ else
+ hashcpy(patch->threeway_stage[0], pre_sha1);
+ hashcpy(patch->threeway_stage[1], our_sha1);
+ hashcpy(patch->threeway_stage[2], post_sha1);
+ fprintf(stderr, "Applied patch to '%s' with conflicts.\n", patch->new_name);
+ } else {
+ fprintf(stderr, "Applied patch to '%s' cleanly.\n", patch->new_name);
}
- else if ((errno != ENOENT) && (errno != ENOTDIR))
- return error("%s: %s", new_name, strerror(errno));
return 0;
}
-static int verify_index_match(struct cache_entry *ce, struct stat *st)
+static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce)
{
- if (S_ISGITLINK(ce->ce_mode)) {
- if (!S_ISDIR(st->st_mode))
+ struct image image;
+
+ if (load_preimage(&image, patch, st, ce) < 0)
+ return -1;
+
+ if (patch->direct_to_threeway ||
+ apply_fragments(&image, patch) < 0) {
+ /* Note: with --reject, apply_fragments() returns 0 */
+ if (!threeway || try_threeway(&image, patch, st, ce) < 0)
return -1;
- return 0;
}
- return ce_match_stat(ce, st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);
+ patch->result = image.buf;
+ patch->resultsize = image.len;
+ add_to_fn_table(patch);
+ free(image.line_allocated);
+
+ if (0 < patch->is_delete && patch->resultsize)
+ return error(_("removal patch leaves file contents"));
+
+ return 0;
}
+/*
+ * If "patch" that we are looking at modifies or deletes what we have,
+ * we would want it not to lose any local modification we have, either
+ * in the working tree or in the index.
+ *
+ * This also decides if a non-git patch is a creation patch or a
+ * modification to an existing empty file. We do not check the state
+ * of the current tree for a creation patch in this function; the caller
+ * check_patch() separately makes sure (and errors out otherwise) that
+ * the path the patch creates does not exist in the current tree.
+ */
static int check_preimage(struct patch *patch, struct cache_entry **ce, struct stat *st)
{
const char *old_name = patch->old_name;
- struct patch *tpatch = NULL;
- int stat_ret = 0;
+ struct patch *previous = NULL;
+ int stat_ret = 0, status;
unsigned st_mode = 0;
- /*
- * Make sure that we do not have local modifications from the
- * index when we are looking at the index. Also make sure
- * we have the preimage file to be patched in the work tree,
- * unless --cached, which tells git to apply only in the index.
- */
if (!old_name)
return 0;
assert(patch->is_new <= 0);
+ previous = previous_patch(patch, &status);
- if (!(patch->is_copy || patch->is_rename) &&
- (tpatch = in_fn_table(old_name)) != NULL && !to_be_deleted(tpatch)) {
- if (was_deleted(tpatch))
- return error(_("%s: has been deleted/renamed"), old_name);
- st_mode = tpatch->new_mode;
+ if (status)
+ return error(_("path %s has been renamed/deleted"), old_name);
+ if (previous) {
+ st_mode = previous->new_mode;
} else if (!cached) {
stat_ret = lstat(old_name, st);
if (stat_ret && errno != ENOENT)
return error(_("%s: %s"), old_name, strerror(errno));
}
- if (to_be_deleted(tpatch))
- tpatch = NULL;
-
- if (check_index && !tpatch) {
+ if (check_index && !previous) {
int pos = cache_name_pos(old_name, strlen(old_name));
if (pos < 0) {
if (patch->is_new < 0)
@@ -3177,13 +3393,7 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s
}
*ce = active_cache[pos];
if (stat_ret < 0) {
- struct checkout costate;
- /* checkout */
- memset(&costate, 0, sizeof(costate));
- costate.base_dir = "";
- costate.refresh_cache = 1;
- if (checkout_entry(*ce, &costate, NULL) ||
- lstat(old_name, st))
+ if (checkout_target(*ce, st))
return -1;
}
if (!cached && verify_index_match(*ce, st))
@@ -3196,7 +3406,7 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s
return error(_("%s: %s"), old_name, strerror(errno));
}
- if (!cached && !tpatch)
+ if (!cached && !previous)
st_mode = ce_mode_from_stat(*ce, st->st_mode);
if (patch->is_new < 0)
@@ -3220,6 +3430,41 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s
return 0;
}
+
+#define EXISTS_IN_INDEX 1
+#define EXISTS_IN_WORKTREE 2
+
+static int check_to_create(const char *new_name, int ok_if_exists)
+{
+ struct stat nst;
+
+ if (check_index &&
+ cache_name_pos(new_name, strlen(new_name)) >= 0 &&
+ !ok_if_exists)
+ return EXISTS_IN_INDEX;
+ if (cached)
+ return 0;
+
+ if (!lstat(new_name, &nst)) {
+ if (S_ISDIR(nst.st_mode) || ok_if_exists)
+ return 0;
+ /*
+ * A leading component of new_name might be a symlink
+ * that is going to be removed with this patch, but
+ * still pointing at somewhere that has the path.
+ * In such a case, path "new_name" does not exist as
+ * far as git is concerned.
+ */
+ if (has_symlink_leading_path(new_name, strlen(new_name)))
+ return 0;
+
+ return EXISTS_IN_WORKTREE;
+ } else if ((errno != ENOENT) && (errno != ENOTDIR)) {
+ return error("%s: %s", new_name, strerror(errno));
+ }
+ return 0;
+}
+
/*
* Check and apply the patch in-core; leave the result in patch->result
* for the caller to write it out to the final destination.
@@ -3242,31 +3487,45 @@ static int check_patch(struct patch *patch)
return status;
old_name = patch->old_name;
+ /*
+ * A type-change diff is always split into a patch to delete
+ * old, immediately followed by a patch to create new (see
+ * diff.c::run_diff()); in such a case it is Ok that the entry
+ * to be deleted by the previous patch is still in the working
+ * tree and in the index.
+ *
+ * A patch to swap-rename between A and B would first rename A
+ * to B and then rename B to A. While applying the first one,
+ * the presense of B should not stop A from getting renamed to
+ * B; ask to_be_deleted() about the later rename. Removal of
+ * B and rename from A to B is handled the same way by asking
+ * was_deleted().
+ */
if ((tpatch = in_fn_table(new_name)) &&
- (was_deleted(tpatch) || to_be_deleted(tpatch)))
- /*
- * A type-change diff is always split into a patch to
- * delete old, immediately followed by a patch to
- * create new (see diff.c::run_diff()); in such a case
- * it is Ok that the entry to be deleted by the
- * previous patch is still in the working tree and in
- * the index.
- */
+ (was_deleted(tpatch) || to_be_deleted(tpatch)))
ok_if_exists = 1;
else
ok_if_exists = 0;
if (new_name &&
((0 < patch->is_new) | (0 < patch->is_rename) | patch->is_copy)) {
- if (check_index &&
- cache_name_pos(new_name, strlen(new_name)) >= 0 &&
- !ok_if_exists)
+ int err = check_to_create(new_name, ok_if_exists);
+
+ if (err && threeway) {
+ patch->direct_to_threeway = 1;
+ } else switch (err) {
+ case 0:
+ break; /* happy */
+ case EXISTS_IN_INDEX:
return error(_("%s: already exists in index"), new_name);
- if (!cached) {
- int err = check_to_create_blob(new_name, ok_if_exists);
- if (err)
- return err;
+ break;
+ case EXISTS_IN_WORKTREE:
+ return error(_("%s: already exists in working directory"),
+ new_name);
+ default:
+ return err;
}
+
if (!patch->new_mode) {
if (0 < patch->is_new)
patch->new_mode = S_IFREG | 0644;
@@ -3347,7 +3606,7 @@ static void build_fake_ancestor(struct patch *list, const char *filename)
name = patch->old_name ? patch->old_name : patch->new_name;
if (0 < patch->is_new)
continue;
- else if (get_sha1(patch->old_sha1_prefix, sha1))
+ else if (get_sha1_blob(patch->old_sha1_prefix, sha1))
/* git diff has no index line for mode/type changes */
if (!patch->lines_added && !patch->lines_deleted) {
if (get_current_sha1(patch->old_name, sha1))
@@ -3527,7 +3786,8 @@ static void add_index_file(const char *path, unsigned mode, void *buf, unsigned
ce = xcalloc(1, ce_size);
memcpy(ce->name, path, namelen);
ce->ce_mode = create_ce_mode(mode);
- ce->ce_flags = namelen;
+ ce->ce_flags = create_ce_flags(0);
+ ce->ce_namelen = namelen;
if (S_ISGITLINK(mode)) {
const char *s = buf;
@@ -3629,6 +3889,33 @@ static void create_one_file(char *path, unsigned mode, const char *buf, unsigned
die_errno(_("unable to write file '%s' mode %o"), path, mode);
}
+static void add_conflicted_stages_file(struct patch *patch)
+{
+ int stage, namelen;
+ unsigned ce_size, mode;
+ struct cache_entry *ce;
+
+ if (!update_index)
+ return;
+ namelen = strlen(patch->new_name);
+ ce_size = cache_entry_size(namelen);
+ mode = patch->new_mode ? patch->new_mode : (S_IFREG | 0644);
+
+ remove_file_from_cache(patch->new_name);
+ for (stage = 1; stage < 4; stage++) {
+ if (is_null_sha1(patch->threeway_stage[stage - 1]))
+ continue;
+ ce = xcalloc(1, ce_size);
+ memcpy(ce->name, patch->new_name, namelen);
+ ce->ce_mode = create_ce_mode(mode);
+ ce->ce_flags = create_ce_flags(stage);
+ ce->ce_namelen = namelen;
+ hashcpy(ce->sha1, patch->threeway_stage[stage - 1]);
+ if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD) < 0)
+ die(_("unable to add cache entry for %s"), patch->new_name);
+ }
+}
+
static void create_file(struct patch *patch)
{
char *path = patch->new_name;
@@ -3639,7 +3926,11 @@ static void create_file(struct patch *patch)
if (!mode)
mode = S_IFREG | 0644;
create_one_file(path, mode, buf, size);
- add_index_file(path, mode, buf, size);
+
+ if (patch->conflicted_threeway)
+ add_conflicted_stages_file(patch);
+ else
+ add_index_file(path, mode, buf, size);
}
/* phase zero is to remove, phase one is to create */
@@ -3741,6 +4032,7 @@ static int write_out_results(struct patch *list)
int phase;
int errs = 0;
struct patch *l;
+ struct string_list cpath = STRING_LIST_INIT_DUP;
for (phase = 0; phase < 2; phase++) {
l = list;
@@ -3749,12 +4041,30 @@ static int write_out_results(struct patch *list)
errs = 1;
else {
write_out_one_result(l, phase);
- if (phase == 1 && write_out_one_reject(l))
- errs = 1;
+ if (phase == 1) {
+ if (write_out_one_reject(l))
+ errs = 1;
+ if (l->conflicted_threeway) {
+ string_list_append(&cpath, l->new_name);
+ errs = 1;
+ }
+ }
}
l = l->next;
}
}
+
+ if (cpath.nr) {
+ struct string_list_item *item;
+
+ sort_string_list(&cpath);
+ for_each_string_list_item(item, &cpath)
+ fprintf(stderr, "U %s\n", item->string);
+ string_list_clear(&cpath, 0);
+
+ rerere(0);
+ }
+
return errs;
}
@@ -3877,8 +4187,12 @@ static int apply_patch(int fd, const char *filename, int options)
!apply_with_reject)
exit(1);
- if (apply && write_out_results(list))
- exit(1);
+ if (apply && write_out_results(list)) {
+ if (apply_with_reject)
+ exit(1);
+ /* with --3way, we still need to write the index out */
+ return 1;
+ }
if (fake_ancestor)
build_fake_ancestor(list, fake_ancestor);
@@ -4000,7 +4314,7 @@ int cmd_apply(int argc, const char **argv, const char *prefix_)
OPT_NOOP_NOARG(0, "allow-binary-replacement"),
OPT_NOOP_NOARG(0, "binary"),
OPT_BOOLEAN(0, "numstat", &numstat,
- N_("shows number of added and deleted lines in decimal notation")),
+ N_("show number of added and deleted lines in decimal notation")),
OPT_BOOLEAN(0, "summary", &summary,
N_("instead of applying the patch, output a summary for the input")),
OPT_BOOLEAN(0, "check", &check,
@@ -4011,6 +4325,8 @@ int cmd_apply(int argc, const char **argv, const char *prefix_)
N_("apply a patch without touching the working tree")),
OPT_BOOLEAN(0, "apply", &force_apply,
N_("also apply the patch (use with --stat/--summary/--check)")),
+ OPT_BOOL('3', "3way", &threeway,
+ N_( "attempt three-way merge if a patch does not apply")),
OPT_FILENAME(0, "build-fake-ancestor", &fake_ancestor,
N_("build a temporary index based on embedded index information")),
{ OPTION_CALLBACK, 'z', NULL, NULL, NULL,
@@ -4059,6 +4375,15 @@ int cmd_apply(int argc, const char **argv, const char *prefix_)
argc = parse_options(argc, argv, prefix, builtin_apply_options,
apply_usage, 0);
+ if (apply_with_reject && threeway)
+ die("--reject and --3way cannot be used together.");
+ if (cached && threeway)
+ die("--cached and --3way cannot be used together.");
+ if (threeway) {
+ if (is_not_gitdir)
+ die(_("--3way outside a repository"));
+ check_index = 1;
+ }
if (apply_with_reject)
apply = apply_verbosely = 1;
if (!force_apply && (diffstat || numstat || summary || check || fake_ancestor))
diff --git a/builtin/archive.c b/builtin/archive.c
index 931956d..9a1cfd3 100644
--- a/builtin/archive.c
+++ b/builtin/archive.c
@@ -88,12 +88,12 @@ int cmd_archive(int argc, const char **argv, const char *prefix)
const char *output = NULL;
const char *remote = NULL;
struct option local_opts[] = {
- OPT_STRING('o', "output", &output, "file",
- "write the archive to this file"),
- OPT_STRING(0, "remote", &remote, "repo",
- "retrieve the archive from remote repository <repo>"),
- OPT_STRING(0, "exec", &exec, "cmd",
- "path to the remote git-upload-archive command"),
+ OPT_STRING('o', "output", &output, N_("file"),
+ N_("write the archive to this file")),
+ OPT_STRING(0, "remote", &remote, N_("repo"),
+ N_("retrieve the archive from remote repository <repo>")),
+ OPT_STRING(0, "exec", &exec, N_("command"),
+ N_("path to the remote git-upload-archive command")),
OPT_END()
};
diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 8d325a5..e3884e3 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -4,7 +4,7 @@
#include "bisect.h"
static const char * const git_bisect_helper_usage[] = {
- "git bisect--helper --next-all [--no-checkout]",
+ N_("git bisect--helper --next-all [--no-checkout]"),
NULL
};
@@ -14,9 +14,9 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
int no_checkout = 0;
struct option options[] = {
OPT_BOOLEAN(0, "next-all", &next_all,
- "perform 'git bisect next'"),
+ N_("perform 'git bisect next'")),
OPT_BOOLEAN(0, "no-checkout", &no_checkout,
- "update BISECT_HEAD instead of checking out the current commit"),
+ N_("update BISECT_HEAD instead of checking out the current commit")),
OPT_END()
};
diff --git a/builtin/blame.c b/builtin/blame.c
index cad4111..c27ef21 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -22,12 +22,12 @@
#include "utf8.h"
#include "userdiff.h"
-static char blame_usage[] = "git blame [options] [rev-opts] [rev] [--] file";
+static char blame_usage[] = N_("git blame [options] [rev-opts] [rev] [--] file");
static const char *blame_opt_usage[] = {
blame_usage,
"",
- "[rev-opts] are documented in git-rev-list(1)",
+ N_("[rev-opts] are documented in git-rev-list(1)"),
NULL
};
@@ -2069,6 +2069,55 @@ static int git_blame_config(const char *var, const char *value, void *cb)
return git_default_config(var, value, cb);
}
+static void verify_working_tree_path(struct commit *work_tree, const char *path)
+{
+ struct commit_list *parents;
+
+ for (parents = work_tree->parents; parents; parents = parents->next) {
+ const unsigned char *commit_sha1 = parents->item->object.sha1;
+ unsigned char blob_sha1[20];
+ unsigned mode;
+
+ if (!get_tree_entry(commit_sha1, path, blob_sha1, &mode) &&
+ sha1_object_info(blob_sha1, NULL) == OBJ_BLOB)
+ return;
+ }
+ die("no such path '%s' in HEAD", path);
+}
+
+static struct commit_list **append_parent(struct commit_list **tail, const unsigned char *sha1)
+{
+ struct commit *parent;
+
+ parent = lookup_commit_reference(sha1);
+ if (!parent)
+ die("no such commit %s", sha1_to_hex(sha1));
+ return &commit_list_insert(parent, tail)->next;
+}
+
+static void append_merge_parents(struct commit_list **tail)
+{
+ int merge_head;
+ const char *merge_head_file = git_path("MERGE_HEAD");
+ struct strbuf line = STRBUF_INIT;
+
+ merge_head = open(merge_head_file, O_RDONLY);
+ if (merge_head < 0) {
+ if (errno == ENOENT)
+ return;
+ die("cannot open '%s' for reading", merge_head_file);
+ }
+
+ while (!strbuf_getwholeline_fd(&line, merge_head, '\n')) {
+ unsigned char sha1[20];
+ if (line.len < 40 || get_sha1_hex(line.buf, sha1))
+ die("unknown line in '%s': %s", merge_head_file, line.buf);
+ tail = append_parent(tail, sha1);
+ }
+ close(merge_head);
+ strbuf_release(&line);
+}
+
/*
* Prepare a dummy commit that represents the work tree (or staged) item.
* Note that annotating work tree item never works in the reverse.
@@ -2079,6 +2128,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
{
struct commit *commit;
struct origin *origin;
+ struct commit_list **parent_tail, *parent;
unsigned char head_sha1[20];
struct strbuf buf = STRBUF_INIT;
const char *ident;
@@ -2086,20 +2136,38 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
int size, len;
struct cache_entry *ce;
unsigned mode;
-
- if (get_sha1("HEAD", head_sha1))
- die("No such ref: HEAD");
+ struct strbuf msg = STRBUF_INIT;
time(&now);
commit = xcalloc(1, sizeof(*commit));
- commit->parents = xcalloc(1, sizeof(*commit->parents));
- commit->parents->item = lookup_commit_reference(head_sha1);
commit->object.parsed = 1;
commit->date = now;
commit->object.type = OBJ_COMMIT;
+ parent_tail = &commit->parents;
+
+ if (!resolve_ref_unsafe("HEAD", head_sha1, 1, NULL))
+ die("no such ref: HEAD");
+
+ parent_tail = append_parent(parent_tail, head_sha1);
+ append_merge_parents(parent_tail);
+ verify_working_tree_path(commit, path);
origin = make_origin(commit, path);
+ ident = fmt_ident("Not Committed Yet", "not.committed.yet", NULL, 0);
+ strbuf_addstr(&msg, "tree 0000000000000000000000000000000000000000\n");
+ for (parent = commit->parents; parent; parent = parent->next)
+ strbuf_addf(&msg, "parent %s\n",
+ sha1_to_hex(parent->item->object.sha1));
+ strbuf_addf(&msg,
+ "author %s\n"
+ "committer %s\n\n"
+ "Version of %s from %s\n",
+ ident, ident, path,
+ (!contents_from ? path :
+ (!strcmp(contents_from, "-") ? "standard input" : contents_from)));
+ commit->buffer = strbuf_detach(&msg, NULL);
+
if (!contents_from || strcmp("-", contents_from)) {
struct stat st;
const char *read_from;
@@ -2136,7 +2204,6 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
}
else {
/* Reading from stdin */
- contents_from = "standard input";
mode = 0;
if (strbuf_read(&buf, 0, 0) < 0)
die_errno("failed to read from stdin");
@@ -2169,7 +2236,8 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
ce = xcalloc(1, size);
hashcpy(ce->sha1, origin->blob_sha1);
memcpy(ce->name, path, len);
- ce->ce_flags = create_ce_flags(len, 0);
+ ce->ce_flags = create_ce_flags(0);
+ ce->ce_namelen = len;
ce->ce_mode = create_ce_mode(mode);
add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
@@ -2180,16 +2248,6 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
*/
cache_tree_invalidate_path(active_cache_tree, path);
- commit->buffer = xmalloc(400);
- ident = fmt_ident("Not Committed Yet", "not.committed.yet", NULL, 0);
- snprintf(commit->buffer, 400,
- "tree 0000000000000000000000000000000000000000\n"
- "parent %s\n"
- "author %s\n"
- "committer %s\n\n"
- "Version of %s from %s\n",
- sha1_to_hex(head_sha1),
- ident, ident, path, contents_from ? contents_from : path);
return commit;
}
@@ -2312,27 +2370,27 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
static const char *revs_file = NULL;
static const char *contents_from = NULL;
static const struct option options[] = {
- OPT_BOOLEAN(0, "incremental", &incremental, "Show blame entries as we find them, incrementally"),
- OPT_BOOLEAN('b', NULL, &blank_boundary, "Show blank SHA-1 for boundary commits (Default: off)"),
- OPT_BOOLEAN(0, "root", &show_root, "Do not treat root commits as boundaries (Default: off)"),
- OPT_BOOLEAN(0, "show-stats", &show_stats, "Show work cost statistics"),
- OPT_BIT(0, "score-debug", &output_option, "Show output score for blame entries", OUTPUT_SHOW_SCORE),
- OPT_BIT('f', "show-name", &output_option, "Show original filename (Default: auto)", OUTPUT_SHOW_NAME),
- OPT_BIT('n', "show-number", &output_option, "Show original linenumber (Default: off)", OUTPUT_SHOW_NUMBER),
- OPT_BIT('p', "porcelain", &output_option, "Show in a format designed for machine consumption", OUTPUT_PORCELAIN),
- OPT_BIT(0, "line-porcelain", &output_option, "Show porcelain format with per-line commit information", OUTPUT_PORCELAIN|OUTPUT_LINE_PORCELAIN),
- OPT_BIT('c', NULL, &output_option, "Use the same output mode as git-annotate (Default: off)", OUTPUT_ANNOTATE_COMPAT),
- OPT_BIT('t', NULL, &output_option, "Show raw timestamp (Default: off)", OUTPUT_RAW_TIMESTAMP),
- OPT_BIT('l', NULL, &output_option, "Show long commit SHA1 (Default: off)", OUTPUT_LONG_OBJECT_NAME),
- OPT_BIT('s', NULL, &output_option, "Suppress author name and timestamp (Default: off)", OUTPUT_NO_AUTHOR),
- OPT_BIT('e', "show-email", &output_option, "Show author email instead of name (Default: off)", OUTPUT_SHOW_EMAIL),
- OPT_BIT('w', NULL, &xdl_opts, "Ignore whitespace differences", XDF_IGNORE_WHITESPACE),
- OPT_BIT(0, "minimal", &xdl_opts, "Spend extra cycles to find better match", XDF_NEED_MINIMAL),
- OPT_STRING('S', NULL, &revs_file, "file", "Use revisions from <file> instead of calling git-rev-list"),
- OPT_STRING(0, "contents", &contents_from, "file", "Use <file>'s contents as the final image"),
- { OPTION_CALLBACK, 'C', NULL, &opt, "score", "Find line copies within and across files", PARSE_OPT_OPTARG, blame_copy_callback },
- { OPTION_CALLBACK, 'M', NULL, &opt, "score", "Find line movements within and across files", PARSE_OPT_OPTARG, blame_move_callback },
- OPT_CALLBACK('L', NULL, &bottomtop, "n,m", "Process only line range n,m, counting from 1", blame_bottomtop_callback),
+ OPT_BOOLEAN(0, "incremental", &incremental, N_("Show blame entries as we find them, incrementally")),
+ OPT_BOOLEAN('b', NULL, &blank_boundary, N_("Show blank SHA-1 for boundary commits (Default: off)")),
+ OPT_BOOLEAN(0, "root", &show_root, N_("Do not treat root commits as boundaries (Default: off)")),
+ OPT_BOOLEAN(0, "show-stats", &show_stats, N_("Show work cost statistics")),
+ OPT_BIT(0, "score-debug", &output_option, N_("Show output score for blame entries"), OUTPUT_SHOW_SCORE),
+ OPT_BIT('f', "show-name", &output_option, N_("Show original filename (Default: auto)"), OUTPUT_SHOW_NAME),
+ OPT_BIT('n', "show-number", &output_option, N_("Show original linenumber (Default: off)"), OUTPUT_SHOW_NUMBER),
+ OPT_BIT('p', "porcelain", &output_option, N_("Show in a format designed for machine consumption"), OUTPUT_PORCELAIN),
+ OPT_BIT(0, "line-porcelain", &output_option, N_("Show porcelain format with per-line commit information"), OUTPUT_PORCELAIN|OUTPUT_LINE_PORCELAIN),
+ OPT_BIT('c', NULL, &output_option, N_("Use the same output mode as git-annotate (Default: off)"), OUTPUT_ANNOTATE_COMPAT),
+ OPT_BIT('t', NULL, &output_option, N_("Show raw timestamp (Default: off)"), OUTPUT_RAW_TIMESTAMP),
+ OPT_BIT('l', NULL, &output_option, N_("Show long commit SHA1 (Default: off)"), OUTPUT_LONG_OBJECT_NAME),
+ OPT_BIT('s', NULL, &output_option, N_("Suppress author name and timestamp (Default: off)"), OUTPUT_NO_AUTHOR),
+ OPT_BIT('e', "show-email", &output_option, N_("Show author email instead of name (Default: off)"), OUTPUT_SHOW_EMAIL),
+ OPT_BIT('w', NULL, &xdl_opts, N_("Ignore whitespace differences"), XDF_IGNORE_WHITESPACE),
+ OPT_BIT(0, "minimal", &xdl_opts, N_("Spend extra cycles to find better match"), XDF_NEED_MINIMAL),
+ OPT_STRING('S', NULL, &revs_file, N_("file"), N_("Use revisions from <file> instead of calling git-rev-list")),
+ OPT_STRING(0, "contents", &contents_from, N_("file"), N_("Use <file>'s contents as the final image")),
+ { OPTION_CALLBACK, 'C', NULL, &opt, N_("score"), N_("Find line copies within and across files"), PARSE_OPT_OPTARG, blame_copy_callback },
+ { OPTION_CALLBACK, 'M', NULL, &opt, N_("score"), N_("Find line movements within and across files"), PARSE_OPT_OPTARG, blame_move_callback },
+ OPT_CALLBACK('L', NULL, &bottomtop, N_("n,m"), N_("Process only line range n,m, counting from 1"), blame_bottomtop_callback),
OPT__ABBREV(&abbrev),
OPT_END()
};
diff --git a/builtin/branch.c b/builtin/branch.c
index 0e060f2..ffd2684 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -17,12 +17,13 @@
#include "revision.h"
#include "string-list.h"
#include "column.h"
+#include "utf8.h"
static const char * const builtin_branch_usage[] = {
- "git branch [options] [-r | -a] [--merged | --no-merged]",
- "git branch [options] [-l] [-f] <branchname> [<start-point>]",
- "git branch [options] [-r] (-d | -D) <branchname>...",
- "git branch [options] (-m | -M) [<oldbranch>] <newbranch>",
+ N_("git branch [options] [-r | -a] [--merged | --no-merged]"),
+ N_("git branch [options] [-l] [-f] <branchname> [<start-point>]"),
+ N_("git branch [options] [-r] (-d | -D) <branchname>..."),
+ N_("git branch [options] (-m | -M) [<oldbranch>] <newbranch>"),
NULL
};
@@ -129,7 +130,7 @@ static int branch_merged(int kind, const char *name,
if (!reference_rev)
reference_rev = head_rev;
- merged = in_merge_bases(rev, &reference_rev, 1);
+ merged = in_merge_bases(rev, reference_rev);
/*
* After the safety valve is fully redefined to "check with
@@ -139,7 +140,7 @@ static int branch_merged(int kind, const char *name,
* a gentle reminder is in order.
*/
if ((head_rev != reference_rev) &&
- in_merge_bases(rev, &head_rev, 1) != merged) {
+ in_merge_bases(rev, head_rev) != merged) {
if (merged)
warning(_("deleting branch '%s' that has been merged to\n"
" '%s', but not yet merged to HEAD."),
@@ -196,7 +197,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
free(name);
- name = xstrdup(mkpath(fmt, bname.buf));
+ name = mkpathdup(fmt, bname.buf);
if (read_ref(name, sha1)) {
error(remote_branch
? _("remote branch '%s' not found.")
@@ -249,7 +250,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
struct ref_item {
char *name;
char *dest;
- unsigned int kind, len;
+ unsigned int kind, width;
struct commit *commit;
};
@@ -354,14 +355,14 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags,
newitem->name = xstrdup(refname);
newitem->kind = kind;
newitem->commit = commit;
- newitem->len = strlen(refname);
+ newitem->width = utf8_strwidth(refname);
newitem->dest = resolve_symref(orig_refname, prefix);
/* adjust for "remotes/" */
if (newitem->kind == REF_REMOTE_BRANCH &&
ref_list->kinds != REF_REMOTE_BRANCH)
- newitem->len += 8;
- if (newitem->len > ref_list->maxwidth)
- ref_list->maxwidth = newitem->len;
+ newitem->width += 8;
+ if (newitem->width > ref_list->maxwidth)
+ ref_list->maxwidth = newitem->width;
return 0;
}
@@ -490,11 +491,12 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
}
strbuf_addf(&name, "%s%s", prefix, item->name);
- if (verbose)
+ if (verbose) {
+ int utf8_compensation = strlen(name.buf) - utf8_strwidth(name.buf);
strbuf_addf(&out, "%c %s%-*s%s", c, branch_get_color(color),
- maxwidth, name.buf,
+ maxwidth + utf8_compensation, name.buf,
branch_get_color(BRANCH_COLOR_RESET));
- else
+ } else
strbuf_addf(&out, "%c %s%s%s", c, branch_get_color(color),
name.buf, branch_get_color(BRANCH_COLOR_RESET));
@@ -519,8 +521,8 @@ static int calc_maxwidth(struct ref_list *refs)
for (i = 0; i < refs->index; i++) {
if (!matches_merge_filter(refs->list[i].commit))
continue;
- if (refs->list[i].len > w)
- w = refs->list[i].len;
+ if (refs->list[i].width > w)
+ w = refs->list[i].width;
}
return w;
}
@@ -533,12 +535,12 @@ static void show_detached(struct ref_list *ref_list)
if (head_commit && is_descendant_of(head_commit, ref_list->with_commit)) {
struct ref_item item;
item.name = xstrdup(_("(no branch)"));
- item.len = strlen(item.name);
+ item.width = utf8_strwidth(item.name);
item.kind = REF_LOCAL_BRANCH;
item.dest = NULL;
item.commit = head_commit;
- if (item.len > ref_list->maxwidth)
- ref_list->maxwidth = item.len;
+ if (item.width > ref_list->maxwidth)
+ ref_list->maxwidth = item.width;
print_ref_item(&item, ref_list->maxwidth, ref_list->verbose, ref_list->abbrev, 1, "");
free(item.name);
}
@@ -712,62 +714,65 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
int delete = 0, rename = 0, force_create = 0, list = 0;
int verbose = 0, abbrev = -1, detached = 0;
int reflog = 0, edit_description = 0;
- int quiet = 0;
+ int quiet = 0, unset_upstream = 0;
+ const char *new_upstream = NULL;
enum branch_track track;
int kinds = REF_LOCAL_BRANCH;
struct commit_list *with_commit = NULL;
struct option options[] = {
- OPT_GROUP("Generic options"),
+ OPT_GROUP(N_("Generic options")),
OPT__VERBOSE(&verbose,
- "show hash and subject, give twice for upstream branch"),
- OPT__QUIET(&quiet, "suppress informational messages"),
- OPT_SET_INT('t', "track", &track, "set up tracking mode (see git-pull(1))",
+ N_("show hash and subject, give twice for upstream branch")),
+ OPT__QUIET(&quiet, N_("suppress informational messages")),
+ OPT_SET_INT('t', "track", &track, N_("set up tracking mode (see git-pull(1))"),
BRANCH_TRACK_EXPLICIT),
- OPT_SET_INT( 0, "set-upstream", &track, "change upstream info",
+ OPT_SET_INT( 0, "set-upstream", &track, N_("change upstream info"),
BRANCH_TRACK_OVERRIDE),
- OPT__COLOR(&branch_use_color, "use colored output"),
- OPT_SET_INT('r', "remotes", &kinds, "act on remote-tracking branches",
+ OPT_STRING('u', "set-upstream-to", &new_upstream, "upstream", "change the upstream info"),
+ OPT_BOOLEAN(0, "unset-upstream", &unset_upstream, "Unset the upstream info"),
+ OPT__COLOR(&branch_use_color, N_("use colored output")),
+ OPT_SET_INT('r', "remotes", &kinds, N_("act on remote-tracking branches"),
REF_REMOTE_BRANCH),
{
- OPTION_CALLBACK, 0, "contains", &with_commit, "commit",
- "print only branches that contain the commit",
+ OPTION_CALLBACK, 0, "contains", &with_commit, N_("commit"),
+ N_("print only branches that contain the commit"),
PARSE_OPT_LASTARG_DEFAULT,
parse_opt_with_commit, (intptr_t)"HEAD",
},
{
- OPTION_CALLBACK, 0, "with", &with_commit, "commit",
- "print only branches that contain the commit",
+ OPTION_CALLBACK, 0, "with", &with_commit, N_("commit"),
+ N_("print only branches that contain the commit"),
PARSE_OPT_HIDDEN | PARSE_OPT_LASTARG_DEFAULT,
parse_opt_with_commit, (intptr_t) "HEAD",
},
OPT__ABBREV(&abbrev),
- OPT_GROUP("Specific git-branch actions:"),
- OPT_SET_INT('a', "all", &kinds, "list both remote-tracking and local branches",
+ OPT_GROUP(N_("Specific git-branch actions:")),
+ OPT_SET_INT('a', "all", &kinds, N_("list both remote-tracking and local branches"),
REF_REMOTE_BRANCH | REF_LOCAL_BRANCH),
- OPT_BIT('d', "delete", &delete, "delete fully merged branch", 1),
- OPT_BIT('D', NULL, &delete, "delete branch (even if not merged)", 2),
- OPT_BIT('m', "move", &rename, "move/rename a branch and its reflog", 1),
- OPT_BIT('M', NULL, &rename, "move/rename a branch, even if target exists", 2),
- OPT_BOOLEAN(0, "list", &list, "list branch names"),
- OPT_BOOLEAN('l', "create-reflog", &reflog, "create the branch's reflog"),
+ OPT_BIT('d', "delete", &delete, N_("delete fully merged branch"), 1),
+ OPT_BIT('D', NULL, &delete, N_("delete branch (even if not merged)"), 2),
+ OPT_BIT('m', "move", &rename, N_("move/rename a branch and its reflog"), 1),
+ OPT_BIT('M', NULL, &rename, N_("move/rename a branch, even if target exists"), 2),
+ OPT_BOOLEAN(0, "list", &list, N_("list branch names")),
+ OPT_BOOLEAN('l', "create-reflog", &reflog, N_("create the branch's reflog")),
OPT_BOOLEAN(0, "edit-description", &edit_description,
- "edit the description for the branch"),
- OPT__FORCE(&force_create, "force creation (when already exists)"),
+ N_("edit the description for the branch")),
+ OPT__FORCE(&force_create, N_("force creation (when already exists)")),
{
OPTION_CALLBACK, 0, "no-merged", &merge_filter_ref,
- "commit", "print only not merged branches",
+ N_("commit"), N_("print only not merged branches"),
PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NONEG,
opt_parse_merge_filter, (intptr_t) "HEAD",
},
{
OPTION_CALLBACK, 0, "merged", &merge_filter_ref,
- "commit", "print only merged branches",
+ N_("commit"), N_("print only merged branches"),
PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NONEG,
opt_parse_merge_filter, (intptr_t) "HEAD",
},
- OPT_COLUMN(0, "column", &colopts, "list branches in columns"),
+ OPT_COLUMN(0, "column", &colopts, N_("list branches in columns")),
OPT_END(),
};
@@ -794,10 +799,10 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, options, builtin_branch_usage,
0);
- if (!delete && !rename && !edit_description && argc == 0)
+ if (!delete && !rename && !edit_description && !new_upstream && !unset_upstream && argc == 0)
list = 1;
- if (!!delete + !!rename + !!force_create + !!list > 1)
+ if (!!delete + !!rename + !!force_create + !!list + !!new_upstream + !!unset_upstream > 1)
usage_with_options(builtin_branch_usage, options);
if (abbrev == -1)
@@ -852,11 +857,62 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
rename_branch(argv[0], argv[1], rename > 1);
else
usage_with_options(builtin_branch_usage, options);
+ } else if (new_upstream) {
+ struct branch *branch = branch_get(argv[0]);
+
+ if (!ref_exists(branch->refname))
+ die(_("branch '%s' does not exist"), branch->name);
+
+ /*
+ * create_branch takes care of setting up the tracking
+ * info and making sure new_upstream is correct
+ */
+ create_branch(head, branch->name, new_upstream, 0, 0, 0, quiet, BRANCH_TRACK_OVERRIDE);
+ } else if (unset_upstream) {
+ struct branch *branch = branch_get(argv[0]);
+ struct strbuf buf = STRBUF_INIT;
+
+ if (!branch_has_merge_config(branch)) {
+ die(_("Branch '%s' has no upstream information"), branch->name);
+ }
+
+ strbuf_addf(&buf, "branch.%s.remote", branch->name);
+ git_config_set_multivar(buf.buf, NULL, NULL, 1);
+ strbuf_reset(&buf);
+ strbuf_addf(&buf, "branch.%s.merge", branch->name);
+ git_config_set_multivar(buf.buf, NULL, NULL, 1);
+ strbuf_release(&buf);
} else if (argc > 0 && argc <= 2) {
+ struct branch *branch = branch_get(argv[0]);
+ int branch_existed = 0, remote_tracking = 0;
+ struct strbuf buf = STRBUF_INIT;
+
if (kinds != REF_LOCAL_BRANCH)
die(_("-a and -r options to 'git branch' do not make sense with a branch name"));
+
+ if (track == BRANCH_TRACK_OVERRIDE)
+ fprintf(stderr, _("The --set-upstream flag is deprecated and will be removed. Consider using --track or --set-upstream-to\n"));
+
+ strbuf_addf(&buf, "refs/remotes/%s", branch->name);
+ remote_tracking = ref_exists(buf.buf);
+ strbuf_release(&buf);
+
+ branch_existed = ref_exists(branch->refname);
create_branch(head, argv[0], (argc == 2) ? argv[1] : head,
force_create, reflog, 0, quiet, track);
+
+ /*
+ * We only show the instructions if the user gave us
+ * one branch which doesn't exist locally, but is the
+ * name of a remote-tracking branch.
+ */
+ if (argc == 1 && track == BRANCH_TRACK_OVERRIDE &&
+ !branch_existed && remote_tracking) {
+ fprintf(stderr, _("\nIf you wanted to make '%s' track '%s', do this:\n\n"), head, branch->name);
+ fprintf(stderr, _(" git branch -d %s\n"), branch->name);
+ fprintf(stderr, _(" git branch --set-upstream-to %s\n"), branch->name);
+ }
+
} else
usage_with_options(builtin_branch_usage, options);
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 60568f9..00528dd 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -91,7 +91,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
unsigned long size;
struct object_context obj_context;
- if (get_sha1_with_context(obj_name, sha1, &obj_context))
+ if (get_sha1_with_context(obj_name, 0, sha1, &obj_context))
die("Not a valid object name %s", obj_name);
buf = NULL;
@@ -244,8 +244,8 @@ static int batch_objects(int print_contents)
}
static const char * const cat_file_usage[] = {
- "git cat-file (-t|-s|-e|-p|<type>|--textconv) <object>",
- "git cat-file (--batch|--batch-check) < <list_of_objects>",
+ N_("git cat-file (-t|-s|-e|-p|<type>|--textconv) <object>"),
+ N_("git cat-file (--batch|--batch-check) < <list_of_objects>"),
NULL
};
@@ -263,19 +263,19 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
const char *exp_type = NULL, *obj_name = NULL;
const struct option options[] = {
- OPT_GROUP("<type> can be one of: blob, tree, commit, tag"),
- OPT_SET_INT('t', NULL, &opt, "show object type", 't'),
- OPT_SET_INT('s', NULL, &opt, "show object size", 's'),
+ OPT_GROUP(N_("<type> can be one of: blob, tree, commit, tag")),
+ OPT_SET_INT('t', NULL, &opt, N_("show object type"), 't'),
+ OPT_SET_INT('s', NULL, &opt, N_("show object size"), 's'),
OPT_SET_INT('e', NULL, &opt,
- "exit with zero when there's no error", 'e'),
- OPT_SET_INT('p', NULL, &opt, "pretty-print object's content", 'p'),
+ N_("exit with zero when there's no error"), 'e'),
+ OPT_SET_INT('p', NULL, &opt, N_("pretty-print object's content"), 'p'),
OPT_SET_INT(0, "textconv", &opt,
- "for blob objects, run textconv on object's content", 'c'),
+ N_("for blob objects, run textconv on object's content"), 'c'),
OPT_SET_INT(0, "batch", &batch,
- "show info and content of objects fed from the standard input",
+ N_("show info and content of objects fed from the standard input"),
BATCH),
OPT_SET_INT(0, "batch-check", &batch,
- "show info about objects fed from the standard input",
+ N_("show info about objects fed from the standard input"),
BATCH_CHECK),
OPT_END()
};
diff --git a/builtin/check-attr.c b/builtin/check-attr.c
index 44c421e..075d01d 100644
--- a/builtin/check-attr.c
+++ b/builtin/check-attr.c
@@ -8,19 +8,19 @@ static int all_attrs;
static int cached_attrs;
static int stdin_paths;
static const char * const check_attr_usage[] = {
-"git check-attr [-a | --all | attr...] [--] pathname...",
-"git check-attr --stdin [-a | --all | attr...] < <list-of-paths>",
+N_("git check-attr [-a | --all | attr...] [--] pathname..."),
+N_("git check-attr --stdin [-z] [-a | --all | attr...] < <list-of-paths>"),
NULL
};
static int null_term_line;
static const struct option check_attr_options[] = {
- OPT_BOOLEAN('a', "all", &all_attrs, "report all attributes set on file"),
- OPT_BOOLEAN(0, "cached", &cached_attrs, "use .gitattributes only from the index"),
- OPT_BOOLEAN(0 , "stdin", &stdin_paths, "read file names from stdin"),
+ OPT_BOOLEAN('a', "all", &all_attrs, N_("report all attributes set on file")),
+ OPT_BOOLEAN(0, "cached", &cached_attrs, N_("use .gitattributes only from the index")),
+ OPT_BOOLEAN(0 , "stdin", &stdin_paths, N_("read file names from stdin")),
OPT_BOOLEAN('z', NULL, &null_term_line,
- "input paths are terminated by a null character"),
+ N_("input paths are terminated by a null character")),
OPT_END()
};
diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c
index c16d82b..b1feda7 100644
--- a/builtin/checkout-index.c
+++ b/builtin/checkout-index.c
@@ -123,7 +123,7 @@ static void checkout_all(const char *prefix, int prefix_length)
}
static const char * const builtin_checkout_index_usage[] = {
- "git checkout-index [options] [--] [<file>...]",
+ N_("git checkout-index [options] [--] [<file>...]"),
NULL
};
@@ -184,27 +184,27 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
int force = 0, quiet = 0, not_new = 0;
struct option builtin_checkout_index_options[] = {
OPT_BOOLEAN('a', "all", &all,
- "checks out all files in the index"),
- OPT__FORCE(&force, "forces overwrite of existing files"),
+ N_("check out all files in the index")),
+ OPT__FORCE(&force, N_("force overwrite of existing files")),
OPT__QUIET(&quiet,
- "no warning for existing files and files not in index"),
+ N_("no warning for existing files and files not in index")),
OPT_BOOLEAN('n', "no-create", &not_new,
- "don't checkout new files"),
+ N_("don't checkout new files")),
{ OPTION_CALLBACK, 'u', "index", &newfd, NULL,
- "update stat information in the index file",
+ N_("update stat information in the index file"),
PARSE_OPT_NOARG, option_parse_u },
{ OPTION_CALLBACK, 'z', NULL, NULL, NULL,
- "paths are separated with NUL character",
+ N_("paths are separated with NUL character"),
PARSE_OPT_NOARG, option_parse_z },
OPT_BOOLEAN(0, "stdin", &read_from_stdin,
- "read list of paths from the standard input"),
+ N_("read list of paths from the standard input")),
OPT_BOOLEAN(0, "temp", &to_tempfile,
- "write the content to temporary files"),
- OPT_CALLBACK(0, "prefix", NULL, "string",
- "when creating files, prepend <string>",
+ N_("write the content to temporary files")),
+ OPT_CALLBACK(0, "prefix", NULL, N_("string"),
+ N_("when creating files, prepend <string>"),
option_parse_prefix),
OPT_CALLBACK(0, "stage", NULL, NULL,
- "copy out the files from named stage",
+ N_("copy out the files from named stage"),
option_parse_stage),
OPT_END()
};
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 45aa0a8..781295b 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -22,29 +22,31 @@
#include "argv-array.h"
static const char * const checkout_usage[] = {
- "git checkout [options] <branch>",
- "git checkout [options] [<branch>] -- <file>...",
+ N_("git checkout [options] <branch>"),
+ N_("git checkout [options] [<branch>] -- <file>..."),
NULL,
};
struct checkout_opts {
+ int patch_mode;
int quiet;
int merge;
int force;
int force_detach;
int writeout_stage;
- int writeout_error;
int overwrite_ignore;
- /* not set by parse_options */
- int branch_exists;
-
const char *new_branch;
const char *new_branch_force;
const char *new_orphan_branch;
int new_branch_log;
enum branch_track track;
struct diff_options diff_options;
+
+ int branch_exists;
+ const char *prefix;
+ const char **pathspec;
+ struct tree *source_tree;
};
static int post_checkout_hook(struct commit *old, struct commit *new,
@@ -73,7 +75,8 @@ static int update_some(const unsigned char *sha1, const char *base, int baselen,
hashcpy(ce->sha1, sha1);
memcpy(ce->name, base, baselen);
memcpy(ce->name + baselen, pathname, len - baselen);
- ce->ce_flags = create_ce_flags(len, 0) | CE_UPDATE;
+ ce->ce_flags = create_ce_flags(0) | CE_UPDATE;
+ ce->ce_namelen = len;
ce->ce_mode = create_ce_mode(mode);
add_cache_entry(ce, ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
return 0;
@@ -214,8 +217,8 @@ static int checkout_merged(int pos, struct checkout *state)
return status;
}
-static int checkout_paths(struct tree *source_tree, const char **pathspec,
- const char *prefix, struct checkout_opts *opts)
+static int checkout_paths(const struct checkout_opts *opts,
+ const char *revision)
{
int pos;
struct checkout state;
@@ -227,37 +230,65 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec,
int stage = opts->writeout_stage;
int merge = opts->merge;
int newfd;
- struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
+ struct lock_file *lock_file;
+
+ if (opts->track != BRANCH_TRACK_UNSPECIFIED)
+ die(_("'%s' cannot be used with updating paths"), "--track");
+
+ if (opts->new_branch_log)
+ die(_("'%s' cannot be used with updating paths"), "-l");
+
+ if (opts->force && opts->patch_mode)
+ die(_("'%s' cannot be used with updating paths"), "-f");
+
+ if (opts->force_detach)
+ die(_("'%s' cannot be used with updating paths"), "--detach");
+
+ if (opts->merge && opts->patch_mode)
+ die(_("'%s' cannot be used with %s"), "--merge", "--patch");
+
+ if (opts->force && opts->merge)
+ die(_("'%s' cannot be used with %s"), "-f", "-m");
+
+ if (opts->new_branch)
+ die(_("Cannot update paths and switch to branch '%s' at the same time."),
+ opts->new_branch);
+
+ if (opts->patch_mode)
+ return run_add_interactive(revision, "--patch=checkout",
+ opts->pathspec);
+
+ lock_file = xcalloc(1, sizeof(struct lock_file));
newfd = hold_locked_index(lock_file, 1);
- if (read_cache_preload(pathspec) < 0)
+ if (read_cache_preload(opts->pathspec) < 0)
return error(_("corrupt index file"));
- if (source_tree)
- read_tree_some(source_tree, pathspec);
+ if (opts->source_tree)
+ read_tree_some(opts->source_tree, opts->pathspec);
- for (pos = 0; pathspec[pos]; pos++)
+ for (pos = 0; opts->pathspec[pos]; pos++)
;
ps_matched = xcalloc(1, pos);
for (pos = 0; pos < active_nr; pos++) {
struct cache_entry *ce = active_cache[pos];
- if (source_tree && !(ce->ce_flags & CE_UPDATE))
+ if (opts->source_tree && !(ce->ce_flags & CE_UPDATE))
continue;
- match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, ps_matched);
+ match_pathspec(opts->pathspec, ce->name, ce_namelen(ce), 0, ps_matched);
}
- if (report_path_error(ps_matched, pathspec, prefix))
+ if (report_path_error(ps_matched, opts->pathspec, opts->prefix))
return 1;
/* "checkout -m path" to recreate conflicted state */
if (opts->merge)
- unmerge_cache(pathspec);
+ unmerge_cache(opts->pathspec);
/* Any unmerged paths? */
for (pos = 0; pos < active_nr; pos++) {
struct cache_entry *ce = active_cache[pos];
- if (match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, NULL)) {
+ if (match_pathspec(opts->pathspec, ce->name, ce_namelen(ce), 0, NULL)) {
if (!ce_stage(ce))
continue;
if (opts->force) {
@@ -282,9 +313,9 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec,
state.refresh_cache = 1;
for (pos = 0; pos < active_nr; pos++) {
struct cache_entry *ce = active_cache[pos];
- if (source_tree && !(ce->ce_flags & CE_UPDATE))
+ if (opts->source_tree && !(ce->ce_flags & CE_UPDATE))
continue;
- if (match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, NULL)) {
+ if (match_pathspec(opts->pathspec, ce->name, ce_namelen(ce), 0, NULL)) {
if (!ce_stage(ce)) {
errs |= checkout_entry(ce, &state, NULL);
continue;
@@ -308,7 +339,8 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec,
return errs;
}
-static void show_local_changes(struct object *head, struct diff_options *opts)
+static void show_local_changes(struct object *head,
+ const struct diff_options *opts)
{
struct rev_info rev;
/* I think we want full paths, even if we're in a subdirectory. */
@@ -330,7 +362,8 @@ static void describe_detached_head(const char *msg, struct commit *commit)
strbuf_release(&sb);
}
-static int reset_tree(struct tree *tree, struct checkout_opts *o, int worktree)
+static int reset_tree(struct tree *tree, const struct checkout_opts *o,
+ int worktree, int *writeout_error)
{
struct unpack_trees_options opts;
struct tree_desc tree_desc;
@@ -349,7 +382,7 @@ static int reset_tree(struct tree *tree, struct checkout_opts *o, int worktree)
init_tree_desc(&tree_desc, tree->buffer, tree->size);
switch (unpack_trees(1, &tree_desc, &opts)) {
case -2:
- o->writeout_error = 1;
+ *writeout_error = 1;
/*
* We return 0 nevertheless, as the index is all right
* and more importantly we have made best efforts to
@@ -380,8 +413,10 @@ static void setup_branch_path(struct branch_info *branch)
branch->path = strbuf_detach(&buf, NULL);
}
-static int merge_working_tree(struct checkout_opts *opts,
- struct branch_info *old, struct branch_info *new)
+static int merge_working_tree(const struct checkout_opts *opts,
+ struct branch_info *old,
+ struct branch_info *new,
+ int *writeout_error)
{
int ret;
struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
@@ -392,7 +427,7 @@ static int merge_working_tree(struct checkout_opts *opts,
resolve_undo_clear();
if (opts->force) {
- ret = reset_tree(new->commit->tree, opts, 1);
+ ret = reset_tree(new->commit->tree, opts, 1, writeout_error);
if (ret)
return ret;
} else {
@@ -478,7 +513,8 @@ static int merge_working_tree(struct checkout_opts *opts,
o.verbosity = 0;
work = write_tree_from_memory(&o);
- ret = reset_tree(new->commit->tree, opts, 1);
+ ret = reset_tree(new->commit->tree, opts, 1,
+ writeout_error);
if (ret)
return ret;
o.ancestor = old->name;
@@ -486,7 +522,8 @@ static int merge_working_tree(struct checkout_opts *opts,
o.branch2 = "local";
merge_trees(&o, new->commit->tree, work,
old->commit->tree, &result);
- ret = reset_tree(new->commit->tree, opts, 0);
+ ret = reset_tree(new->commit->tree, opts, 0,
+ writeout_error);
if (ret)
return ret;
}
@@ -513,7 +550,7 @@ static void report_tracking(struct branch_info *new)
strbuf_release(&sb);
}
-static void update_refs_for_switch(struct checkout_opts *opts,
+static void update_refs_for_switch(const struct checkout_opts *opts,
struct branch_info *old,
struct branch_info *new)
{
@@ -700,13 +737,14 @@ static void orphaned_commit_warning(struct commit *old, struct commit *new)
free(refs.objects);
}
-static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
+static int switch_branches(const struct checkout_opts *opts,
+ struct branch_info *new)
{
int ret = 0;
struct branch_info old;
void *path_to_free;
unsigned char rev[20];
- int flag;
+ int flag, writeout_error = 0;
memset(&old, 0, sizeof(old));
old.path = path_to_free = resolve_refdup("HEAD", rev, 0, &flag);
old.commit = lookup_commit_reference_gently(rev, 1);
@@ -724,7 +762,7 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
parse_commit(new->commit);
}
- ret = merge_working_tree(opts, &old, new);
+ ret = merge_working_tree(opts, &old, new, &writeout_error);
if (ret) {
free(path_to_free);
return ret;
@@ -737,7 +775,7 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
ret = post_checkout_hook(old.commit, new->commit, 1);
free(path_to_free);
- return ret || opts->writeout_error;
+ return ret || writeout_error;
}
static int git_checkout_config(const char *var, const char *value, void *cb)
@@ -754,12 +792,6 @@ static int git_checkout_config(const char *var, const char *value, void *cb)
return git_xmerge_config(var, value, NULL);
}
-static int interactive_checkout(const char *revision, const char **pathspec,
- struct checkout_opts *opts)
-{
- return run_add_interactive(revision, "--patch=checkout", pathspec);
-}
-
struct tracking_name_data {
const char *name;
char *remote;
@@ -909,7 +941,7 @@ static int parse_branchname_arg(int argc, const char **argv,
return argcount;
}
-static int switch_unborn_to_new_branch(struct checkout_opts *opts)
+static int switch_unborn_to_new_branch(const struct checkout_opts *opts)
{
int status;
struct strbuf branch_ref = STRBUF_INIT;
@@ -922,38 +954,80 @@ static int switch_unborn_to_new_branch(struct checkout_opts *opts)
return status;
}
+static int checkout_branch(struct checkout_opts *opts,
+ struct branch_info *new)
+{
+ if (opts->pathspec)
+ die(_("paths cannot be used with switching branches"));
+
+ if (opts->patch_mode)
+ die(_("'%s' cannot be used with switching branches"),
+ "--patch");
+
+ if (opts->writeout_stage)
+ die(_("'%s' cannot be used with switching branches"),
+ "--ours/--theirs");
+
+ if (opts->force && opts->merge)
+ die(_("'%s' cannot be used with '%s'"), "-f", "-m");
+
+ if (opts->force_detach && opts->new_branch)
+ die(_("'%s' cannot be used with '%s'"),
+ "--detach", "-b/-B/--orphan");
+
+ if (opts->new_orphan_branch) {
+ if (opts->track != BRANCH_TRACK_UNSPECIFIED)
+ die(_("'%s' cannot be used with '%s'"), "--orphan", "-t");
+ } else if (opts->force_detach) {
+ if (opts->track != BRANCH_TRACK_UNSPECIFIED)
+ die(_("'%s' cannot be used with '%s'"), "--detach", "-t");
+ } else if (opts->track == BRANCH_TRACK_UNSPECIFIED)
+ opts->track = git_branch_track;
+
+ if (new->name && !new->commit)
+ die(_("Cannot switch branch to a non-commit '%s'"),
+ new->name);
+
+ if (!new->commit && opts->new_branch) {
+ unsigned char rev[20];
+ int flag;
+
+ if (!read_ref_full("HEAD", rev, 0, &flag) &&
+ (flag & REF_ISSYMREF) && is_null_sha1(rev))
+ return switch_unborn_to_new_branch(opts);
+ }
+ return switch_branches(opts, new);
+}
+
int cmd_checkout(int argc, const char **argv, const char *prefix)
{
struct checkout_opts opts;
- unsigned char rev[20];
struct branch_info new;
- struct tree *source_tree = NULL;
char *conflict_style = NULL;
- int patch_mode = 0;
int dwim_new_local_branch = 1;
struct option options[] = {
- OPT__QUIET(&opts.quiet, "suppress progress reporting"),
- OPT_STRING('b', NULL, &opts.new_branch, "branch",
- "create and checkout a new branch"),
- OPT_STRING('B', NULL, &opts.new_branch_force, "branch",
- "create/reset and checkout a branch"),
- OPT_BOOLEAN('l', NULL, &opts.new_branch_log, "create reflog for new branch"),
- OPT_BOOLEAN(0, "detach", &opts.force_detach, "detach the HEAD at named commit"),
- OPT_SET_INT('t', "track", &opts.track, "set upstream info for new branch",
+ OPT__QUIET(&opts.quiet, N_("suppress progress reporting")),
+ OPT_STRING('b', NULL, &opts.new_branch, N_("branch"),
+ N_("create and checkout a new branch")),
+ OPT_STRING('B', NULL, &opts.new_branch_force, N_("branch"),
+ N_("create/reset and checkout a branch")),
+ OPT_BOOLEAN('l', NULL, &opts.new_branch_log, N_("create reflog for new branch")),
+ OPT_BOOLEAN(0, "detach", &opts.force_detach, N_("detach the HEAD at named commit")),
+ OPT_SET_INT('t', "track", &opts.track, N_("set upstream info for new branch"),
BRANCH_TRACK_EXPLICIT),
- OPT_STRING(0, "orphan", &opts.new_orphan_branch, "new branch", "new unparented branch"),
- OPT_SET_INT('2', "ours", &opts.writeout_stage, "checkout our version for unmerged files",
+ OPT_STRING(0, "orphan", &opts.new_orphan_branch, N_("new branch"), N_("new unparented branch")),
+ OPT_SET_INT('2', "ours", &opts.writeout_stage, N_("checkout our version for unmerged files"),
2),
- OPT_SET_INT('3', "theirs", &opts.writeout_stage, "checkout their version for unmerged files",
+ OPT_SET_INT('3', "theirs", &opts.writeout_stage, N_("checkout their version for unmerged files"),
3),
- OPT__FORCE(&opts.force, "force checkout (throw away local modifications)"),
- OPT_BOOLEAN('m', "merge", &opts.merge, "perform a 3-way merge with the new branch"),
- OPT_BOOLEAN(0, "overwrite-ignore", &opts.overwrite_ignore, "update ignored files (default)"),
- OPT_STRING(0, "conflict", &conflict_style, "style",
- "conflict style (merge or diff3)"),
- OPT_BOOLEAN('p', "patch", &patch_mode, "select hunks interactively"),
+ OPT__FORCE(&opts.force, N_("force checkout (throw away local modifications)")),
+ OPT_BOOLEAN('m', "merge", &opts.merge, N_("perform a 3-way merge with the new branch")),
+ OPT_BOOLEAN(0, "overwrite-ignore", &opts.overwrite_ignore, N_("update ignored files (default)")),
+ OPT_STRING(0, "conflict", &conflict_style, N_("style"),
+ N_("conflict style (merge or diff3)")),
+ OPT_BOOLEAN('p', "patch", &opts.patch_mode, N_("select hunks interactively")),
{ OPTION_BOOLEAN, 0, "guess", &dwim_new_local_branch, NULL,
- "second guess 'git checkout no-such-branch'",
+ N_("second guess 'git checkout no-such-branch'"),
PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
OPT_END(),
};
@@ -961,6 +1035,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
memset(&opts, 0, sizeof(opts));
memset(&new, 0, sizeof(new));
opts.overwrite_ignore = 1;
+ opts.prefix = prefix;
gitmodules_config();
git_config(git_checkout_config, &opts);
@@ -970,26 +1045,27 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, options, checkout_usage,
PARSE_OPT_KEEP_DASHDASH);
- /* we can assume from now on new_branch = !new_branch_force */
- if (opts.new_branch && opts.new_branch_force)
- die(_("-B cannot be used with -b"));
+ if (conflict_style) {
+ opts.merge = 1; /* implied */
+ git_xmerge_config("merge.conflictstyle", conflict_style, NULL);
+ }
+
+ if ((!!opts.new_branch + !!opts.new_branch_force + !!opts.new_orphan_branch) > 1)
+ die(_("-b, -B and --orphan are mutually exclusive"));
- /* copy -B over to -b, so that we can just check the latter */
+ /*
+ * From here on, new_branch will contain the branch to be checked out,
+ * and new_branch_force and new_orphan_branch will tell us which one of
+ * -b/-B/--orphan is being used.
+ */
if (opts.new_branch_force)
opts.new_branch = opts.new_branch_force;
- if (patch_mode && (opts.track > 0 || opts.new_branch
- || opts.new_branch_log || opts.merge || opts.force
- || opts.force_detach))
- die (_("--patch is incompatible with all other options"));
-
- if (opts.force_detach && (opts.new_branch || opts.new_orphan_branch))
- die(_("--detach cannot be used with -b/-B/--orphan"));
- if (opts.force_detach && 0 < opts.track)
- die(_("--detach cannot be used with -t"));
+ if (opts.new_orphan_branch)
+ opts.new_branch = opts.new_orphan_branch;
- /* --track without -b should DWIM */
- if (0 < opts.track && !opts.new_branch) {
+ /* --track without -b/-B/--orphan should DWIM */
+ if (opts.track != BRANCH_TRACK_UNSPECIFIED && !opts.new_branch) {
const char *argv0 = argv[0];
if (!argc || !strcmp(argv0, "--"))
die (_("--track needs a branch name"));
@@ -1003,22 +1079,6 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
opts.new_branch = argv0 + 1;
}
- if (opts.new_orphan_branch) {
- if (opts.new_branch)
- die(_("--orphan and -b|-B are mutually exclusive"));
- if (opts.track > 0)
- die(_("--orphan cannot be used with -t"));
- opts.new_branch = opts.new_orphan_branch;
- }
-
- if (conflict_style) {
- opts.merge = 1; /* implied */
- git_xmerge_config("merge.conflictstyle", conflict_style, NULL);
- }
-
- if (opts.force && opts.merge)
- die(_("git checkout: -f and -m are incompatible"));
-
/*
* Extract branch name from command line arguments, so
* all that is left is pathspecs.
@@ -1033,73 +1093,56 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
* remote branches, erroring out for invalid or ambiguous cases.
*/
if (argc) {
+ unsigned char rev[20];
int dwim_ok =
- !patch_mode &&
+ !opts.patch_mode &&
dwim_new_local_branch &&
opts.track == BRANCH_TRACK_UNSPECIFIED &&
!opts.new_branch;
int n = parse_branchname_arg(argc, argv, dwim_ok,
- &new, &source_tree, rev, &opts.new_branch);
+ &new, &opts.source_tree,
+ rev, &opts.new_branch);
argv += n;
argc -= n;
}
- if (opts.track == BRANCH_TRACK_UNSPECIFIED)
- opts.track = git_branch_track;
-
if (argc) {
- const char **pathspec = get_pathspec(prefix, argv);
+ opts.pathspec = get_pathspec(prefix, argv);
- if (!pathspec)
+ if (!opts.pathspec)
die(_("invalid path specification"));
- if (patch_mode)
- return interactive_checkout(new.name, pathspec, &opts);
-
- /* Checkout paths */
- if (opts.new_branch) {
- if (argc == 1) {
- die(_("git checkout: updating paths is incompatible with switching branches.\nDid you intend to checkout '%s' which can not be resolved as commit?"), argv[0]);
- } else {
- die(_("git checkout: updating paths is incompatible with switching branches."));
- }
- }
+ /*
+ * Try to give more helpful suggestion.
+ * new_branch && argc > 1 will be caught later.
+ */
+ if (opts.new_branch && argc == 1)
+ die(_("Cannot update paths and switch to branch '%s' at the same time.\n"
+ "Did you intend to checkout '%s' which can not be resolved as commit?"),
+ opts.new_branch, argv[0]);
if (opts.force_detach)
- die(_("git checkout: --detach does not take a path argument"));
+ die(_("git checkout: --detach does not take a path argument '%s'"),
+ argv[0]);
if (1 < !!opts.writeout_stage + !!opts.force + !!opts.merge)
- die(_("git checkout: --ours/--theirs, --force and --merge are incompatible when\nchecking out of the index."));
-
- return checkout_paths(source_tree, pathspec, prefix, &opts);
+ die(_("git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
+ "checking out of the index."));
}
- if (patch_mode)
- return interactive_checkout(new.name, NULL, &opts);
-
if (opts.new_branch) {
struct strbuf buf = STRBUF_INIT;
- opts.branch_exists = validate_new_branchname(opts.new_branch, &buf,
- !!opts.new_branch_force,
- !!opts.new_branch_force);
+ opts.branch_exists =
+ validate_new_branchname(opts.new_branch, &buf,
+ !!opts.new_branch_force,
+ !!opts.new_branch_force);
strbuf_release(&buf);
}
- if (new.name && !new.commit) {
- die(_("Cannot switch branch to a non-commit."));
- }
- if (opts.writeout_stage)
- die(_("--ours/--theirs is incompatible with switching branches."));
-
- if (!new.commit && opts.new_branch) {
- unsigned char rev[20];
- int flag;
-
- if (!read_ref_full("HEAD", rev, 0, &flag) &&
- (flag & REF_ISSYMREF) && is_null_sha1(rev))
- return switch_unborn_to_new_branch(&opts);
- }
- return switch_branches(&opts, &new);
+ if (opts.patch_mode || opts.pathspec)
+ return checkout_paths(&opts, new.name);
+ else
+ return checkout_branch(&opts, &new);
}
diff --git a/builtin/clean.c b/builtin/clean.c
index 0c7b3d0..69c1cda 100644
--- a/builtin/clean.c
+++ b/builtin/clean.c
@@ -16,7 +16,7 @@
static int force = -1; /* unset */
static const char *const builtin_clean_usage[] = {
- "git clean [-d] [-f] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>...",
+ N_("git clean [-d] [-f] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>..."),
NULL
};
@@ -48,16 +48,16 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
const char *qname;
char *seen = NULL;
struct option options[] = {
- OPT__QUIET(&quiet, "do not print names of files removed"),
- OPT__DRY_RUN(&show_only, "dry run"),
- OPT__FORCE(&force, "force"),
+ OPT__QUIET(&quiet, N_("do not print names of files removed")),
+ OPT__DRY_RUN(&show_only, N_("dry run")),
+ OPT__FORCE(&force, N_("force")),
OPT_BOOLEAN('d', NULL, &remove_directories,
- "remove whole directories"),
- { OPTION_CALLBACK, 'e', "exclude", &exclude_list, "pattern",
- "add <pattern> to ignore rules", PARSE_OPT_NONEG, exclude_cb },
- OPT_BOOLEAN('x', NULL, &ignored, "remove ignored files, too"),
+ N_("remove whole directories")),
+ { OPTION_CALLBACK, 'e', "exclude", &exclude_list, N_("pattern"),
+ N_("add <pattern> to ignore rules"), PARSE_OPT_NONEG, exclude_cb },
+ OPT_BOOLEAN('x', NULL, &ignored, N_("remove ignored files, too")),
OPT_BOOLEAN('X', NULL, &ignored_only,
- "remove only ignored files"),
+ N_("remove only ignored files")),
OPT_END()
};
diff --git a/builtin/clone.c b/builtin/clone.c
index 920ef7f..ec2f75b 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -33,12 +33,12 @@
*
*/
static const char * const builtin_clone_usage[] = {
- "git clone [options] [--] <repo> [<dir>]",
+ N_("git clone [options] [--] <repo> [<dir>]"),
NULL
};
static int option_no_checkout, option_bare, option_mirror, option_single_branch = -1;
-static int option_local, option_no_hardlinks, option_shared, option_recursive;
+static int option_local = -1, option_no_hardlinks, option_shared, option_recursive;
static char *option_template, *option_depth;
static char *option_origin = NULL;
static char *option_branch = NULL;
@@ -61,43 +61,43 @@ static int opt_parse_reference(const struct option *opt, const char *arg, int un
static struct option builtin_clone_options[] = {
OPT__VERBOSITY(&option_verbosity),
OPT_BOOL(0, "progress", &option_progress,
- "force progress reporting"),
+ N_("force progress reporting")),
OPT_BOOLEAN('n', "no-checkout", &option_no_checkout,
- "don't create a checkout"),
- OPT_BOOLEAN(0, "bare", &option_bare, "create a bare repository"),
+ N_("don't create a checkout")),
+ OPT_BOOLEAN(0, "bare", &option_bare, N_("create a bare repository")),
{ OPTION_BOOLEAN, 0, "naked", &option_bare, NULL,
- "create a bare repository",
+ N_("create a bare repository"),
PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
OPT_BOOLEAN(0, "mirror", &option_mirror,
- "create a mirror repository (implies bare)"),
- OPT_BOOLEAN('l', "local", &option_local,
- "to clone from a local repository"),
+ N_("create a mirror repository (implies bare)")),
+ OPT_BOOL('l', "local", &option_local,
+ N_("to clone from a local repository")),
OPT_BOOLEAN(0, "no-hardlinks", &option_no_hardlinks,
- "don't use local hardlinks, always copy"),
+ N_("don't use local hardlinks, always copy")),
OPT_BOOLEAN('s', "shared", &option_shared,
- "setup as shared repository"),
+ N_("setup as shared repository")),
OPT_BOOLEAN(0, "recursive", &option_recursive,
- "initialize submodules in the clone"),
+ N_("initialize submodules in the clone")),
OPT_BOOLEAN(0, "recurse-submodules", &option_recursive,
- "initialize submodules in the clone"),
- OPT_STRING(0, "template", &option_template, "template-directory",
- "directory from which templates will be used"),
- OPT_CALLBACK(0 , "reference", &option_reference, "repo",
- "reference repository", &opt_parse_reference),
- OPT_STRING('o', "origin", &option_origin, "name",
- "use <name> instead of 'origin' to track upstream"),
- OPT_STRING('b', "branch", &option_branch, "branch",
- "checkout <branch> instead of the remote's HEAD"),
- OPT_STRING('u', "upload-pack", &option_upload_pack, "path",
- "path to git-upload-pack on the remote"),
- OPT_STRING(0, "depth", &option_depth, "depth",
- "create a shallow clone of that depth"),
+ N_("initialize submodules in the clone")),
+ OPT_STRING(0, "template", &option_template, N_("template-directory"),
+ N_("directory from which templates will be used")),
+ OPT_CALLBACK(0 , "reference", &option_reference, N_("repo"),
+ N_("reference repository"), &opt_parse_reference),
+ OPT_STRING('o', "origin", &option_origin, N_("name"),
+ N_("use <name> instead of 'origin' to track upstream")),
+ OPT_STRING('b', "branch", &option_branch, N_("branch"),
+ N_("checkout <branch> instead of the remote's HEAD")),
+ OPT_STRING('u', "upload-pack", &option_upload_pack, N_("path"),
+ N_("path to git-upload-pack on the remote")),
+ OPT_STRING(0, "depth", &option_depth, N_("depth"),
+ N_("create a shallow clone of that depth")),
OPT_BOOL(0, "single-branch", &option_single_branch,
- "clone only one branch, HEAD or --branch"),
- OPT_STRING(0, "separate-git-dir", &real_git_dir, "gitdir",
- "separate git dir from working tree"),
- OPT_STRING_LIST('c', "config", &option_config, "key=value",
- "set config inside the new repository"),
+ N_("clone only one branch, HEAD or --branch")),
+ OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"),
+ N_("separate git dir from working tree")),
+ OPT_STRING_LIST('c', "config", &option_config, N_("key=value"),
+ N_("set config inside the new repository")),
OPT_END()
};
@@ -236,7 +236,7 @@ static int add_one_reference(struct string_list_item *item, void *cb_data)
/* Beware: real_path() and mkpath() return static buffer */
ref_git = xstrdup(real_path(item->string));
if (is_directory(mkpath("%s/.git/objects", ref_git))) {
- char *ref_git_git = xstrdup(mkpath("%s/.git", ref_git));
+ char *ref_git_git = mkpathdup("%s/.git", ref_git);
free(ref_git);
ref_git = ref_git_git;
} else if (!is_directory(mkpath("%s/objects", ref_git)))
@@ -342,7 +342,7 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
if (!option_no_hardlinks) {
if (!link(src->buf, dest->buf))
continue;
- if (option_local)
+ if (option_local > 0)
die_errno(_("failed to create link '%s'"), dest->buf);
option_no_hardlinks = 1;
}
@@ -610,6 +610,54 @@ static void write_config(struct string_list *config)
}
}
+static void write_refspec_config(const char* src_ref_prefix,
+ const struct ref* our_head_points_at,
+ const struct ref* remote_head_points_at, struct strbuf* branch_top)
+{
+ struct strbuf key = STRBUF_INIT;
+ struct strbuf value = STRBUF_INIT;
+
+ if (option_mirror || !option_bare) {
+ if (option_single_branch && !option_mirror) {
+ if (option_branch) {
+ if (strstr(our_head_points_at->name, "refs/tags/"))
+ strbuf_addf(&value, "+%s:%s", our_head_points_at->name,
+ our_head_points_at->name);
+ else
+ strbuf_addf(&value, "+%s:%s%s", our_head_points_at->name,
+ branch_top->buf, option_branch);
+ } else if (remote_head_points_at) {
+ strbuf_addf(&value, "+%s:%s%s", remote_head_points_at->name,
+ branch_top->buf,
+ skip_prefix(remote_head_points_at->name, "refs/heads/"));
+ }
+ /*
+ * otherwise, the next "git fetch" will
+ * simply fetch from HEAD without updating
+ * any remote tracking branch, which is what
+ * we want.
+ */
+ } else {
+ strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top->buf);
+ }
+ /* Configure the remote */
+ if (value.len) {
+ strbuf_addf(&key, "remote.%s.fetch", option_origin);
+ git_config_set_multivar(key.buf, value.buf, "^$", 0);
+ strbuf_reset(&key);
+
+ if (option_mirror) {
+ strbuf_addf(&key, "remote.%s.mirror", option_origin);
+ git_config_set(key.buf, "true");
+ strbuf_reset(&key);
+ }
+ }
+ }
+
+ strbuf_release(&key);
+ strbuf_release(&value);
+}
+
int cmd_clone(int argc, const char **argv, const char *prefix)
{
int is_bundle = 0, is_local;
@@ -671,7 +719,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
die(_("repository '%s' does not exist"), repo_name);
else
repo = repo_name;
- is_local = path && !is_bundle;
+ is_local = option_local != 0 && path && !is_bundle;
if (is_local && option_depth)
warning(_("--depth is ignored in local clones; use file:// instead."));
@@ -700,7 +748,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
git_dir = xstrdup(dir);
else {
work_tree = dir;
- git_dir = xstrdup(mkpath("%s/.git", dir));
+ git_dir = mkpathdup("%s/.git", dir);
}
if (!option_bare) {
@@ -755,20 +803,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
}
strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top.buf);
-
- if (option_mirror || !option_bare) {
- /* Configure the remote */
- strbuf_addf(&key, "remote.%s.fetch", option_origin);
- git_config_set_multivar(key.buf, value.buf, "^$", 0);
- strbuf_reset(&key);
-
- if (option_mirror) {
- strbuf_addf(&key, "remote.%s.mirror", option_origin);
- git_config_set(key.buf, "true");
- strbuf_reset(&key);
- }
- }
-
strbuf_addf(&key, "remote.%s.url", option_origin);
git_config_set(key.buf, repo);
strbuf_reset(&key);
@@ -853,6 +887,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
"refs/heads/master");
}
+ write_refspec_config(src_ref_prefix, our_head_points_at,
+ remote_head_points_at, &branch_top);
+
if (is_local)
clone_local(path, git_dir);
else if (refs && complete_refs_before_fetch)
diff --git a/builtin/column.c b/builtin/column.c
index 5ea798a..e125a55 100644
--- a/builtin/column.c
+++ b/builtin/column.c
@@ -6,7 +6,7 @@
#include "column.h"
static const char * const builtin_column_usage[] = {
- "git column [options]",
+ N_("git column [options]"),
NULL
};
static unsigned int colopts;
@@ -23,13 +23,13 @@ int cmd_column(int argc, const char **argv, const char *prefix)
struct column_options copts;
const char *command = NULL, *real_command = NULL;
struct option options[] = {
- OPT_STRING(0, "command", &real_command, "name", "lookup config vars"),
- OPT_COLUMN(0, "mode", &colopts, "layout to use"),
- OPT_INTEGER(0, "raw-mode", &colopts, "layout to use"),
- OPT_INTEGER(0, "width", &copts.width, "Maximum width"),
- OPT_STRING(0, "indent", &copts.indent, "string", "Padding space on left border"),
- OPT_INTEGER(0, "nl", &copts.nl, "Padding space on right border"),
- OPT_INTEGER(0, "padding", &copts.padding, "Padding space between columns"),
+ OPT_STRING(0, "command", &real_command, N_("name"), N_("lookup config vars")),
+ OPT_COLUMN(0, "mode", &colopts, N_("layout to use")),
+ OPT_INTEGER(0, "raw-mode", &colopts, N_("layout to use")),
+ OPT_INTEGER(0, "width", &copts.width, N_("Maximum width")),
+ OPT_STRING(0, "indent", &copts.indent, N_("string"), N_("Padding space on left border")),
+ OPT_INTEGER(0, "nl", &copts.nl, N_("Padding space on right border")),
+ OPT_INTEGER(0, "padding", &copts.padding, N_("Padding space between columns")),
OPT_END()
};
diff --git a/builtin/commit-tree.c b/builtin/commit-tree.c
index a0df12c..eac901a 100644
--- a/builtin/commit-tree.c
+++ b/builtin/commit-tree.c
@@ -54,7 +54,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
unsigned char sha1[20];
if (argc <= ++i)
usage(commit_tree_usage);
- if (get_sha1(argv[i], sha1))
+ if (get_sha1_commit(argv[i], sha1))
die("Not a valid object name %s", argv[i]);
assert_sha1_type(sha1, OBJ_COMMIT);
new_parent(lookup_commit(sha1), &parents);
@@ -101,7 +101,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
continue;
}
- if (get_sha1(arg, tree_sha1))
+ if (get_sha1_tree(arg, tree_sha1))
die("Not a valid object name %s", arg);
if (got_tree)
die("Cannot give more than one trees");
diff --git a/builtin/commit.c b/builtin/commit.c
index 62028e7..a17a5df 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -28,14 +28,15 @@
#include "submodule.h"
#include "gpg-interface.h"
#include "column.h"
+#include "sequencer.h"
static const char * const builtin_commit_usage[] = {
- "git commit [options] [--] <filepattern>...",
+ N_("git commit [options] [--] <filepattern>..."),
NULL
};
static const char * const builtin_status_usage[] = {
- "git status [options] [--] <filepattern>...",
+ N_("git status [options] [--] <filepattern>..."),
NULL
};
@@ -466,8 +467,6 @@ static int is_a_merge(const struct commit *current_head)
return !!(current_head->parents && current_head->parents->next);
}
-static const char sign_off_header[] = "Signed-off-by: ";
-
static void export_one(const char *var, const char *s, const char *e, int hack)
{
struct strbuf buf = STRBUF_INIT;
@@ -552,47 +551,6 @@ static void determine_author_info(struct strbuf *author_ident)
}
}
-static int ends_rfc2822_footer(struct strbuf *sb)
-{
- int ch;
- int hit = 0;
- int i, j, k;
- int len = sb->len;
- int first = 1;
- const char *buf = sb->buf;
-
- for (i = len - 1; i > 0; i--) {
- if (hit && buf[i] == '\n')
- break;
- hit = (buf[i] == '\n');
- }
-
- while (i < len - 1 && buf[i] == '\n')
- i++;
-
- for (; i < len; i = k) {
- for (k = i; k < len && buf[k] != '\n'; k++)
- ; /* do nothing */
- k++;
-
- if ((buf[k] == ' ' || buf[k] == '\t') && !first)
- continue;
-
- first = 0;
-
- for (j = 0; i + j < len; j++) {
- ch = buf[i + j];
- if (ch == ':')
- break;
- if (isalnum(ch) ||
- (ch == '-'))
- continue;
- return 0;
- }
- }
- return 1;
-}
-
static char *cut_ident_timestamp_part(char *string)
{
char *ket = strrchr(string, '>');
@@ -717,21 +675,30 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
stripspace(&sb, 0);
if (signoff) {
- struct strbuf sob = STRBUF_INIT;
- int i;
-
- strbuf_addstr(&sob, sign_off_header);
- strbuf_addstr(&sob, fmt_name(getenv("GIT_COMMITTER_NAME"),
- getenv("GIT_COMMITTER_EMAIL")));
- strbuf_addch(&sob, '\n');
- for (i = sb.len - 1; i > 0 && sb.buf[i - 1] != '\n'; i--)
- ; /* do nothing */
- if (prefixcmp(sb.buf + i, sob.buf)) {
- if (!i || !ends_rfc2822_footer(&sb))
- strbuf_addch(&sb, '\n');
- strbuf_addbuf(&sb, &sob);
+ /*
+ * See if we have a Conflicts: block at the end. If yes, count
+ * its size, so we can ignore it.
+ */
+ int ignore_footer = 0;
+ int i, eol, previous = 0;
+ const char *nl;
+
+ for (i = 0; i < sb.len; i++) {
+ nl = memchr(sb.buf + i, '\n', sb.len - i);
+ if (nl)
+ eol = nl - sb.buf;
+ else
+ eol = sb.len;
+ if (!prefixcmp(sb.buf + previous, "\nConflicts:\n")) {
+ ignore_footer = sb.len - previous;
+ break;
+ }
+ while (i < eol)
+ i++;
+ previous = eol;
}
- strbuf_release(&sob);
+
+ append_signoff(&sb, ignore_footer);
}
if (fwrite(sb.buf, 1, sb.len, s->fp) < sb.len)
@@ -1184,26 +1151,26 @@ int cmd_status(int argc, const char **argv, const char *prefix)
int fd;
unsigned char sha1[20];
static struct option builtin_status_options[] = {
- OPT__VERBOSE(&verbose, "be verbose"),
+ OPT__VERBOSE(&verbose, N_("be verbose")),
OPT_SET_INT('s', "short", &status_format,
- "show status concisely", STATUS_FORMAT_SHORT),
+ N_("show status concisely"), STATUS_FORMAT_SHORT),
OPT_BOOLEAN('b', "branch", &s.show_branch,
- "show branch information"),
+ N_("show branch information")),
OPT_SET_INT(0, "porcelain", &status_format,
- "machine-readable output",
+ N_("machine-readable output"),
STATUS_FORMAT_PORCELAIN),
OPT_BOOLEAN('z', "null", &s.null_termination,
- "terminate entries with NUL"),
+ N_("terminate entries with NUL")),
{ OPTION_STRING, 'u', "untracked-files", &untracked_files_arg,
- "mode",
- "show untracked files, optional modes: all, normal, no. (Default: all)",
+ N_("mode"),
+ N_("show untracked files, optional modes: all, normal, no. (Default: all)"),
PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
OPT_BOOLEAN(0, "ignored", &show_ignored_in_status,
- "show ignored files"),
- { OPTION_STRING, 0, "ignore-submodules", &ignore_submodule_arg, "when",
- "ignore changes to submodules, optional when: all, dirty, untracked. (Default: all)",
+ N_("show ignored files")),
+ { OPTION_STRING, 0, "ignore-submodules", &ignore_submodule_arg, N_("when"),
+ N_("ignore changes to submodules, optional when: all, dirty, untracked. (Default: all)"),
PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
- OPT_COLUMN(0, "column", &s.colopts, "list untracked files in columns"),
+ OPT_COLUMN(0, "column", &s.colopts, N_("list untracked files in columns")),
OPT_END(),
};
@@ -1384,53 +1351,53 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
{
static struct wt_status s;
static struct option builtin_commit_options[] = {
- OPT__QUIET(&quiet, "suppress summary after successful commit"),
- OPT__VERBOSE(&verbose, "show diff in commit message template"),
-
- OPT_GROUP("Commit message options"),
- OPT_FILENAME('F', "file", &logfile, "read message from file"),
- OPT_STRING(0, "author", &force_author, "author", "override author for commit"),
- OPT_STRING(0, "date", &force_date, "date", "override date for commit"),
- OPT_CALLBACK('m', "message", &message, "message", "commit message", opt_parse_m),
- OPT_STRING('c', "reedit-message", &edit_message, "commit", "reuse and edit message from specified commit"),
- OPT_STRING('C', "reuse-message", &use_message, "commit", "reuse message from specified commit"),
- OPT_STRING(0, "fixup", &fixup_message, "commit", "use autosquash formatted message to fixup specified commit"),
- OPT_STRING(0, "squash", &squash_message, "commit", "use autosquash formatted message to squash specified commit"),
- OPT_BOOLEAN(0, "reset-author", &renew_authorship, "the commit is authored by me now (used with -C/-c/--amend)"),
- OPT_BOOLEAN('s', "signoff", &signoff, "add Signed-off-by:"),
- OPT_FILENAME('t', "template", &template_file, "use specified template file"),
- OPT_BOOL('e', "edit", &edit_flag, "force edit of commit"),
- OPT_STRING(0, "cleanup", &cleanup_arg, "default", "how to strip spaces and #comments from message"),
- OPT_BOOLEAN(0, "status", &include_status, "include status in commit message template"),
- { OPTION_STRING, 'S', "gpg-sign", &sign_commit, "key id",
- "GPG sign commit", PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
+ OPT__QUIET(&quiet, N_("suppress summary after successful commit")),
+ OPT__VERBOSE(&verbose, N_("show diff in commit message template")),
+
+ OPT_GROUP(N_("Commit message options")),
+ OPT_FILENAME('F', "file", &logfile, N_("read message from file")),
+ OPT_STRING(0, "author", &force_author, N_("author"), N_("override author for commit")),
+ OPT_STRING(0, "date", &force_date, N_("date"), N_("override date for commit")),
+ OPT_CALLBACK('m', "message", &message, N_("message"), N_("commit message"), opt_parse_m),
+ OPT_STRING('c', "reedit-message", &edit_message, N_("commit"), N_("reuse and edit message from specified commit")),
+ OPT_STRING('C', "reuse-message", &use_message, N_("commit"), N_("reuse message from specified commit")),
+ OPT_STRING(0, "fixup", &fixup_message, N_("commit"), N_("use autosquash formatted message to fixup specified commit")),
+ OPT_STRING(0, "squash", &squash_message, N_("commit"), N_("use autosquash formatted message to squash specified commit")),
+ OPT_BOOLEAN(0, "reset-author", &renew_authorship, N_("the commit is authored by me now (used with -C/-c/--amend)")),
+ OPT_BOOLEAN('s', "signoff", &signoff, N_("add Signed-off-by:")),
+ OPT_FILENAME('t', "template", &template_file, N_("use specified template file")),
+ OPT_BOOL('e', "edit", &edit_flag, N_("force edit of commit")),
+ OPT_STRING(0, "cleanup", &cleanup_arg, N_("default"), N_("how to strip spaces and #comments from message")),
+ OPT_BOOLEAN(0, "status", &include_status, N_("include status in commit message template")),
+ { OPTION_STRING, 'S', "gpg-sign", &sign_commit, N_("key id"),
+ N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
/* end commit message options */
- OPT_GROUP("Commit contents options"),
- OPT_BOOLEAN('a', "all", &all, "commit all changed files"),
- OPT_BOOLEAN('i', "include", &also, "add specified files to index for commit"),
- OPT_BOOLEAN(0, "interactive", &interactive, "interactively add files"),
- OPT_BOOLEAN('p', "patch", &patch_interactive, "interactively add changes"),
- OPT_BOOLEAN('o', "only", &only, "commit only specified files"),
- OPT_BOOLEAN('n', "no-verify", &no_verify, "bypass pre-commit hook"),
- OPT_BOOLEAN(0, "dry-run", &dry_run, "show what would be committed"),
- OPT_SET_INT(0, "short", &status_format, "show status concisely",
+ OPT_GROUP(N_("Commit contents options")),
+ OPT_BOOLEAN('a', "all", &all, N_("commit all changed files")),
+ OPT_BOOLEAN('i', "include", &also, N_("add specified files to index for commit")),
+ OPT_BOOLEAN(0, "interactive", &interactive, N_("interactively add files")),
+ OPT_BOOLEAN('p', "patch", &patch_interactive, N_("interactively add changes")),
+ OPT_BOOLEAN('o', "only", &only, N_("commit only specified files")),
+ OPT_BOOLEAN('n', "no-verify", &no_verify, N_("bypass pre-commit hook")),
+ OPT_BOOLEAN(0, "dry-run", &dry_run, N_("show what would be committed")),
+ OPT_SET_INT(0, "short", &status_format, N_("show status concisely"),
STATUS_FORMAT_SHORT),
- OPT_BOOLEAN(0, "branch", &s.show_branch, "show branch information"),
+ OPT_BOOLEAN(0, "branch", &s.show_branch, N_("show branch information")),
OPT_SET_INT(0, "porcelain", &status_format,
- "machine-readable output", STATUS_FORMAT_PORCELAIN),
+ N_("machine-readable output"), STATUS_FORMAT_PORCELAIN),
OPT_BOOLEAN('z', "null", &s.null_termination,
- "terminate entries with NUL"),
- OPT_BOOLEAN(0, "amend", &amend, "amend previous commit"),
- OPT_BOOLEAN(0, "no-post-rewrite", &no_post_rewrite, "bypass post-rewrite hook"),
- { OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, "mode", "show untracked files, optional modes: all, normal, no. (Default: all)", PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
+ N_("terminate entries with NUL")),
+ OPT_BOOLEAN(0, "amend", &amend, N_("amend previous commit")),
+ OPT_BOOLEAN(0, "no-post-rewrite", &no_post_rewrite, N_("bypass post-rewrite hook")),
+ { OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, N_("mode"), N_("show untracked files, optional modes: all, normal, no. (Default: all)"), PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
/* end commit contents options */
{ OPTION_BOOLEAN, 0, "allow-empty", &allow_empty, NULL,
- "ok to record an empty change",
+ N_("ok to record an empty change"),
PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
{ OPTION_BOOLEAN, 0, "allow-empty-message", &allow_empty_message, NULL,
- "ok to record a change with an empty message",
+ N_("ok to record a change with an empty message"),
PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
OPT_END()
@@ -1452,6 +1419,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
usage_with_options(builtin_commit_usage, builtin_commit_options);
wt_status_prepare(&s);
+ gitmodules_config();
git_config(git_commit_config, &s);
determine_whence(&s);
s.colopts = 0;
diff --git a/builtin/config.c b/builtin/config.c
index b44277c..e1c33e0 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -4,7 +4,7 @@
#include "parse-options.h"
static const char *const builtin_config_usage[] = {
- "git config [options]",
+ N_("git config [options]"),
NULL
};
@@ -49,33 +49,33 @@ static int respect_includes = -1;
#define TYPE_PATH (1<<3)
static struct option builtin_config_options[] = {
- OPT_GROUP("Config file location"),
- OPT_BOOLEAN(0, "global", &use_global_config, "use global config file"),
- OPT_BOOLEAN(0, "system", &use_system_config, "use system config file"),
- OPT_BOOLEAN(0, "local", &use_local_config, "use repository config file"),
- OPT_STRING('f', "file", &given_config_file, "file", "use given config file"),
- OPT_GROUP("Action"),
- OPT_BIT(0, "get", &actions, "get value: name [value-regex]", ACTION_GET),
- OPT_BIT(0, "get-all", &actions, "get all values: key [value-regex]", ACTION_GET_ALL),
- OPT_BIT(0, "get-regexp", &actions, "get values for regexp: name-regex [value-regex]", ACTION_GET_REGEXP),
- OPT_BIT(0, "replace-all", &actions, "replace all matching variables: name value [value_regex]", ACTION_REPLACE_ALL),
- OPT_BIT(0, "add", &actions, "adds a new variable: name value", ACTION_ADD),
- OPT_BIT(0, "unset", &actions, "removes a variable: name [value-regex]", ACTION_UNSET),
- OPT_BIT(0, "unset-all", &actions, "removes all matches: name [value-regex]", ACTION_UNSET_ALL),
- OPT_BIT(0, "rename-section", &actions, "rename section: old-name new-name", ACTION_RENAME_SECTION),
- OPT_BIT(0, "remove-section", &actions, "remove a section: name", ACTION_REMOVE_SECTION),
- OPT_BIT('l', "list", &actions, "list all", ACTION_LIST),
- OPT_BIT('e', "edit", &actions, "opens an editor", ACTION_EDIT),
- OPT_STRING(0, "get-color", &get_color_slot, "slot", "find the color configured: [default]"),
- OPT_STRING(0, "get-colorbool", &get_colorbool_slot, "slot", "find the color setting: [stdout-is-tty]"),
- OPT_GROUP("Type"),
- OPT_BIT(0, "bool", &types, "value is \"true\" or \"false\"", TYPE_BOOL),
- OPT_BIT(0, "int", &types, "value is decimal number", TYPE_INT),
- OPT_BIT(0, "bool-or-int", &types, "value is --bool or --int", TYPE_BOOL_OR_INT),
- OPT_BIT(0, "path", &types, "value is a path (file or directory name)", TYPE_PATH),
- OPT_GROUP("Other"),
- OPT_BOOLEAN('z', "null", &end_null, "terminate values with NUL byte"),
- OPT_BOOL(0, "includes", &respect_includes, "respect include directives on lookup"),
+ OPT_GROUP(N_("Config file location")),
+ OPT_BOOLEAN(0, "global", &use_global_config, N_("use global config file")),
+ OPT_BOOLEAN(0, "system", &use_system_config, N_("use system config file")),
+ OPT_BOOLEAN(0, "local", &use_local_config, N_("use repository config file")),
+ OPT_STRING('f', "file", &given_config_file, N_("file"), N_("use given config file")),
+ OPT_GROUP(N_("Action")),
+ OPT_BIT(0, "get", &actions, N_("get value: name [value-regex]"), ACTION_GET),
+ OPT_BIT(0, "get-all", &actions, N_("get all values: key [value-regex]"), ACTION_GET_ALL),
+ OPT_BIT(0, "get-regexp", &actions, N_("get values for regexp: name-regex [value-regex]"), ACTION_GET_REGEXP),
+ OPT_BIT(0, "replace-all", &actions, N_("replace all matching variables: name value [value_regex]"), ACTION_REPLACE_ALL),
+ OPT_BIT(0, "add", &actions, N_("add a new variable: name value"), ACTION_ADD),
+ OPT_BIT(0, "unset", &actions, N_("remove a variable: name [value-regex]"), ACTION_UNSET),
+ OPT_BIT(0, "unset-all", &actions, N_("remove all matches: name [value-regex]"), ACTION_UNSET_ALL),
+ OPT_BIT(0, "rename-section", &actions, N_("rename section: old-name new-name"), ACTION_RENAME_SECTION),
+ OPT_BIT(0, "remove-section", &actions, N_("remove a section: name"), ACTION_REMOVE_SECTION),
+ OPT_BIT('l', "list", &actions, N_("list all"), ACTION_LIST),
+ OPT_BIT('e', "edit", &actions, N_("open an editor"), ACTION_EDIT),
+ OPT_STRING(0, "get-color", &get_color_slot, N_("slot"), N_("find the color configured: [default]")),
+ OPT_STRING(0, "get-colorbool", &get_colorbool_slot, N_("slot"), N_("find the color setting: [stdout-is-tty]")),
+ OPT_GROUP(N_("Type")),
+ OPT_BIT(0, "bool", &types, N_("value is \"true\" or \"false\""), TYPE_BOOL),
+ OPT_BIT(0, "int", &types, N_("value is decimal number"), TYPE_INT),
+ OPT_BIT(0, "bool-or-int", &types, N_("value is --bool or --int"), TYPE_BOOL_OR_INT),
+ OPT_BIT(0, "path", &types, N_("value is a path (file or directory name)"), TYPE_PATH),
+ OPT_GROUP(N_("Other")),
+ OPT_BOOLEAN('z', "null", &end_null, N_("terminate values with NUL byte")),
+ OPT_BOOL(0, "includes", &respect_includes, N_("respect include directives on lookup")),
OPT_END(),
};
@@ -161,7 +161,7 @@ static int show_config(const char *key_, const char *value_, void *cb)
static int get_value(const char *key_, const char *regex_)
{
int ret = CONFIG_GENERIC_ERROR;
- char *global = NULL, *repo_config = NULL;
+ char *global = NULL, *xdg = NULL, *repo_config = NULL;
const char *system_wide = NULL, *local;
struct config_include_data inc = CONFIG_INCLUDE_INIT;
config_fn_t fn;
@@ -169,12 +169,10 @@ static int get_value(const char *key_, const char *regex_)
local = given_config_file;
if (!local) {
- const char *home = getenv("HOME");
local = repo_config = git_pathdup("config");
- if (home)
- global = xstrdup(mkpath("%s/.gitconfig", home));
if (git_config_system())
system_wide = git_etc_gitconfig();
+ home_config_paths(&global, &xdg, "config");
}
if (use_key_regexp) {
@@ -233,6 +231,8 @@ static int get_value(const char *key_, const char *regex_)
if (do_all && system_wide)
git_config_from_file(fn, system_wide, data);
+ if (do_all && xdg)
+ git_config_from_file(fn, xdg, data);
if (do_all && global)
git_config_from_file(fn, global, data);
if (do_all)
@@ -242,6 +242,8 @@ static int get_value(const char *key_, const char *regex_)
git_config_from_file(fn, local, data);
if (!do_all && !seen && global)
git_config_from_file(fn, global, data);
+ if (!do_all && !seen && xdg)
+ git_config_from_file(fn, xdg, data);
if (!do_all && !seen && system_wide)
git_config_from_file(fn, system_wide, data);
@@ -259,6 +261,7 @@ static int get_value(const char *key_, const char *regex_)
free_strings:
free(repo_config);
free(global);
+ free(xdg);
return ret;
}
@@ -383,13 +386,25 @@ int cmd_config(int argc, const char **argv, const char *prefix)
}
if (use_global_config) {
- char *home = getenv("HOME");
- if (home) {
- char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
- given_config_file = user_config;
- } else {
+ char *user_config = NULL;
+ char *xdg_config = NULL;
+
+ home_config_paths(&user_config, &xdg_config, "config");
+
+ if (!user_config)
+ /*
+ * It is unknown if HOME/.gitconfig exists, so
+ * we do not know if we should write to XDG
+ * location; error out even if XDG_CONFIG_HOME
+ * is set and points at a sane location.
+ */
die("$HOME not set");
- }
+
+ if (access_or_warn(user_config, R_OK) &&
+ xdg_config && !access_or_warn(xdg_config, R_OK))
+ given_config_file = xdg_config;
+ else
+ given_config_file = user_config;
}
else if (use_system_config)
given_config_file = git_etc_gitconfig();
diff --git a/builtin/count-objects.c b/builtin/count-objects.c
index c37cb98..9afaa88 100644
--- a/builtin/count-objects.c
+++ b/builtin/count-objects.c
@@ -66,7 +66,7 @@ static void count_objects(DIR *d, char *path, int len, int verbose,
}
static char const * const count_objects_usage[] = {
- "git count-objects [-v]",
+ N_("git count-objects [-v]"),
NULL
};
@@ -79,7 +79,7 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix)
unsigned long loose = 0, packed = 0, packed_loose = 0, garbage = 0;
off_t loose_size = 0;
struct option opts[] = {
- OPT__VERBOSE(&verbose, "be verbose"),
+ OPT__VERBOSE(&verbose, N_("be verbose")),
OPT_END(),
};
diff --git a/builtin/credential.c b/builtin/credential.c
new file mode 100644
index 0000000..0412fa0
--- /dev/null
+++ b/builtin/credential.c
@@ -0,0 +1,31 @@
+#include "git-compat-util.h"
+#include "credential.h"
+#include "builtin.h"
+
+static const char usage_msg[] =
+ "git credential [fill|approve|reject]";
+
+int cmd_credential(int argc, const char **argv, const char *prefix)
+{
+ const char *op;
+ struct credential c = CREDENTIAL_INIT;
+
+ op = argv[1];
+ if (!op)
+ usage(usage_msg);
+
+ if (credential_read(&c, stdin) < 0)
+ die("unable to read credential from stdin");
+
+ if (!strcmp(op, "fill")) {
+ credential_fill(&c);
+ credential_write(&c, stdout);
+ } else if (!strcmp(op, "approve")) {
+ credential_approve(&c);
+ } else if (!strcmp(op, "reject")) {
+ credential_reject(&c);
+ } else {
+ usage(usage_msg);
+ }
+ return 0;
+}
diff --git a/builtin/describe.c b/builtin/describe.c
index 9f63067..9fe11ed 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -12,8 +12,8 @@
#define MAX_TAGS (FLAG_BITS - 1)
static const char * const describe_usage[] = {
- "git describe [options] <committish>*",
- "git describe [options] --dirty",
+ N_("git describe [options] <committish>*"),
+ N_("git describe [options] --dirty"),
NULL
};
@@ -400,22 +400,22 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
{
int contains = 0;
struct option options[] = {
- OPT_BOOLEAN(0, "contains", &contains, "find the tag that comes after the commit"),
- OPT_BOOLEAN(0, "debug", &debug, "debug search strategy on stderr"),
- OPT_BOOLEAN(0, "all", &all, "use any ref in .git/refs"),
- OPT_BOOLEAN(0, "tags", &tags, "use any tag in .git/refs/tags"),
- OPT_BOOLEAN(0, "long", &longformat, "always use long format"),
+ OPT_BOOLEAN(0, "contains", &contains, N_("find the tag that comes after the commit")),
+ OPT_BOOLEAN(0, "debug", &debug, N_("debug search strategy on stderr")),
+ OPT_BOOLEAN(0, "all", &all, N_("use any ref in .git/refs")),
+ OPT_BOOLEAN(0, "tags", &tags, N_("use any tag in .git/refs/tags")),
+ OPT_BOOLEAN(0, "long", &longformat, N_("always use long format")),
OPT__ABBREV(&abbrev),
OPT_SET_INT(0, "exact-match", &max_candidates,
- "only output exact matches", 0),
+ N_("only output exact matches"), 0),
OPT_INTEGER(0, "candidates", &max_candidates,
- "consider <n> most recent tags (default: 10)"),
- OPT_STRING(0, "match", &pattern, "pattern",
- "only consider tags matching <pattern>"),
+ N_("consider <n> most recent tags (default: 10)")),
+ OPT_STRING(0, "match", &pattern, N_("pattern"),
+ N_("only consider tags matching <pattern>")),
OPT_BOOLEAN(0, "always", &always,
- "show abbreviated commit object as fallback"),
- {OPTION_STRING, 0, "dirty", &dirty, "mark",
- "append <mark> on dirty working tree (default: \"-dirty\")",
+ N_("show abbreviated commit object as fallback")),
+ {OPTION_STRING, 0, "dirty", &dirty, N_("mark"),
+ N_("append <mark> on dirty working tree (default: \"-dirty\")"),
PARSE_OPT_OPTARG, NULL, (intptr_t) "-dirty"},
OPT_END(),
};
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 9ab6db3..12220ad 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -19,7 +19,7 @@
#include "quote.h"
static const char *fast_export_usage[] = {
- "git fast-export [rev-list-opts]",
+ N_("git fast-export [rev-list-opts]"),
NULL
};
@@ -632,24 +632,24 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
char *export_filename = NULL, *import_filename = NULL;
struct option options[] = {
OPT_INTEGER(0, "progress", &progress,
- "show progress after <n> objects"),
- OPT_CALLBACK(0, "signed-tags", &signed_tag_mode, "mode",
- "select handling of signed tags",
+ N_("show progress after <n> objects")),
+ OPT_CALLBACK(0, "signed-tags", &signed_tag_mode, N_("mode"),
+ N_("select handling of signed tags"),
parse_opt_signed_tag_mode),
- OPT_CALLBACK(0, "tag-of-filtered-object", &tag_of_filtered_mode, "mode",
- "select handling of tags that tag filtered objects",
+ OPT_CALLBACK(0, "tag-of-filtered-object", &tag_of_filtered_mode, N_("mode"),
+ N_("select handling of tags that tag filtered objects"),
parse_opt_tag_of_filtered_mode),
- OPT_STRING(0, "export-marks", &export_filename, "file",
- "Dump marks to this file"),
- OPT_STRING(0, "import-marks", &import_filename, "file",
- "Import marks from this file"),
+ OPT_STRING(0, "export-marks", &export_filename, N_("file"),
+ N_("Dump marks to this file")),
+ OPT_STRING(0, "import-marks", &import_filename, N_("file"),
+ N_("Import marks from this file")),
OPT_BOOLEAN(0, "fake-missing-tagger", &fake_missing_tagger,
- "Fake a tagger when tags lack one"),
+ N_("Fake a tagger when tags lack one")),
OPT_BOOLEAN(0, "full-tree", &full_tree,
- "Output full tree for each commit"),
+ N_("Output full tree for each commit")),
OPT_BOOLEAN(0, "use-done-feature", &use_done_feature,
- "Use the done feature to terminate the stream"),
- OPT_BOOL(0, "no-data", &no_data, "Skip output of blob data"),
+ N_("Use the done feature to terminate the stream")),
+ OPT_BOOL(0, "no-data", &no_data, N_("Skip output of blob data")),
OPT_END()
};
diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c
index 149db88..e644398 100644
--- a/builtin/fetch-pack.c
+++ b/builtin/fetch-pack.c
@@ -10,6 +10,7 @@
#include "remote.h"
#include "run-command.h"
#include "transport.h"
+#include "version.h"
static int transfer_unpack_limit = -1;
static int fetch_unpack_limit = -1;
@@ -18,6 +19,7 @@ static int prefer_ofs_delta = 1;
static int no_done;
static int fetch_fsck_objects = -1;
static int transfer_fsck_objects = -1;
+static int agent_supported;
static struct fetch_pack_args args = {
/* .uploadpack = */ "git-upload-pack",
};
@@ -327,6 +329,8 @@ static int find_common(int fd[2], unsigned char *result_sha1,
if (args.no_progress) strbuf_addstr(&c, " no-progress");
if (args.include_tag) strbuf_addstr(&c, " include-tag");
if (prefer_ofs_delta) strbuf_addstr(&c, " ofs-delta");
+ if (agent_supported) strbuf_addf(&c, " agent=%s",
+ git_user_agent_sanitized());
packet_buf_write(&req_buf, "want %s%s\n", remote_hex, c.buf);
strbuf_release(&c);
} else
@@ -521,72 +525,59 @@ static void mark_recent_complete_commits(unsigned long cutoff)
}
}
-static void filter_refs(struct ref **refs, int nr_match, char **match)
+static int non_matching_ref(struct string_list_item *item, void *unused)
+{
+ if (item->util) {
+ item->util = NULL;
+ return 0;
+ }
+ else
+ return 1;
+}
+
+static void filter_refs(struct ref **refs, struct string_list *sought)
{
- struct ref **return_refs;
struct ref *newlist = NULL;
struct ref **newtail = &newlist;
struct ref *ref, *next;
- struct ref *fastarray[32];
- int match_pos;
-
- if (nr_match && !args.fetch_all) {
- if (ARRAY_SIZE(fastarray) < nr_match)
- return_refs = xcalloc(nr_match, sizeof(struct ref *));
- else {
- return_refs = fastarray;
- memset(return_refs, 0, sizeof(struct ref *) * nr_match);
- }
- }
- else
- return_refs = NULL;
+ int sought_pos;
- match_pos = 0;
+ sought_pos = 0;
for (ref = *refs; ref; ref = next) {
+ int keep = 0;
next = ref->next;
if (!memcmp(ref->name, "refs/", 5) &&
check_refname_format(ref->name + 5, 0))
; /* trash */
- else if (args.fetch_all &&
- (!args.depth || prefixcmp(ref->name, "refs/tags/") )) {
- *newtail = ref;
- ref->next = NULL;
- newtail = &ref->next;
- continue;
- }
else {
- int cmp = -1;
- while (match_pos < nr_match) {
- cmp = strcmp(ref->name, match[match_pos]);
- if (cmp < 0) /* definitely do not have it */
- break;
- else if (cmp == 0) { /* definitely have it */
- match[match_pos][0] = '\0';
- return_refs[match_pos] = ref;
+ while (sought_pos < sought->nr) {
+ int cmp = strcmp(ref->name, sought->items[sought_pos].string);
+ if (cmp < 0)
+ break; /* definitely do not have it */
+ else if (cmp == 0) {
+ keep = 1; /* definitely have it */
+ sought->items[sought_pos++].util = "matched";
break;
}
- else /* might have it; keep looking */
- match_pos++;
+ else
+ sought_pos++; /* might have it; keep looking */
}
- if (!cmp)
- continue; /* we will link it later */
}
- free(ref);
- }
- if (!args.fetch_all) {
- int i;
- for (i = 0; i < nr_match; i++) {
- ref = return_refs[i];
- if (ref) {
- *newtail = ref;
- ref->next = NULL;
- newtail = &ref->next;
- }
+ if (! keep && args.fetch_all &&
+ (!args.depth || prefixcmp(ref->name, "refs/tags/")))
+ keep = 1;
+
+ if (keep) {
+ *newtail = ref;
+ ref->next = NULL;
+ newtail = &ref->next;
+ } else {
+ free(ref);
}
- if (return_refs != fastarray)
- free(return_refs);
}
+
+ filter_string_list(sought, 0, non_matching_ref, NULL);
*refs = newlist;
}
@@ -595,7 +586,7 @@ static void mark_alternate_complete(const struct ref *ref, void *unused)
mark_complete(NULL, ref->old_sha1, 0, NULL);
}
-static int everything_local(struct ref **refs, int nr_match, char **match)
+static int everything_local(struct ref **refs, struct string_list *sought)
{
struct ref *ref;
int retval;
@@ -646,7 +637,7 @@ static int everything_local(struct ref **refs, int nr_match, char **match)
}
}
- filter_refs(refs, nr_match, match);
+ filter_refs(refs, sought);
for (retval = 1, ref = *refs; ref ; ref = ref->next) {
const unsigned char *remote = ref->old_sha1;
@@ -777,12 +768,13 @@ static int get_pack(int xd[2], char **pack_lockfile)
static struct ref *do_fetch_pack(int fd[2],
const struct ref *orig_ref,
- int nr_match,
- char **match,
+ struct string_list *sought,
char **pack_lockfile)
{
struct ref *ref = copy_ref_list(orig_ref);
unsigned char sha1[20];
+ const char *agent_feature;
+ int agent_len;
sort_ref_list(&ref, ref_compare_name);
@@ -814,12 +806,26 @@ static struct ref *do_fetch_pack(int fd[2],
fprintf(stderr, "Server supports side-band\n");
use_sideband = 1;
}
+ if (!server_supports("thin-pack"))
+ args.use_thin_pack = 0;
+ if (!server_supports("no-progress"))
+ args.no_progress = 0;
+ if (!server_supports("include-tag"))
+ args.include_tag = 0;
if (server_supports("ofs-delta")) {
if (args.verbose)
fprintf(stderr, "Server supports ofs-delta\n");
} else
prefer_ofs_delta = 0;
- if (everything_local(&ref, nr_match, match)) {
+
+ if ((agent_feature = server_feature_value("agent", &agent_len))) {
+ agent_supported = 1;
+ if (args.verbose && agent_len)
+ fprintf(stderr, "Server version is %.*s\n",
+ agent_len, agent_feature);
+ }
+
+ if (everything_local(&ref, sought)) {
packet_flush(fd[1]);
goto all_done;
}
@@ -839,19 +845,6 @@ static struct ref *do_fetch_pack(int fd[2],
return ref;
}
-static int remove_duplicates(int nr_heads, char **heads)
-{
- int src, dst;
-
- if (!nr_heads)
- return 0;
-
- for (src = dst = 1; src < nr_heads; src++)
- if (strcmp(heads[src], heads[dst-1]))
- heads[dst++] = heads[src];
- return dst;
-}
-
static int fetch_pack_config(const char *var, const char *value, void *cb)
{
if (strcmp(var, "fetch.unpacklimit") == 0) {
@@ -902,8 +895,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
int i, ret;
struct ref *ref = NULL;
const char *dest = NULL;
- int alloc_heads = 0, nr_heads = 0;
- char **heads = NULL;
+ struct string_list sought = STRING_LIST_INIT_DUP;
int fd[2];
char *pack_lockfile = NULL;
char **pack_lockfile_ptr = NULL;
@@ -980,9 +972,8 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
* Copy refs from cmdline to growable list, then append any
* refs from the standard input:
*/
- ALLOC_GROW(heads, argc - i, alloc_heads);
for (; i < argc; i++)
- heads[nr_heads++] = xstrdup(argv[i]);
+ string_list_append(&sought, xstrdup(argv[i]));
if (args.stdin_refs) {
if (args.stateless_rpc) {
/* in stateless RPC mode we use pkt-line to read
@@ -995,17 +986,14 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
break;
if (line[n-1] == '\n')
n--;
- ALLOC_GROW(heads, nr_heads + 1, alloc_heads);
- heads[nr_heads++] = xmemdupz(line, n);
+ string_list_append(&sought, xmemdupz(line, n));
}
}
else {
/* read from stdin one ref per line, until EOF */
struct strbuf line = STRBUF_INIT;
- while (strbuf_getline(&line, stdin, '\n') != EOF) {
- ALLOC_GROW(heads, nr_heads + 1, alloc_heads);
- heads[nr_heads++] = strbuf_detach(&line, NULL);
- }
+ while (strbuf_getline(&line, stdin, '\n') != EOF)
+ string_list_append(&sought, strbuf_detach(&line, NULL));
strbuf_release(&line);
}
}
@@ -1022,7 +1010,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
get_remote_heads(fd[0], &ref, 0, NULL);
ref = fetch_pack(&args, fd, conn, ref, dest,
- nr_heads, heads, pack_lockfile_ptr);
+ &sought, pack_lockfile_ptr);
if (pack_lockfile) {
printf("lock %s\n", pack_lockfile);
fflush(stdout);
@@ -1030,21 +1018,18 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
close(fd[0]);
close(fd[1]);
if (finish_connect(conn))
- ref = NULL;
- ret = !ref;
-
- if (!ret && nr_heads) {
- /* If the heads to pull were given, we should have
- * consumed all of them by matching the remote.
- * Otherwise, 'git fetch remote no-such-ref' would
- * silently succeed without issuing an error.
- */
- for (i = 0; i < nr_heads; i++)
- if (heads[i] && heads[i][0]) {
- error("no such remote ref %s", heads[i]);
- ret = 1;
- }
- }
+ return 1;
+
+ ret = !ref || sought.nr;
+
+ /*
+ * If the heads to pull were given, we should have consumed
+ * all of them by matching the remote. Otherwise, 'git fetch
+ * remote no-such-ref' would silently succeed without issuing
+ * an error.
+ */
+ for (i = 0; i < sought.nr; i++)
+ error("no such remote ref %s", sought.items[i].string);
while (ref) {
printf("%s %s\n",
sha1_to_hex(ref->old_sha1), ref->name);
@@ -1054,18 +1039,12 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
return ret;
}
-static int compare_heads(const void *a, const void *b)
-{
- return strcmp(*(const char **)a, *(const char **)b);
-}
-
struct ref *fetch_pack(struct fetch_pack_args *my_args,
int fd[], struct child_process *conn,
const struct ref *ref,
- const char *dest,
- int nr_heads,
- char **heads,
- char **pack_lockfile)
+ const char *dest,
+ struct string_list *sought,
+ char **pack_lockfile)
{
struct stat st;
struct ref *ref_cpy;
@@ -1078,16 +1057,16 @@ struct ref *fetch_pack(struct fetch_pack_args *my_args,
st.st_mtime = 0;
}
- if (heads && nr_heads) {
- qsort(heads, nr_heads, sizeof(*heads), compare_heads);
- nr_heads = remove_duplicates(nr_heads, heads);
+ if (sought->nr) {
+ sort_string_list(sought);
+ string_list_remove_duplicates(sought, 0);
}
if (!ref) {
packet_flush(fd[1]);
die("no matching remote head");
}
- ref_cpy = do_fetch_pack(fd, ref, nr_heads, heads, pack_lockfile);
+ ref_cpy = do_fetch_pack(fd, ref, sought, pack_lockfile);
if (args.depth > 0) {
struct cache_time mtime;
diff --git a/builtin/fetch.c b/builtin/fetch.c
index bb9a074..4b5a898 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -14,12 +14,13 @@
#include "transport.h"
#include "submodule.h"
#include "connected.h"
+#include "argv-array.h"
static const char * const builtin_fetch_usage[] = {
- "git fetch [<options>] [<repository> [<refspec>...]]",
- "git fetch [<options>] <group>",
- "git fetch --multiple [<options>] [(<repository> | <group>)...]",
- "git fetch --all [<options>]",
+ N_("git fetch [<options>] [<repository> [<refspec>...]]"),
+ N_("git fetch [<options>] <group>"),
+ N_("git fetch --multiple [<options>] [(<repository> | <group>)...]"),
+ N_("git fetch --all [<options>]"),
NULL
};
@@ -56,36 +57,36 @@ static int option_parse_recurse_submodules(const struct option *opt,
static struct option builtin_fetch_options[] = {
OPT__VERBOSITY(&verbosity),
OPT_BOOLEAN(0, "all", &all,
- "fetch from all remotes"),
+ N_("fetch from all remotes")),
OPT_BOOLEAN('a', "append", &append,
- "append to .git/FETCH_HEAD instead of overwriting"),
- OPT_STRING(0, "upload-pack", &upload_pack, "path",
- "path to upload pack on remote end"),
- OPT__FORCE(&force, "force overwrite of local branch"),
+ N_("append to .git/FETCH_HEAD instead of overwriting")),
+ OPT_STRING(0, "upload-pack", &upload_pack, N_("path"),
+ N_("path to upload pack on remote end")),
+ OPT__FORCE(&force, N_("force overwrite of local branch")),
OPT_BOOLEAN('m', "multiple", &multiple,
- "fetch from multiple remotes"),
+ N_("fetch from multiple remotes")),
OPT_SET_INT('t', "tags", &tags,
- "fetch all tags and associated objects", TAGS_SET),
+ N_("fetch all tags and associated objects"), TAGS_SET),
OPT_SET_INT('n', NULL, &tags,
- "do not fetch all tags (--no-tags)", TAGS_UNSET),
+ N_("do not fetch all tags (--no-tags)"), TAGS_UNSET),
OPT_BOOLEAN('p', "prune", &prune,
- "prune remote-tracking branches no longer on remote"),
- { OPTION_CALLBACK, 0, "recurse-submodules", NULL, "on-demand",
- "control recursive fetching of submodules",
+ N_("prune remote-tracking branches no longer on remote")),
+ { OPTION_CALLBACK, 0, "recurse-submodules", NULL, N_("on-demand"),
+ N_("control recursive fetching of submodules"),
PARSE_OPT_OPTARG, option_parse_recurse_submodules },
OPT_BOOLEAN(0, "dry-run", &dry_run,
- "dry run"),
- OPT_BOOLEAN('k', "keep", &keep, "keep downloaded pack"),
+ N_("dry run")),
+ OPT_BOOLEAN('k', "keep", &keep, N_("keep downloaded pack")),
OPT_BOOLEAN('u', "update-head-ok", &update_head_ok,
- "allow updating of HEAD ref"),
- OPT_BOOL(0, "progress", &progress, "force progress reporting"),
- OPT_STRING(0, "depth", &depth, "depth",
- "deepen history of shallow clone"),
- { OPTION_STRING, 0, "submodule-prefix", &submodule_prefix, "dir",
- "prepend this to submodule path output", PARSE_OPT_HIDDEN },
+ N_("allow updating of HEAD ref")),
+ OPT_BOOL(0, "progress", &progress, N_("force progress reporting")),
+ OPT_STRING(0, "depth", &depth, N_("depth"),
+ N_("deepen history of shallow clone")),
+ { OPTION_STRING, 0, "submodule-prefix", &submodule_prefix, N_("dir"),
+ N_("prepend this to submodule path output"), PARSE_OPT_HIDDEN },
{ OPTION_STRING, 0, "recurse-submodules-default",
&recurse_submodules_default, NULL,
- "default mode for recursion", PARSE_OPT_HIDDEN },
+ N_("default mode for recursion"), PARSE_OPT_HIDDEN },
OPT_END()
};
@@ -255,9 +256,8 @@ static int update_local_ref(struct ref *ref,
if (!hashcmp(ref->old_sha1, ref->new_sha1)) {
if (verbosity > 0)
strbuf_addf(display, "= %-*s %-*s -> %s",
- TRANSPORT_SUMMARY_WIDTH,
- _("[up to date]"), REFCOL_WIDTH,
- remote, pretty_ref);
+ TRANSPORT_SUMMARY(_("[up to date]")),
+ REFCOL_WIDTH, remote, pretty_ref);
return 0;
}
@@ -271,7 +271,7 @@ static int update_local_ref(struct ref *ref,
*/
strbuf_addf(display,
_("! %-*s %-*s -> %s (can't fetch in current branch)"),
- TRANSPORT_SUMMARY_WIDTH, _("[rejected]"),
+ TRANSPORT_SUMMARY(_("[rejected]")),
REFCOL_WIDTH, remote, pretty_ref);
return 1;
}
@@ -282,7 +282,7 @@ static int update_local_ref(struct ref *ref,
r = s_update_ref("updating tag", ref, 0);
strbuf_addf(display, "%c %-*s %-*s -> %s%s",
r ? '!' : '-',
- TRANSPORT_SUMMARY_WIDTH, _("[tag update]"),
+ TRANSPORT_SUMMARY(_("[tag update]")),
REFCOL_WIDTH, remote, pretty_ref,
r ? _(" (unable to update local ref)") : "");
return r;
@@ -317,13 +317,13 @@ static int update_local_ref(struct ref *ref,
r = s_update_ref(msg, ref, 0);
strbuf_addf(display, "%c %-*s %-*s -> %s%s",
r ? '!' : '*',
- TRANSPORT_SUMMARY_WIDTH, what,
+ TRANSPORT_SUMMARY(what),
REFCOL_WIDTH, remote, pretty_ref,
r ? _(" (unable to update local ref)") : "");
return r;
}
- if (in_merge_bases(current, &updated, 1)) {
+ if (in_merge_bases(current, updated)) {
char quickref[83];
int r;
strcpy(quickref, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV));
@@ -357,7 +357,7 @@ static int update_local_ref(struct ref *ref,
return r;
} else {
strbuf_addf(display, "! %-*s %-*s -> %s %s",
- TRANSPORT_SUMMARY_WIDTH, _("[rejected]"),
+ TRANSPORT_SUMMARY(_("[rejected]")),
REFCOL_WIDTH, remote, pretty_ref,
_("(non-fast-forward)"));
return 1;
@@ -554,7 +554,7 @@ static int prune_refs(struct refspec *refs, int ref_count, struct ref *ref_map)
result |= delete_ref(ref->name, NULL, 0);
if (verbosity >= 0) {
fprintf(stderr, " x %-*s %-*s -> %s\n",
- TRANSPORT_SUMMARY_WIDTH, _("[deleted]"),
+ TRANSPORT_SUMMARY(_("[deleted]")),
REFCOL_WIDTH, _("(none)"), prettify_refname(ref->name));
warn_dangling_symref(stderr, dangling_msg, ref->name);
}
@@ -841,38 +841,39 @@ static int add_remote_or_group(const char *name, struct string_list *list)
return 1;
}
-static void add_options_to_argv(int *argc, const char **argv)
+static void add_options_to_argv(struct argv_array *argv)
{
if (dry_run)
- argv[(*argc)++] = "--dry-run";
+ argv_array_push(argv, "--dry-run");
if (prune)
- argv[(*argc)++] = "--prune";
+ argv_array_push(argv, "--prune");
if (update_head_ok)
- argv[(*argc)++] = "--update-head-ok";
+ argv_array_push(argv, "--update-head-ok");
if (force)
- argv[(*argc)++] = "--force";
+ argv_array_push(argv, "--force");
if (keep)
- argv[(*argc)++] = "--keep";
+ argv_array_push(argv, "--keep");
if (recurse_submodules == RECURSE_SUBMODULES_ON)
- argv[(*argc)++] = "--recurse-submodules";
+ argv_array_push(argv, "--recurse-submodules");
else if (recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND)
- argv[(*argc)++] = "--recurse-submodules=on-demand";
+ argv_array_push(argv, "--recurse-submodules=on-demand");
+ if (tags == TAGS_SET)
+ argv_array_push(argv, "--tags");
+ else if (tags == TAGS_UNSET)
+ argv_array_push(argv, "--no-tags");
if (verbosity >= 2)
- argv[(*argc)++] = "-v";
+ argv_array_push(argv, "-v");
if (verbosity >= 1)
- argv[(*argc)++] = "-v";
+ argv_array_push(argv, "-v");
else if (verbosity < 0)
- argv[(*argc)++] = "-q";
+ argv_array_push(argv, "-q");
}
static int fetch_multiple(struct string_list *list)
{
int i, result = 0;
- const char *argv[12] = { "fetch", "--append" };
- int argc = 2;
-
- add_options_to_argv(&argc, argv);
+ struct argv_array argv = ARGV_ARRAY_INIT;
if (!append && !dry_run) {
int errcode = truncate_fetch_head();
@@ -880,18 +881,22 @@ static int fetch_multiple(struct string_list *list)
return errcode;
}
+ argv_array_pushl(&argv, "fetch", "--append", NULL);
+ add_options_to_argv(&argv);
+
for (i = 0; i < list->nr; i++) {
const char *name = list->items[i].string;
- argv[argc] = name;
- argv[argc + 1] = NULL;
+ argv_array_push(&argv, name);
if (verbosity >= 0)
printf(_("Fetching %s\n"), name);
- if (run_command_v_opt(argv, RUN_GIT_CMD)) {
+ if (run_command_v_opt(argv.argv, RUN_GIT_CMD)) {
error(_("Could not fetch %s"), name);
result = 1;
}
+ argv_array_pop(&argv);
}
+ argv_array_clear(&argv);
return result;
}
@@ -1007,13 +1012,14 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
}
if (!result && (recurse_submodules != RECURSE_SUBMODULES_OFF)) {
- const char *options[10];
- int num_options = 0;
- add_options_to_argv(&num_options, options);
- result = fetch_populated_submodules(num_options, options,
+ struct argv_array options = ARGV_ARRAY_INIT;
+
+ add_options_to_argv(&options);
+ result = fetch_populated_submodules(&options,
submodule_prefix,
recurse_submodules,
verbosity < 0);
+ argv_array_clear(&options);
}
/* All names were strdup()ed or strndup()ed */
diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c
index 2c4d435..e2e27b2 100644
--- a/builtin/fmt-merge-msg.c
+++ b/builtin/fmt-merge-msg.c
@@ -10,7 +10,7 @@
#include "gpg-interface.h"
static const char * const fmt_merge_msg_usage[] = {
- "git fmt-merge-msg [-m <message>] [--log[=<n>]|--no-log] [--file <file>]",
+ N_("git fmt-merge-msg [-m <message>] [--log[=<n>]|--no-log] [--file <file>]"),
NULL
};
@@ -650,16 +650,16 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
const char *message = NULL;
int shortlog_len = -1;
struct option options[] = {
- { OPTION_INTEGER, 0, "log", &shortlog_len, "n",
- "populate log with at most <n> entries from shortlog",
+ { OPTION_INTEGER, 0, "log", &shortlog_len, N_("n"),
+ N_("populate log with at most <n> entries from shortlog"),
PARSE_OPT_OPTARG, NULL, DEFAULT_MERGE_LOG_LEN },
- { OPTION_INTEGER, 0, "summary", &shortlog_len, "n",
- "alias for --log (deprecated)",
+ { OPTION_INTEGER, 0, "summary", &shortlog_len, N_("n"),
+ N_("alias for --log (deprecated)"),
PARSE_OPT_OPTARG | PARSE_OPT_HIDDEN, NULL,
DEFAULT_MERGE_LOG_LEN },
- OPT_STRING('m', "message", &message, "text",
- "use <text> as start of message"),
- OPT_FILENAME('F', "file", &inpath, "file to read from"),
+ OPT_STRING('m', "message", &message, N_("text"),
+ N_("use <text> as start of message")),
+ OPT_FILENAME('F', "file", &inpath, N_("file to read from")),
OPT_END()
};
diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
index 0c5294e..7f059c3 100644
--- a/builtin/for-each-ref.c
+++ b/builtin/for-each-ref.c
@@ -976,7 +976,7 @@ static int opt_parse_sort(const struct option *opt, const char *arg, int unset)
}
static char const * const for_each_ref_usage[] = {
- "git for-each-ref [options] [<pattern>]",
+ N_("git for-each-ref [options] [<pattern>]"),
NULL
};
@@ -991,19 +991,19 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
struct option opts[] = {
OPT_BIT('s', "shell", &quote_style,
- "quote placeholders suitably for shells", QUOTE_SHELL),
+ N_("quote placeholders suitably for shells"), QUOTE_SHELL),
OPT_BIT('p', "perl", &quote_style,
- "quote placeholders suitably for perl", QUOTE_PERL),
+ N_("quote placeholders suitably for perl"), QUOTE_PERL),
OPT_BIT(0 , "python", &quote_style,
- "quote placeholders suitably for python", QUOTE_PYTHON),
+ N_("quote placeholders suitably for python"), QUOTE_PYTHON),
OPT_BIT(0 , "tcl", &quote_style,
- "quote placeholders suitably for tcl", QUOTE_TCL),
+ N_("quote placeholders suitably for tcl"), QUOTE_TCL),
OPT_GROUP(""),
- OPT_INTEGER( 0 , "count", &maxcount, "show only <n> matched refs"),
- OPT_STRING( 0 , "format", &format, "format", "format to use for the output"),
- OPT_CALLBACK(0 , "sort", sort_tail, "key",
- "field name to sort on", &opt_parse_sort),
+ OPT_INTEGER( 0 , "count", &maxcount, N_("show only <n> matched refs")),
+ OPT_STRING( 0 , "format", &format, N_("format"), N_("format to use for the output")),
+ OPT_CALLBACK(0 , "sort", sort_tail, N_("key"),
+ N_("field name to sort on"), &opt_parse_sort),
OPT_END(),
};
diff --git a/builtin/fsck.c b/builtin/fsck.c
index a710227..bb9a2cd 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -605,23 +605,23 @@ static int fsck_cache_tree(struct cache_tree *it)
}
static char const * const fsck_usage[] = {
- "git fsck [options] [<object>...]",
+ N_("git fsck [options] [<object>...]"),
NULL
};
static struct option fsck_opts[] = {
- OPT__VERBOSE(&verbose, "be verbose"),
- OPT_BOOLEAN(0, "unreachable", &show_unreachable, "show unreachable objects"),
- OPT_BOOL(0, "dangling", &show_dangling, "show dangling objects"),
- OPT_BOOLEAN(0, "tags", &show_tags, "report tags"),
- OPT_BOOLEAN(0, "root", &show_root, "report root nodes"),
- OPT_BOOLEAN(0, "cache", &keep_cache_objects, "make index objects head nodes"),
- OPT_BOOLEAN(0, "reflogs", &include_reflogs, "make reflogs head nodes (default)"),
- OPT_BOOLEAN(0, "full", &check_full, "also consider packs and alternate objects"),
- OPT_BOOLEAN(0, "strict", &check_strict, "enable more strict checking"),
+ OPT__VERBOSE(&verbose, N_("be verbose")),
+ OPT_BOOLEAN(0, "unreachable", &show_unreachable, N_("show unreachable objects")),
+ OPT_BOOL(0, "dangling", &show_dangling, N_("show dangling objects")),
+ OPT_BOOLEAN(0, "tags", &show_tags, N_("report tags")),
+ OPT_BOOLEAN(0, "root", &show_root, N_("report root nodes")),
+ OPT_BOOLEAN(0, "cache", &keep_cache_objects, N_("make index objects head nodes")),
+ OPT_BOOLEAN(0, "reflogs", &include_reflogs, N_("make reflogs head nodes (default)")),
+ OPT_BOOLEAN(0, "full", &check_full, N_("also consider packs and alternate objects")),
+ OPT_BOOLEAN(0, "strict", &check_strict, N_("enable more strict checking")),
OPT_BOOLEAN(0, "lost-found", &write_lost_and_found,
- "write dangling objects in .git/lost-found"),
- OPT_BOOL(0, "progress", &show_progress, "show progress"),
+ N_("write dangling objects in .git/lost-found")),
+ OPT_BOOL(0, "progress", &show_progress, N_("show progress")),
OPT_END(),
};
diff --git a/builtin/gc.c b/builtin/gc.c
index 9b4232c..6be6c8d 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -19,7 +19,7 @@
#define FAILED_RUN "failed to run %s"
static const char * const builtin_gc_usage[] = {
- "git gc [options]",
+ N_("git gc [options]"),
NULL
};
@@ -174,12 +174,12 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
int quiet = 0;
struct option builtin_gc_options[] = {
- OPT__QUIET(&quiet, "suppress progress reporting"),
- { OPTION_STRING, 0, "prune", &prune_expire, "date",
- "prune unreferenced objects",
+ OPT__QUIET(&quiet, N_("suppress progress reporting")),
+ { OPTION_STRING, 0, "prune", &prune_expire, N_("date"),
+ N_("prune unreferenced objects"),
PARSE_OPT_OPTARG, NULL, (intptr_t)prune_expire },
- OPT_BOOLEAN(0, "aggressive", &aggressive, "be more thorough (increased runtime)"),
- OPT_BOOLEAN(0, "auto", &auto_gc, "enable auto-gc mode"),
+ OPT_BOOLEAN(0, "aggressive", &aggressive, N_("be more thorough (increased runtime)")),
+ OPT_BOOLEAN(0, "auto", &auto_gc, N_("enable auto-gc mode")),
OPT_END()
};
@@ -217,9 +217,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
*/
if (!need_to_gc())
return 0;
- if (quiet)
- fprintf(stderr, _("Auto packing the repository for optimum performance.\n"));
- else
+ if (!quiet)
fprintf(stderr,
_("Auto packing the repository for optimum performance. You may also\n"
"run \"git gc\" manually. See "
diff --git a/builtin/grep.c b/builtin/grep.c
index 29adb0a..82530a6 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -19,7 +19,7 @@
#include "dir.h"
static char const * const grep_usage[] = {
- "git grep [options] [-e] <pattern> [<rev>...] [[--] <path>...]",
+ N_("git grep [options] [-e] <pattern> [<rev>...] [[--] <path>...]"),
NULL
};
@@ -209,6 +209,7 @@ static void start_threads(struct grep_opt *opt)
int err;
struct grep_opt *o = grep_opt_dup(opt);
o->output = strbuf_out;
+ o->debug = 0;
compile_grep_patterns(o);
err = pthread_create(&threads[i], NULL, run, o);
@@ -260,6 +261,53 @@ static int wait_all(void)
}
#endif
+static int parse_pattern_type_arg(const char *opt, const char *arg)
+{
+ if (!strcmp(arg, "default"))
+ return GREP_PATTERN_TYPE_UNSPECIFIED;
+ else if (!strcmp(arg, "basic"))
+ return GREP_PATTERN_TYPE_BRE;
+ else if (!strcmp(arg, "extended"))
+ return GREP_PATTERN_TYPE_ERE;
+ else if (!strcmp(arg, "fixed"))
+ return GREP_PATTERN_TYPE_FIXED;
+ else if (!strcmp(arg, "perl"))
+ return GREP_PATTERN_TYPE_PCRE;
+ die("bad %s argument: %s", opt, arg);
+}
+
+static void grep_pattern_type_options(const int pattern_type, struct grep_opt *opt)
+{
+ switch (pattern_type) {
+ case GREP_PATTERN_TYPE_UNSPECIFIED:
+ /* fall through */
+
+ case GREP_PATTERN_TYPE_BRE:
+ opt->fixed = 0;
+ opt->pcre = 0;
+ opt->regflags &= ~REG_EXTENDED;
+ break;
+
+ case GREP_PATTERN_TYPE_ERE:
+ opt->fixed = 0;
+ opt->pcre = 0;
+ opt->regflags |= REG_EXTENDED;
+ break;
+
+ case GREP_PATTERN_TYPE_FIXED:
+ opt->fixed = 1;
+ opt->pcre = 0;
+ opt->regflags &= ~REG_EXTENDED;
+ break;
+
+ case GREP_PATTERN_TYPE_PCRE:
+ opt->fixed = 0;
+ opt->pcre = 1;
+ opt->regflags &= ~REG_EXTENDED;
+ break;
+ }
+}
+
static int grep_config(const char *var, const char *value, void *cb)
{
struct grep_opt *opt = cb;
@@ -270,12 +318,17 @@ static int grep_config(const char *var, const char *value, void *cb)
if (!strcmp(var, "grep.extendedregexp")) {
if (git_config_bool(var, value))
- opt->regflags |= REG_EXTENDED;
+ opt->extended_regexp_option = 1;
else
- opt->regflags &= ~REG_EXTENDED;
+ opt->extended_regexp_option = 0;
return 0;
}
+ if (!strcmp(var, "grep.patterntype")) {
+ opt->pattern_type_option = parse_pattern_type_arg(var, value);
+ return 0;
+ }
+
if (!strcmp(var, "grep.linenumber")) {
opt->linenum = git_config_bool(var, value);
return 0;
@@ -669,95 +722,88 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
int i;
int dummy;
int use_index = 1;
- enum {
- pattern_type_unspecified = 0,
- pattern_type_bre,
- pattern_type_ere,
- pattern_type_fixed,
- pattern_type_pcre,
- };
- int pattern_type = pattern_type_unspecified;
+ int pattern_type_arg = GREP_PATTERN_TYPE_UNSPECIFIED;
struct option options[] = {
OPT_BOOLEAN(0, "cached", &cached,
- "search in index instead of in the work tree"),
+ N_("search in index instead of in the work tree")),
OPT_NEGBIT(0, "no-index", &use_index,
- "finds in contents not managed by git", 1),
+ N_("find in contents not managed by git"), 1),
OPT_BOOLEAN(0, "untracked", &untracked,
- "search in both tracked and untracked files"),
+ N_("search in both tracked and untracked files")),
OPT_SET_INT(0, "exclude-standard", &opt_exclude,
- "search also in ignored files", 1),
+ N_("search also in ignored files"), 1),
OPT_GROUP(""),
OPT_BOOLEAN('v', "invert-match", &opt.invert,
- "show non-matching lines"),
+ N_("show non-matching lines")),
OPT_BOOLEAN('i', "ignore-case", &opt.ignore_case,
- "case insensitive matching"),
+ N_("case insensitive matching")),
OPT_BOOLEAN('w', "word-regexp", &opt.word_regexp,
- "match patterns only at word boundaries"),
+ N_("match patterns only at word boundaries")),
OPT_SET_INT('a', "text", &opt.binary,
- "process binary files as text", GREP_BINARY_TEXT),
+ N_("process binary files as text"), GREP_BINARY_TEXT),
OPT_SET_INT('I', NULL, &opt.binary,
- "don't match patterns in binary files",
+ N_("don't match patterns in binary files"),
GREP_BINARY_NOMATCH),
- { OPTION_INTEGER, 0, "max-depth", &opt.max_depth, "depth",
- "descend at most <depth> levels", PARSE_OPT_NONEG,
+ { OPTION_INTEGER, 0, "max-depth", &opt.max_depth, N_("depth"),
+ N_("descend at most <depth> levels"), PARSE_OPT_NONEG,
NULL, 1 },
OPT_GROUP(""),
- OPT_SET_INT('E', "extended-regexp", &pattern_type,
- "use extended POSIX regular expressions",
- pattern_type_ere),
- OPT_SET_INT('G', "basic-regexp", &pattern_type,
- "use basic POSIX regular expressions (default)",
- pattern_type_bre),
- OPT_SET_INT('F', "fixed-strings", &pattern_type,
- "interpret patterns as fixed strings",
- pattern_type_fixed),
- OPT_SET_INT('P', "perl-regexp", &pattern_type,
- "use Perl-compatible regular expressions",
- pattern_type_pcre),
+ OPT_SET_INT('E', "extended-regexp", &pattern_type_arg,
+ N_("use extended POSIX regular expressions"),
+ GREP_PATTERN_TYPE_ERE),
+ OPT_SET_INT('G', "basic-regexp", &pattern_type_arg,
+ N_("use basic POSIX regular expressions (default)"),
+ GREP_PATTERN_TYPE_BRE),
+ OPT_SET_INT('F', "fixed-strings", &pattern_type_arg,
+ N_("interpret patterns as fixed strings"),
+ GREP_PATTERN_TYPE_FIXED),
+ OPT_SET_INT('P', "perl-regexp", &pattern_type_arg,
+ N_("use Perl-compatible regular expressions"),
+ GREP_PATTERN_TYPE_PCRE),
OPT_GROUP(""),
- OPT_BOOLEAN('n', "line-number", &opt.linenum, "show line numbers"),
- OPT_NEGBIT('h', NULL, &opt.pathname, "don't show filenames", 1),
- OPT_BIT('H', NULL, &opt.pathname, "show filenames", 1),
+ OPT_BOOLEAN('n', "line-number", &opt.linenum, N_("show line numbers")),
+ OPT_NEGBIT('h', NULL, &opt.pathname, N_("don't show filenames"), 1),
+ OPT_BIT('H', NULL, &opt.pathname, N_("show filenames"), 1),
OPT_NEGBIT(0, "full-name", &opt.relative,
- "show filenames relative to top directory", 1),
+ N_("show filenames relative to top directory"), 1),
OPT_BOOLEAN('l', "files-with-matches", &opt.name_only,
- "show only filenames instead of matching lines"),
+ N_("show only filenames instead of matching lines")),
OPT_BOOLEAN(0, "name-only", &opt.name_only,
- "synonym for --files-with-matches"),
+ N_("synonym for --files-with-matches")),
OPT_BOOLEAN('L', "files-without-match",
&opt.unmatch_name_only,
- "show only the names of files without match"),
+ N_("show only the names of files without match")),
OPT_BOOLEAN('z', "null", &opt.null_following_name,
- "print NUL after filenames"),
+ N_("print NUL after filenames")),
OPT_BOOLEAN('c', "count", &opt.count,
- "show the number of matches instead of matching lines"),
- OPT__COLOR(&opt.color, "highlight matches"),
+ N_("show the number of matches instead of matching lines")),
+ OPT__COLOR(&opt.color, N_("highlight matches")),
OPT_BOOLEAN(0, "break", &opt.file_break,
- "print empty line between matches from different files"),
+ N_("print empty line between matches from different files")),
OPT_BOOLEAN(0, "heading", &opt.heading,
- "show filename only once above matches from same file"),
+ N_("show filename only once above matches from same file")),
OPT_GROUP(""),
- OPT_CALLBACK('C', "context", &opt, "n",
- "show <n> context lines before and after matches",
+ OPT_CALLBACK('C', "context", &opt, N_("n"),
+ N_("show <n> context lines before and after matches"),
context_callback),
OPT_INTEGER('B', "before-context", &opt.pre_context,
- "show <n> context lines before matches"),
+ N_("show <n> context lines before matches")),
OPT_INTEGER('A', "after-context", &opt.post_context,
- "show <n> context lines after matches"),
- OPT_NUMBER_CALLBACK(&opt, "shortcut for -C NUM",
+ N_("show <n> context lines after matches")),
+ OPT_NUMBER_CALLBACK(&opt, N_("shortcut for -C NUM"),
context_callback),
OPT_BOOLEAN('p', "show-function", &opt.funcname,
- "show a line with the function name before matches"),
+ N_("show a line with the function name before matches")),
OPT_BOOLEAN('W', "function-context", &opt.funcbody,
- "show the surrounding function"),
+ N_("show the surrounding function")),
OPT_GROUP(""),
- OPT_CALLBACK('f', NULL, &opt, "file",
- "read patterns from file", file_callback),
- { OPTION_CALLBACK, 'e', NULL, &opt, "pattern",
- "match <pattern>", PARSE_OPT_NONEG, pattern_callback },
+ OPT_CALLBACK('f', NULL, &opt, N_("file"),
+ N_("read patterns from file"), file_callback),
+ { OPTION_CALLBACK, 'e', NULL, &opt, N_("pattern"),
+ N_("match <pattern>"), PARSE_OPT_NONEG, pattern_callback },
{ OPTION_CALLBACK, 0, "and", &opt, NULL,
- "combine patterns specified with -e",
+ N_("combine patterns specified with -e"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, and_callback },
OPT_BOOLEAN(0, "or", &dummy, ""),
{ OPTION_CALLBACK, 0, "not", &opt, NULL, "",
@@ -769,16 +815,19 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH,
close_callback },
OPT__QUIET(&opt.status_only,
- "indicate hit with exit status without output"),
+ N_("indicate hit with exit status without output")),
OPT_BOOLEAN(0, "all-match", &opt.all_match,
- "show only matches from files that match all patterns"),
+ N_("show only matches from files that match all patterns")),
+ { OPTION_SET_INT, 0, "debug", &opt.debug, NULL,
+ N_("show parse tree for grep expression"),
+ PARSE_OPT_NOARG | PARSE_OPT_HIDDEN, NULL, 1 },
OPT_GROUP(""),
{ OPTION_STRING, 'O', "open-files-in-pager", &show_in_pager,
- "pager", "show matching files in the pager",
+ N_("pager"), N_("show matching files in the pager"),
PARSE_OPT_OPTARG, NULL, (intptr_t)default_pager },
OPT_BOOLEAN(0, "ext-grep", &external_grep_allowed__ignored,
- "allow calling of grep(1) (ignored by this build)"),
- { OPTION_CALLBACK, 0, "help-all", &options, NULL, "show usage",
+ N_("allow calling of grep(1) (ignored by this build)")),
+ { OPTION_CALLBACK, 0, "help-all", &options, NULL, N_("show usage"),
PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, help_callback },
OPT_END()
};
@@ -799,6 +848,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
opt.header_tail = &opt.header_list;
opt.regflags = REG_NEWLINE;
opt.max_depth = -1;
+ opt.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED;
+ opt.extended_regexp_option = 0;
strcpy(opt.color_context, "");
strcpy(opt.color_filename, "");
@@ -824,28 +875,13 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
PARSE_OPT_KEEP_DASHDASH |
PARSE_OPT_STOP_AT_NON_OPTION |
PARSE_OPT_NO_INTERNAL_HELP);
- switch (pattern_type) {
- case pattern_type_fixed:
- opt.fixed = 1;
- opt.pcre = 0;
- break;
- case pattern_type_bre:
- opt.fixed = 0;
- opt.pcre = 0;
- opt.regflags &= ~REG_EXTENDED;
- break;
- case pattern_type_ere:
- opt.fixed = 0;
- opt.pcre = 0;
- opt.regflags |= REG_EXTENDED;
- break;
- case pattern_type_pcre:
- opt.fixed = 0;
- opt.pcre = 1;
- break;
- default:
- break; /* nothing */
- }
+
+ if (pattern_type_arg != GREP_PATTERN_TYPE_UNSPECIFIED)
+ grep_pattern_type_options(pattern_type_arg, &opt);
+ else if (opt.pattern_type_option != GREP_PATTERN_TYPE_UNSPECIFIED)
+ grep_pattern_type_options(opt.pattern_type_option, &opt);
+ else if (opt.extended_regexp_option)
+ grep_pattern_type_options(GREP_PATTERN_TYPE_ERE, &opt);
if (use_index && !startup_info->have_repository)
/* die the same way as if we did it at the beginning */
diff --git a/builtin/hash-object.c b/builtin/hash-object.c
index 33911fd..8d184f1 100644
--- a/builtin/hash-object.c
+++ b/builtin/hash-object.c
@@ -57,8 +57,8 @@ static void hash_stdin_paths(const char *type, int write_objects)
}
static const char * const hash_object_usage[] = {
- "git hash-object [-t <type>] [-w] [--path=<file>|--no-filters] [--stdin] [--] <file>...",
- "git hash-object --stdin-paths < <list-of-paths>",
+ N_("git hash-object [-t <type>] [-w] [--path=<file>|--no-filters] [--stdin] [--] <file>..."),
+ N_("git hash-object --stdin-paths < <list-of-paths>"),
NULL
};
@@ -69,12 +69,12 @@ static int stdin_paths;
static const char *vpath;
static const struct option hash_object_options[] = {
- OPT_STRING('t', NULL, &type, "type", "object type"),
- OPT_BOOLEAN('w', NULL, &write_object, "write the object into the object database"),
- OPT_BOOLEAN( 0 , "stdin", &hashstdin, "read the object from stdin"),
- OPT_BOOLEAN( 0 , "stdin-paths", &stdin_paths, "read file names from stdin"),
- OPT_BOOLEAN( 0 , "no-filters", &no_filters, "store file as is without filters"),
- OPT_STRING( 0 , "path", &vpath, "file", "process file as it were from this path"),
+ OPT_STRING('t', NULL, &type, N_("type"), N_("object type")),
+ OPT_BOOLEAN('w', NULL, &write_object, N_("write the object into the object database")),
+ OPT_BOOLEAN( 0 , "stdin", &hashstdin, N_("read the object from stdin")),
+ OPT_BOOLEAN( 0 , "stdin-paths", &stdin_paths, N_("read file names from stdin")),
+ OPT_BOOLEAN( 0 , "no-filters", &no_filters, N_("store file as is without filters")),
+ OPT_STRING( 0 , "path", &vpath, N_("file"), N_("process file as it were from this path")),
OPT_END()
};
diff --git a/builtin/help.c b/builtin/help.c
index 43d3c84..bd86253 100644
--- a/builtin/help.c
+++ b/builtin/help.c
@@ -12,6 +12,10 @@
#include "column.h"
#include "help.h"
+#ifndef DEFAULT_HELP_FORMAT
+#define DEFAULT_HELP_FORMAT "man"
+#endif
+
static struct man_viewer_list {
struct man_viewer_list *next;
char name[FLEX_ARRAY];
@@ -30,21 +34,23 @@ enum help_format {
HELP_FORMAT_WEB
};
+static const char *html_path;
+
static int show_all = 0;
static unsigned int colopts;
static enum help_format help_format = HELP_FORMAT_NONE;
static struct option builtin_help_options[] = {
- OPT_BOOLEAN('a', "all", &show_all, "print all available commands"),
- OPT_SET_INT('m', "man", &help_format, "show man page", HELP_FORMAT_MAN),
- OPT_SET_INT('w', "web", &help_format, "show manual in web browser",
+ OPT_BOOLEAN('a', "all", &show_all, N_("print all available commands")),
+ OPT_SET_INT('m', "man", &help_format, N_("show man page"), HELP_FORMAT_MAN),
+ OPT_SET_INT('w', "web", &help_format, N_("show manual in web browser"),
HELP_FORMAT_WEB),
- OPT_SET_INT('i', "info", &help_format, "show info page",
+ OPT_SET_INT('i', "info", &help_format, N_("show info page"),
HELP_FORMAT_INFO),
OPT_END(),
};
static const char * const builtin_help_usage[] = {
- "git help [--all] [--man|--web|--info] [command]",
+ N_("git help [--all] [--man|--web|--info] [command]"),
NULL
};
@@ -261,6 +267,12 @@ static int git_help_config(const char *var, const char *value, void *cb)
help_format = parse_help_format(value);
return 0;
}
+ if (!strcmp(var, "help.htmlpath")) {
+ if (!value)
+ return config_error_nonbool(var);
+ html_path = xstrdup(value);
+ return 0;
+ }
if (!strcmp(var, "man.viewer")) {
if (!value)
return config_error_nonbool(var);
@@ -383,12 +395,15 @@ static void show_info_page(const char *git_cmd)
static void get_html_page_path(struct strbuf *page_path, const char *page)
{
struct stat st;
- const char *html_path = system_path(GIT_HTML_PATH);
+ if (!html_path)
+ html_path = system_path(GIT_HTML_PATH);
/* Check that we have a git documentation directory. */
- if (stat(mkpath("%s/git.html", html_path), &st)
- || !S_ISREG(st.st_mode))
- die(_("'%s': not a documentation directory."), html_path);
+ if (!strstr(html_path, "://")) {
+ if (stat(mkpath("%s/git.html", html_path), &st)
+ || !S_ISREG(st.st_mode))
+ die("'%s': not a documentation directory.", html_path);
+ }
strbuf_init(page_path, 0);
strbuf_addf(page_path, "%s/%s.html", html_path, page);
@@ -447,6 +462,8 @@ int cmd_help(int argc, const char **argv, const char *prefix)
if (parsed_help_format != HELP_FORMAT_NONE)
help_format = parsed_help_format;
+ if (help_format == HELP_FORMAT_NONE)
+ help_format = parse_help_format(DEFAULT_HELP_FORMAT);
alias = alias_lookup(argv[0]);
if (alias && !is_git_command(argv[0])) {
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index 4705478..43d364b 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -9,6 +9,7 @@
#include "progress.h"
#include "fsck.h"
#include "exec_cmd.h"
+#include "streaming.h"
#include "thread-utils.h"
static const char index_pack_usage[] =
@@ -290,7 +291,7 @@ static void parse_pack_header(void)
if (hdr->hdr_signature != htonl(PACK_SIGNATURE))
die(_("pack signature mismatch"));
if (!pack_version_ok(hdr->hdr_version))
- die("pack version %"PRIu32" unsupported",
+ die(_("pack version %"PRIu32" unsupported"),
ntohl(hdr->hdr_version));
nr_objects = ntohl(hdr->hdr_entries);
@@ -384,30 +385,62 @@ static void unlink_base_data(struct base_data *c)
free_base_data(c);
}
-static void *unpack_entry_data(unsigned long offset, unsigned long size)
+static int is_delta_type(enum object_type type)
+{
+ return (type == OBJ_REF_DELTA || type == OBJ_OFS_DELTA);
+}
+
+static void *unpack_entry_data(unsigned long offset, unsigned long size,
+ enum object_type type, unsigned char *sha1)
{
+ static char fixed_buf[8192];
int status;
git_zstream stream;
- void *buf = xmalloc(size);
+ void *buf;
+ git_SHA_CTX c;
+ char hdr[32];
+ int hdrlen;
+
+ if (!is_delta_type(type)) {
+ hdrlen = sprintf(hdr, "%s %lu", typename(type), size) + 1;
+ git_SHA1_Init(&c);
+ git_SHA1_Update(&c, hdr, hdrlen);
+ } else
+ sha1 = NULL;
+ if (type == OBJ_BLOB && size > big_file_threshold)
+ buf = fixed_buf;
+ else
+ buf = xmalloc(size);
memset(&stream, 0, sizeof(stream));
git_inflate_init(&stream);
stream.next_out = buf;
- stream.avail_out = size;
+ stream.avail_out = buf == fixed_buf ? sizeof(fixed_buf) : size;
do {
+ unsigned char *last_out = stream.next_out;
stream.next_in = fill(1);
stream.avail_in = input_len;
status = git_inflate(&stream, 0);
use(input_len - stream.avail_in);
+ if (sha1)
+ git_SHA1_Update(&c, last_out, stream.next_out - last_out);
+ if (buf == fixed_buf) {
+ stream.next_out = buf;
+ stream.avail_out = sizeof(fixed_buf);
+ }
} while (status == Z_OK);
if (stream.total_out != size || status != Z_STREAM_END)
bad_object(offset, _("inflate returned %d"), status);
git_inflate_end(&stream);
- return buf;
+ if (sha1)
+ git_SHA1_Final(sha1, &c);
+ return buf == fixed_buf ? NULL : buf;
}
-static void *unpack_raw_entry(struct object_entry *obj, union delta_base *delta_base)
+static void *unpack_raw_entry(struct object_entry *obj,
+ union delta_base *delta_base,
+ unsigned char *sha1)
{
unsigned char *p;
unsigned long size, c;
@@ -467,12 +500,14 @@ static void *unpack_raw_entry(struct object_entry *obj, union delta_base *delta_
}
obj->hdr_size = consumed_bytes - obj->idx.offset;
- data = unpack_entry_data(obj->idx.offset, obj->size);
+ data = unpack_entry_data(obj->idx.offset, obj->size, obj->type, sha1);
obj->idx.crc32 = input_crc32;
return data;
}
-static void *get_data_from_pack(struct object_entry *obj)
+static void *unpack_data(struct object_entry *obj,
+ int (*consume)(const unsigned char *, unsigned long, void *),
+ void *cb_data)
{
off_t from = obj[0].idx.offset + obj[0].hdr_size;
unsigned long len = obj[1].idx.offset - from;
@@ -480,13 +515,13 @@ static void *get_data_from_pack(struct object_entry *obj)
git_zstream stream;
int status;
- data = xmalloc(obj->size);
+ data = xmalloc(consume ? 64*1024 : obj->size);
inbuf = xmalloc((len < 64*1024) ? len : 64*1024);
memset(&stream, 0, sizeof(stream));
git_inflate_init(&stream);
stream.next_out = data;
- stream.avail_out = obj->size;
+ stream.avail_out = consume ? 64*1024 : obj->size;
do {
ssize_t n = (len < 64*1024) ? len : 64*1024;
@@ -502,7 +537,20 @@ static void *get_data_from_pack(struct object_entry *obj)
len -= n;
stream.next_in = inbuf;
stream.avail_in = n;
- status = git_inflate(&stream, 0);
+ if (!consume)
+ status = git_inflate(&stream, 0);
+ else {
+ do {
+ status = git_inflate(&stream, 0);
+ if (consume(data, stream.next_out - data, cb_data)) {
+ free(inbuf);
+ free(data);
+ return NULL;
+ }
+ stream.next_out = data;
+ stream.avail_out = 64*1024;
+ } while (status == Z_OK && stream.avail_in);
+ }
} while (len && status == Z_OK && !stream.avail_in);
/* This has been inflated OK when first encountered, so... */
@@ -511,9 +559,18 @@ static void *get_data_from_pack(struct object_entry *obj)
git_inflate_end(&stream);
free(inbuf);
+ if (consume) {
+ free(data);
+ data = NULL;
+ }
return data;
}
+static void *get_data_from_pack(struct object_entry *obj)
+{
+ return unpack_data(obj, NULL, NULL);
+}
+
static int compare_delta_bases(const union delta_base *base1,
const union delta_base *base2,
enum object_type type1,
@@ -568,25 +625,102 @@ static void find_delta_children(const union delta_base *base,
*last_index = last;
}
-static void sha1_object(const void *data, unsigned long size,
- enum object_type type, unsigned char *sha1)
+struct compare_data {
+ struct object_entry *entry;
+ struct git_istream *st;
+ unsigned char *buf;
+ unsigned long buf_size;
+};
+
+static int compare_objects(const unsigned char *buf, unsigned long size,
+ void *cb_data)
+{
+ struct compare_data *data = cb_data;
+
+ if (data->buf_size < size) {
+ free(data->buf);
+ data->buf = xmalloc(size);
+ data->buf_size = size;
+ }
+
+ while (size) {
+ ssize_t len = read_istream(data->st, data->buf, size);
+ if (len == 0)
+ die(_("SHA1 COLLISION FOUND WITH %s !"),
+ sha1_to_hex(data->entry->idx.sha1));
+ if (len < 0)
+ die(_("unable to read %s"),
+ sha1_to_hex(data->entry->idx.sha1));
+ if (memcmp(buf, data->buf, len))
+ die(_("SHA1 COLLISION FOUND WITH %s !"),
+ sha1_to_hex(data->entry->idx.sha1));
+ size -= len;
+ buf += len;
+ }
+ return 0;
+}
+
+static int check_collison(struct object_entry *entry)
+{
+ struct compare_data data;
+ enum object_type type;
+ unsigned long size;
+
+ if (entry->size <= big_file_threshold || entry->type != OBJ_BLOB)
+ return -1;
+
+ memset(&data, 0, sizeof(data));
+ data.entry = entry;
+ data.st = open_istream(entry->idx.sha1, &type, &size, NULL);
+ if (!data.st)
+ return -1;
+ if (size != entry->size || type != entry->type)
+ die(_("SHA1 COLLISION FOUND WITH %s !"),
+ sha1_to_hex(entry->idx.sha1));
+ unpack_data(entry, compare_objects, &data);
+ close_istream(data.st);
+ free(data.buf);
+ return 0;
+}
+
+static void sha1_object(const void *data, struct object_entry *obj_entry,
+ unsigned long size, enum object_type type,
+ const unsigned char *sha1)
{
- hash_sha1_file(data, size, typename(type), sha1);
+ void *new_data = NULL;
+ int collision_test_needed;
+
+ assert(data || obj_entry);
+
read_lock();
- if (has_sha1_file(sha1)) {
+ collision_test_needed = has_sha1_file(sha1);
+ read_unlock();
+
+ if (collision_test_needed && !data) {
+ read_lock();
+ if (!check_collison(obj_entry))
+ collision_test_needed = 0;
+ read_unlock();
+ }
+ if (collision_test_needed) {
void *has_data;
enum object_type has_type;
unsigned long has_size;
+ read_lock();
+ has_type = sha1_object_info(sha1, &has_size);
+ if (has_type != type || has_size != size)
+ die(_("SHA1 COLLISION FOUND WITH %s !"), sha1_to_hex(sha1));
has_data = read_sha1_file(sha1, &has_type, &has_size);
read_unlock();
+ if (!data)
+ data = new_data = get_data_from_pack(obj_entry);
if (!has_data)
die(_("cannot read existing object %s"), sha1_to_hex(sha1));
if (size != has_size || type != has_type ||
memcmp(data, has_data, size) != 0)
die(_("SHA1 COLLISION FOUND WITH %s !"), sha1_to_hex(sha1));
free(has_data);
- } else
- read_unlock();
+ }
if (strict) {
read_lock();
@@ -601,6 +735,9 @@ static void sha1_object(const void *data, unsigned long size,
int eaten;
void *buf = (void *) data;
+ if (!buf)
+ buf = new_data = get_data_from_pack(obj_entry);
+
/*
* we do not need to free the memory here, as the
* buf is deleted by the caller.
@@ -625,11 +762,8 @@ static void sha1_object(const void *data, unsigned long size,
}
read_unlock();
}
-}
-static int is_delta_type(enum object_type type)
-{
- return (type == OBJ_REF_DELTA || type == OBJ_OFS_DELTA);
+ free(new_data);
}
/*
@@ -711,7 +845,9 @@ static void resolve_delta(struct object_entry *delta_obj,
free(delta_data);
if (!result->data)
bad_object(delta_obj->idx.offset, _("failed to apply delta"));
- sha1_object(result->data, result->size, delta_obj->real_type,
+ hash_sha1_file(result->data, result->size,
+ typename(delta_obj->real_type), delta_obj->idx.sha1);
+ sha1_object(result->data, NULL, result->size, delta_obj->real_type,
delta_obj->idx.sha1);
counter_lock();
nr_resolved_deltas++;
@@ -841,7 +977,7 @@ static void *threaded_second_pass(void *data)
*/
static void parse_pack_objects(unsigned char *sha1)
{
- int i;
+ int i, nr_delays = 0;
struct delta_entry *delta = deltas;
struct stat st;
@@ -851,14 +987,18 @@ static void parse_pack_objects(unsigned char *sha1)
nr_objects);
for (i = 0; i < nr_objects; i++) {
struct object_entry *obj = &objects[i];
- void *data = unpack_raw_entry(obj, &delta->base);
+ void *data = unpack_raw_entry(obj, &delta->base, obj->idx.sha1);
obj->real_type = obj->type;
if (is_delta_type(obj->type)) {
nr_deltas++;
delta->obj_no = i;
delta++;
+ } else if (!data) {
+ /* large blobs, check later */
+ obj->real_type = OBJ_BAD;
+ nr_delays++;
} else
- sha1_object(data, obj->size, obj->type, obj->idx.sha1);
+ sha1_object(data, NULL, obj->size, obj->type, obj->idx.sha1);
free(data);
display_progress(progress, i+1);
}
@@ -878,6 +1018,17 @@ static void parse_pack_objects(unsigned char *sha1)
if (S_ISREG(st.st_mode) &&
lseek(input_fd, 0, SEEK_CUR) - input_len != st.st_size)
die(_("pack has junk at the end"));
+
+ for (i = 0; i < nr_objects; i++) {
+ struct object_entry *obj = &objects[i];
+ if (obj->real_type != OBJ_BAD)
+ continue;
+ obj->real_type = obj->type;
+ sha1_object(NULL, obj, obj->size, obj->type, obj->idx.sha1);
+ nr_delays--;
+ }
+ if (nr_delays)
+ die(_("confusion beyond insanity in parse_pack_objects()"));
}
/*
@@ -910,7 +1061,8 @@ static void resolve_deltas(void)
int ret = pthread_create(&thread_data[i].thread, NULL,
threaded_second_pass, thread_data + i);
if (ret)
- die("unable to create thread: %s", strerror(ret));
+ die(_("unable to create thread: %s"),
+ strerror(ret));
}
for (i = 0; i < nr_threads; i++)
pthread_join(thread_data[i].thread, NULL);
@@ -957,7 +1109,7 @@ static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned cha
* sizeof(*objects));
f = sha1fd(output_fd, curr_pack);
fix_unresolved_deltas(f, nr_unresolved);
- sprintf(msg, "completed with %d local objects",
+ sprintf(msg, _("completed with %d local objects"),
nr_objects - nr_objects_initial);
stop_progress_msg(&progress, msg);
sha1close(f, tail_sha1, 0);
@@ -966,8 +1118,8 @@ static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned cha
curr_pack, nr_objects,
read_sha1, consumed_bytes-20);
if (hashcmp(read_sha1, tail_sha1) != 0)
- die("Unexpected tail checksum for %s "
- "(disk corruption?)", curr_pack);
+ die(_("Unexpected tail checksum for %s "
+ "(disk corruption?)"), curr_pack);
}
if (nr_deltas != nr_resolved_deltas)
die(Q_("pack has %d unresolved delta",
@@ -1176,17 +1328,17 @@ static int git_index_pack_config(const char *k, const char *v, void *cb)
if (!strcmp(k, "pack.indexversion")) {
opts->version = git_config_int(k, v);
if (opts->version > 2)
- die("bad pack.indexversion=%"PRIu32, opts->version);
+ die(_("bad pack.indexversion=%"PRIu32), opts->version);
return 0;
}
if (!strcmp(k, "pack.threads")) {
nr_threads = git_config_int(k, v);
if (nr_threads < 0)
- die("invalid number of threads specified (%d)",
+ die(_("invalid number of threads specified (%d)"),
nr_threads);
#ifdef NO_PTHREADS
if (nr_threads != 1)
- warning("no threads support, ignoring %s", k);
+ warning(_("no threads support, ignoring %s"), k);
nr_threads = 1;
#endif
return 0;
@@ -1359,8 +1511,8 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
usage(index_pack_usage);
#ifdef NO_PTHREADS
if (nr_threads != 1)
- warning("no threads support, "
- "ignoring %s", arg);
+ warning(_("no threads support, "
+ "ignoring %s"), arg);
nr_threads = 1;
#endif
} else if (!prefixcmp(arg, "--pack_header=")) {
diff --git a/builtin/init-db.c b/builtin/init-db.c
index 0dacb8b..78aa387 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -290,6 +290,7 @@ static int create_default_files(const char *template_path)
strcpy(path + len, "CoNfIg");
if (!access(path, F_OK))
git_config_set("core.ignorecase", "true");
+ probe_utf8_pathname_composition(path, len);
}
return reinit;
@@ -463,7 +464,7 @@ static int shared_callback(const struct option *opt, const char *arg, int unset)
}
static const char *const init_db_usage[] = {
- "git init [-q | --quiet] [--bare] [--template=<template-directory>] [--shared[=<permissions>]] [directory]",
+ N_("git init [-q | --quiet] [--bare] [--template=<template-directory>] [--shared[=<permissions>]] [directory]"),
NULL
};
@@ -481,17 +482,17 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
const char *template_dir = NULL;
unsigned int flags = 0;
const struct option init_db_options[] = {
- OPT_STRING(0, "template", &template_dir, "template-directory",
- "directory from which templates will be used"),
+ OPT_STRING(0, "template", &template_dir, N_("template-directory"),
+ N_("directory from which templates will be used")),
OPT_SET_INT(0, "bare", &is_bare_repository_cfg,
- "create a bare repository", 1),
+ N_("create a bare repository"), 1),
{ OPTION_CALLBACK, 0, "shared", &init_shared_repository,
- "permissions",
- "specify that the git repository is to be shared amongst several users",
+ N_("permissions"),
+ N_("specify that the git repository is to be shared amongst several users"),
PARSE_OPT_OPTARG | PARSE_OPT_NONEG, shared_callback, 0},
- OPT_BIT('q', "quiet", &flags, "be quiet", INIT_DB_QUIET),
- OPT_STRING(0, "separate-git-dir", &real_git_dir, "gitdir",
- "separate git dir from working tree"),
+ OPT_BIT('q', "quiet", &flags, N_("be quiet"), INIT_DB_QUIET),
+ OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"),
+ N_("separate git dir from working tree")),
OPT_END()
};
diff --git a/builtin/log.c b/builtin/log.c
index a8249d3..09cf43e 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -21,6 +21,7 @@
#include "parse-options.h"
#include "branch.h"
#include "streaming.h"
+#include "version.h"
/* Set a default date-time format for git log ("log.date" config variable) */
static const char *default_date_mode = NULL;
@@ -33,8 +34,8 @@ static const char *fmt_patch_subject_prefix = "PATCH";
static const char *fmt_pretty;
static const char * const builtin_log_usage[] = {
- "git log [<options>] [<since>..<until>] [[--] <path>...]\n"
- " or: git show [options] <object>...",
+ N_("git log [<options>] [<since>..<until>] [[--] <path>...]\n")
+ N_(" or: git show [options] <object>..."),
NULL
};
@@ -96,9 +97,9 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
int quiet = 0, source = 0;
const struct option builtin_log_options[] = {
- OPT_BOOLEAN(0, "quiet", &quiet, "suppress diff output"),
- OPT_BOOLEAN(0, "source", &source, "show source"),
- { OPTION_CALLBACK, 0, "decorate", NULL, NULL, "decorate options",
+ OPT_BOOLEAN(0, "quiet", &quiet, N_("suppress diff output")),
+ OPT_BOOLEAN(0, "source", &source, N_("show source")),
+ { OPTION_CALLBACK, 0, "decorate", NULL, NULL, N_("decorate options"),
PARSE_OPT_OPTARG, decorate_callback},
OPT_END()
};
@@ -366,6 +367,7 @@ int cmd_whatchanged(int argc, const char **argv, const char *prefix)
rev.simplify_history = 0;
memset(&opt, 0, sizeof(opt));
opt.def = "HEAD";
+ opt.revarg_opt = REVARG_COMMITTISH;
cmd_log_init(argc, argv, prefix, &rev, &opt);
if (!rev.diffopt.output_format)
rev.diffopt.output_format = DIFF_FORMAT_RAW;
@@ -454,7 +456,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)
init_revisions(&rev, prefix);
rev.diff = 1;
rev.always_show_header = 1;
- rev.no_walk = 1;
+ rev.no_walk = REVISION_WALK_NO_WALK_SORTED;
rev.diffopt.stat_width = -1; /* Scale to real terminal size */
memset(&opt, 0, sizeof(opt));
@@ -556,6 +558,7 @@ int cmd_log(int argc, const char **argv, const char *prefix)
rev.always_show_header = 1;
memset(&opt, 0, sizeof(opt));
opt.def = "HEAD";
+ opt.revarg_opt = REVARG_COMMITTISH;
cmd_log_init(argc, argv, prefix, &rev, &opt);
return cmd_log_walk(&rev);
}
@@ -693,7 +696,7 @@ static int reopen_stdout(struct commit *commit, const char *subject,
return 0;
}
-static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids, const char *prefix)
+static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids)
{
struct rev_info check_rev;
struct commit *commit;
@@ -714,7 +717,8 @@ static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids, const cha
init_patch_ids(ids);
/* given a range a..b get all patch ids for b..a */
- init_revisions(&check_rev, prefix);
+ init_revisions(&check_rev, rev->prefix);
+ check_rev.max_parents = 1;
o1->flags ^= UNINTERESTING;
o2->flags ^= UNINTERESTING;
add_pending_object(&check_rev, o1, "o1");
@@ -723,10 +727,6 @@ static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids, const cha
die(_("revision walk setup failed"));
while ((commit = get_revision(&check_rev)) != NULL) {
- /* ignore merges */
- if (commit->parents && commit->parents->next)
- continue;
-
add_commit_patch_id(commit, ids);
}
@@ -887,7 +887,7 @@ static const char *set_outdir(const char *prefix, const char *output_directory)
}
static const char * const builtin_format_patch_usage[] = {
- "git format-patch [options] [<since> | <revision range>]",
+ N_("git format-patch [options] [<since> | <revision range>]"),
NULL
};
@@ -1060,61 +1060,61 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
char *branch_name = NULL;
const struct option builtin_format_patch_options[] = {
{ OPTION_CALLBACK, 'n', "numbered", &numbered, NULL,
- "use [PATCH n/m] even with a single patch",
+ N_("use [PATCH n/m] even with a single patch"),
PARSE_OPT_NOARG, numbered_callback },
{ OPTION_CALLBACK, 'N', "no-numbered", &numbered, NULL,
- "use [PATCH] even with multiple patches",
+ N_("use [PATCH] even with multiple patches"),
PARSE_OPT_NOARG, no_numbered_callback },
- OPT_BOOLEAN('s', "signoff", &do_signoff, "add Signed-off-by:"),
+ OPT_BOOLEAN('s', "signoff", &do_signoff, N_("add Signed-off-by:")),
OPT_BOOLEAN(0, "stdout", &use_stdout,
- "print patches to standard out"),
+ N_("print patches to standard out")),
OPT_BOOLEAN(0, "cover-letter", &cover_letter,
- "generate a cover letter"),
+ N_("generate a cover letter")),
OPT_BOOLEAN(0, "numbered-files", &numbered_files,
- "use simple number sequence for output file names"),
- OPT_STRING(0, "suffix", &fmt_patch_suffix, "sfx",
- "use <sfx> instead of '.patch'"),
+ N_("use simple number sequence for output file names")),
+ OPT_STRING(0, "suffix", &fmt_patch_suffix, N_("sfx"),
+ N_("use <sfx> instead of '.patch'")),
OPT_INTEGER(0, "start-number", &start_number,
- "start numbering patches at <n> instead of 1"),
- { OPTION_CALLBACK, 0, "subject-prefix", &rev, "prefix",
- "Use [<prefix>] instead of [PATCH]",
+ N_("start numbering patches at <n> instead of 1")),
+ { OPTION_CALLBACK, 0, "subject-prefix", &rev, N_("prefix"),
+ N_("Use [<prefix>] instead of [PATCH]"),
PARSE_OPT_NONEG, subject_prefix_callback },
{ OPTION_CALLBACK, 'o', "output-directory", &output_directory,
- "dir", "store resulting files in <dir>",
+ N_("dir"), N_("store resulting files in <dir>"),
PARSE_OPT_NONEG, output_directory_callback },
{ OPTION_CALLBACK, 'k', "keep-subject", &rev, NULL,
- "don't strip/add [PATCH]",
+ N_("don't strip/add [PATCH]"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, keep_callback },
OPT_BOOLEAN(0, "no-binary", &no_binary_diff,
- "don't output binary diffs"),
+ N_("don't output binary diffs")),
OPT_BOOLEAN(0, "ignore-if-in-upstream", &ignore_if_in_upstream,
- "don't include a patch matching a commit upstream"),
+ N_("don't include a patch matching a commit upstream")),
{ OPTION_BOOLEAN, 'p', "no-stat", &use_patch_format, NULL,
- "show patch format instead of default (patch + stat)",
+ N_("show patch format instead of default (patch + stat)"),
PARSE_OPT_NONEG | PARSE_OPT_NOARG },
- OPT_GROUP("Messaging"),
- { OPTION_CALLBACK, 0, "add-header", NULL, "header",
- "add email header", 0, header_callback },
- { OPTION_CALLBACK, 0, "to", NULL, "email", "add To: header",
+ OPT_GROUP(N_("Messaging")),
+ { OPTION_CALLBACK, 0, "add-header", NULL, N_("header"),
+ N_("add email header"), 0, header_callback },
+ { OPTION_CALLBACK, 0, "to", NULL, N_("email"), N_("add To: header"),
0, to_callback },
- { OPTION_CALLBACK, 0, "cc", NULL, "email", "add Cc: header",
+ { OPTION_CALLBACK, 0, "cc", NULL, N_("email"), N_("add Cc: header"),
0, cc_callback },
- OPT_STRING(0, "in-reply-to", &in_reply_to, "message-id",
- "make first mail a reply to <message-id>"),
- { OPTION_CALLBACK, 0, "attach", &rev, "boundary",
- "attach the patch", PARSE_OPT_OPTARG,
+ OPT_STRING(0, "in-reply-to", &in_reply_to, N_("message-id"),
+ N_("make first mail a reply to <message-id>")),
+ { OPTION_CALLBACK, 0, "attach", &rev, N_("boundary"),
+ N_("attach the patch"), PARSE_OPT_OPTARG,
attach_callback },
- { OPTION_CALLBACK, 0, "inline", &rev, "boundary",
- "inline the patch",
+ { OPTION_CALLBACK, 0, "inline", &rev, N_("boundary"),
+ N_("inline the patch"),
PARSE_OPT_OPTARG | PARSE_OPT_NONEG,
inline_callback },
- { OPTION_CALLBACK, 0, "thread", &thread, "style",
- "enable message threading, styles: shallow, deep",
+ { OPTION_CALLBACK, 0, "thread", &thread, N_("style"),
+ N_("enable message threading, styles: shallow, deep"),
PARSE_OPT_OPTARG, thread_callback },
- OPT_STRING(0, "signature", &signature, "signature",
- "add a signature"),
+ OPT_STRING(0, "signature", &signature, N_("signature"),
+ N_("add a signature")),
OPT_BOOLEAN(0, "quiet", &quiet,
- "don't print the patch filenames"),
+ N_("don't print the patch filenames")),
OPT_END()
};
@@ -1131,6 +1131,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
rev.subject_prefix = fmt_patch_subject_prefix;
memset(&s_r_opt, 0, sizeof(s_r_opt));
s_r_opt.def = "HEAD";
+ s_r_opt.revarg_opt = REVARG_COMMITTISH;
if (default_attach) {
rev.mime_boundary = default_attach;
@@ -1302,7 +1303,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
if (hashcmp(o[0].item->sha1, o[1].item->sha1) == 0)
return 0;
}
- get_patch_ids(&rev, &ids, prefix);
+ get_patch_ids(&rev, &ids);
}
if (!use_stdout)
@@ -1439,7 +1440,7 @@ static int add_pending_commit(const char *arg, struct rev_info *revs, int flags)
}
static const char * const cherry_usage[] = {
- "git cherry [-v] [<upstream> [<head> [<limit>]]]",
+ N_("git cherry [-v] [<upstream> [<head> [<limit>]]]"),
NULL
};
@@ -1473,7 +1474,7 @@ int cmd_cherry(int argc, const char **argv, const char *prefix)
struct option options[] = {
OPT__ABBREV(&abbrev),
- OPT__VERBOSE(&verbose, "be verbose"),
+ OPT__VERBOSE(&verbose, N_("be verbose")),
OPT_END()
};
@@ -1504,10 +1505,7 @@ int cmd_cherry(int argc, const char **argv, const char *prefix)
}
init_revisions(&revs, prefix);
- revs.diff = 1;
- revs.combine_merges = 0;
- revs.ignore_merges = 1;
- DIFF_OPT_SET(&revs.diffopt, RECURSIVE);
+ revs.max_parents = 1;
if (add_pending_commit(head, &revs, 0))
die(_("Unknown commit %s"), head);
@@ -1521,7 +1519,7 @@ int cmd_cherry(int argc, const char **argv, const char *prefix)
return 0;
}
- get_patch_ids(&revs, &ids, prefix);
+ get_patch_ids(&revs, &ids);
if (limit && add_pending_commit(limit, &revs, UNINTERESTING))
die(_("Unknown commit %s"), limit);
@@ -1530,10 +1528,6 @@ int cmd_cherry(int argc, const char **argv, const char *prefix)
if (prepare_revision_walk(&revs))
die(_("revision walk setup failed"));
while ((commit = get_revision(&revs)) != NULL) {
- /* ignore merges */
- if (commit->parents && commit->parents->next)
- continue;
-
commit_list_insert(commit, &list);
}
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 31b3f2d..b5434af 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -405,7 +405,7 @@ int report_path_error(const char *ps_matched, const char **pathspec, const char
}
static const char * const ls_files_usage[] = {
- "git ls-files [options] [<file>...]",
+ N_("git ls-files [options] [<file>...]"),
NULL
};
@@ -457,57 +457,57 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
struct dir_struct dir;
struct option builtin_ls_files_options[] = {
{ OPTION_CALLBACK, 'z', NULL, NULL, NULL,
- "paths are separated with NUL character",
+ N_("paths are separated with NUL character"),
PARSE_OPT_NOARG, option_parse_z },
OPT_BOOLEAN('t', NULL, &show_tag,
- "identify the file status with tags"),
+ N_("identify the file status with tags")),
OPT_BOOLEAN('v', NULL, &show_valid_bit,
- "use lowercase letters for 'assume unchanged' files"),
+ N_("use lowercase letters for 'assume unchanged' files")),
OPT_BOOLEAN('c', "cached", &show_cached,
- "show cached files in the output (default)"),
+ N_("show cached files in the output (default)")),
OPT_BOOLEAN('d', "deleted", &show_deleted,
- "show deleted files in the output"),
+ N_("show deleted files in the output")),
OPT_BOOLEAN('m', "modified", &show_modified,
- "show modified files in the output"),
+ N_("show modified files in the output")),
OPT_BOOLEAN('o', "others", &show_others,
- "show other files in the output"),
+ N_("show other files in the output")),
OPT_BIT('i', "ignored", &dir.flags,
- "show ignored files in the output",
+ N_("show ignored files in the output"),
DIR_SHOW_IGNORED),
OPT_BOOLEAN('s', "stage", &show_stage,
- "show staged contents' object name in the output"),
+ N_("show staged contents' object name in the output")),
OPT_BOOLEAN('k', "killed", &show_killed,
- "show files on the filesystem that need to be removed"),
+ N_("show files on the filesystem that need to be removed")),
OPT_BIT(0, "directory", &dir.flags,
- "show 'other' directories' name only",
+ N_("show 'other' directories' name only"),
DIR_SHOW_OTHER_DIRECTORIES),
OPT_NEGBIT(0, "empty-directory", &dir.flags,
- "don't show empty directories",
+ N_("don't show empty directories"),
DIR_HIDE_EMPTY_DIRECTORIES),
OPT_BOOLEAN('u', "unmerged", &show_unmerged,
- "show unmerged files in the output"),
+ N_("show unmerged files in the output")),
OPT_BOOLEAN(0, "resolve-undo", &show_resolve_undo,
- "show resolve-undo information"),
- { OPTION_CALLBACK, 'x', "exclude", &dir.exclude_list[EXC_CMDL], "pattern",
- "skip files matching pattern",
+ N_("show resolve-undo information")),
+ { OPTION_CALLBACK, 'x', "exclude", &dir.exclude_list[EXC_CMDL], N_("pattern"),
+ N_("skip files matching pattern"),
0, option_parse_exclude },
- { OPTION_CALLBACK, 'X', "exclude-from", &dir, "file",
- "exclude patterns are read from <file>",
+ { OPTION_CALLBACK, 'X', "exclude-from", &dir, N_("file"),
+ N_("exclude patterns are read from <file>"),
0, option_parse_exclude_from },
- OPT_STRING(0, "exclude-per-directory", &dir.exclude_per_dir, "file",
- "read additional per-directory exclude patterns in <file>"),
+ OPT_STRING(0, "exclude-per-directory", &dir.exclude_per_dir, N_("file"),
+ N_("read additional per-directory exclude patterns in <file>")),
{ OPTION_CALLBACK, 0, "exclude-standard", &dir, NULL,
- "add the standard git exclusions",
+ N_("add the standard git exclusions"),
PARSE_OPT_NOARG, option_parse_exclude_standard },
{ OPTION_SET_INT, 0, "full-name", &prefix_len, NULL,
- "make the output relative to the project top directory",
+ N_("make the output relative to the project top directory"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL },
OPT_BOOLEAN(0, "error-unmatch", &error_unmatch,
- "if any <file> is not in the index, treat this as an error"),
- OPT_STRING(0, "with-tree", &with_tree, "tree-ish",
- "pretend that paths removed since <tree-ish> are still present"),
+ N_("if any <file> is not in the index, treat this as an error")),
+ OPT_STRING(0, "with-tree", &with_tree, N_("tree-ish"),
+ N_("pretend that paths removed since <tree-ish> are still present")),
OPT__ABBREV(&abbrev),
- OPT_BOOLEAN(0, "debug", &debug_mode, "show debugging data"),
+ OPT_BOOLEAN(0, "debug", &debug_mode, N_("show debugging data")),
OPT_END()
};
diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c
index 41c88a9..25e83cf 100644
--- a/builtin/ls-remote.c
+++ b/builtin/ls-remote.c
@@ -5,7 +5,7 @@
static const char ls_remote_usage[] =
"git ls-remote [--heads] [--tags] [-u <exec> | --upload-pack <exec>]\n"
-" [-q|--quiet] [--exit-code] [<repository> [<refs>...]]";
+" [-q|--quiet] [--exit-code] [--get-url] [<repository> [<refs>...]]";
/*
* Is there one among the list of patterns that match the tail part
diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
index 6b666e1..235c17c 100644
--- a/builtin/ls-tree.c
+++ b/builtin/ls-tree.c
@@ -24,7 +24,7 @@ static int chomp_prefix;
static const char *ls_tree_prefix;
static const char * const ls_tree_usage[] = {
- "git ls-tree [<options>] <tree-ish> [<path>...]",
+ N_("git ls-tree [<options>] <tree-ish> [<path>...]"),
NULL
};
@@ -122,25 +122,25 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
struct tree *tree;
int i, full_tree = 0;
const struct option ls_tree_options[] = {
- OPT_BIT('d', NULL, &ls_options, "only show trees",
+ OPT_BIT('d', NULL, &ls_options, N_("only show trees"),
LS_TREE_ONLY),
- OPT_BIT('r', NULL, &ls_options, "recurse into subtrees",
+ OPT_BIT('r', NULL, &ls_options, N_("recurse into subtrees"),
LS_RECURSIVE),
- OPT_BIT('t', NULL, &ls_options, "show trees when recursing",
+ OPT_BIT('t', NULL, &ls_options, N_("show trees when recursing"),
LS_SHOW_TREES),
OPT_SET_INT('z', NULL, &line_termination,
- "terminate entries with NUL byte", 0),
- OPT_BIT('l', "long", &ls_options, "include object size",
+ N_("terminate entries with NUL byte"), 0),
+ OPT_BIT('l', "long", &ls_options, N_("include object size"),
LS_SHOW_SIZE),
- OPT_BIT(0, "name-only", &ls_options, "list only filenames",
+ OPT_BIT(0, "name-only", &ls_options, N_("list only filenames"),
LS_NAME_ONLY),
- OPT_BIT(0, "name-status", &ls_options, "list only filenames",
+ OPT_BIT(0, "name-status", &ls_options, N_("list only filenames"),
LS_NAME_ONLY),
OPT_SET_INT(0, "full-name", &chomp_prefix,
- "use full path names", 0),
+ N_("use full path names"), 0),
OPT_BOOLEAN(0, "full-tree", &full_tree,
- "list entire tree; not just current directory "
- "(implies --full-name)"),
+ N_("list entire tree; not just current directory "
+ "(implies --full-name)")),
OPT__ABBREV(&abbrev),
OPT_END()
};
diff --git a/builtin/mailinfo.c b/builtin/mailinfo.c
index eaf9e15..da23140 100644
--- a/builtin/mailinfo.c
+++ b/builtin/mailinfo.c
@@ -19,9 +19,6 @@ static struct strbuf email = STRBUF_INIT;
static enum {
TE_DONTCARE, TE_QP, TE_BASE64
} transfer_encoding;
-static enum {
- TYPE_TEXT, TYPE_OTHER
-} message_type;
static struct strbuf charset = STRBUF_INIT;
static int patch_lines;
@@ -160,10 +157,9 @@ static int slurp_attr(const char *line, const char *name, struct strbuf *attr)
const char *ends, *ap = strcasestr(line, name);
size_t sz;
- if (!ap) {
- strbuf_setlen(attr, 0);
+ strbuf_setlen(attr, 0);
+ if (!ap)
return 0;
- }
ap += strlen(name);
if (*ap == '"') {
ap++;
@@ -185,8 +181,6 @@ static void handle_content_type(struct strbuf *line)
struct strbuf *boundary = xmalloc(sizeof(struct strbuf));
strbuf_init(boundary, line->len);
- if (!strcasestr(line->buf, "text/"))
- message_type = TYPE_OTHER;
if (slurp_attr(line->buf, "boundary=", boundary)) {
strbuf_insert(boundary, 0, "--", 2);
if (++content_top > &content[MAX_BOUNDARIES]) {
@@ -232,7 +226,9 @@ static void cleanup_subject(struct strbuf *subject)
case 'r': case 'R':
if (subject->len <= at + 3)
break;
- if (!memcmp(subject->buf + at + 1, "e:", 2)) {
+ if ((subject->buf[at + 1] == 'e' ||
+ subject->buf[at + 1] == 'E') &&
+ subject->buf[at + 2] == ':') {
strbuf_remove(subject, at, 3);
continue;
}
@@ -481,36 +477,12 @@ static struct strbuf *decode_b_segment(const struct strbuf *b_seg)
return out;
}
-/*
- * When there is no known charset, guess.
- *
- * Right now we assume that if the target is UTF-8 (the default),
- * and it already looks like UTF-8 (which includes US-ASCII as its
- * subset, of course) then that is what it is and there is nothing
- * to do.
- *
- * Otherwise, we default to assuming it is Latin1 for historical
- * reasons.
- */
-static const char *guess_charset(const struct strbuf *line, const char *target_charset)
-{
- if (is_encoding_utf8(target_charset)) {
- if (is_utf8(line->buf))
- return NULL;
- }
- return "ISO8859-1";
-}
-
static void convert_to_utf8(struct strbuf *line, const char *charset)
{
char *out;
- if (!charset || !*charset) {
- charset = guess_charset(line, metainfo_charset);
- if (!charset)
- return;
- }
-
+ if (!charset || !*charset)
+ return;
if (!strcasecmp(metainfo_charset, charset))
return;
out = reencode_string(line->buf, metainfo_charset, charset);
@@ -680,7 +652,6 @@ again:
/* set some defaults */
transfer_encoding = TE_DONTCARE;
strbuf_reset(&charset);
- message_type = TYPE_TEXT;
/* slurp in this section's info */
while (read_one_header_line(&line, fin))
@@ -894,11 +865,6 @@ static void handle_body(void)
strbuf_insert(&line, 0, prev.buf, prev.len);
strbuf_reset(&prev);
- /* binary data most likely doesn't have newlines */
- if (message_type != TYPE_TEXT) {
- handle_filter(&line);
- break;
- }
/*
* This is a decoded line that may contain
* multiple new lines. Pass only one chunk
diff --git a/builtin/merge-base.c b/builtin/merge-base.c
index 4f30f1b..1bc7991 100644
--- a/builtin/merge-base.c
+++ b/builtin/merge-base.c
@@ -23,9 +23,10 @@ static int show_merge_base(struct commit **rev, int rev_nr, int show_all)
}
static const char * const merge_base_usage[] = {
- "git merge-base [-a|--all] <commit> <commit>...",
- "git merge-base [-a|--all] --octopus <commit>...",
- "git merge-base --independent <commit>...",
+ N_("git merge-base [-a|--all] <commit> <commit>..."),
+ N_("git merge-base [-a|--all] --octopus <commit>..."),
+ N_("git merge-base --independent <commit>..."),
+ N_("git merge-base --is-ancestor <commit> <commit>"),
NULL
};
@@ -70,6 +71,20 @@ static int handle_octopus(int count, const char **args, int reduce, int show_all
return 0;
}
+static int handle_is_ancestor(int argc, const char **argv)
+{
+ struct commit *one, *two;
+
+ if (argc != 2)
+ die("--is-ancestor takes exactly two commits");
+ one = get_commit_reference(argv[0]);
+ two = get_commit_reference(argv[1]);
+ if (in_merge_bases(one, two))
+ return 0;
+ else
+ return 1;
+}
+
int cmd_merge_base(int argc, const char **argv, const char *prefix)
{
struct commit **rev;
@@ -77,11 +92,14 @@ int cmd_merge_base(int argc, const char **argv, const char *prefix)
int show_all = 0;
int octopus = 0;
int reduce = 0;
+ int is_ancestor = 0;
struct option options[] = {
- OPT_BOOLEAN('a', "all", &show_all, "output all common ancestors"),
- OPT_BOOLEAN(0, "octopus", &octopus, "find ancestors for a single n-way merge"),
- OPT_BOOLEAN(0, "independent", &reduce, "list revs not reachable from others"),
+ OPT_BOOLEAN('a', "all", &show_all, N_("output all common ancestors")),
+ OPT_BOOLEAN(0, "octopus", &octopus, N_("find ancestors for a single n-way merge")),
+ OPT_BOOLEAN(0, "independent", &reduce, N_("list revs not reachable from others")),
+ OPT_BOOLEAN(0, "is-ancestor", &is_ancestor,
+ N_("is the first one ancestor of the other?")),
OPT_END()
};
@@ -89,6 +107,10 @@ int cmd_merge_base(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, options, merge_base_usage, 0);
if (!octopus && !reduce && argc < 2)
usage_with_options(merge_base_usage, options);
+ if (is_ancestor && (show_all | octopus | reduce))
+ die("--is-ancestor cannot be used with other options");
+ if (is_ancestor)
+ return handle_is_ancestor(argc, argv);
if (reduce && (show_all || octopus))
die("--independent cannot be used with other options");
diff --git a/builtin/merge-file.c b/builtin/merge-file.c
index 6f0efef..c0570f2 100644
--- a/builtin/merge-file.c
+++ b/builtin/merge-file.c
@@ -5,7 +5,7 @@
#include "parse-options.h"
static const char *const merge_file_usage[] = {
- "git merge-file [options] [-L name1 [-L orig [-L name2]]] file1 orig_file file2",
+ N_("git merge-file [options] [-L name1 [-L orig [-L name2]]] file1 orig_file file2"),
NULL
};
@@ -30,19 +30,19 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
int quiet = 0;
int prefixlen = 0;
struct option options[] = {
- OPT_BOOLEAN('p', "stdout", &to_stdout, "send results to standard output"),
- OPT_SET_INT(0, "diff3", &xmp.style, "use a diff3 based merge", XDL_MERGE_DIFF3),
- OPT_SET_INT(0, "ours", &xmp.favor, "for conflicts, use our version",
+ OPT_BOOLEAN('p', "stdout", &to_stdout, N_("send results to standard output")),
+ OPT_SET_INT(0, "diff3", &xmp.style, N_("use a diff3 based merge"), XDL_MERGE_DIFF3),
+ OPT_SET_INT(0, "ours", &xmp.favor, N_("for conflicts, use our version"),
XDL_MERGE_FAVOR_OURS),
- OPT_SET_INT(0, "theirs", &xmp.favor, "for conflicts, use their version",
+ OPT_SET_INT(0, "theirs", &xmp.favor, N_("for conflicts, use their version"),
XDL_MERGE_FAVOR_THEIRS),
- OPT_SET_INT(0, "union", &xmp.favor, "for conflicts, use a union version",
+ OPT_SET_INT(0, "union", &xmp.favor, N_("for conflicts, use a union version"),
XDL_MERGE_FAVOR_UNION),
OPT_INTEGER(0, "marker-size", &xmp.marker_size,
- "for conflicts, use this marker size"),
- OPT__QUIET(&quiet, "do not warn about conflicts"),
- OPT_CALLBACK('L', NULL, names, "name",
- "set labels for file1/orig_file/file2", &label_cb),
+ N_("for conflicts, use this marker size")),
+ OPT__QUIET(&quiet, N_("do not warn about conflicts")),
+ OPT_CALLBACK('L', NULL, names, N_("name"),
+ N_("set labels for file1/orig_file/file2"), &label_cb),
OPT_END(),
};
diff --git a/builtin/merge.c b/builtin/merge.c
index e81fde6..0ec8f0d 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -40,9 +40,9 @@ struct strategy {
};
static const char * const builtin_merge_usage[] = {
- "git merge [options] [<commit>...]",
- "git merge [options] <msg> HEAD <commit>",
- "git merge --abort",
+ N_("git merge [options] [<commit>...]"),
+ N_("git merge [options] <msg> HEAD <commit>"),
+ N_("git merge --abort"),
NULL
};
@@ -180,39 +180,39 @@ static int option_parse_n(const struct option *opt,
static struct option builtin_merge_options[] = {
{ OPTION_CALLBACK, 'n', NULL, NULL, NULL,
- "do not show a diffstat at the end of the merge",
+ N_("do not show a diffstat at the end of the merge"),
PARSE_OPT_NOARG, option_parse_n },
OPT_BOOLEAN(0, "stat", &show_diffstat,
- "show a diffstat at the end of the merge"),
- OPT_BOOLEAN(0, "summary", &show_diffstat, "(synonym to --stat)"),
- { OPTION_INTEGER, 0, "log", &shortlog_len, "n",
- "add (at most <n>) entries from shortlog to merge commit message",
+ N_("show a diffstat at the end of the merge")),
+ OPT_BOOLEAN(0, "summary", &show_diffstat, N_("(synonym to --stat)")),
+ { OPTION_INTEGER, 0, "log", &shortlog_len, N_("n"),
+ N_("add (at most <n>) entries from shortlog to merge commit message"),
PARSE_OPT_OPTARG, NULL, DEFAULT_MERGE_LOG_LEN },
OPT_BOOLEAN(0, "squash", &squash,
- "create a single commit instead of doing a merge"),
+ N_("create a single commit instead of doing a merge")),
OPT_BOOLEAN(0, "commit", &option_commit,
- "perform a commit if the merge succeeds (default)"),
+ N_("perform a commit if the merge succeeds (default)")),
OPT_BOOL('e', "edit", &option_edit,
- "edit message before committing"),
+ N_("edit message before committing")),
OPT_BOOLEAN(0, "ff", &allow_fast_forward,
- "allow fast-forward (default)"),
+ N_("allow fast-forward (default)")),
OPT_BOOLEAN(0, "ff-only", &fast_forward_only,
- "abort if fast-forward is not possible"),
+ N_("abort if fast-forward is not possible")),
OPT_RERERE_AUTOUPDATE(&allow_rerere_auto),
- OPT_CALLBACK('s', "strategy", &use_strategies, "strategy",
- "merge strategy to use", option_parse_strategy),
- OPT_CALLBACK('X', "strategy-option", &xopts, "option=value",
- "option for selected merge strategy", option_parse_x),
- OPT_CALLBACK('m', "message", &merge_msg, "message",
- "merge commit message (for a non-fast-forward merge)",
+ OPT_CALLBACK('s', "strategy", &use_strategies, N_("strategy"),
+ N_("merge strategy to use"), option_parse_strategy),
+ OPT_CALLBACK('X', "strategy-option", &xopts, N_("option=value"),
+ N_("option for selected merge strategy"), option_parse_x),
+ OPT_CALLBACK('m', "message", &merge_msg, N_("message"),
+ N_("merge commit message (for a non-fast-forward merge)"),
option_parse_message),
OPT__VERBOSITY(&verbosity),
OPT_BOOLEAN(0, "abort", &abort_current_merge,
- "abort the current in-progress merge"),
- OPT_SET_INT(0, "progress", &show_progress, "force progress reporting", 1),
- { OPTION_STRING, 'S', "gpg-sign", &sign_commit, "key id",
- "GPG sign commit", PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
- OPT_BOOLEAN(0, "overwrite-ignore", &overwrite_ignore, "update ignored files (default)"),
+ N_("abort the current in-progress merge")),
+ OPT_SET_INT(0, "progress", &show_progress, N_("force progress reporting"), 1),
+ { OPTION_STRING, 'S', "gpg-sign", &sign_commit, N_("key id"),
+ N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
+ OPT_BOOLEAN(0, "overwrite-ignore", &overwrite_ignore, N_("update ignored files (default)")),
OPT_END()
};
diff --git a/builtin/mktree.c b/builtin/mktree.c
index 4ae1c41..f92ba40 100644
--- a/builtin/mktree.c
+++ b/builtin/mktree.c
@@ -64,7 +64,7 @@ static void write_tree(unsigned char *sha1)
}
static const char *mktree_usage[] = {
- "git mktree [-z] [--missing] [--batch]",
+ N_("git mktree [-z] [--missing] [--batch]"),
NULL
};
@@ -150,9 +150,9 @@ int cmd_mktree(int ac, const char **av, const char *prefix)
int got_eof = 0;
const struct option option[] = {
- OPT_SET_INT('z', NULL, &line_termination, "input is NUL terminated", '\0'),
- OPT_SET_INT( 0 , "missing", &allow_missing, "allow missing objects", 1),
- OPT_SET_INT( 0 , "batch", &is_batch_mode, "allow creation of more than one tree", 1),
+ OPT_SET_INT('z', NULL, &line_termination, N_("input is NUL terminated"), '\0'),
+ OPT_SET_INT( 0 , "missing", &allow_missing, N_("allow missing objects"), 1),
+ OPT_SET_INT( 0 , "batch", &is_batch_mode, N_("allow creation of more than one tree"), 1),
OPT_END()
};
diff --git a/builtin/mv.c b/builtin/mv.c
index 2a144b0..034fec9 100644
--- a/builtin/mv.c
+++ b/builtin/mv.c
@@ -11,7 +11,7 @@
#include "parse-options.h"
static const char * const builtin_mv_usage[] = {
- "git mv [options] <source>... <destination>",
+ N_("git mv [options] <source>... <destination>"),
NULL
};
@@ -59,10 +59,10 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
int i, newfd;
int verbose = 0, show_only = 0, force = 0, ignore_errors = 0;
struct option builtin_mv_options[] = {
- OPT__VERBOSE(&verbose, "be verbose"),
- OPT__DRY_RUN(&show_only, "dry run"),
- OPT__FORCE(&force, "force move/rename even if target exists"),
- OPT_BOOLEAN('k', NULL, &ignore_errors, "skip move/rename errors"),
+ OPT__VERBOSE(&verbose, N_("be verbose")),
+ OPT__DRY_RUN(&show_only, N_("dry run")),
+ OPT__FORCE(&force, N_("force move/rename even if target exists")),
+ OPT_BOOLEAN('k', NULL, &ignore_errors, N_("skip move/rename errors")),
OPT_END(),
};
const char **source, **destination, **dest_path;
diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index 1b37458..6238247 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -172,9 +172,9 @@ static void show_name(const struct object *obj,
}
static char const * const name_rev_usage[] = {
- "git name-rev [options] <commit>...",
- "git name-rev [options] --all",
- "git name-rev [options] --stdin",
+ N_("git name-rev [options] <commit>..."),
+ N_("git name-rev [options] --all"),
+ N_("git name-rev [options] --stdin"),
NULL
};
@@ -226,16 +226,16 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
int all = 0, transform_stdin = 0, allow_undefined = 1, always = 0;
struct name_ref_data data = { 0, 0, NULL };
struct option opts[] = {
- OPT_BOOLEAN(0, "name-only", &data.name_only, "print only names (no SHA-1)"),
- OPT_BOOLEAN(0, "tags", &data.tags_only, "only use tags to name the commits"),
- OPT_STRING(0, "refs", &data.ref_filter, "pattern",
- "only use refs matching <pattern>"),
+ OPT_BOOLEAN(0, "name-only", &data.name_only, N_("print only names (no SHA-1)")),
+ OPT_BOOLEAN(0, "tags", &data.tags_only, N_("only use tags to name the commits")),
+ OPT_STRING(0, "refs", &data.ref_filter, N_("pattern"),
+ N_("only use refs matching <pattern>")),
OPT_GROUP(""),
- OPT_BOOLEAN(0, "all", &all, "list all commits reachable from all refs"),
- OPT_BOOLEAN(0, "stdin", &transform_stdin, "read from stdin"),
- OPT_BOOLEAN(0, "undefined", &allow_undefined, "allow to print `undefined` names"),
+ OPT_BOOLEAN(0, "all", &all, N_("list all commits reachable from all refs")),
+ OPT_BOOLEAN(0, "stdin", &transform_stdin, N_("read from stdin")),
+ OPT_BOOLEAN(0, "undefined", &allow_undefined, N_("allow to print `undefined` names")),
OPT_BOOLEAN(0, "always", &always,
- "show abbreviated commit object as fallback"),
+ N_("show abbreviated commit object as fallback")),
OPT_END(),
};
diff --git a/builtin/notes.c b/builtin/notes.c
index 3644d14..453457a 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -19,72 +19,75 @@
#include "string-list.h"
#include "notes-merge.h"
+static void commit_notes(struct notes_tree *t, const char *msg);
+static combine_notes_fn parse_combine_notes_fn(const char *v);
+
static const char * const git_notes_usage[] = {
- "git notes [--ref <notes_ref>] [list [<object>]]",
- "git notes [--ref <notes_ref>] add [-f] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]",
- "git notes [--ref <notes_ref>] copy [-f] <from-object> <to-object>",
- "git notes [--ref <notes_ref>] append [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]",
- "git notes [--ref <notes_ref>] edit [<object>]",
- "git notes [--ref <notes_ref>] show [<object>]",
- "git notes [--ref <notes_ref>] merge [-v | -q] [-s <strategy> ] <notes_ref>",
- "git notes merge --commit [-v | -q]",
- "git notes merge --abort [-v | -q]",
- "git notes [--ref <notes_ref>] remove [<object>...]",
- "git notes [--ref <notes_ref>] prune [-n | -v]",
- "git notes [--ref <notes_ref>] get-ref",
+ N_("git notes [--ref <notes_ref>] [list [<object>]]"),
+ N_("git notes [--ref <notes_ref>] add [-f] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
+ N_("git notes [--ref <notes_ref>] copy [-f] <from-object> <to-object>"),
+ N_("git notes [--ref <notes_ref>] append [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
+ N_("git notes [--ref <notes_ref>] edit [<object>]"),
+ N_("git notes [--ref <notes_ref>] show [<object>]"),
+ N_("git notes [--ref <notes_ref>] merge [-v | -q] [-s <strategy> ] <notes_ref>"),
+ N_("git notes merge --commit [-v | -q]"),
+ N_("git notes merge --abort [-v | -q]"),
+ N_("git notes [--ref <notes_ref>] remove [<object>...]"),
+ N_("git notes [--ref <notes_ref>] prune [-n | -v]"),
+ N_("git notes [--ref <notes_ref>] get-ref"),
NULL
};
static const char * const git_notes_list_usage[] = {
- "git notes [list [<object>]]",
+ N_("git notes [list [<object>]]"),
NULL
};
static const char * const git_notes_add_usage[] = {
- "git notes add [<options>] [<object>]",
+ N_("git notes add [<options>] [<object>]"),
NULL
};
static const char * const git_notes_copy_usage[] = {
- "git notes copy [<options>] <from-object> <to-object>",
- "git notes copy --stdin [<from-object> <to-object>]...",
+ N_("git notes copy [<options>] <from-object> <to-object>"),
+ N_("git notes copy --stdin [<from-object> <to-object>]..."),
NULL
};
static const char * const git_notes_append_usage[] = {
- "git notes append [<options>] [<object>]",
+ N_("git notes append [<options>] [<object>]"),
NULL
};
static const char * const git_notes_edit_usage[] = {
- "git notes edit [<object>]",
+ N_("git notes edit [<object>]"),
NULL
};
static const char * const git_notes_show_usage[] = {
- "git notes show [<object>]",
+ N_("git notes show [<object>]"),
NULL
};
static const char * const git_notes_merge_usage[] = {
- "git notes merge [<options>] <notes_ref>",
- "git notes merge --commit [<options>]",
- "git notes merge --abort [<options>]",
+ N_("git notes merge [<options>] <notes_ref>"),
+ N_("git notes merge --commit [<options>]"),
+ N_("git notes merge --abort [<options>]"),
NULL
};
static const char * const git_notes_remove_usage[] = {
- "git notes remove [<object>]",
+ N_("git notes remove [<object>]"),
NULL
};
static const char * const git_notes_prune_usage[] = {
- "git notes prune [<options>]",
+ N_("git notes prune [<options>]"),
NULL
};
static const char * const git_notes_get_ref_usage[] = {
- "git notes get-ref",
+ N_("git notes get-ref"),
NULL
};
@@ -288,7 +291,7 @@ static int parse_reedit_arg(const struct option *opt, const char *arg, int unset
return parse_reuse_arg(opt, arg, unset);
}
-void commit_notes(struct notes_tree *t, const char *msg)
+static void commit_notes(struct notes_tree *t, const char *msg)
{
struct strbuf buf = STRBUF_INIT;
unsigned char commit_sha1[20];
@@ -312,7 +315,7 @@ void commit_notes(struct notes_tree *t, const char *msg)
strbuf_release(&buf);
}
-combine_notes_fn parse_combine_notes_fn(const char *v)
+static combine_notes_fn parse_combine_notes_fn(const char *v)
{
if (!strcasecmp(v, "overwrite"))
return combine_notes_overwrite;
@@ -531,19 +534,19 @@ static int add(int argc, const char **argv, const char *prefix)
const unsigned char *note;
struct msg_arg msg = { 0, 0, STRBUF_INIT };
struct option options[] = {
- { OPTION_CALLBACK, 'm', "message", &msg, "msg",
- "note contents as a string", PARSE_OPT_NONEG,
+ { OPTION_CALLBACK, 'm', "message", &msg, N_("message"),
+ N_("note contents as a string"), PARSE_OPT_NONEG,
parse_msg_arg},
- { OPTION_CALLBACK, 'F', "file", &msg, "file",
- "note contents in a file", PARSE_OPT_NONEG,
+ { OPTION_CALLBACK, 'F', "file", &msg, N_("file"),
+ N_("note contents in a file"), PARSE_OPT_NONEG,
parse_file_arg},
- { OPTION_CALLBACK, 'c', "reedit-message", &msg, "object",
- "reuse and edit specified note object", PARSE_OPT_NONEG,
+ { OPTION_CALLBACK, 'c', "reedit-message", &msg, N_("object"),
+ N_("reuse and edit specified note object"), PARSE_OPT_NONEG,
parse_reedit_arg},
- { OPTION_CALLBACK, 'C', "reuse-message", &msg, "object",
- "reuse specified note object", PARSE_OPT_NONEG,
+ { OPTION_CALLBACK, 'C', "reuse-message", &msg, N_("object"),
+ N_("reuse specified note object"), PARSE_OPT_NONEG,
parse_reuse_arg},
- OPT__FORCE(&force, "replace existing notes"),
+ OPT__FORCE(&force, N_("replace existing notes")),
OPT_END()
};
@@ -611,11 +614,11 @@ static int copy(int argc, const char **argv, const char *prefix)
struct notes_tree *t;
const char *rewrite_cmd = NULL;
struct option options[] = {
- OPT__FORCE(&force, "replace existing notes"),
- OPT_BOOLEAN(0, "stdin", &from_stdin, "read objects from stdin"),
- OPT_STRING(0, "for-rewrite", &rewrite_cmd, "command",
- "load rewriting config for <command> (implies "
- "--stdin)"),
+ OPT__FORCE(&force, N_("replace existing notes")),
+ OPT_BOOLEAN(0, "stdin", &from_stdin, N_("read objects from stdin")),
+ OPT_STRING(0, "for-rewrite", &rewrite_cmd, N_("command"),
+ N_("load rewriting config for <command> (implies "
+ "--stdin)")),
OPT_END()
};
@@ -688,17 +691,17 @@ static int append_edit(int argc, const char **argv, const char *prefix)
const char * const *usage;
struct msg_arg msg = { 0, 0, STRBUF_INIT };
struct option options[] = {
- { OPTION_CALLBACK, 'm', "message", &msg, "msg",
- "note contents as a string", PARSE_OPT_NONEG,
+ { OPTION_CALLBACK, 'm', "message", &msg, N_("message"),
+ N_("note contents as a string"), PARSE_OPT_NONEG,
parse_msg_arg},
- { OPTION_CALLBACK, 'F', "file", &msg, "file",
- "note contents in a file", PARSE_OPT_NONEG,
+ { OPTION_CALLBACK, 'F', "file", &msg, N_("file"),
+ N_("note contents in a file"), PARSE_OPT_NONEG,
parse_file_arg},
- { OPTION_CALLBACK, 'c', "reedit-message", &msg, "object",
- "reuse and edit specified note object", PARSE_OPT_NONEG,
+ { OPTION_CALLBACK, 'c', "reedit-message", &msg, N_("object"),
+ N_("reuse and edit specified note object"), PARSE_OPT_NONEG,
parse_reedit_arg},
- { OPTION_CALLBACK, 'C', "reuse-message", &msg, "object",
- "reuse specified note object", PARSE_OPT_NONEG,
+ { OPTION_CALLBACK, 'C', "reuse-message", &msg, N_("object"),
+ N_("reuse specified note object"), PARSE_OPT_NONEG,
parse_reuse_arg},
OPT_END()
};
@@ -861,19 +864,19 @@ static int merge(int argc, const char **argv, const char *prefix)
int verbosity = 0, result;
const char *strategy = NULL;
struct option options[] = {
- OPT_GROUP("General options"),
+ OPT_GROUP(N_("General options")),
OPT__VERBOSITY(&verbosity),
- OPT_GROUP("Merge options"),
- OPT_STRING('s', "strategy", &strategy, "strategy",
- "resolve notes conflicts using the given strategy "
- "(manual/ours/theirs/union/cat_sort_uniq)"),
- OPT_GROUP("Committing unmerged notes"),
+ OPT_GROUP(N_("Merge options")),
+ OPT_STRING('s', "strategy", &strategy, N_("strategy"),
+ N_("resolve notes conflicts using the given strategy "
+ "(manual/ours/theirs/union/cat_sort_uniq)")),
+ OPT_GROUP(N_("Committing unmerged notes")),
{ OPTION_BOOLEAN, 0, "commit", &do_commit, NULL,
- "finalize notes merge by committing unmerged notes",
+ N_("finalize notes merge by committing unmerged notes"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG },
- OPT_GROUP("Aborting notes merge resolution"),
+ OPT_GROUP(N_("Aborting notes merge resolution")),
{ OPTION_BOOLEAN, 0, "abort", &do_abort, NULL,
- "abort notes merge",
+ N_("abort notes merge"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG },
OPT_END()
};
@@ -980,10 +983,10 @@ static int remove_cmd(int argc, const char **argv, const char *prefix)
int from_stdin = 0;
struct option options[] = {
OPT_BIT(0, "ignore-missing", &flag,
- "attempt to remove non-existent note is not an error",
+ N_("attempt to remove non-existent note is not an error"),
IGNORE_MISSING),
OPT_BOOLEAN(0, "stdin", &from_stdin,
- "read object names from the standard input"),
+ N_("read object names from the standard input")),
OPT_END()
};
struct notes_tree *t;
@@ -1064,8 +1067,8 @@ int cmd_notes(int argc, const char **argv, const char *prefix)
int result;
const char *override_notes_ref = NULL;
struct option options[] = {
- OPT_STRING(0, "ref", &override_notes_ref, "notes_ref",
- "use notes from <notes_ref>"),
+ OPT_STRING(0, "ref", &override_notes_ref, N_("notes_ref"),
+ N_("use notes from <notes_ref>")),
OPT_END()
};
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index ccfcbad..5e14064 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -16,11 +16,12 @@
#include "list-objects.h"
#include "progress.h"
#include "refs.h"
+#include "streaming.h"
#include "thread-utils.h"
static const char *pack_usage[] = {
- "git pack-objects --stdout [options...] [< ref-list | < object-list]",
- "git pack-objects [options...] base-name [< ref-list | < object-list]",
+ N_("git pack-objects --stdout [options...] [< ref-list | < object-list]"),
+ N_("git pack-objects [options...] base-name [< ref-list | < object-list]"),
NULL
};
@@ -150,6 +151,46 @@ static unsigned long do_compress(void **pptr, unsigned long size)
return stream.total_out;
}
+static unsigned long write_large_blob_data(struct git_istream *st, struct sha1file *f,
+ const unsigned char *sha1)
+{
+ git_zstream stream;
+ unsigned char ibuf[1024 * 16];
+ unsigned char obuf[1024 * 16];
+ unsigned long olen = 0;
+
+ memset(&stream, 0, sizeof(stream));
+ git_deflate_init(&stream, pack_compression_level);
+
+ for (;;) {
+ ssize_t readlen;
+ int zret = Z_OK;
+ readlen = read_istream(st, ibuf, sizeof(ibuf));
+ if (readlen == -1)
+ die(_("unable to read %s"), sha1_to_hex(sha1));
+
+ stream.next_in = ibuf;
+ stream.avail_in = readlen;
+ while ((stream.avail_in || readlen == 0) &&
+ (zret == Z_OK || zret == Z_BUF_ERROR)) {
+ stream.next_out = obuf;
+ stream.avail_out = sizeof(obuf);
+ zret = git_deflate(&stream, readlen ? 0 : Z_FINISH);
+ sha1write(f, obuf, stream.next_out - obuf);
+ olen += stream.next_out - obuf;
+ }
+ if (stream.avail_in)
+ die(_("deflate error (%d)"), zret);
+ if (readlen == 0) {
+ if (zret != Z_STREAM_END)
+ die(_("deflate error (%d)"), zret);
+ break;
+ }
+ }
+ git_deflate_end(&stream);
+ return olen;
+}
+
/*
* we are going to reuse the existing object data as is. make
* sure it is not corrupt.
@@ -208,11 +249,18 @@ static unsigned long write_no_reuse_object(struct sha1file *f, struct object_ent
unsigned hdrlen;
enum object_type type;
void *buf;
+ struct git_istream *st = NULL;
if (!usable_delta) {
- buf = read_sha1_file(entry->idx.sha1, &type, &size);
- if (!buf)
- die("unable to read %s", sha1_to_hex(entry->idx.sha1));
+ if (entry->type == OBJ_BLOB &&
+ entry->size > big_file_threshold &&
+ (st = open_istream(entry->idx.sha1, &type, &size, NULL)) != NULL)
+ buf = NULL;
+ else {
+ buf = read_sha1_file(entry->idx.sha1, &type, &size);
+ if (!buf)
+ die(_("unable to read %s"), sha1_to_hex(entry->idx.sha1));
+ }
/*
* make sure no cached delta data remains from a
* previous attempt before a pack split occurred.
@@ -233,7 +281,9 @@ static unsigned long write_no_reuse_object(struct sha1file *f, struct object_ent
OBJ_OFS_DELTA : OBJ_REF_DELTA;
}
- if (entry->z_delta_size)
+ if (st) /* large blob case, just assume we don't compress well */
+ datalen = size;
+ else if (entry->z_delta_size)
datalen = entry->z_delta_size;
else
datalen = do_compress(&buf, size);
@@ -256,6 +306,8 @@ static unsigned long write_no_reuse_object(struct sha1file *f, struct object_ent
while (ofs >>= 7)
dheader[--pos] = 128 | (--ofs & 127);
if (limit && hdrlen + sizeof(dheader) - pos + datalen + 20 >= limit) {
+ if (st)
+ close_istream(st);
free(buf);
return 0;
}
@@ -268,6 +320,8 @@ static unsigned long write_no_reuse_object(struct sha1file *f, struct object_ent
* an additional 20 bytes for the base sha1.
*/
if (limit && hdrlen + 20 + datalen + 20 >= limit) {
+ if (st)
+ close_istream(st);
free(buf);
return 0;
}
@@ -276,13 +330,20 @@ static unsigned long write_no_reuse_object(struct sha1file *f, struct object_ent
hdrlen += 20;
} else {
if (limit && hdrlen + datalen + 20 >= limit) {
+ if (st)
+ close_istream(st);
free(buf);
return 0;
}
sha1write(f, header, hdrlen);
}
- sha1write(f, buf, datalen);
- free(buf);
+ if (st) {
+ datalen = write_large_blob_data(st, f, entry->idx.sha1);
+ close_istream(st);
+ } else {
+ sha1write(f, buf, datalen);
+ free(buf);
+ }
return hdrlen + datalen;
}
@@ -2312,7 +2373,7 @@ static void get_object_list(int ac, const char **av)
}
die("not a rev '%s'", line);
}
- if (handle_revision_arg(line, &revs, flags, 1))
+ if (handle_revision_arg(line, &revs, flags, REVARG_CANNOT_BE_FILENAME))
die("bad revision '%s'", line);
}
@@ -2384,67 +2445,67 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
int rev_list_unpacked = 0, rev_list_all = 0, rev_list_reflog = 0;
struct option pack_objects_options[] = {
OPT_SET_INT('q', "quiet", &progress,
- "do not show progress meter", 0),
+ N_("do not show progress meter"), 0),
OPT_SET_INT(0, "progress", &progress,
- "show progress meter", 1),
+ N_("show progress meter"), 1),
OPT_SET_INT(0, "all-progress", &progress,
- "show progress meter during object writing phase", 2),
+ N_("show progress meter during object writing phase"), 2),
OPT_BOOL(0, "all-progress-implied",
&all_progress_implied,
- "similar to --all-progress when progress meter is shown"),
- { OPTION_CALLBACK, 0, "index-version", NULL, "version[,offset]",
- "write the pack index file in the specified idx format version",
+ N_("similar to --all-progress when progress meter is shown")),
+ { OPTION_CALLBACK, 0, "index-version", NULL, N_("version[,offset]"),
+ N_("write the pack index file in the specified idx format version"),
0, option_parse_index_version },
OPT_ULONG(0, "max-pack-size", &pack_size_limit,
- "maximum size of each output pack file"),
+ N_("maximum size of each output pack file")),
OPT_BOOL(0, "local", &local,
- "ignore borrowed objects from alternate object store"),
+ N_("ignore borrowed objects from alternate object store")),
OPT_BOOL(0, "incremental", &incremental,
- "ignore packed objects"),
+ N_("ignore packed objects")),
OPT_INTEGER(0, "window", &window,
- "limit pack window by objects"),
+ N_("limit pack window by objects")),
OPT_ULONG(0, "window-memory", &window_memory_limit,
- "limit pack window by memory in addition to object limit"),
+ N_("limit pack window by memory in addition to object limit")),
OPT_INTEGER(0, "depth", &depth,
- "maximum length of delta chain allowed in the resulting pack"),
+ N_("maximum length of delta chain allowed in the resulting pack")),
OPT_BOOL(0, "reuse-delta", &reuse_delta,
- "reuse existing deltas"),
+ N_("reuse existing deltas")),
OPT_BOOL(0, "reuse-object", &reuse_object,
- "reuse existing objects"),
+ N_("reuse existing objects")),
OPT_BOOL(0, "delta-base-offset", &allow_ofs_delta,
- "use OFS_DELTA objects"),
+ N_("use OFS_DELTA objects")),
OPT_INTEGER(0, "threads", &delta_search_threads,
- "use threads when searching for best delta matches"),
+ N_("use threads when searching for best delta matches")),
OPT_BOOL(0, "non-empty", &non_empty,
- "do not create an empty pack output"),
+ N_("do not create an empty pack output")),
OPT_BOOL(0, "revs", &use_internal_rev_list,
- "read revision arguments from standard input"),
+ N_("read revision arguments from standard input")),
{ OPTION_SET_INT, 0, "unpacked", &rev_list_unpacked, NULL,
- "limit the objects to those that are not yet packed",
+ N_("limit the objects to those that are not yet packed"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 },
{ OPTION_SET_INT, 0, "all", &rev_list_all, NULL,
- "include objects reachable from any reference",
+ N_("include objects reachable from any reference"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 },
{ OPTION_SET_INT, 0, "reflog", &rev_list_reflog, NULL,
- "include objects referred by reflog entries",
+ N_("include objects referred by reflog entries"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 },
OPT_BOOL(0, "stdout", &pack_to_stdout,
- "output pack to stdout"),
+ N_("output pack to stdout")),
OPT_BOOL(0, "include-tag", &include_tag,
- "include tag objects that refer to objects to be packed"),
+ N_("include tag objects that refer to objects to be packed")),
OPT_BOOL(0, "keep-unreachable", &keep_unreachable,
- "keep unreachable objects"),
- { OPTION_CALLBACK, 0, "unpack-unreachable", NULL, "time",
- "unpack unreachable objects newer than <time>",
+ N_("keep unreachable objects")),
+ { OPTION_CALLBACK, 0, "unpack-unreachable", NULL, N_("time"),
+ N_("unpack unreachable objects newer than <time>"),
PARSE_OPT_OPTARG, option_parse_unpack_unreachable },
OPT_BOOL(0, "thin", &thin,
- "create thin packs"),
+ N_("create thin packs")),
OPT_BOOL(0, "honor-pack-keep", &ignore_packed_keep,
- "ignore packs that have companion .keep file"),
+ N_("ignore packs that have companion .keep file")),
OPT_INTEGER(0, "compression", &pack_compression_level,
- "pack compression level"),
+ N_("pack compression level")),
OPT_SET_INT(0, "keep-true-parents", &grafts_replace_parents,
- "do not hide commits by grafts", 0),
+ N_("do not hide commits by grafts"), 0),
OPT_END(),
};
diff --git a/builtin/pack-refs.c b/builtin/pack-refs.c
index 39a9d89..b5a0f88 100644
--- a/builtin/pack-refs.c
+++ b/builtin/pack-refs.c
@@ -3,7 +3,7 @@
#include "pack-refs.h"
static char const * const pack_refs_usage[] = {
- "git pack-refs [options]",
+ N_("git pack-refs [options]"),
NULL
};
@@ -11,8 +11,8 @@ int cmd_pack_refs(int argc, const char **argv, const char *prefix)
{
unsigned int flags = PACK_REFS_PRUNE;
struct option opts[] = {
- OPT_BIT(0, "all", &flags, "pack everything", PACK_REFS_ALL),
- OPT_BIT(0, "prune", &flags, "prune loose refs (default)", PACK_REFS_PRUNE),
+ OPT_BIT(0, "all", &flags, N_("pack everything"), PACK_REFS_ALL),
+ OPT_BIT(0, "prune", &flags, N_("prune loose refs (default)"), PACK_REFS_PRUNE),
OPT_END(),
};
if (parse_options(argc, argv, prefix, opts, pack_refs_usage, 0))
diff --git a/builtin/prune-packed.c b/builtin/prune-packed.c
index b58a2e1..83382c1 100644
--- a/builtin/prune-packed.c
+++ b/builtin/prune-packed.c
@@ -4,7 +4,7 @@
#include "parse-options.h"
static const char * const prune_packed_usage[] = {
- "git prune-packed [-n|--dry-run] [-q|--quiet]",
+ N_("git prune-packed [-n|--dry-run] [-q|--quiet]"),
NULL
};
@@ -73,8 +73,8 @@ int cmd_prune_packed(int argc, const char **argv, const char *prefix)
{
int opts = isatty(2) ? VERBOSE : 0;
const struct option prune_packed_options[] = {
- OPT_BIT('n', "dry-run", &opts, "dry run", DRY_RUN),
- OPT_NEGBIT('q', "quiet", &opts, "be quiet", VERBOSE),
+ OPT_BIT('n', "dry-run", &opts, N_("dry run"), DRY_RUN),
+ OPT_NEGBIT('q', "quiet", &opts, N_("be quiet"), VERBOSE),
OPT_END()
};
diff --git a/builtin/prune.c b/builtin/prune.c
index b99b635..8cb8b91 100644
--- a/builtin/prune.c
+++ b/builtin/prune.c
@@ -9,7 +9,7 @@
#include "dir.h"
static const char * const prune_usage[] = {
- "git prune [-n] [-v] [--expire <time>] [--] [<head>...]",
+ N_("git prune [-n] [-v] [--expire <time>] [--] [<head>...]"),
NULL
};
static int show_only;
@@ -25,7 +25,8 @@ static int prune_tmp_object(const char *path, const char *filename)
return error("Could not stat '%s'", fullpath);
if (st.st_mtime > expire)
return 0;
- printf("Removing stale temporary file %s\n", fullpath);
+ if (show_only || verbose)
+ printf("Removing stale temporary file %s\n", fullpath);
if (!show_only)
unlink_or_warn(fullpath);
return 0;
@@ -128,11 +129,11 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
struct rev_info revs;
struct progress *progress = NULL;
const struct option options[] = {
- OPT__DRY_RUN(&show_only, "do not remove, show only"),
- OPT__VERBOSE(&verbose, "report pruned objects"),
- OPT_BOOL(0, "progress", &show_progress, "show progress"),
+ OPT__DRY_RUN(&show_only, N_("do not remove, show only")),
+ OPT__VERBOSE(&verbose, N_("report pruned objects")),
+ OPT_BOOL(0, "progress", &show_progress, N_("show progress")),
OPT_DATE(0, "expire", &expire,
- "expire objects older than <time>"),
+ N_("expire objects older than <time>")),
OPT_END()
};
char *s;
@@ -168,7 +169,7 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
prune_packed_objects(show_only);
remove_temporary_files(get_object_directory());
- s = xstrdup(mkpath("%s/pack", get_object_directory()));
+ s = mkpathdup("%s/pack", get_object_directory());
remove_temporary_files(s);
free(s);
return 0;
diff --git a/builtin/push.c b/builtin/push.c
index fdfcc6c..db9ba30 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -11,7 +11,7 @@
#include "submodule.h"
static const char * const push_usage[] = {
- "git push [<options>] [<repository> [<refspec>...]]",
+ N_("git push [<options>] [<repository> [<refspec>...]]"),
NULL,
};
@@ -147,12 +147,37 @@ static void setup_push_upstream(struct remote *remote, int simple)
add_refspec(refspec.buf);
}
+static char warn_unspecified_push_default_msg[] =
+N_("push.default is unset; its implicit value is changing in\n"
+ "Git 2.0 from 'matching' to 'simple'. To squelch this message\n"
+ "and maintain the current behavior after the default changes, use:\n"
+ "\n"
+ " git config --global push.default matching\n"
+ "\n"
+ "To squelch this message and adopt the new behavior now, use:\n"
+ "\n"
+ " git config --global push.default simple\n"
+ "\n"
+ "See 'git help config' and search for 'push.default' for further information.\n"
+ "(the 'simple' mode was introduced in Git 1.7.11. Use the similar mode\n"
+ "'current' instead of 'simple' if you sometimes use older versions of Git)");
+
+static void warn_unspecified_push_default_configuration(void)
+{
+ static int warn_once;
+
+ if (warn_once++)
+ return;
+ warning("%s\n", _(warn_unspecified_push_default_msg));
+}
+
static void setup_default_push_refspecs(struct remote *remote)
{
switch (push_default) {
default:
case PUSH_DEFAULT_UNSPECIFIED:
default_matching_used = 1;
+ warn_unspecified_push_default_configuration();
/* fallthru */
case PUSH_DEFAULT_MATCHING:
add_refspec(":");
@@ -186,8 +211,8 @@ static const char message_advice_pull_before_push[] =
static const char message_advice_use_upstream[] =
N_("Updates were rejected because a pushed branch tip is behind its remote\n"
"counterpart. If you did not intend to push that branch, you may want to\n"
- "specify branches to push or set the 'push.default' configuration\n"
- "variable to 'current' or 'upstream' to push only the current branch.");
+ "specify branches to push or set the 'push.default' configuration variable\n"
+ "to 'simple', 'current' or 'upstream' to push only the current branch.");
static const char message_advice_checkout_pull_push[] =
N_("Updates were rejected because a pushed branch tip is behind its remote\n"
@@ -354,25 +379,25 @@ int cmd_push(int argc, const char **argv, const char *prefix)
const char *repo = NULL; /* default repository */
struct option options[] = {
OPT__VERBOSITY(&verbosity),
- OPT_STRING( 0 , "repo", &repo, "repository", "repository"),
- OPT_BIT( 0 , "all", &flags, "push all refs", TRANSPORT_PUSH_ALL),
- OPT_BIT( 0 , "mirror", &flags, "mirror all refs",
+ OPT_STRING( 0 , "repo", &repo, N_("repository"), N_("repository")),
+ OPT_BIT( 0 , "all", &flags, N_("push all refs"), TRANSPORT_PUSH_ALL),
+ OPT_BIT( 0 , "mirror", &flags, N_("mirror all refs"),
(TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE)),
- OPT_BOOLEAN( 0, "delete", &deleterefs, "delete refs"),
- OPT_BOOLEAN( 0 , "tags", &tags, "push tags (can't be used with --all or --mirror)"),
- OPT_BIT('n' , "dry-run", &flags, "dry run", TRANSPORT_PUSH_DRY_RUN),
- OPT_BIT( 0, "porcelain", &flags, "machine-readable output", TRANSPORT_PUSH_PORCELAIN),
- OPT_BIT('f', "force", &flags, "force updates", TRANSPORT_PUSH_FORCE),
- { OPTION_CALLBACK, 0, "recurse-submodules", &flags, "check",
- "controls recursive pushing of submodules",
+ OPT_BOOLEAN( 0, "delete", &deleterefs, N_("delete refs")),
+ OPT_BOOLEAN( 0 , "tags", &tags, N_("push tags (can't be used with --all or --mirror)")),
+ OPT_BIT('n' , "dry-run", &flags, N_("dry run"), TRANSPORT_PUSH_DRY_RUN),
+ OPT_BIT( 0, "porcelain", &flags, N_("machine-readable output"), TRANSPORT_PUSH_PORCELAIN),
+ OPT_BIT('f', "force", &flags, N_("force updates"), TRANSPORT_PUSH_FORCE),
+ { OPTION_CALLBACK, 0, "recurse-submodules", &flags, N_("check"),
+ N_("control recursive pushing of submodules"),
PARSE_OPT_OPTARG, option_parse_recurse_submodules },
- OPT_BOOLEAN( 0 , "thin", &thin, "use thin pack"),
- OPT_STRING( 0 , "receive-pack", &receivepack, "receive-pack", "receive pack program"),
- OPT_STRING( 0 , "exec", &receivepack, "receive-pack", "receive pack program"),
- OPT_BIT('u', "set-upstream", &flags, "set upstream for git pull/status",
+ OPT_BOOLEAN( 0 , "thin", &thin, N_("use thin pack")),
+ OPT_STRING( 0 , "receive-pack", &receivepack, "receive-pack", N_("receive pack program")),
+ OPT_STRING( 0 , "exec", &receivepack, "receive-pack", N_("receive pack program")),
+ OPT_BIT('u', "set-upstream", &flags, N_("set upstream for git pull/status"),
TRANSPORT_PUSH_SET_UPSTREAM),
- OPT_BOOL(0, "progress", &progress, "force progress reporting"),
- OPT_BIT(0, "prune", &flags, "prune locally removed refs",
+ OPT_BOOL(0, "progress", &progress, N_("force progress reporting")),
+ OPT_BIT(0, "prune", &flags, N_("prune locally removed refs"),
TRANSPORT_PUSH_PRUNE),
OPT_END()
};
diff --git a/builtin/read-tree.c b/builtin/read-tree.c
index df6c4c8..042ac1b 100644
--- a/builtin/read-tree.c
+++ b/builtin/read-tree.c
@@ -33,7 +33,7 @@ static int list_tree(unsigned char *sha1)
}
static const char * const read_tree_usage[] = {
- "git read-tree [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>] [-u [--exclude-per-directory=<gitignore>] | -i]] [--no-sparse-checkout] [--index-output=<file>] (--empty | <tree-ish1> [<tree-ish2> [<tree-ish3>]])",
+ N_("git read-tree [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>] [-u [--exclude-per-directory=<gitignore>] | -i]] [--no-sparse-checkout] [--index-output=<file>] (--empty | <tree-ish1> [<tree-ish2> [<tree-ish3>]])"),
NULL
};
@@ -104,37 +104,37 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
struct unpack_trees_options opts;
int prefix_set = 0;
const struct option read_tree_options[] = {
- { OPTION_CALLBACK, 0, "index-output", NULL, "file",
- "write resulting index to <file>",
+ { OPTION_CALLBACK, 0, "index-output", NULL, N_("file"),
+ N_("write resulting index to <file>"),
PARSE_OPT_NONEG, index_output_cb },
OPT_SET_INT(0, "empty", &read_empty,
- "only empty the index", 1),
- OPT__VERBOSE(&opts.verbose_update, "be verbose"),
- OPT_GROUP("Merging"),
+ N_("only empty the index"), 1),
+ OPT__VERBOSE(&opts.verbose_update, N_("be verbose")),
+ OPT_GROUP(N_("Merging")),
OPT_SET_INT('m', NULL, &opts.merge,
- "perform a merge in addition to a read", 1),
+ N_("perform a merge in addition to a read"), 1),
OPT_SET_INT(0, "trivial", &opts.trivial_merges_only,
- "3-way merge if no file level merging required", 1),
+ N_("3-way merge if no file level merging required"), 1),
OPT_SET_INT(0, "aggressive", &opts.aggressive,
- "3-way merge in presence of adds and removes", 1),
+ N_("3-way merge in presence of adds and removes"), 1),
OPT_SET_INT(0, "reset", &opts.reset,
- "same as -m, but discard unmerged entries", 1),
- { OPTION_STRING, 0, "prefix", &opts.prefix, "<subdirectory>/",
- "read the tree into the index under <subdirectory>/",
+ N_("same as -m, but discard unmerged entries"), 1),
+ { OPTION_STRING, 0, "prefix", &opts.prefix, N_("<subdirectory>/"),
+ N_("read the tree into the index under <subdirectory>/"),
PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP },
OPT_SET_INT('u', NULL, &opts.update,
- "update working tree with merge result", 1),
+ N_("update working tree with merge result"), 1),
{ OPTION_CALLBACK, 0, "exclude-per-directory", &opts,
- "gitignore",
- "allow explicitly ignored files to be overwritten",
+ N_("gitignore"),
+ N_("allow explicitly ignored files to be overwritten"),
PARSE_OPT_NONEG, exclude_per_directory_cb },
OPT_SET_INT('i', NULL, &opts.index_only,
- "don't check the working tree after merging", 1),
- OPT__DRY_RUN(&opts.dry_run, "don't update the index or the work tree"),
+ N_("don't check the working tree after merging"), 1),
+ OPT__DRY_RUN(&opts.dry_run, N_("don't update the index or the work tree")),
OPT_SET_INT(0, "no-sparse-checkout", &opts.skip_sparse_checkout,
- "skip applying sparse checkout filter", 1),
+ N_("skip applying sparse checkout filter"), 1),
OPT_SET_INT(0, "debug-unpack", &opts.debug_unpack,
- "debug unpack-trees", 1),
+ N_("debug unpack-trees"), 1),
OPT_END()
};
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 3f05d97..ff781fe 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -12,6 +12,7 @@
#include "string-list.h"
#include "sha1-array.h"
#include "connected.h"
+#include "version.h"
static const char receive_pack_usage[] = "git receive-pack <git-dir>";
@@ -121,10 +122,11 @@ static void show_ref(const char *path, const unsigned char *sha1)
if (sent_capabilities)
packet_write(1, "%s %s\n", sha1_to_hex(sha1), path);
else
- packet_write(1, "%s %s%c%s%s\n",
+ packet_write(1, "%s %s%c%s%s agent=%s\n",
sha1_to_hex(sha1), path, 0,
" report-status delete-refs side-band-64k quiet",
- prefer_ofs_delta ? " ofs-delta" : "");
+ prefer_ofs_delta ? " ofs-delta" : "",
+ git_user_agent_sanitized());
sent_capabilities = 1;
}
@@ -478,7 +480,6 @@ static const char *update(struct command *cmd)
!prefixcmp(name, "refs/heads/")) {
struct object *old_object, *new_object;
struct commit *old_commit, *new_commit;
- struct commit_list *bases, *ent;
old_object = parse_object(old_sha1);
new_object = parse_object(new_sha1);
@@ -491,12 +492,7 @@ static const char *update(struct command *cmd)
}
old_commit = (struct commit *)old_object;
new_commit = (struct commit *)new_object;
- bases = get_merge_bases(old_commit, new_commit, 1);
- for (ent = bases; ent; ent = ent->next)
- if (!hashcmp(old_sha1, ent->item->object.sha1))
- break;
- free_commit_list(bases);
- if (!ent) {
+ if (!in_merge_bases(old_commit, new_commit)) {
rp_error("denying non-fast-forward %s"
" (you should pull first)", name);
return "non-fast-forward";
@@ -699,7 +695,7 @@ static void execute_commands(struct command *commands, const char *unpacker_erro
if (unpacker_error) {
for (cmd = commands; cmd; cmd = cmd->next)
- cmd->error_string = "n/a (unpacker error)";
+ cmd->error_string = "unpacker error";
return;
}
@@ -799,7 +795,7 @@ static const char *parse_pack_header(struct pack_header *hdr)
static const char *pack_lockfile;
-static const char *unpack(void)
+static const char *unpack(int err_fd)
{
struct pack_header hdr;
const char *hdr_err;
@@ -819,6 +815,7 @@ static const char *unpack(void)
if (ntohl(hdr.hdr_entries) < unpack_limit) {
int code, i = 0;
+ struct child_process child;
const char *unpacker[5];
unpacker[i++] = "unpack-objects";
if (quiet)
@@ -827,7 +824,12 @@ static const char *unpack(void)
unpacker[i++] = "--strict";
unpacker[i++] = hdr_arg;
unpacker[i++] = NULL;
- code = run_command_v_opt(unpacker, RUN_GIT_CMD);
+ memset(&child, 0, sizeof(child));
+ child.argv = unpacker;
+ child.no_stdout = 1;
+ child.err = err_fd;
+ child.git_cmd = 1;
+ code = run_command(&child);
if (!code)
return NULL;
return "unpack-objects abnormal exit";
@@ -852,6 +854,7 @@ static const char *unpack(void)
memset(&ip, 0, sizeof(ip));
ip.argv = keeper;
ip.out = -1;
+ ip.err = err_fd;
ip.git_cmd = 1;
status = start_command(&ip);
if (status) {
@@ -868,6 +871,26 @@ static const char *unpack(void)
}
}
+static const char *unpack_with_sideband(void)
+{
+ struct async muxer;
+ const char *ret;
+
+ if (!use_sideband)
+ return unpack(0);
+
+ memset(&muxer, 0, sizeof(muxer));
+ muxer.proc = copy_to_sideband;
+ muxer.in = -1;
+ if (start_async(&muxer))
+ return NULL;
+
+ ret = unpack(muxer.in);
+
+ finish_async(&muxer);
+ return ret;
+}
+
static void report(struct command *commands, const char *unpack_status)
{
struct command *cmd;
@@ -965,7 +988,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
const char *unpack_status = NULL;
if (!delete_only(commands))
- unpack_status = unpack();
+ unpack_status = unpack_with_sideband();
execute_commands(commands, unpack_status);
if (pack_lockfile)
unlink_or_warn(pack_lockfile);
diff --git a/builtin/reflog.c b/builtin/reflog.c
index 062d7da..b3c9e27 100644
--- a/builtin/reflog.c
+++ b/builtin/reflog.c
@@ -330,8 +330,10 @@ static int expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
printf("keep %s", message);
return 0;
prune:
- if (!cb->newlog || cb->cmd->verbose)
- printf("%sprune %s", cb->newlog ? "" : "would ", message);
+ if (!cb->newlog)
+ printf("would prune %s", message);
+ else if (cb->cmd->verbose)
+ printf("prune %s", message);
return 0;
}
diff --git a/builtin/remote.c b/builtin/remote.c
index 920262d..a5a4b23 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -8,66 +8,66 @@
#include "refs.h"
static const char * const builtin_remote_usage[] = {
- "git remote [-v | --verbose]",
- "git remote add [-t <branch>] [-m <master>] [-f] [--tags|--no-tags] [--mirror=<fetch|push>] <name> <url>",
- "git remote rename <old> <new>",
- "git remote rm <name>",
- "git remote set-head <name> (-a | -d | <branch>)",
- "git remote [-v | --verbose] show [-n] <name>",
- "git remote prune [-n | --dry-run] <name>",
- "git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]",
- "git remote set-branches [--add] <name> <branch>...",
- "git remote set-url [--push] <name> <newurl> [<oldurl>]",
- "git remote set-url --add <name> <newurl>",
- "git remote set-url --delete <name> <url>",
+ N_("git remote [-v | --verbose]"),
+ N_("git remote add [-t <branch>] [-m <master>] [-f] [--tags|--no-tags] [--mirror=<fetch|push>] <name> <url>"),
+ N_("git remote rename <old> <new>"),
+ N_("git remote remove <name>"),
+ N_("git remote set-head <name> (-a | -d | <branch>)"),
+ N_("git remote [-v | --verbose] show [-n] <name>"),
+ N_("git remote prune [-n | --dry-run] <name>"),
+ N_("git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]"),
+ N_("git remote set-branches [--add] <name> <branch>..."),
+ N_("git remote set-url [--push] <name> <newurl> [<oldurl>]"),
+ N_("git remote set-url --add <name> <newurl>"),
+ N_("git remote set-url --delete <name> <url>"),
NULL
};
static const char * const builtin_remote_add_usage[] = {
- "git remote add [<options>] <name> <url>",
+ N_("git remote add [<options>] <name> <url>"),
NULL
};
static const char * const builtin_remote_rename_usage[] = {
- "git remote rename <old> <new>",
+ N_("git remote rename <old> <new>"),
NULL
};
static const char * const builtin_remote_rm_usage[] = {
- "git remote rm <name>",
+ N_("git remote remove <name>"),
NULL
};
static const char * const builtin_remote_sethead_usage[] = {
- "git remote set-head <name> (-a | -d | <branch>])",
+ N_("git remote set-head <name> (-a | -d | <branch>])"),
NULL
};
static const char * const builtin_remote_setbranches_usage[] = {
- "git remote set-branches <name> <branch>...",
- "git remote set-branches --add <name> <branch>...",
+ N_("git remote set-branches <name> <branch>..."),
+ N_("git remote set-branches --add <name> <branch>..."),
NULL
};
static const char * const builtin_remote_show_usage[] = {
- "git remote show [<options>] <name>",
+ N_("git remote show [<options>] <name>"),
NULL
};
static const char * const builtin_remote_prune_usage[] = {
- "git remote prune [<options>] <name>",
+ N_("git remote prune [<options>] <name>"),
NULL
};
static const char * const builtin_remote_update_usage[] = {
- "git remote update [<options>] [<group> | <remote>]...",
+ N_("git remote update [<options>] [<group> | <remote>]..."),
NULL
};
static const char * const builtin_remote_seturl_usage[] = {
- "git remote set-url [--push] <name> <newurl> [<oldurl>]",
- "git remote set-url --add <name> <newurl>",
- "git remote set-url --delete <name> <url>",
+ N_("git remote set-url [--push] <name> <newurl> [<oldurl>]"),
+ N_("git remote set-url --add <name> <newurl>"),
+ N_("git remote set-url --delete <name> <url>"),
NULL
};
@@ -160,17 +160,17 @@ static int add(int argc, const char **argv)
int i;
struct option options[] = {
- OPT_BOOLEAN('f', "fetch", &fetch, "fetch the remote branches"),
+ OPT_BOOLEAN('f', "fetch", &fetch, N_("fetch the remote branches")),
OPT_SET_INT(0, "tags", &fetch_tags,
- "import all tags and associated objects when fetching",
+ N_("import all tags and associated objects when fetching"),
TAGS_SET),
OPT_SET_INT(0, NULL, &fetch_tags,
- "or do not fetch any tag at all (--no-tags)", TAGS_UNSET),
- OPT_STRING_LIST('t', "track", &track, "branch",
- "branch(es) to track"),
- OPT_STRING('m', "master", &master, "branch", "master branch"),
- { OPTION_CALLBACK, 0, "mirror", &mirror, "push|fetch",
- "set up remote as a mirror to push to or fetch from",
+ N_("or do not fetch any tag at all (--no-tags)"), TAGS_UNSET),
+ OPT_STRING_LIST('t', "track", &track, N_("branch"),
+ N_("branch(es) to track")),
+ OPT_STRING('m', "master", &master, N_("branch"), N_("master branch")),
+ { OPTION_CALLBACK, 0, "mirror", &mirror, N_("push|fetch"),
+ N_("set up remote as a mirror to push to or fetch from"),
PARSE_OPT_OPTARG, parse_mirror_opt },
OPT_END()
};
@@ -1088,7 +1088,7 @@ static int show(int argc, const char **argv)
{
int no_query = 0, result = 0, query_flag = 0;
struct option options[] = {
- OPT_BOOLEAN('n', NULL, &no_query, "do not query remotes"),
+ OPT_BOOLEAN('n', NULL, &no_query, N_("do not query remotes")),
OPT_END()
};
struct ref_states states;
@@ -1196,9 +1196,9 @@ static int set_head(int argc, const char **argv)
struct option options[] = {
OPT_BOOLEAN('a', "auto", &opt_a,
- "set refs/remotes/<name>/HEAD according to remote"),
+ N_("set refs/remotes/<name>/HEAD according to remote")),
OPT_BOOLEAN('d', "delete", &opt_d,
- "delete refs/remotes/<name>/HEAD"),
+ N_("delete refs/remotes/<name>/HEAD")),
OPT_END()
};
argc = parse_options(argc, argv, NULL, options, builtin_remote_sethead_usage,
@@ -1250,7 +1250,7 @@ static int prune(int argc, const char **argv)
{
int dry_run = 0, result = 0;
struct option options[] = {
- OPT__DRY_RUN(&dry_run, "dry run"),
+ OPT__DRY_RUN(&dry_run, N_("dry run")),
OPT_END()
};
@@ -1318,7 +1318,7 @@ static int update(int argc, const char **argv)
int i, prune = 0;
struct option options[] = {
OPT_BOOLEAN('p', "prune", &prune,
- "prune remotes after fetching"),
+ N_("prune remotes after fetching")),
OPT_END()
};
const char **fetch_argv;
@@ -1404,7 +1404,7 @@ static int set_branches(int argc, const char **argv)
{
int add_mode = 0;
struct option options[] = {
- OPT_BOOLEAN('\0', "add", &add_mode, "add branch"),
+ OPT_BOOLEAN('\0', "add", &add_mode, N_("add branch")),
OPT_END()
};
@@ -1433,11 +1433,11 @@ static int set_url(int argc, const char **argv)
struct strbuf name_buf = STRBUF_INIT;
struct option options[] = {
OPT_BOOLEAN('\0', "push", &push_mode,
- "manipulate push URLs"),
+ N_("manipulate push URLs")),
OPT_BOOLEAN('\0', "add", &add_mode,
- "add URL"),
+ N_("add URL")),
OPT_BOOLEAN('\0', "delete", &delete_mode,
- "delete URLs"),
+ N_("delete URLs")),
OPT_END()
};
argc = parse_options(argc, argv, NULL, options, builtin_remote_seturl_usage,
@@ -1566,7 +1566,7 @@ static int show_all(void)
int cmd_remote(int argc, const char **argv, const char *prefix)
{
struct option options[] = {
- OPT__VERBOSE(&verbose, "be verbose; must be placed before a subcommand"),
+ OPT__VERBOSE(&verbose, N_("be verbose; must be placed before a subcommand")),
OPT_END()
};
int result;
@@ -1580,7 +1580,7 @@ int cmd_remote(int argc, const char **argv, const char *prefix)
result = add(argc, argv);
else if (!strcmp(argv[0], "rename"))
result = mv(argc, argv);
- else if (!strcmp(argv[0], "rm"))
+ else if (!strcmp(argv[0], "rm") || !strcmp(argv[0], "remove"))
result = rm(argc, argv);
else if (!strcmp(argv[0], "set-head"))
result = set_head(argc, argv);
diff --git a/builtin/replace.c b/builtin/replace.c
index 4a8970e..e3aaf70 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -14,9 +14,9 @@
#include "parse-options.h"
static const char * const git_replace_usage[] = {
- "git replace [-f] <object> <replacement>",
- "git replace -d <object>...",
- "git replace -l [<pattern>]",
+ N_("git replace [-f] <object> <replacement>"),
+ N_("git replace -d <object>..."),
+ N_("git replace -l [<pattern>]"),
NULL
};
@@ -115,9 +115,9 @@ int cmd_replace(int argc, const char **argv, const char *prefix)
{
int list = 0, delete = 0, force = 0;
struct option options[] = {
- OPT_BOOLEAN('l', NULL, &list, "list replace refs"),
- OPT_BOOLEAN('d', NULL, &delete, "delete replace refs"),
- OPT_BOOLEAN('f', NULL, &force, "replace the ref if it exists"),
+ OPT_BOOLEAN('l', NULL, &list, N_("list replace refs")),
+ OPT_BOOLEAN('d', NULL, &delete, N_("delete replace refs")),
+ OPT_BOOLEAN('f', NULL, &force, N_("replace the ref if it exists")),
OPT_END()
};
diff --git a/builtin/rerere.c b/builtin/rerere.c
index 08213c7..dc1708e 100644
--- a/builtin/rerere.c
+++ b/builtin/rerere.c
@@ -8,7 +8,7 @@
#include "xdiff-interface.h"
static const char * const rerere_usage[] = {
- "git rerere [clear | forget path... | status | remaining | diff | gc]",
+ N_("git rerere [clear | forget path... | status | remaining | diff | gc]"),
NULL,
};
@@ -53,7 +53,7 @@ int cmd_rerere(int argc, const char **argv, const char *prefix)
struct option options[] = {
OPT_SET_INT(0, "rerere-autoupdate", &autoupdate,
- "register clean resolutions in index", 1),
+ N_("register clean resolutions in index"), 1),
OPT_END(),
};
diff --git a/builtin/reset.c b/builtin/reset.c
index 4cc34c9..915cc9f 100644
--- a/builtin/reset.c
+++ b/builtin/reset.c
@@ -22,9 +22,9 @@
#include "cache-tree.h"
static const char * const git_reset_usage[] = {
- "git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]",
- "git reset [-q] <commit> [--] <paths>...",
- "git reset --patch [<commit>] [--] [<paths>...]",
+ N_("git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]"),
+ N_("git reset [-q] <commit> [--] <paths>..."),
+ N_("git reset --patch [<commit>] [--] [<paths>...]"),
NULL
};
@@ -235,17 +235,17 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
struct commit *commit;
struct strbuf msg = STRBUF_INIT;
const struct option options[] = {
- OPT__QUIET(&quiet, "be quiet, only report errors"),
+ OPT__QUIET(&quiet, N_("be quiet, only report errors")),
OPT_SET_INT(0, "mixed", &reset_type,
- "reset HEAD and index", MIXED),
- OPT_SET_INT(0, "soft", &reset_type, "reset only HEAD", SOFT),
+ N_("reset HEAD and index"), MIXED),
+ OPT_SET_INT(0, "soft", &reset_type, N_("reset only HEAD"), SOFT),
OPT_SET_INT(0, "hard", &reset_type,
- "reset HEAD, index and working tree", HARD),
+ N_("reset HEAD, index and working tree"), HARD),
OPT_SET_INT(0, "merge", &reset_type,
- "reset HEAD, index and working tree", MERGE),
+ N_("reset HEAD, index and working tree"), MERGE),
OPT_SET_INT(0, "keep", &reset_type,
- "reset HEAD but keep local changes", KEEP),
- OPT_BOOLEAN('p', "patch", &patch_mode, "select hunks interactively"),
+ N_("reset HEAD but keep local changes"), KEEP),
+ OPT_BOOLEAN('p', "patch", &patch_mode, N_("select hunks interactively")),
OPT_END()
};
@@ -276,7 +276,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
* Otherwise, argv[i] could be either <rev> or <paths> and
* has to be unambiguous.
*/
- else if (!get_sha1(argv[i], sha1)) {
+ else if (!get_sha1_committish(argv[i], sha1)) {
/*
* Ok, argv[i] looks like a rev; it should not
* be a filename.
@@ -289,9 +289,15 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
}
}
- if (get_sha1(rev, sha1))
+ if (get_sha1_committish(rev, sha1))
die(_("Failed to resolve '%s' as a valid ref."), rev);
+ /*
+ * NOTE: As "git reset $treeish -- $path" should be usable on
+ * any tree-ish, this is not strictly correct. We are not
+ * moving the HEAD to any commit; we are merely resetting the
+ * entries in the index to that of a treeish.
+ */
commit = lookup_commit_reference(sha1);
if (!commit)
die(_("Could not parse object '%s'."), rev);
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index 47b4e7a..f267a1d 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -195,6 +195,12 @@ static int anti_reference(const char *refname, const unsigned char *sha1, int fl
return 0;
}
+static int show_abbrev(const unsigned char *sha1, void *cb_data)
+{
+ show_rev(NORMAL, sha1, NULL);
+ return 0;
+}
+
static void show_datestring(const char *flag, const char *datestr)
{
static char buffer[100];
@@ -250,7 +256,7 @@ static int try_difference(const char *arg)
return 0;
}
- if (!get_sha1(this, sha1) && !get_sha1(next, end)) {
+ if (!get_sha1_committish(this, sha1) && !get_sha1_committish(next, end)) {
show_rev(NORMAL, end, next);
show_rev(symmetric ? NORMAL : REVERSED, sha1, this);
if (symmetric) {
@@ -290,7 +296,7 @@ static int try_parent_shorthands(const char *arg)
return 0;
*dotdot = 0;
- if (get_sha1(arg, sha1))
+ if (get_sha1_committish(arg, sha1))
return 0;
if (!parents_only)
@@ -330,15 +336,15 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)
{
static int keep_dashdash = 0, stop_at_non_option = 0;
static char const * const parseopt_usage[] = {
- "git rev-parse --parseopt [options] -- [<args>...]",
+ N_("git rev-parse --parseopt [options] -- [<args>...]"),
NULL
};
static struct option parseopt_opts[] = {
OPT_BOOLEAN(0, "keep-dashdash", &keep_dashdash,
- "keep the `--` passed as an arg"),
+ N_("keep the `--` passed as an arg")),
OPT_BOOLEAN(0, "stop-at-non-option", &stop_at_non_option,
- "stop parsing after the "
- "first non-option argument"),
+ N_("stop parsing after the "
+ "first non-option argument")),
OPT_END(),
};
@@ -455,11 +461,11 @@ static void die_no_single_rev(int quiet)
}
static const char builtin_rev_parse_usage[] =
-"git rev-parse --parseopt [options] -- [<args>...]\n"
-" or: git rev-parse --sq-quote [<arg>...]\n"
-" or: git rev-parse [options] [<arg>...]\n"
-"\n"
-"Run \"git rev-parse --parseopt -h\" for more information on the first usage.";
+N_("git rev-parse --parseopt [options] -- [<args>...]\n"
+ " or: git rev-parse --sq-quote [<arg>...]\n"
+ " or: git rev-parse [options] [<arg>...]\n"
+ "\n"
+ "Run \"git rev-parse --parseopt -h\" for more information on the first usage.");
int cmd_rev_parse(int argc, const char **argv, const char *prefix)
{
@@ -601,6 +607,10 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
for_each_ref(show_reference, NULL);
continue;
}
+ if (!prefixcmp(arg, "--disambiguate=")) {
+ for_each_abbrev(arg + 15, show_abbrev, NULL);
+ continue;
+ }
if (!strcmp(arg, "--bisect")) {
for_each_ref_in("refs/bisect/bad", show_reference, NULL);
for_each_ref_in("refs/bisect/good", anti_reference, NULL);
diff --git a/builtin/revert.c b/builtin/revert.c
index 82d1bf8..c5e36b9 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -19,14 +19,14 @@
*/
static const char * const revert_usage[] = {
- "git revert [options] <commit-ish>",
- "git revert <subcommand>",
+ N_("git revert [options] <commit-ish>"),
+ N_("git revert <subcommand>"),
NULL
};
static const char * const cherry_pick_usage[] = {
- "git cherry-pick [options] <commit-ish>",
- "git cherry-pick <subcommand>",
+ N_("git cherry-pick [options] <commit-ish>"),
+ N_("git cherry-pick <subcommand>"),
NULL
};
@@ -100,18 +100,19 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
int contin = 0;
int rollback = 0;
struct option options[] = {
- OPT_BOOLEAN(0, "quit", &remove_state, "end revert or cherry-pick sequence"),
- OPT_BOOLEAN(0, "continue", &contin, "resume revert or cherry-pick sequence"),
- OPT_BOOLEAN(0, "abort", &rollback, "cancel revert or cherry-pick sequence"),
- OPT_BOOLEAN('n', "no-commit", &opts->no_commit, "don't automatically commit"),
- OPT_BOOLEAN('e', "edit", &opts->edit, "edit the commit message"),
+ OPT_BOOLEAN(0, "quit", &remove_state, N_("end revert or cherry-pick sequence")),
+ OPT_BOOLEAN(0, "continue", &contin, N_("resume revert or cherry-pick sequence")),
+ OPT_BOOLEAN(0, "abort", &rollback, N_("cancel revert or cherry-pick sequence")),
+ OPT_BOOLEAN('n', "no-commit", &opts->no_commit, N_("don't automatically commit")),
+ OPT_BOOLEAN('e', "edit", &opts->edit, N_("edit the commit message")),
OPT_NOOP_NOARG('r', NULL),
- OPT_BOOLEAN('s', "signoff", &opts->signoff, "add Signed-off-by:"),
- OPT_INTEGER('m', "mainline", &opts->mainline, "parent number"),
+ OPT_BOOLEAN('s', "signoff", &opts->signoff, N_("add Signed-off-by:")),
+ OPT_INTEGER('m', "mainline", &opts->mainline, N_("parent number")),
OPT_RERERE_AUTOUPDATE(&opts->allow_rerere_auto),
- OPT_STRING(0, "strategy", &opts->strategy, "strategy", "merge strategy"),
- OPT_CALLBACK('X', "strategy-option", &opts, "option",
- "option for merge strategy", option_parse_x),
+ OPT_STRING(0, "strategy", &opts->strategy, N_("strategy"), N_("merge strategy")),
+ OPT_CALLBACK('X', "strategy-option", &opts, N_("option"),
+ N_("option for merge strategy"), option_parse_x),
+ OPT_END(),
OPT_END(),
OPT_END(),
OPT_END(),
@@ -121,10 +122,11 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
if (opts->action == REPLAY_PICK) {
struct option cp_extra[] = {
- OPT_BOOLEAN('x', NULL, &opts->record_origin, "append commit name"),
- OPT_BOOLEAN(0, "ff", &opts->allow_ff, "allow fast-forward"),
- OPT_BOOLEAN(0, "allow-empty", &opts->allow_empty, "preserve initially empty commits"),
- OPT_BOOLEAN(0, "keep-redundant-commits", &opts->keep_redundant_commits, "keep redundant, empty commits"),
+ OPT_BOOLEAN('x', NULL, &opts->record_origin, N_("append commit name")),
+ OPT_BOOLEAN(0, "ff", &opts->allow_ff, N_("allow fast-forward")),
+ OPT_BOOLEAN(0, "allow-empty", &opts->allow_empty, N_("preserve initially empty commits")),
+ OPT_BOOLEAN(0, "allow-empty-message", &opts->allow_empty_message, N_("allow commits with empty messages")),
+ OPT_BOOLEAN(0, "keep-redundant-commits", &opts->keep_redundant_commits, N_("keep redundant, empty commits")),
OPT_END(),
};
if (parse_options_concat(options, ARRAY_SIZE(options), cp_extra))
@@ -193,7 +195,7 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
struct setup_revision_opt s_r_opt;
opts->revs = xmalloc(sizeof(*opts->revs));
init_revisions(opts->revs, NULL);
- opts->revs->no_walk = 1;
+ opts->revs->no_walk = REVISION_WALK_NO_WALK_UNSORTED;
if (argc < 2)
usage_with_options(usage_str, options);
memset(&s_r_opt, 0, sizeof(s_r_opt));
diff --git a/builtin/rm.c b/builtin/rm.c
index 90c8a50..b384c4c 100644
--- a/builtin/rm.c
+++ b/builtin/rm.c
@@ -11,7 +11,7 @@
#include "parse-options.h"
static const char * const builtin_rm_usage[] = {
- "git rm [options] [--] <file>...",
+ N_("git rm [options] [--] <file>..."),
NULL
};
@@ -130,13 +130,13 @@ static int show_only = 0, force = 0, index_only = 0, recursive = 0, quiet = 0;
static int ignore_unmatch = 0;
static struct option builtin_rm_options[] = {
- OPT__DRY_RUN(&show_only, "dry run"),
- OPT__QUIET(&quiet, "do not list removed files"),
- OPT_BOOLEAN( 0 , "cached", &index_only, "only remove from the index"),
- OPT__FORCE(&force, "override the up-to-date check"),
- OPT_BOOLEAN('r', NULL, &recursive, "allow recursive removal"),
+ OPT__DRY_RUN(&show_only, N_("dry run")),
+ OPT__QUIET(&quiet, N_("do not list removed files")),
+ OPT_BOOLEAN( 0 , "cached", &index_only, N_("only remove from the index")),
+ OPT__FORCE(&force, N_("override the up-to-date check")),
+ OPT_BOOLEAN('r', NULL, &recursive, N_("allow recursive removal")),
OPT_BOOLEAN( 0 , "ignore-unmatch", &ignore_unmatch,
- "exit with a zero status even if nothing matched"),
+ N_("exit with a zero status even if nothing matched")),
OPT_END(),
};
diff --git a/builtin/send-pack.c b/builtin/send-pack.c
index d5d7105..7d05064 100644
--- a/builtin/send-pack.c
+++ b/builtin/send-pack.c
@@ -8,6 +8,7 @@
#include "send-pack.h"
#include "quote.h"
#include "transport.h"
+#include "version.h"
static const char send_pack_usage[] =
"git send-pack [--all | --mirror] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\n"
@@ -251,6 +252,7 @@ int send_pack(struct send_pack_args *args,
int status_report = 0;
int use_sideband = 0;
int quiet_supported = 0;
+ int agent_supported = 0;
unsigned cmds_sent = 0;
int ret;
struct async demux;
@@ -266,6 +268,8 @@ int send_pack(struct send_pack_args *args,
use_sideband = 1;
if (server_supports("quiet"))
quiet_supported = 1;
+ if (server_supports("agent"))
+ agent_supported = 1;
if (!remote_refs) {
fprintf(stderr, "No refs in common and none specified; doing nothing.\n"
@@ -305,12 +309,17 @@ int send_pack(struct send_pack_args *args,
char *new_hex = sha1_to_hex(ref->new_sha1);
int quiet = quiet_supported && (args->quiet || !args->progress);
- if (!cmds_sent && (status_report || use_sideband || args->quiet)) {
- packet_buf_write(&req_buf, "%s %s %s%c%s%s%s",
+ if (!cmds_sent && (status_report || use_sideband ||
+ quiet || agent_supported)) {
+ packet_buf_write(&req_buf,
+ "%s %s %s%c%s%s%s%s%s",
old_hex, new_hex, ref->name, 0,
status_report ? " report-status" : "",
use_sideband ? " side-band-64k" : "",
- quiet ? " quiet" : "");
+ quiet ? " quiet" : "",
+ agent_supported ? " agent=" : "",
+ agent_supported ? git_user_agent_sanitized() : ""
+ );
}
else
packet_buf_write(&req_buf, "%s %s %s",
diff --git a/builtin/shortlog.c b/builtin/shortlog.c
index 37f3193..b316cf3 100644
--- a/builtin/shortlog.c
+++ b/builtin/shortlog.c
@@ -10,9 +10,9 @@
#include "parse-options.h"
static char const * const shortlog_usage[] = {
- "git shortlog [-n] [-s] [-e] [-w] [rev-opts] [--] [<commit-id>... ]",
+ N_("git shortlog [-n] [-s] [-e] [-w] [rev-opts] [--] [<commit-id>... ]"),
"",
- "[rev-opts] are documented in git-rev-list(1)",
+ N_("[rev-opts] are documented in git-rev-list(1)"),
NULL
};
@@ -250,13 +250,13 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)
static const struct option options[] = {
OPT_BOOLEAN('n', "numbered", &log.sort_by_number,
- "sort output according to the number of commits per author"),
+ N_("sort output according to the number of commits per author")),
OPT_BOOLEAN('s', "summary", &log.summary,
- "Suppress commit descriptions, only provides commit count"),
+ N_("Suppress commit descriptions, only provides commit count")),
OPT_BOOLEAN('e', "email", &log.email,
- "Show the email address of each author"),
- { OPTION_CALLBACK, 'w', NULL, &log, "w[,i1[,i2]]",
- "Linewrap output", PARSE_OPT_OPTARG, &parse_wrap_args },
+ N_("Show the email address of each author")),
+ { OPTION_CALLBACK, 'w', NULL, &log, N_("w[,i1[,i2]]"),
+ N_("Linewrap output"), PARSE_OPT_OPTARG, &parse_wrap_args },
OPT_END(),
};
diff --git a/builtin/show-branch.c b/builtin/show-branch.c
index a59e088..d208fd6 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -6,8 +6,8 @@
#include "parse-options.h"
static const char* show_branch_usage[] = {
- "git show-branch [-a|--all] [-r|--remotes] [--topo-order | --date-order] [--current] [--color[=<when>] | --no-color] [--sparse] [--more=<n> | --list | --independent | --merge-base] [--no-name | --sha1-name] [--topics] [(<rev> | <glob>)...]",
- "git show-branch (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]",
+ N_("git show-branch [-a|--all] [-r|--remotes] [--topo-order | --date-order] [--current] [--color[=<when>] | --no-color] [--sparse] [--more=<n> | --list | --independent | --merge-base] [--no-name | --sha1-name] [--topics] [(<rev> | <glob>)...]"),
+ N_("git show-branch (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]"),
NULL
};
@@ -648,36 +648,36 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
const char *reflog_base = NULL;
struct option builtin_show_branch_options[] = {
OPT_BOOLEAN('a', "all", &all_heads,
- "show remote-tracking and local branches"),
+ N_("show remote-tracking and local branches")),
OPT_BOOLEAN('r', "remotes", &all_remotes,
- "show remote-tracking branches"),
+ N_("show remote-tracking branches")),
OPT__COLOR(&showbranch_use_color,
- "color '*!+-' corresponding to the branch"),
- { OPTION_INTEGER, 0, "more", &extra, "n",
- "show <n> more commits after the common ancestor",
+ N_("color '*!+-' corresponding to the branch")),
+ { OPTION_INTEGER, 0, "more", &extra, N_("n"),
+ N_("show <n> more commits after the common ancestor"),
PARSE_OPT_OPTARG, NULL, (intptr_t)1 },
- OPT_SET_INT(0, "list", &extra, "synonym to more=-1", -1),
- OPT_BOOLEAN(0, "no-name", &no_name, "suppress naming strings"),
+ OPT_SET_INT(0, "list", &extra, N_("synonym to more=-1"), -1),
+ OPT_BOOLEAN(0, "no-name", &no_name, N_("suppress naming strings")),
OPT_BOOLEAN(0, "current", &with_current_branch,
- "include the current branch"),
+ N_("include the current branch")),
OPT_BOOLEAN(0, "sha1-name", &sha1_name,
- "name commits with their object names"),
+ N_("name commits with their object names")),
OPT_BOOLEAN(0, "merge-base", &merge_base,
- "show possible merge bases"),
+ N_("show possible merge bases")),
OPT_BOOLEAN(0, "independent", &independent,
- "show refs unreachable from any other ref"),
+ N_("show refs unreachable from any other ref")),
OPT_BOOLEAN(0, "topo-order", &lifo,
- "show commits in topological order"),
+ N_("show commits in topological order")),
OPT_BOOLEAN(0, "topics", &topics,
- "show only commits not on the first branch"),
+ N_("show only commits not on the first branch")),
OPT_SET_INT(0, "sparse", &dense,
- "show merges reachable from only one tip", 0),
+ N_("show merges reachable from only one tip"), 0),
OPT_SET_INT(0, "date-order", &lifo,
- "show commits where no parent comes before its "
- "children", 0),
- { OPTION_CALLBACK, 'g', "reflog", &reflog_base, "<n>[,<base>]",
- "show <n> most recent ref-log entries starting at "
- "base",
+ N_("show commits where no parent comes before its "
+ "children"), 0),
+ { OPTION_CALLBACK, 'g', "reflog", &reflog_base, N_("<n>[,<base>]"),
+ N_("show <n> most recent ref-log entries starting at "
+ "base"),
PARSE_OPT_OPTARG | PARSE_OPT_LITERAL_ARGHELP,
parse_reflog_param },
OPT_END()
diff --git a/builtin/show-ref.c b/builtin/show-ref.c
index 3911661..4eb016d 100644
--- a/builtin/show-ref.c
+++ b/builtin/show-ref.c
@@ -7,8 +7,8 @@
#include "parse-options.h"
static const char * const show_ref_usage[] = {
- "git show-ref [-q|--quiet] [--verify] [--head] [-d|--dereference] [-s|--hash[=<n>]] [--abbrev[=<n>]] [--tags] [--heads] [--] [pattern*] ",
- "git show-ref --exclude-existing[=pattern] < ref-list",
+ N_("git show-ref [-q|--quiet] [--verify] [--head] [-d|--dereference] [-s|--hash[=<n>]] [--abbrev[=<n>]] [--tags] [--heads] [--] [pattern*] "),
+ N_("git show-ref --exclude-existing[=pattern] < ref-list"),
NULL
};
@@ -179,26 +179,26 @@ static int help_callback(const struct option *opt, const char *arg, int unset)
}
static const struct option show_ref_options[] = {
- OPT_BOOLEAN(0, "tags", &tags_only, "only show tags (can be combined with heads)"),
- OPT_BOOLEAN(0, "heads", &heads_only, "only show heads (can be combined with tags)"),
- OPT_BOOLEAN(0, "verify", &verify, "stricter reference checking, "
- "requires exact ref path"),
+ OPT_BOOLEAN(0, "tags", &tags_only, N_("only show tags (can be combined with heads)")),
+ OPT_BOOLEAN(0, "heads", &heads_only, N_("only show heads (can be combined with tags)")),
+ OPT_BOOLEAN(0, "verify", &verify, N_("stricter reference checking, "
+ "requires exact ref path")),
{ OPTION_BOOLEAN, 'h', NULL, &show_head, NULL,
- "show the HEAD reference",
+ N_("show the HEAD reference"),
PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
- OPT_BOOLEAN(0, "head", &show_head, "show the HEAD reference"),
+ OPT_BOOLEAN(0, "head", &show_head, N_("show the HEAD reference")),
OPT_BOOLEAN('d', "dereference", &deref_tags,
- "dereference tags into object IDs"),
- { OPTION_CALLBACK, 's', "hash", &abbrev, "n",
- "only show SHA1 hash using <n> digits",
+ N_("dereference tags into object IDs")),
+ { OPTION_CALLBACK, 's', "hash", &abbrev, N_("n"),
+ N_("only show SHA1 hash using <n> digits"),
PARSE_OPT_OPTARG, &hash_callback },
OPT__ABBREV(&abbrev),
OPT__QUIET(&quiet,
- "do not print results to stdout (useful with --verify)"),
+ N_("do not print results to stdout (useful with --verify)")),
{ OPTION_CALLBACK, 0, "exclude-existing", &exclude_existing_arg,
- "pattern", "show refs from stdin that aren't in local repository",
+ N_("pattern"), N_("show refs from stdin that aren't in local repository"),
PARSE_OPT_OPTARG | PARSE_OPT_NONEG, exclude_existing_callback },
- { OPTION_CALLBACK, 0, "help-all", NULL, NULL, "show usage",
+ { OPTION_CALLBACK, 0, "help-all", NULL, NULL, N_("show usage"),
PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, help_callback },
OPT_END()
};
diff --git a/builtin/symbolic-ref.c b/builtin/symbolic-ref.c
index 801d62e..9e92828 100644
--- a/builtin/symbolic-ref.c
+++ b/builtin/symbolic-ref.c
@@ -4,7 +4,7 @@
#include "parse-options.h"
static const char * const git_symbolic_ref_usage[] = {
- "git symbolic-ref [options] name [ref]",
+ N_("git symbolic-ref [options] name [ref]"),
NULL
};
@@ -35,9 +35,9 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
const char *msg = NULL;
struct option options[] = {
OPT__QUIET(&quiet,
- "suppress error message for non-symbolic (detached) refs"),
- OPT_BOOL(0, "short", &shorten, "shorten ref output"),
- OPT_STRING('m', NULL, &msg, "reason", "reason of the update"),
+ N_("suppress error message for non-symbolic (detached) refs")),
+ OPT_BOOL(0, "short", &shorten, N_("shorten ref output")),
+ OPT_STRING('m', NULL, &msg, N_("reason"), N_("reason of the update")),
OPT_END(),
};
diff --git a/builtin/tag.c b/builtin/tag.c
index 7b1be85..9c3e067 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -19,11 +19,11 @@
#include "column.h"
static const char * const git_tag_usage[] = {
- "git tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]",
- "git tag -d <tagname>...",
- "git tag -l [-n[<num>]] [--contains <commit>] [--points-at <object>] "
- "\n\t\t[<pattern>...]",
- "git tag -v <tagname>...",
+ N_("git tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]"),
+ N_("git tag -d <tagname>..."),
+ N_("git tag -l [-n[<num>]] [--contains <commit>] [--points-at <object>] "
+ "\n\t\t[<pattern>...]"),
+ N_("git tag -v <tagname>..."),
NULL
};
@@ -444,37 +444,37 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
struct msg_arg msg = { 0, STRBUF_INIT };
struct commit_list *with_commit = NULL;
struct option options[] = {
- OPT_BOOLEAN('l', "list", &list, "list tag names"),
- { OPTION_INTEGER, 'n', NULL, &lines, "n",
- "print <n> lines of each tag message",
+ OPT_BOOLEAN('l', "list", &list, N_("list tag names")),
+ { OPTION_INTEGER, 'n', NULL, &lines, N_("n"),
+ N_("print <n> lines of each tag message"),
PARSE_OPT_OPTARG, NULL, 1 },
- OPT_BOOLEAN('d', "delete", &delete, "delete tags"),
- OPT_BOOLEAN('v', "verify", &verify, "verify tags"),
+ OPT_BOOLEAN('d', "delete", &delete, N_("delete tags")),
+ OPT_BOOLEAN('v', "verify", &verify, N_("verify tags")),
- OPT_GROUP("Tag creation options"),
+ OPT_GROUP(N_("Tag creation options")),
OPT_BOOLEAN('a', "annotate", &annotate,
- "annotated tag, needs a message"),
- OPT_CALLBACK('m', "message", &msg, "message",
- "tag message", parse_msg_arg),
- OPT_FILENAME('F', "file", &msgfile, "read message from file"),
- OPT_BOOLEAN('s', "sign", &opt.sign, "annotated and GPG-signed tag"),
- OPT_STRING(0, "cleanup", &cleanup_arg, "mode",
- "how to strip spaces and #comments from message"),
- OPT_STRING('u', "local-user", &keyid, "key-id",
- "use another key to sign the tag"),
- OPT__FORCE(&force, "replace the tag if exists"),
- OPT_COLUMN(0, "column", &colopts, "show tag list in columns"),
-
- OPT_GROUP("Tag listing options"),
+ N_("annotated tag, needs a message")),
+ OPT_CALLBACK('m', "message", &msg, N_("message"),
+ N_("tag message"), parse_msg_arg),
+ OPT_FILENAME('F', "file", &msgfile, N_("read message from file")),
+ OPT_BOOLEAN('s', "sign", &opt.sign, N_("annotated and GPG-signed tag")),
+ OPT_STRING(0, "cleanup", &cleanup_arg, N_("mode"),
+ N_("how to strip spaces and #comments from message")),
+ OPT_STRING('u', "local-user", &keyid, N_("key id"),
+ N_("use another key to sign the tag")),
+ OPT__FORCE(&force, N_("replace the tag if exists")),
+ OPT_COLUMN(0, "column", &colopts, N_("show tag list in columns")),
+
+ OPT_GROUP(N_("Tag listing options")),
{
- OPTION_CALLBACK, 0, "contains", &with_commit, "commit",
- "print only tags that contain the commit",
+ OPTION_CALLBACK, 0, "contains", &with_commit, N_("commit"),
+ N_("print only tags that contain the commit"),
PARSE_OPT_LASTARG_DEFAULT,
parse_opt_with_commit, (intptr_t)"HEAD",
},
{
- OPTION_CALLBACK, 0, "points-at", NULL, "object",
- "print only tags of the object", 0, parse_opt_points_at
+ OPTION_CALLBACK, 0, "points-at", NULL, N_("object"),
+ N_("print only tags of the object"), 0, parse_opt_points_at
},
OPT_END()
};
diff --git a/builtin/update-index.c b/builtin/update-index.c
index 5a4e9ea..74986bf 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -95,7 +95,8 @@ static int add_one_path(struct cache_entry *old, const char *path, int len, stru
size = cache_entry_size(len);
ce = xcalloc(1, size);
memcpy(ce->name, path, len);
- ce->ce_flags = len;
+ ce->ce_flags = create_ce_flags(0);
+ ce->ce_namelen = len;
fill_stat_cache_info(ce, st);
ce->ce_mode = ce_mode_from_stat(old, st->st_mode);
@@ -229,7 +230,8 @@ static int add_cacheinfo(unsigned int mode, const unsigned char *sha1,
hashcpy(ce->sha1, sha1);
memcpy(ce->name, path, len);
- ce->ce_flags = create_ce_flags(len, stage);
+ ce->ce_flags = create_ce_flags(stage);
+ ce->ce_namelen = len;
ce->ce_mode = create_ce_mode(mode);
if (assume_unchanged)
ce->ce_flags |= CE_VALID;
@@ -396,7 +398,7 @@ static void read_index_info(int line_termination)
}
static const char * const update_index_usage[] = {
- "git update-index [options] [--] [<file>...]",
+ N_("git update-index [options] [--] [<file>...]"),
NULL
};
@@ -427,7 +429,8 @@ static struct cache_entry *read_one_ent(const char *which,
hashcpy(ce->sha1, sha1);
memcpy(ce->name, path, namelen);
- ce->ce_flags = create_ce_flags(namelen, stage);
+ ce->ce_flags = create_ce_flags(stage);
+ ce->ce_namelen = namelen;
ce->ce_mode = create_ce_mode(mode);
return ce;
}
@@ -711,83 +714,83 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
int parseopt_state = PARSE_OPT_UNKNOWN;
struct option options[] = {
OPT_BIT('q', NULL, &refresh_args.flags,
- "continue refresh even when index needs update",
+ N_("continue refresh even when index needs update"),
REFRESH_QUIET),
OPT_BIT(0, "ignore-submodules", &refresh_args.flags,
- "refresh: ignore submodules",
+ N_("refresh: ignore submodules"),
REFRESH_IGNORE_SUBMODULES),
OPT_SET_INT(0, "add", &allow_add,
- "do not ignore new files", 1),
+ N_("do not ignore new files"), 1),
OPT_SET_INT(0, "replace", &allow_replace,
- "let files replace directories and vice-versa", 1),
+ N_("let files replace directories and vice-versa"), 1),
OPT_SET_INT(0, "remove", &allow_remove,
- "notice files missing from worktree", 1),
+ N_("notice files missing from worktree"), 1),
OPT_BIT(0, "unmerged", &refresh_args.flags,
- "refresh even if index contains unmerged entries",
+ N_("refresh even if index contains unmerged entries"),
REFRESH_UNMERGED),
{OPTION_CALLBACK, 0, "refresh", &refresh_args, NULL,
- "refresh stat information",
+ N_("refresh stat information"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG,
refresh_callback},
{OPTION_CALLBACK, 0, "really-refresh", &refresh_args, NULL,
- "like --refresh, but ignore assume-unchanged setting",
+ N_("like --refresh, but ignore assume-unchanged setting"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG,
really_refresh_callback},
{OPTION_LOWLEVEL_CALLBACK, 0, "cacheinfo", NULL,
- "<mode> <object> <path>",
- "add the specified entry to the index",
+ N_("<mode> <object> <path>"),
+ N_("add the specified entry to the index"),
PARSE_OPT_NOARG | /* disallow --cacheinfo=<mode> form */
PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP,
(parse_opt_cb *) cacheinfo_callback},
- {OPTION_CALLBACK, 0, "chmod", &set_executable_bit, "(+/-)x",
- "override the executable bit of the listed files",
+ {OPTION_CALLBACK, 0, "chmod", &set_executable_bit, N_("(+/-)x"),
+ N_("override the executable bit of the listed files"),
PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP,
chmod_callback},
{OPTION_SET_INT, 0, "assume-unchanged", &mark_valid_only, NULL,
- "mark files as \"not changing\"",
+ N_("mark files as \"not changing\""),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, MARK_FLAG},
{OPTION_SET_INT, 0, "no-assume-unchanged", &mark_valid_only, NULL,
- "clear assumed-unchanged bit",
+ N_("clear assumed-unchanged bit"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, UNMARK_FLAG},
{OPTION_SET_INT, 0, "skip-worktree", &mark_skip_worktree_only, NULL,
- "mark files as \"index-only\"",
+ N_("mark files as \"index-only\""),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, MARK_FLAG},
{OPTION_SET_INT, 0, "no-skip-worktree", &mark_skip_worktree_only, NULL,
- "clear skip-worktree bit",
+ N_("clear skip-worktree bit"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, UNMARK_FLAG},
OPT_SET_INT(0, "info-only", &info_only,
- "add to index only; do not add content to object database", 1),
+ N_("add to index only; do not add content to object database"), 1),
OPT_SET_INT(0, "force-remove", &force_remove,
- "remove named paths even if present in worktree", 1),
+ N_("remove named paths even if present in worktree"), 1),
OPT_SET_INT('z', NULL, &line_termination,
- "with --stdin: input lines are terminated by null bytes", '\0'),
+ N_("with --stdin: input lines are terminated by null bytes"), '\0'),
{OPTION_LOWLEVEL_CALLBACK, 0, "stdin", &read_from_stdin, NULL,
- "read list of paths to be updated from standard input",
+ N_("read list of paths to be updated from standard input"),
PARSE_OPT_NONEG | PARSE_OPT_NOARG,
(parse_opt_cb *) stdin_callback},
{OPTION_LOWLEVEL_CALLBACK, 0, "index-info", &line_termination, NULL,
- "add entries from standard input to the index",
+ N_("add entries from standard input to the index"),
PARSE_OPT_NONEG | PARSE_OPT_NOARG,
(parse_opt_cb *) stdin_cacheinfo_callback},
{OPTION_LOWLEVEL_CALLBACK, 0, "unresolve", &has_errors, NULL,
- "repopulate stages #2 and #3 for the listed paths",
+ N_("repopulate stages #2 and #3 for the listed paths"),
PARSE_OPT_NONEG | PARSE_OPT_NOARG,
(parse_opt_cb *) unresolve_callback},
{OPTION_LOWLEVEL_CALLBACK, 'g', "again", &has_errors, NULL,
- "only update entries that differ from HEAD",
+ N_("only update entries that differ from HEAD"),
PARSE_OPT_NONEG | PARSE_OPT_NOARG,
(parse_opt_cb *) reupdate_callback},
OPT_BIT(0, "ignore-missing", &refresh_args.flags,
- "ignore files missing from worktree",
+ N_("ignore files missing from worktree"),
REFRESH_IGNORE_MISSING),
OPT_SET_INT(0, "verbose", &verbose,
- "report actions to standard output", 1),
+ N_("report actions to standard output"), 1),
{OPTION_CALLBACK, 0, "clear-resolve-undo", NULL, NULL,
- "(for porcelains) forget saved unresolved conflicts",
+ N_("(for porcelains) forget saved unresolved conflicts"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG,
resolve_undo_clear_callback},
OPT_INTEGER(0, "index-version", &preferred_index_format,
- "write index in this format"),
+ N_("write index in this format")),
OPT_END()
};
diff --git a/builtin/update-ref.c b/builtin/update-ref.c
index 835c62a..51d2684 100644
--- a/builtin/update-ref.c
+++ b/builtin/update-ref.c
@@ -4,8 +4,8 @@
#include "parse-options.h"
static const char * const git_update_ref_usage[] = {
- "git update-ref [options] -d <refname> [<oldval>]",
- "git update-ref [options] <refname> <newval> [<oldval>]",
+ N_("git update-ref [options] -d <refname> [<oldval>]"),
+ N_("git update-ref [options] <refname> <newval> [<oldval>]"),
NULL
};
@@ -15,10 +15,10 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
unsigned char sha1[20], oldsha1[20];
int delete = 0, no_deref = 0, flags = 0;
struct option options[] = {
- OPT_STRING( 'm', NULL, &msg, "reason", "reason of the update"),
- OPT_BOOLEAN('d', NULL, &delete, "deletes the reference"),
+ OPT_STRING( 'm', NULL, &msg, N_("reason"), N_("reason of the update")),
+ OPT_BOOLEAN('d', NULL, &delete, N_("delete the reference")),
OPT_BOOLEAN( 0 , "no-deref", &no_deref,
- "update <refname> not the one it points to"),
+ N_("update <refname> not the one it points to")),
OPT_END(),
};
diff --git a/builtin/update-server-info.c b/builtin/update-server-info.c
index 0d63c44..6c8cc3e 100644
--- a/builtin/update-server-info.c
+++ b/builtin/update-server-info.c
@@ -3,7 +3,7 @@
#include "parse-options.h"
static const char * const update_server_info_usage[] = {
- "git update-server-info [--force]",
+ N_("git update-server-info [--force]"),
NULL
};
@@ -11,7 +11,7 @@ int cmd_update_server_info(int argc, const char **argv, const char *prefix)
{
int force = 0;
struct option options[] = {
- OPT__FORCE(&force, "update the info files from scratch"),
+ OPT__FORCE(&force, N_("update the info files from scratch")),
OPT_END()
};
diff --git a/builtin/verify-pack.c b/builtin/verify-pack.c
index e841b4a..66cd2df 100644
--- a/builtin/verify-pack.c
+++ b/builtin/verify-pack.c
@@ -53,7 +53,7 @@ static int verify_one_pack(const char *path, unsigned int flags)
}
static const char * const verify_pack_usage[] = {
- "git verify-pack [-v|--verbose] [-s|--stat-only] <pack>...",
+ N_("git verify-pack [-v|--verbose] [-s|--stat-only] <pack>..."),
NULL
};
@@ -63,9 +63,9 @@ int cmd_verify_pack(int argc, const char **argv, const char *prefix)
unsigned int flags = 0;
int i;
const struct option verify_pack_options[] = {
- OPT_BIT('v', "verbose", &flags, "verbose",
+ OPT_BIT('v', "verbose", &flags, N_("verbose"),
VERIFY_PACK_VERBOSE),
- OPT_BIT('s', "stat-only", &flags, "show statistics only",
+ OPT_BIT('s', "stat-only", &flags, N_("show statistics only"),
VERIFY_PACK_STAT_ONLY),
OPT_END()
};
diff --git a/builtin/verify-tag.c b/builtin/verify-tag.c
index 986789f..a8eee88 100644
--- a/builtin/verify-tag.c
+++ b/builtin/verify-tag.c
@@ -14,7 +14,7 @@
#include "gpg-interface.h"
static const char * const verify_tag_usage[] = {
- "git verify-tag [-v|--verbose] <tag>...",
+ N_("git verify-tag [-v|--verbose] <tag>..."),
NULL
};
@@ -70,7 +70,7 @@ int cmd_verify_tag(int argc, const char **argv, const char *prefix)
{
int i = 1, verbose = 0, had_error = 0;
const struct option verify_tag_options[] = {
- OPT__VERBOSE(&verbose, "print tag contents"),
+ OPT__VERBOSE(&verbose, N_("print tag contents")),
OPT_END()
};
diff --git a/builtin/write-tree.c b/builtin/write-tree.c
index b223af4..084c0df 100644
--- a/builtin/write-tree.c
+++ b/builtin/write-tree.c
@@ -10,7 +10,7 @@
#include "parse-options.h"
static const char * const write_tree_usage[] = {
- "git write-tree [--missing-ok] [--prefix=<prefix>/]",
+ N_("git write-tree [--missing-ok] [--prefix=<prefix>/]"),
NULL
};
@@ -21,13 +21,13 @@ int cmd_write_tree(int argc, const char **argv, const char *unused_prefix)
unsigned char sha1[20];
const char *me = "git-write-tree";
struct option write_tree_options[] = {
- OPT_BIT(0, "missing-ok", &flags, "allow missing objects",
+ OPT_BIT(0, "missing-ok", &flags, N_("allow missing objects"),
WRITE_TREE_MISSING_OK),
- { OPTION_STRING, 0, "prefix", &prefix, "<prefix>/",
- "write tree object for a subdirectory <prefix>" ,
+ { OPTION_STRING, 0, "prefix", &prefix, N_("<prefix>/"),
+ N_("write tree object for a subdirectory <prefix>") ,
PARSE_OPT_LITERAL_ARGHELP },
{ OPTION_BIT, 0, "ignore-cache-tree", &flags, NULL,
- "only useful for debugging",
+ N_("only useful for debugging"),
PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, NULL,
WRITE_TREE_IGNORE_CACHE_TREE },
OPT_END()
diff --git a/cache.h b/cache.h
index 75b3bea..a58df84 100644
--- a/cache.h
+++ b/cache.h
@@ -128,13 +128,13 @@ struct cache_entry {
unsigned int ce_gid;
unsigned int ce_size;
unsigned int ce_flags;
+ unsigned int ce_namelen;
unsigned char sha1[20];
struct cache_entry *next;
struct cache_entry *dir_next;
char name[FLEX_ARRAY]; /* more */
};
-#define CE_NAMEMASK (0x0fff)
#define CE_STAGEMASK (0x3000)
#define CE_EXTENDED (0x4000)
#define CE_VALID (0x8000)
@@ -198,21 +198,12 @@ static inline void copy_cache_entry(struct cache_entry *dst, struct cache_entry
dst->ce_flags = (dst->ce_flags & ~CE_STATE_MASK) | state;
}
-static inline unsigned create_ce_flags(size_t len, unsigned stage)
+static inline unsigned create_ce_flags(unsigned stage)
{
- if (len >= CE_NAMEMASK)
- len = CE_NAMEMASK;
- return (len | (stage << CE_STAGESHIFT));
-}
-
-static inline size_t ce_namelen(const struct cache_entry *ce)
-{
- size_t len = ce->ce_flags & CE_NAMEMASK;
- if (len < CE_NAMEMASK)
- return len;
- return strlen(ce->name + CE_NAMEMASK) + CE_NAMEMASK;
+ return (stage << CE_STAGESHIFT);
}
+#define ce_namelen(ce) ((ce)->ce_namelen)
#define ce_size(ce) cache_entry_size(ce_namelen(ce))
#define ce_stage(ce) ((CE_STAGEMASK & (ce)->ce_flags) >> CE_STAGESHIFT)
#define ce_uptodate(ce) ((ce)->ce_flags & CE_UPTODATE)
@@ -563,6 +554,7 @@ extern int read_replace_refs;
extern int fsync_object_files;
extern int core_preload_index;
extern int core_apply_sparse_checkout;
+extern int precomposed_unicode;
enum branch_track {
BRANCH_TRACK_UNSPECIFIED = -1,
@@ -622,6 +614,8 @@ extern char *git_snpath(char *buf, size_t n, const char *fmt, ...)
__attribute__((format (printf, 3, 4)));
extern char *git_pathdup(const char *fmt, ...)
__attribute__((format (printf, 1, 2)));
+extern char *mkpathdup(const char *fmt, ...)
+ __attribute__((format (printf, 1, 2)));
/* Return a statically allocated filename matching the sha1 signature */
extern char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
@@ -711,6 +705,7 @@ int set_shared_perm(const char *path, int mode);
int safe_create_leading_directories(char *path);
int safe_create_leading_directories_const(const char *path);
int mkdir_in_gitdir(const char *path);
+extern void home_config_paths(char **global, char **xdg, char *file);
extern char *expand_user_path(const char *path);
const char *enter_repo(const char *path, int strict);
static inline int is_absolute_path(const char *path)
@@ -786,17 +781,25 @@ struct object_context {
unsigned mode;
};
+#define GET_SHA1_QUIETLY 01
+#define GET_SHA1_COMMIT 02
+#define GET_SHA1_COMMITTISH 04
+#define GET_SHA1_TREE 010
+#define GET_SHA1_TREEISH 020
+#define GET_SHA1_BLOB 040
+#define GET_SHA1_ONLY_TO_DIE 04000
+
extern int get_sha1(const char *str, unsigned char *sha1);
-extern int get_sha1_with_mode_1(const char *str, unsigned char *sha1, unsigned *mode, int only_to_die, const char *prefix);
-static inline int get_sha1_with_mode(const char *str, unsigned char *sha1, unsigned *mode)
-{
- return get_sha1_with_mode_1(str, sha1, mode, 0, NULL);
-}
-extern int get_sha1_with_context_1(const char *name, unsigned char *sha1, struct object_context *orc, int only_to_die, const char *prefix);
-static inline int get_sha1_with_context(const char *str, unsigned char *sha1, struct object_context *orc)
-{
- return get_sha1_with_context_1(str, sha1, orc, 0, NULL);
-}
+extern int get_sha1_commit(const char *str, unsigned char *sha1);
+extern int get_sha1_committish(const char *str, unsigned char *sha1);
+extern int get_sha1_tree(const char *str, unsigned char *sha1);
+extern int get_sha1_treeish(const char *str, unsigned char *sha1);
+extern int get_sha1_blob(const char *str, unsigned char *sha1);
+extern void maybe_die_on_misspelt_object_name(const char *name, const char *prefix);
+extern int get_sha1_with_context(const char *str, unsigned flags, unsigned char *sha1, struct object_context *orc);
+
+typedef int each_abbrev_fn(const unsigned char *sha1, void *);
+extern int for_each_abbrev(const char *prefix, each_abbrev_fn, void *);
/*
* Try to read a SHA1 in hexadecimal format from the 40 characters
@@ -860,6 +863,7 @@ extern int validate_headref(const char *ref);
extern int base_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2);
extern int df_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2);
extern int cache_name_compare(const char *name1, int len1, const char *name2, int len2);
+extern int cache_name_stage_compare(const char *name1, int len1, int stage1, const char *name2, int len2, int stage2);
extern void *read_object_with_reference(const unsigned char *sha1,
const char *required_type,
@@ -897,9 +901,7 @@ extern const char *git_author_info(int);
extern const char *git_committer_info(int);
extern const char *fmt_ident(const char *name, const char *email, const char *date_str, int);
extern const char *fmt_name(const char *name, const char *email);
-extern const char *ident_default_name(void);
extern const char *ident_default_email(void);
-extern const char *ident_default_date(void);
extern const char *git_editor(void);
extern const char *git_pager(int stdout_is_tty);
extern int git_ident_config(const char *, const char *, void *);
@@ -942,9 +944,7 @@ struct cache_def {
extern int has_symlink_leading_path(const char *name, int len);
extern int threaded_has_symlink_leading_path(struct cache_def *, const char *, int);
extern int check_leading_path(const char *name, int len);
-extern int threaded_check_leading_path(struct cache_def *cache, const char *name, int len);
extern int has_dirs_only_path(const char *name, int len, int prefix_len);
-extern int threaded_has_dirs_only_path(struct cache_def *cache, const char *name, int len, int prefix_len);
extern void schedule_dir_for_removal(const char *name, int len);
extern void remove_scheduled_dirs(void);
@@ -1033,7 +1033,9 @@ struct extra_have_objects {
};
extern struct ref **get_remote_heads(int in, struct ref **list, unsigned int flags, struct extra_have_objects *);
extern int server_supports(const char *feature);
-extern const char *parse_feature_request(const char *features, const char *feature);
+extern int parse_feature_request(const char *features, const char *feature);
+extern const char *server_feature_value(const char *feature, int *len_ret);
+extern const char *parse_feature_value(const char *feature_list, const char *feature, int *len_ret);
extern struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path);
@@ -1201,7 +1203,6 @@ extern void alloc_report(void);
/* trace.c */
__attribute__((format (printf, 1, 2)))
extern void trace_printf(const char *format, ...);
-extern void trace_vprintf(const char *key, const char *format, va_list ap);
__attribute__((format (printf, 2, 3)))
extern void trace_argv_printf(const char **argv, const char *format, ...);
extern void trace_repo_setup(const char *prefix);
diff --git a/command-list.txt b/command-list.txt
index 14ea67a..7e8cfec 100644
--- a/command-list.txt
+++ b/command-list.txt
@@ -25,6 +25,9 @@ git-commit mainporcelain common
git-commit-tree plumbingmanipulators
git-config ancillarymanipulators
git-count-objects ancillaryinterrogators
+git-credential purehelpers
+git-credential-cache purehelpers
+git-credential-store purehelpers
git-cvsexportcommit foreignscminterface
git-cvsimport foreignscminterface
git-cvsserver foreignscminterface
@@ -113,6 +116,7 @@ git-show mainporcelain common
git-show-branch ancillaryinterrogators
git-show-index plumbinginterrogators
git-show-ref plumbinginterrogators
+git-sh-i18n purehelpers
git-sh-setup purehelpers
git-stash mainporcelain
git-status mainporcelain common
diff --git a/commit.c b/commit.c
index 8248a99..213bc98 100644
--- a/commit.c
+++ b/commit.c
@@ -9,6 +9,8 @@
#include "gpg-interface.h"
#include "mergesort.h"
+static struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **);
+
int save_commit_buffer = 1;
const char *commit_type = "commit";
@@ -68,7 +70,7 @@ struct commit *lookup_commit_reference_by_name(const char *name)
unsigned char sha1[20];
struct commit *commit;
- if (get_sha1(name, sha1))
+ if (get_sha1_committish(name, sha1))
return NULL;
commit = lookup_commit_reference(sha1);
if (!commit || parse_commit(commit))
@@ -607,30 +609,17 @@ static struct commit *interesting(struct commit_list *list)
return NULL;
}
-static struct commit_list *merge_bases_many(struct commit *one, int n, struct commit **twos)
+/* all input commits in one and twos[] must have been parsed! */
+static struct commit_list *paint_down_to_common(struct commit *one, int n, struct commit **twos)
{
struct commit_list *list = NULL;
struct commit_list *result = NULL;
int i;
- for (i = 0; i < n; i++) {
- if (one == twos[i])
- /*
- * We do not mark this even with RESULT so we do not
- * have to clean it up.
- */
- return commit_list_insert(one, &result);
- }
-
- if (parse_commit(one))
- return NULL;
- for (i = 0; i < n; i++) {
- if (parse_commit(twos[i]))
- return NULL;
- }
-
one->object.flags |= PARENT1;
commit_list_insert_by_date(one, &list);
+ if (!n)
+ return list;
for (i = 0; i < n; i++) {
twos[i]->object.flags |= PARENT2;
commit_list_insert_by_date(twos[i], &list);
@@ -669,9 +658,34 @@ static struct commit_list *merge_bases_many(struct commit *one, int n, struct co
}
}
- /* Clean up the result to remove stale ones */
free_commit_list(list);
- list = result; result = NULL;
+ return result;
+}
+
+static struct commit_list *merge_bases_many(struct commit *one, int n, struct commit **twos)
+{
+ struct commit_list *list = NULL;
+ struct commit_list *result = NULL;
+ int i;
+
+ for (i = 0; i < n; i++) {
+ if (one == twos[i])
+ /*
+ * We do not mark this even with RESULT so we do not
+ * have to clean it up.
+ */
+ return commit_list_insert(one, &result);
+ }
+
+ if (parse_commit(one))
+ return NULL;
+ for (i = 0; i < n; i++) {
+ if (parse_commit(twos[i]))
+ return NULL;
+ }
+
+ list = paint_down_to_common(one, n, twos);
+
while (list) {
struct commit_list *next = list->next;
if (!(list->item->object.flags & STALE))
@@ -709,6 +723,62 @@ struct commit_list *get_octopus_merge_bases(struct commit_list *in)
return ret;
}
+static int remove_redundant(struct commit **array, int cnt)
+{
+ /*
+ * Some commit in the array may be an ancestor of
+ * another commit. Move such commit to the end of
+ * the array, and return the number of commits that
+ * are independent from each other.
+ */
+ struct commit **work;
+ unsigned char *redundant;
+ int *filled_index;
+ int i, j, filled;
+
+ work = xcalloc(cnt, sizeof(*work));
+ redundant = xcalloc(cnt, 1);
+ filled_index = xmalloc(sizeof(*filled_index) * (cnt - 1));
+
+ for (i = 0; i < cnt; i++)
+ parse_commit(array[i]);
+ for (i = 0; i < cnt; i++) {
+ struct commit_list *common;
+
+ if (redundant[i])
+ continue;
+ for (j = filled = 0; j < cnt; j++) {
+ if (i == j || redundant[j])
+ continue;
+ filled_index[filled] = j;
+ work[filled++] = array[j];
+ }
+ common = paint_down_to_common(array[i], filled, work);
+ if (array[i]->object.flags & PARENT2)
+ redundant[i] = 1;
+ for (j = 0; j < filled; j++)
+ if (work[j]->object.flags & PARENT1)
+ redundant[filled_index[j]] = 1;
+ clear_commit_marks(array[i], all_flags);
+ for (j = 0; j < filled; j++)
+ clear_commit_marks(work[j], all_flags);
+ free_commit_list(common);
+ }
+
+ /* Now collect the result */
+ memcpy(work, array, sizeof(*array) * cnt);
+ for (i = filled = 0; i < cnt; i++)
+ if (!redundant[i])
+ array[filled++] = work[i];
+ for (j = filled, i = 0; i < cnt; i++)
+ if (redundant[i])
+ array[j++] = work[i];
+ free(work);
+ free(redundant);
+ free(filled_index);
+ return filled;
+}
+
struct commit_list *get_merge_bases_many(struct commit *one,
int n,
struct commit **twos,
@@ -717,7 +787,7 @@ struct commit_list *get_merge_bases_many(struct commit *one,
struct commit_list *list;
struct commit **rslt;
struct commit_list *result;
- int cnt, i, j;
+ int cnt, i;
result = merge_bases_many(one, n, twos);
for (i = 0; i < n; i++) {
@@ -748,28 +818,11 @@ struct commit_list *get_merge_bases_many(struct commit *one,
clear_commit_marks(one, all_flags);
for (i = 0; i < n; i++)
clear_commit_marks(twos[i], all_flags);
- for (i = 0; i < cnt - 1; i++) {
- for (j = i+1; j < cnt; j++) {
- if (!rslt[i] || !rslt[j])
- continue;
- result = merge_bases_many(rslt[i], 1, &rslt[j]);
- clear_commit_marks(rslt[i], all_flags);
- clear_commit_marks(rslt[j], all_flags);
- for (list = result; list; list = list->next) {
- if (rslt[i] == list->item)
- rslt[i] = NULL;
- if (rslt[j] == list->item)
- rslt[j] = NULL;
- }
- }
- }
- /* Surviving ones in rslt[] are the independent results */
+ cnt = remove_redundant(rslt, cnt);
result = NULL;
- for (i = 0; i < cnt; i++) {
- if (rslt[i])
- commit_list_insert_by_date(rslt[i], &result);
- }
+ for (i = 0; i < cnt; i++)
+ commit_list_insert_by_date(rslt[i], &result);
free(rslt);
return result;
}
@@ -780,6 +833,9 @@ struct commit_list *get_merge_bases(struct commit *one, struct commit *two,
return get_merge_bases_many(one, 1, &two, cleanup);
}
+/*
+ * Is "commit" a decendant of one of the elements on the "with_commit" list?
+ */
int is_descendant_of(struct commit *commit, struct commit_list *with_commit)
{
if (!with_commit)
@@ -789,28 +845,28 @@ int is_descendant_of(struct commit *commit, struct commit_list *with_commit)
other = with_commit->item;
with_commit = with_commit->next;
- if (in_merge_bases(other, &commit, 1))
+ if (in_merge_bases(other, commit))
return 1;
}
return 0;
}
-int in_merge_bases(struct commit *commit, struct commit **reference, int num)
+/*
+ * Is "commit" an ancestor of (i.e. reachable from) the "reference"?
+ */
+int in_merge_bases(struct commit *commit, struct commit *reference)
{
- struct commit_list *bases, *b;
+ struct commit_list *bases;
int ret = 0;
- if (num == 1)
- bases = get_merge_bases(commit, *reference, 1);
- else
- die("not yet");
- for (b = bases; b; b = b->next) {
- if (!hashcmp(commit->object.sha1, b->item->object.sha1)) {
- ret = 1;
- break;
- }
- }
+ if (parse_commit(commit) || parse_commit(reference))
+ return ret;
+ bases = paint_down_to_common(commit, 1, &reference);
+ if (commit->object.flags & PARENT2)
+ ret = 1;
+ clear_commit_marks(commit, all_flags);
+ clear_commit_marks(reference, all_flags);
free_commit_list(bases);
return ret;
}
@@ -819,51 +875,31 @@ struct commit_list *reduce_heads(struct commit_list *heads)
{
struct commit_list *p;
struct commit_list *result = NULL, **tail = &result;
- struct commit **other;
- size_t num_head, num_other;
+ struct commit **array;
+ int num_head, i;
if (!heads)
return NULL;
- /* Avoid unnecessary reallocations */
- for (p = heads, num_head = 0; p; p = p->next)
- num_head++;
- other = xcalloc(sizeof(*other), num_head);
-
- /* For each commit, see if it can be reached by others */
- for (p = heads; p; p = p->next) {
- struct commit_list *q, *base;
-
- /* Do we already have this in the result? */
- for (q = result; q; q = q->next)
- if (p->item == q->item)
- break;
- if (q)
+ /* Uniquify */
+ for (p = heads; p; p = p->next)
+ p->item->object.flags &= ~STALE;
+ for (p = heads, num_head = 0; p; p = p->next) {
+ if (p->item->object.flags & STALE)
continue;
-
- num_other = 0;
- for (q = heads; q; q = q->next) {
- if (p->item == q->item)
- continue;
- other[num_other++] = q->item;
+ p->item->object.flags |= STALE;
+ num_head++;
+ }
+ array = xcalloc(sizeof(*array), num_head);
+ for (p = heads, i = 0; p; p = p->next) {
+ if (p->item->object.flags & STALE) {
+ array[i++] = p->item;
+ p->item->object.flags &= ~STALE;
}
- if (num_other)
- base = get_merge_bases_many(p->item, num_other, other, 1);
- else
- base = NULL;
- /*
- * If p->item does not have anything common with other
- * commits, there won't be any merge base. If it is
- * reachable from some of the others, p->item will be
- * the merge base. If its history is connected with
- * others, but p->item is not reachable by others, we
- * will get something other than p->item back.
- */
- if (!base || (base->item != p->item))
- tail = &(commit_list_insert(p->item, tail)->next);
- free_commit_list(base);
}
- free(other);
+ num_head = remove_redundant(array, num_head);
+ for (i = 0; i < num_head; i++)
+ tail = &commit_list_insert(array[i], tail)->next;
return result;
}
@@ -1044,8 +1080,9 @@ static int excluded_header_field(const char *field, size_t len, const char **exc
return 0;
}
-struct commit_extra_header *read_commit_extra_header_lines(const char *buffer, size_t size,
- const char **exclude)
+static struct commit_extra_header *read_commit_extra_header_lines(
+ const char *buffer, size_t size,
+ const char **exclude)
{
struct commit_extra_header *extra = NULL, **tail = &extra, *it = NULL;
const char *line, *next, *eof, *eob;
@@ -1112,8 +1149,92 @@ int commit_tree(const struct strbuf *msg, unsigned char *tree,
return result;
}
+static int find_invalid_utf8(const char *buf, int len)
+{
+ int offset = 0;
+
+ while (len) {
+ unsigned char c = *buf++;
+ int bytes, bad_offset;
+
+ len--;
+ offset++;
+
+ /* Simple US-ASCII? No worries. */
+ if (c < 0x80)
+ continue;
+
+ bad_offset = offset-1;
+
+ /*
+ * Count how many more high bits set: that's how
+ * many more bytes this sequence should have.
+ */
+ bytes = 0;
+ while (c & 0x40) {
+ c <<= 1;
+ bytes++;
+ }
+
+ /* Must be between 1 and 5 more bytes */
+ if (bytes < 1 || bytes > 5)
+ return bad_offset;
+
+ /* Do we *have* that many bytes? */
+ if (len < bytes)
+ return bad_offset;
+
+ offset += bytes;
+ len -= bytes;
+
+ /* And verify that they are good continuation bytes */
+ do {
+ if ((*buf++ & 0xc0) != 0x80)
+ return bad_offset;
+ } while (--bytes);
+
+ /* We could/should check the value and length here too */
+ }
+ return -1;
+}
+
+/*
+ * This verifies that the buffer is in proper utf8 format.
+ *
+ * If it isn't, it assumes any non-utf8 characters are Latin1,
+ * and does the conversion.
+ *
+ * Fixme: we should probably also disallow overlong forms and
+ * invalid characters. But we don't do that currently.
+ */
+static int verify_utf8(struct strbuf *buf)
+{
+ int ok = 1;
+ long pos = 0;
+
+ for (;;) {
+ int bad;
+ unsigned char c;
+ unsigned char replace[2];
+
+ bad = find_invalid_utf8(buf->buf + pos, buf->len - pos);
+ if (bad < 0)
+ return ok;
+ pos += bad;
+ ok = 0;
+ c = buf->buf[pos];
+ strbuf_remove(buf, pos, 1);
+
+ /* We know 'c' must be in the range 128-255 */
+ replace[0] = 0xc0 + (c >> 6);
+ replace[1] = 0x80 + (c & 0x3f);
+ strbuf_insert(buf, pos, replace, 2);
+ pos += 2;
+ }
+}
+
static const char commit_utf8_warn[] =
-"Warning: commit message does not conform to UTF-8.\n"
+"Warning: commit message did not conform to UTF-8.\n"
"You may want to amend it after fixing the message, or set the config\n"
"variable i18n.commitencoding to the encoding your project uses.\n";
@@ -1170,7 +1291,7 @@ int commit_tree_extended(const struct strbuf *msg, unsigned char *tree,
strbuf_addbuf(&buffer, msg);
/* And check the encoding */
- if (encoding_is_utf8 && !is_utf8(buffer.buf))
+ if (encoding_is_utf8 && !verify_utf8(&buffer))
fprintf(stderr, commit_utf8_warn);
if (sign_commit && do_sign_commit(&buffer, sign_commit))
diff --git a/commit.h b/commit.h
index d617fa3..9f21313 100644
--- a/commit.h
+++ b/commit.h
@@ -171,7 +171,7 @@ extern struct commit_list *get_shallow_commits(struct object_array *heads,
int depth, int shallow_flag, int not_shallow_flag);
int is_descendant_of(struct commit *, struct commit_list *);
-int in_merge_bases(struct commit *, struct commit **, int);
+int in_merge_bases(struct commit *, struct commit *);
extern int interactive_add(int argc, const char **argv, const char *prefix, int patch);
extern int run_add_interactive(const char *revision, const char *patch_mode,
@@ -204,7 +204,6 @@ extern int commit_tree_extended(const struct strbuf *msg, unsigned char *tree,
struct commit_extra_header *);
extern struct commit_extra_header *read_commit_extra_headers(struct commit *, const char **);
-extern struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **);
extern void free_commit_extra_headers(struct commit_extra_header *extra);
diff --git a/compat/mkdir.c b/compat/mkdir.c
new file mode 100644
index 0000000..9e253fb
--- /dev/null
+++ b/compat/mkdir.c
@@ -0,0 +1,24 @@
+#include "../git-compat-util.h"
+#undef mkdir
+
+/* for platforms that can't deal with a trailing '/' */
+int compat_mkdir_wo_trailing_slash(const char *dir, mode_t mode)
+{
+ int retval;
+ char *tmp_dir = NULL;
+ size_t len = strlen(dir);
+
+ if (len && dir[len-1] == '/') {
+ if ((tmp_dir = strdup(dir)) == NULL)
+ return -1;
+ tmp_dir[len-1] = '\0';
+ }
+ else
+ tmp_dir = (char *)dir;
+
+ retval = mkdir(tmp_dir, mode);
+ if (tmp_dir != dir)
+ free(tmp_dir);
+
+ return retval;
+}
diff --git a/compat/win32/poll.c b/compat/poll/poll.c
index 403eaa7..7d226ec 100644
--- a/compat/win32/poll.c
+++ b/compat/poll/poll.c
@@ -24,7 +24,9 @@
# pragma GCC diagnostic ignored "-Wtype-limits"
#endif
-#include <malloc.h>
+#if defined(WIN32)
+# include <malloc.h>
+#endif
#include <sys/types.h>
@@ -48,7 +50,9 @@
#else
# include <sys/time.h>
# include <sys/socket.h>
-# include <sys/select.h>
+# ifndef NO_SYS_SELECT_H
+# include <sys/select.h>
+# endif
# include <unistd.h>
#endif
@@ -302,6 +306,10 @@ compute_revents (int fd, int sought, fd_set *rfds, fd_set *wfds, fd_set *efds)
|| socket_errno == ECONNABORTED || socket_errno == ENETRESET)
happened |= POLLHUP;
+ /* some systems can't use recv() on non-socket, including HP NonStop */
+ else if (/* (r == -1) && */ socket_errno == ENOTSOCK)
+ happened |= (POLLIN | POLLRDNORM) & sought;
+
else
happened |= POLLERR;
}
@@ -349,7 +357,7 @@ poll (struct pollfd *pfd, nfds_t nfd, int timeout)
/* EFAULT is not necessary to implement, but let's do it in the
simplest case. */
- if (!pfd)
+ if (!pfd && nfd)
{
errno = EFAULT;
return -1;
diff --git a/compat/win32/poll.h b/compat/poll/poll.h
index b7aa59d..b7aa59d 100644
--- a/compat/win32/poll.h
+++ b/compat/poll/poll.h
diff --git a/compat/precompose_utf8.c b/compat/precompose_utf8.c
new file mode 100644
index 0000000..8cf5955
--- /dev/null
+++ b/compat/precompose_utf8.c
@@ -0,0 +1,184 @@
+/*
+ * Converts filenames from decomposed unicode into precomposed unicode.
+ * Used on MacOS X.
+ */
+
+#define PRECOMPOSE_UNICODE_C
+
+#include "cache.h"
+#include "utf8.h"
+#include "precompose_utf8.h"
+
+typedef char *iconv_ibp;
+static const char *repo_encoding = "UTF-8";
+static const char *path_encoding = "UTF-8-MAC";
+
+static size_t has_non_ascii(const char *s, size_t maxlen, size_t *strlen_c)
+{
+ const uint8_t *ptr = (const uint8_t *)s;
+ size_t strlen_chars = 0;
+ size_t ret = 0;
+
+ if (!ptr || !*ptr)
+ return 0;
+
+ while (*ptr && maxlen) {
+ if (*ptr & 0x80)
+ ret++;
+ strlen_chars++;
+ ptr++;
+ maxlen--;
+ }
+ if (strlen_c)
+ *strlen_c = strlen_chars;
+
+ return ret;
+}
+
+
+void probe_utf8_pathname_composition(char *path, int len)
+{
+ static const char *auml_nfc = "\xc3\xa4";
+ static const char *auml_nfd = "\x61\xcc\x88";
+ int output_fd;
+ if (precomposed_unicode != -1)
+ return; /* We found it defined in the global config, respect it */
+ strcpy(path + len, auml_nfc);
+ output_fd = open(path, O_CREAT|O_EXCL|O_RDWR, 0600);
+ if (output_fd >= 0) {
+ close(output_fd);
+ strcpy(path + len, auml_nfd);
+ /* Indicate to the user, that we can configure it to true */
+ if (!access(path, R_OK))
+ git_config_set("core.precomposeunicode", "false");
+ /* To be backward compatible, set precomposed_unicode to 0 */
+ precomposed_unicode = 0;
+ strcpy(path + len, auml_nfc);
+ if (unlink(path))
+ die_errno(_("failed to unlink '%s'"), path);
+ }
+}
+
+
+void precompose_argv(int argc, const char **argv)
+{
+ int i = 0;
+ const char *oldarg;
+ char *newarg;
+ iconv_t ic_precompose;
+
+ if (precomposed_unicode != 1)
+ return;
+
+ ic_precompose = iconv_open(repo_encoding, path_encoding);
+ if (ic_precompose == (iconv_t) -1)
+ return;
+
+ while (i < argc) {
+ size_t namelen;
+ oldarg = argv[i];
+ if (has_non_ascii(oldarg, (size_t)-1, &namelen)) {
+ newarg = reencode_string_iconv(oldarg, namelen, ic_precompose);
+ if (newarg)
+ argv[i] = newarg;
+ }
+ i++;
+ }
+ iconv_close(ic_precompose);
+}
+
+
+PREC_DIR *precompose_utf8_opendir(const char *dirname)
+{
+ PREC_DIR *prec_dir = xmalloc(sizeof(PREC_DIR));
+ prec_dir->dirent_nfc = xmalloc(sizeof(dirent_prec_psx));
+ prec_dir->dirent_nfc->max_name_len = sizeof(prec_dir->dirent_nfc->d_name);
+
+ prec_dir->dirp = opendir(dirname);
+ if (!prec_dir->dirp) {
+ free(prec_dir->dirent_nfc);
+ free(prec_dir);
+ return NULL;
+ } else {
+ int ret_errno = errno;
+ prec_dir->ic_precompose = iconv_open(repo_encoding, path_encoding);
+ /* if iconv_open() fails, die() in readdir() if needed */
+ errno = ret_errno;
+ }
+
+ return prec_dir;
+}
+
+struct dirent_prec_psx *precompose_utf8_readdir(PREC_DIR *prec_dir)
+{
+ struct dirent *res;
+ res = readdir(prec_dir->dirp);
+ if (res) {
+ size_t namelenz = strlen(res->d_name) + 1; /* \0 */
+ size_t new_maxlen = namelenz;
+
+ int ret_errno = errno;
+
+ if (new_maxlen > prec_dir->dirent_nfc->max_name_len) {
+ size_t new_len = sizeof(dirent_prec_psx) + new_maxlen -
+ sizeof(prec_dir->dirent_nfc->d_name);
+
+ prec_dir->dirent_nfc = xrealloc(prec_dir->dirent_nfc, new_len);
+ prec_dir->dirent_nfc->max_name_len = new_maxlen;
+ }
+
+ prec_dir->dirent_nfc->d_ino = res->d_ino;
+ prec_dir->dirent_nfc->d_type = res->d_type;
+
+ if ((precomposed_unicode == 1) && has_non_ascii(res->d_name, (size_t)-1, NULL)) {
+ if (prec_dir->ic_precompose == (iconv_t)-1) {
+ die("iconv_open(%s,%s) failed, but needed:\n"
+ " precomposed unicode is not supported.\n"
+ " If you wnat to use decomposed unicode, run\n"
+ " \"git config core.precomposeunicode false\"\n",
+ repo_encoding, path_encoding);
+ } else {
+ iconv_ibp cp = (iconv_ibp)res->d_name;
+ size_t inleft = namelenz;
+ char *outpos = &prec_dir->dirent_nfc->d_name[0];
+ size_t outsz = prec_dir->dirent_nfc->max_name_len;
+ size_t cnt;
+ errno = 0;
+ cnt = iconv(prec_dir->ic_precompose, &cp, &inleft, &outpos, &outsz);
+ if (errno || inleft) {
+ /*
+ * iconv() failed and errno could be E2BIG, EILSEQ, EINVAL, EBADF
+ * MacOS X avoids illegal byte sequemces.
+ * If they occur on a mounted drive (e.g. NFS) it is not worth to
+ * die() for that, but rather let the user see the original name
+ */
+ namelenz = 0; /* trigger strlcpy */
+ }
+ }
+ } else
+ namelenz = 0;
+
+ if (!namelenz)
+ strlcpy(prec_dir->dirent_nfc->d_name, res->d_name,
+ prec_dir->dirent_nfc->max_name_len);
+
+ errno = ret_errno;
+ return prec_dir->dirent_nfc;
+ }
+ return NULL;
+}
+
+
+int precompose_utf8_closedir(PREC_DIR *prec_dir)
+{
+ int ret_value;
+ int ret_errno;
+ ret_value = closedir(prec_dir->dirp);
+ ret_errno = errno;
+ if (prec_dir->ic_precompose != (iconv_t)-1)
+ iconv_close(prec_dir->ic_precompose);
+ free(prec_dir->dirent_nfc);
+ free(prec_dir);
+ errno = ret_errno;
+ return ret_value;
+}
diff --git a/compat/precompose_utf8.h b/compat/precompose_utf8.h
new file mode 100644
index 0000000..3b73585
--- /dev/null
+++ b/compat/precompose_utf8.h
@@ -0,0 +1,45 @@
+#ifndef PRECOMPOSE_UNICODE_H
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <iconv.h>
+
+
+typedef struct dirent_prec_psx {
+ ino_t d_ino; /* Posix */
+ size_t max_name_len; /* See below */
+ unsigned char d_type; /* available on all systems git runs on */
+
+ /*
+ * See http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/dirent.h.html
+ * NAME_MAX + 1 should be enough, but some systems have
+ * NAME_MAX=255 and strlen(d_name) may return 508 or 510
+ * Solution: allocate more when needed, see precompose_utf8_readdir()
+ */
+ char d_name[NAME_MAX+1];
+} dirent_prec_psx;
+
+
+typedef struct {
+ iconv_t ic_precompose;
+ DIR *dirp;
+ struct dirent_prec_psx *dirent_nfc;
+} PREC_DIR;
+
+void precompose_argv(int argc, const char **argv);
+void probe_utf8_pathname_composition(char *, int);
+
+PREC_DIR *precompose_utf8_opendir(const char *dirname);
+struct dirent_prec_psx *precompose_utf8_readdir(PREC_DIR *dirp);
+int precompose_utf8_closedir(PREC_DIR *dirp);
+
+#ifndef PRECOMPOSE_UNICODE_C
+#define dirent dirent_prec_psx
+#define opendir(n) precompose_utf8_opendir(n)
+#define readdir(d) precompose_utf8_readdir(d)
+#define closedir(d) precompose_utf8_closedir(d)
+#define DIR PREC_DIR
+#endif /* PRECOMPOSE_UNICODE_C */
+
+#define PRECOMPOSE_UNICODE_H
+#endif /* PRECOMPOSE_UNICODE_H */
diff --git a/config.c b/config.c
index 71ef171..08e47e2 100644
--- a/config.c
+++ b/config.c
@@ -60,7 +60,7 @@ static int handle_path_include(const char *path, struct config_include_data *inc
path = buf.buf;
}
- if (!access(path, R_OK)) {
+ if (!access_or_warn(path, R_OK)) {
if (++inc->depth > MAX_INCLUDE_DEPTH)
die(include_depth_advice, MAX_INCLUDE_DEPTH, path,
cf && cf->name ? cf->name : "the command line");
@@ -758,6 +758,11 @@ static int git_default_core_config(const char *var, const char *value)
return 0;
}
+ if (!strcmp(var, "core.precomposeunicode")) {
+ precomposed_unicode = git_config_bool(var, value);
+ return 0;
+ }
+
/* Add other config variables here and to Documentation/config.txt. */
return 0;
}
@@ -929,25 +934,28 @@ int git_config_system(void)
int git_config_early(config_fn_t fn, void *data, const char *repo_config)
{
int ret = 0, found = 0;
- const char *home = NULL;
+ char *xdg_config = NULL;
+ char *user_config = NULL;
- if (git_config_system() && !access(git_etc_gitconfig(), R_OK)) {
+ home_config_paths(&user_config, &xdg_config, "config");
+
+ if (git_config_system() && !access_or_warn(git_etc_gitconfig(), R_OK)) {
ret += git_config_from_file(fn, git_etc_gitconfig(),
data);
found += 1;
}
- home = getenv("HOME");
- if (home) {
- char buf[PATH_MAX];
- char *user_config = mksnpath(buf, sizeof(buf), "%s/.gitconfig", home);
- if (!access(user_config, R_OK)) {
- ret += git_config_from_file(fn, user_config, data);
- found += 1;
- }
+ if (xdg_config && !access_or_warn(xdg_config, R_OK)) {
+ ret += git_config_from_file(fn, xdg_config, data);
+ found += 1;
+ }
+
+ if (user_config && !access_or_warn(user_config, R_OK)) {
+ ret += git_config_from_file(fn, user_config, data);
+ found += 1;
}
- if (repo_config && !access(repo_config, R_OK)) {
+ if (repo_config && !access_or_warn(repo_config, R_OK)) {
ret += git_config_from_file(fn, repo_config, data);
found += 1;
}
@@ -963,6 +971,8 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
break;
}
+ free(xdg_config);
+ free(user_config);
return ret == 0 ? found : ret;
}
diff --git a/config.mak.in b/config.mak.in
index b2ba710..69d4838 100644
--- a/config.mak.in
+++ b/config.mak.in
@@ -5,12 +5,10 @@ CC = @CC@
CFLAGS = @CFLAGS@
CPPFLAGS = @CPPFLAGS@
LDFLAGS = @LDFLAGS@
-CC_LD_DYNPATH = @CC_LD_DYNPATH@
AR = @AR@
TAR = @TAR@
DIFF = @DIFF@
#INSTALL = @INSTALL@ # needs install-sh or install.sh in sources
-TCLTK_PATH = @TCLTK_PATH@
prefix = @prefix@
exec_prefix = @exec_prefix@
@@ -27,51 +25,3 @@ VPATH = @srcdir@
export exec_prefix mandir
export srcdir VPATH
-
-ASCIIDOC7=@ASCIIDOC7@
-NEEDS_SSL_WITH_CRYPTO=@NEEDS_SSL_WITH_CRYPTO@
-NO_OPENSSL=@NO_OPENSSL@
-NO_CURL=@NO_CURL@
-NO_EXPAT=@NO_EXPAT@
-NO_LIBGEN_H=@NO_LIBGEN_H@
-HAVE_PATHS_H=@HAVE_PATHS_H@
-HAVE_LIBCHARSET_H=@HAVE_LIBCHARSET_H@
-NO_GETTEXT=@NO_GETTEXT@
-LIBC_CONTAINS_LIBINTL=@LIBC_CONTAINS_LIBINTL@
-NEEDS_LIBICONV=@NEEDS_LIBICONV@
-NEEDS_SOCKET=@NEEDS_SOCKET@
-NEEDS_RESOLV=@NEEDS_RESOLV@
-NEEDS_LIBGEN=@NEEDS_LIBGEN@
-NO_SYS_SELECT_H=@NO_SYS_SELECT_H@
-NO_D_INO_IN_DIRENT=@NO_D_INO_IN_DIRENT@
-NO_D_TYPE_IN_DIRENT=@NO_D_TYPE_IN_DIRENT@
-NO_SOCKADDR_STORAGE=@NO_SOCKADDR_STORAGE@
-NO_IPV6=@NO_IPV6@
-NO_HSTRERROR=@NO_HSTRERROR@
-NO_STRCASESTR=@NO_STRCASESTR@
-NO_STRTOK_R=@NO_STRTOK_R@
-NO_FNMATCH=@NO_FNMATCH@
-NO_FNMATCH_CASEFOLD=@NO_FNMATCH_CASEFOLD@
-NO_MEMMEM=@NO_MEMMEM@
-NO_STRLCPY=@NO_STRLCPY@
-NO_UINTMAX_T=@NO_UINTMAX_T@
-NO_STRTOUMAX=@NO_STRTOUMAX@
-NO_SETENV=@NO_SETENV@
-NO_UNSETENV=@NO_UNSETENV@
-NO_MKDTEMP=@NO_MKDTEMP@
-NO_MKSTEMPS=@NO_MKSTEMPS@
-NO_INET_NTOP=@NO_INET_NTOP@
-NO_INET_PTON=@NO_INET_PTON@
-NO_ICONV=@NO_ICONV@
-OLD_ICONV=@OLD_ICONV@
-NO_REGEX=@NO_REGEX@
-USE_LIBPCRE=@USE_LIBPCRE@
-NO_DEFLATE_BOUND=@NO_DEFLATE_BOUND@
-INLINE=@INLINE@
-SOCKLEN_T=@SOCKLEN_T@
-FREAD_READS_DIRECTORIES=@FREAD_READS_DIRECTORIES@
-SNPRINTF_RETURNS_BOGUS=@SNPRINTF_RETURNS_BOGUS@
-NO_PTHREADS=@NO_PTHREADS@
-PTHREAD_CFLAGS=@PTHREAD_CFLAGS@
-PTHREAD_LIBS=@PTHREAD_LIBS@
-CHARSET_LIB=@CHARSET_LIB@
diff --git a/configure.ac b/configure.ac
index e125550..c85888c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3,11 +3,25 @@
## Definitions of private macros.
-# GIT_CONF_APPEND_LINE(LINE)
-# --------------------------
-# Append LINE to file ${config_append}
-AC_DEFUN([GIT_CONF_APPEND_LINE],
- [echo "$1" >> "${config_append}"])
+# GIT_CONF_SUBST(VAL, VAR)
+# ------------------------
+# Cause the line "VAR=VAL" to be eventually appended to ${config_file}.
+AC_DEFUN([GIT_CONF_SUBST],
+[AC_REQUIRE([GIT_CONF_SUBST_INIT])
+config_appended_defs="$config_appended_defs${newline}dnl
+$1=m4_if([$#],[1],[${$1}],[$2])"])
+
+# GIT_CONF_SUBST_INIT
+# -------------------
+# Prepare shell variables and autoconf machine required by later calls
+# to GIT_CONF_SUBST.
+AC_DEFUN([GIT_CONF_SUBST_INIT],
+ [config_appended_defs=; newline='
+'
+ AC_CONFIG_COMMANDS([$config_file],
+ [echo "$config_appended_defs" >> "$config_file"],
+ [config_file=$config_file
+ config_appended_defs="$config_appended_defs"])])
# GIT_ARG_SET_PATH(PROGRAM)
# -------------------------
@@ -29,13 +43,12 @@ AC_DEFUN([GIT_ARG_SET_PATH],
# --without-PROGRAM is used.
AC_DEFUN([GIT_CONF_APPEND_PATH],
[m4_pushdef([GIT_UC_PROGRAM], m4_toupper([$1]))dnl
- PROGRAM=GIT_UC_PROGRAM
if test "$withval" = "no"; then
if test -n "$2"; then
GIT_UC_PROGRAM[]_PATH=$withval
- AC_MSG_NOTICE([Disabling use of ${PROGRAM}])
- GIT_CONF_APPEND_LINE(NO_${PROGRAM}=YesPlease)
- GIT_CONF_APPEND_LINE(${PROGRAM}_PATH=)
+ AC_MSG_NOTICE([Disabling use of GIT_UC_PROGRAM])
+ GIT_CONF_SUBST([NO_]GIT_UC_PROGRAM, [YesPlease])
+ GIT_CONF_SUBST(GIT_UC_PROGRAM[]_PATH, [])
else
AC_MSG_ERROR([You cannot use git without $1])
fi
@@ -45,7 +58,7 @@ AC_DEFUN([GIT_CONF_APPEND_PATH],
else
GIT_UC_PROGRAM[]_PATH=$withval
AC_MSG_NOTICE([Setting GIT_UC_PROGRAM[]_PATH to $withval])
- GIT_CONF_APPEND_LINE(${PROGRAM}_PATH=$withval)
+ GIT_CONF_SUBST(GIT_UC_PROGRAM[]_PATH, [$withval])
fi
fi
m4_popdef([GIT_UC_PROGRAM])])
@@ -58,7 +71,6 @@ AC_DEFUN([GIT_CONF_APPEND_PATH],
# * Unset NO_PACKAGE for --with-PACKAGE without ARG
AC_DEFUN([GIT_PARSE_WITH],
[m4_pushdef([GIT_UC_PACKAGE], m4_toupper([$1]))dnl
- PACKAGE=GIT_UC_PACKAGE
if test "$withval" = "no"; then
NO_[]GIT_UC_PACKAGE=YesPlease
elif test "$withval" = "yes"; then
@@ -67,7 +79,7 @@ AC_DEFUN([GIT_PARSE_WITH],
NO_[]GIT_UC_PACKAGE=
GIT_UC_PACKAGE[]DIR=$withval
AC_MSG_NOTICE([Setting GIT_UC_PACKAGE[]DIR to $withval])
- GIT_CONF_APPEND_LINE(${PACKAGE}DIR=$withval)
+ GIT_CONF_SUBST(GIT_UC_PACKAGE[DIR], [$withval])
fi
m4_popdef([GIT_UC_PACKAGE])])
@@ -87,7 +99,7 @@ AC_DEFUN([GIT_PARSE_WITH_SET_MAKE_VAR],
[a value for $1 ($2). Maybe you do...?])
fi
AC_MSG_NOTICE([Setting $2 to $withval])
- GIT_CONF_APPEND_LINE($2=$withval)
+ GIT_CONF_SUBST([$2], [$withval])
fi)])# GIT_PARSE_WITH_SET_MAKE_VAR
#
@@ -135,10 +147,9 @@ AC_INIT([git], [@@GIT_VERSION@@], [git@vger.kernel.org])
AC_CONFIG_SRCDIR([git.c])
config_file=config.mak.autogen
-config_append=config.mak.append
config_in=config.mak.in
-echo "# ${config_append}. Generated by configure." > "${config_append}"
+GIT_CONF_SUBST([AUTOCONFIGURED], [YesPlease])
# Directories holding "saner" versions of common or POSIX binaries.
AC_ARG_WITH([sane-tool-path],
@@ -150,7 +161,7 @@ AC_ARG_WITH([sane-tool-path],
else
AC_MSG_NOTICE([Setting SANE_TOOL_PATH to '$withval'])
fi
- GIT_CONF_APPEND_LINE([SANE_TOOL_PATH=$withval])],
+ GIT_CONF_SUBST([SANE_TOOL_PATH], [$withval])],
[# If the "--with-sane-tool-path" option was not given, don't touch
# SANE_TOOL_PATH here, but let defaults in Makefile take care of it.
# This should minimize spurious differences in the behaviour of the
@@ -169,7 +180,7 @@ AC_ARG_WITH([lib],
else
lib=$withval
AC_MSG_NOTICE([Setting lib to '$lib'])
- GIT_CONF_APPEND_LINE(lib=$withval)
+ GIT_CONF_SUBST([lib])
fi])
if test -z "$lib"; then
@@ -205,7 +216,7 @@ AC_ARG_ENABLE([jsmin],
[
JSMIN=$enableval;
AC_MSG_NOTICE([Setting JSMIN to '$JSMIN' to enable JavaScript minifying])
- GIT_CONF_APPEND_LINE(JSMIN=$enableval);
+ GIT_CONF_SUBST([JSMIN])
])
# Define option to enable CSS minification
@@ -215,7 +226,7 @@ AC_ARG_ENABLE([cssmin],
[
CSSMIN=$enableval;
AC_MSG_NOTICE([Setting CSSMIN to '$CSSMIN' to enable CSS minifying])
- GIT_CONF_APPEND_LINE(CSSMIN=$enableval);
+ GIT_CONF_SUBST([CSSMIN])
])
## Site configuration (override autodetection)
@@ -255,8 +266,10 @@ AS_HELP_STRING([], [ARG can be also prefix for libpcre library and hea
else
USE_LIBPCRE=YesPlease
LIBPCREDIR=$withval
- AC_MSG_NOTICE([Setting LIBPCREDIR to $withval])
- GIT_CONF_APPEND_LINE(LIBPCREDIR=$withval)
+ AC_MSG_NOTICE([Setting LIBPCREDIR to $LIBPCREDIR])
+ dnl USE_LIBPCRE can still be modified below, so don't substitute
+ dnl it yet.
+ GIT_CONF_SUBST([LIBPCREDIR])
fi)
#
# Define NO_CURL if you do not have curl installed. git-http-pull and
@@ -376,9 +389,10 @@ AC_MSG_NOTICE([CHECKS for programs])
AC_PROG_CC([cc gcc])
AC_C_INLINE
case $ac_cv_c_inline in
- inline | yes | no) ;;
- *) AC_SUBST([INLINE], [$ac_cv_c_inline]) ;;
+ inline | yes | no) INLINE='';;
+ *) INLINE=$ac_cv_c_inline ;;
esac
+GIT_CONF_SUBST([INLINE])
# which switch to pass runtime path to dynamic libraries to the linker
AC_CACHE_CHECK([if linker supports -R], git_cv_ld_dashr, [
@@ -388,7 +402,7 @@ AC_CACHE_CHECK([if linker supports -R], git_cv_ld_dashr, [
LDFLAGS="${SAVE_LDFLAGS}"
])
if test "$git_cv_ld_dashr" = "yes"; then
- AC_SUBST(CC_LD_DYNPATH, [-R])
+ CC_LD_DYNPATH=-R
else
AC_CACHE_CHECK([if linker supports -Wl,-rpath,], git_cv_ld_wl_rpath, [
SAVE_LDFLAGS="${LDFLAGS}"
@@ -397,7 +411,7 @@ else
LDFLAGS="${SAVE_LDFLAGS}"
])
if test "$git_cv_ld_wl_rpath" = "yes"; then
- AC_SUBST(CC_LD_DYNPATH, [-Wl,-rpath,])
+ CC_LD_DYNPATH=-Wl,-rpath,
else
AC_CACHE_CHECK([if linker supports -rpath], git_cv_ld_rpath, [
SAVE_LDFLAGS="${LDFLAGS}"
@@ -406,52 +420,48 @@ else
LDFLAGS="${SAVE_LDFLAGS}"
])
if test "$git_cv_ld_rpath" = "yes"; then
- AC_SUBST(CC_LD_DYNPATH, [-rpath])
+ CC_LD_DYNPATH=-rpath
else
+ CC_LD_DYNPATH=
AC_MSG_WARN([linker does not support runtime path to dynamic libraries])
fi
fi
fi
+GIT_CONF_SUBST([CC_LD_DYNPATH])
#AC_PROG_INSTALL # needs install-sh or install.sh in sources
AC_CHECK_TOOLS(AR, [gar ar], :)
AC_CHECK_PROGS(TAR, [gtar tar])
AC_CHECK_PROGS(DIFF, [gnudiff gdiff diff])
# TCLTK_PATH will be set to some value if we want Tcl/Tk
# or will be empty otherwise.
-if test -z "$NO_TCLTK"; then
+if test -n "$NO_TCLTK"; then
+ TCLTK_PATH=
+else
if test "$with_tcltk" = ""; then
# No Tcl/Tk switches given. Do not check for Tcl/Tk, use bare 'wish'.
TCLTK_PATH=wish
- AC_SUBST(TCLTK_PATH)
elif test "$with_tcltk" = "yes"; then
# Tcl/Tk check requested.
AC_CHECK_PROGS(TCLTK_PATH, [wish], )
else
AC_MSG_RESULT([Using Tcl/Tk interpreter $with_tcltk])
TCLTK_PATH="$with_tcltk"
- AC_SUBST(TCLTK_PATH)
fi
fi
+GIT_CONF_SUBST([TCLTK_PATH])
AC_CHECK_PROGS(ASCIIDOC, [asciidoc])
if test -n "$ASCIIDOC"; then
AC_MSG_CHECKING([for asciidoc version])
asciidoc_version=`$ASCIIDOC --version 2>/dev/null`
case "${asciidoc_version}" in
- asciidoc' '7*)
- ASCIIDOC7=YesPlease
- AC_MSG_RESULT([${asciidoc_version} > 7])
- ;;
asciidoc' '8*)
- ASCIIDOC7=
AC_MSG_RESULT([${asciidoc_version}])
;;
*)
- ASCIIDOC7=
AC_MSG_RESULT([${asciidoc_version} (unknown)])
;;
esac
fi
-AC_SUBST(ASCIIDOC7)
## Checks for libraries.
@@ -465,13 +475,13 @@ GIT_STASH_FLAGS($OPENSSLDIR)
AC_CHECK_LIB([crypto], [SHA1_Init],
[NEEDS_SSL_WITH_CRYPTO=],
[AC_CHECK_LIB([ssl], [SHA1_Init],
- [NEEDS_SSL_WITH_CRYPTO=YesPlease],
- [NEEDS_SSL_WITH_CRYPTO= NO_OPENSSL=YesPlease])])
+ [NEEDS_SSL_WITH_CRYPTO=YesPlease NO_OPENSSL=],
+ [NEEDS_SSL_WITH_CRYPTO= NO_OPENSSL=YesPlease])])
GIT_UNSTASH_FLAGS($OPENSSLDIR)
-AC_SUBST(NEEDS_SSL_WITH_CRYPTO)
-AC_SUBST(NO_OPENSSL)
+GIT_CONF_SUBST([NEEDS_SSL_WITH_CRYPTO])
+GIT_CONF_SUBST([NO_OPENSSL])
#
# Define USE_LIBPCRE if you have and want to use libpcre. git-grep will be
@@ -488,7 +498,7 @@ AC_CHECK_LIB([pcre], [pcre_version],
GIT_UNSTASH_FLAGS($LIBPCREDIR)
-AC_SUBST(USE_LIBPCRE)
+GIT_CONF_SUBST([USE_LIBPCRE])
fi
@@ -505,7 +515,7 @@ AC_CHECK_LIB([curl], [curl_global_init],
GIT_UNSTASH_FLAGS($CURLDIR)
-AC_SUBST(NO_CURL)
+GIT_CONF_SUBST([NO_CURL])
#
# Define NO_EXPAT if you do not have expat installed. git-http-push is
@@ -519,7 +529,7 @@ AC_CHECK_LIB([expat], [XML_ParserCreate],
GIT_UNSTASH_FLAGS($EXPATDIR)
-AC_SUBST(NO_EXPAT)
+GIT_CONF_SUBST([NO_EXPAT])
#
# Define NEEDS_LIBICONV if linking with libc is not enough (Darwin and
@@ -565,8 +575,8 @@ LIBS="$old_LIBS"
GIT_UNSTASH_FLAGS($ICONVDIR)
-AC_SUBST(NEEDS_LIBICONV)
-AC_SUBST(NO_ICONV)
+GIT_CONF_SUBST([NEEDS_LIBICONV])
+GIT_CONF_SUBST([NO_ICONV])
if test -n "$NO_ICONV"; then
NEEDS_LIBICONV=
@@ -593,7 +603,7 @@ LIBS="$old_LIBS"
GIT_UNSTASH_FLAGS($ZLIB_PATH)
-AC_SUBST(NO_DEFLATE_BOUND)
+GIT_CONF_SUBST([NO_DEFLATE_BOUND])
#
# Define NEEDS_SOCKET if linking with libc is not enough (SunOS,
@@ -601,7 +611,7 @@ AC_SUBST(NO_DEFLATE_BOUND)
AC_CHECK_LIB([c], [socket],
[NEEDS_SOCKET=],
[NEEDS_SOCKET=YesPlease])
-AC_SUBST(NEEDS_SOCKET)
+GIT_CONF_SUBST([NEEDS_SOCKET])
test -n "$NEEDS_SOCKET" && LIBS="$LIBS -lsocket"
#
@@ -609,40 +619,43 @@ test -n "$NEEDS_SOCKET" && LIBS="$LIBS -lsocket"
# libresolv provides some of the functions we would normally get
# from libc.
NEEDS_RESOLV=
-AC_SUBST(NEEDS_RESOLV)
#
# Define NO_INET_NTOP if linking with -lresolv is not enough.
# Solaris 2.7 in particular hos inet_ntop in -lresolv.
NO_INET_NTOP=
-AC_SUBST(NO_INET_NTOP)
AC_CHECK_FUNC([inet_ntop],
- [],
+ [],
[AC_CHECK_LIB([resolv], [inet_ntop],
- [NEEDS_RESOLV=YesPlease],
+ [NEEDS_RESOLV=YesPlease],
[NO_INET_NTOP=YesPlease])
])
+GIT_CONF_SUBST([NO_INET_NTOP])
#
# Define NO_INET_PTON if linking with -lresolv is not enough.
# Solaris 2.7 in particular hos inet_pton in -lresolv.
NO_INET_PTON=
-AC_SUBST(NO_INET_PTON)
AC_CHECK_FUNC([inet_pton],
- [],
+ [],
[AC_CHECK_LIB([resolv], [inet_pton],
- [NEEDS_RESOLV=YesPlease],
+ [NEEDS_RESOLV=YesPlease],
[NO_INET_PTON=YesPlease])
])
+GIT_CONF_SUBST([NO_INET_PTON])
#
# Define NO_HSTRERROR if linking with -lresolv is not enough.
# Solaris 2.6 in particular has no hstrerror, even in -lresolv.
NO_HSTRERROR=
AC_CHECK_FUNC([hstrerror],
- [],
+ [],
[AC_CHECK_LIB([resolv], [hstrerror],
- [NEEDS_RESOLV=YesPlease],
+ [NEEDS_RESOLV=YesPlease],
[NO_HSTRERROR=YesPlease])
])
-AC_SUBST(NO_HSTRERROR)
+GIT_CONF_SUBST([NO_HSTRERROR])
+
+dnl This must go after all the possible places for its initialization,
+dnl in the AC_CHECK_FUNC invocations above.
+GIT_CONF_SUBST([NEEDS_RESOLV])
#
# If any of the above tests determined that -lresolv is needed at
# build-time, also set it here for remaining configure-time checks.
@@ -651,13 +664,13 @@ test -n "$NEEDS_RESOLV" && LIBS="$LIBS -lresolv"
AC_CHECK_LIB([c], [basename],
[NEEDS_LIBGEN=],
[NEEDS_LIBGEN=YesPlease])
-AC_SUBST(NEEDS_LIBGEN)
+GIT_CONF_SUBST([NEEDS_LIBGEN])
test -n "$NEEDS_LIBGEN" && LIBS="$LIBS -lgen"
AC_CHECK_LIB([c], [gettext],
[LIBC_CONTAINS_LIBINTL=YesPlease],
[LIBC_CONTAINS_LIBINTL=])
-AC_SUBST(LIBC_CONTAINS_LIBINTL)
+GIT_CONF_SUBST([LIBC_CONTAINS_LIBINTL])
#
# Define NO_GETTEXT if you don't want Git output to be translated.
@@ -665,7 +678,7 @@ AC_SUBST(LIBC_CONTAINS_LIBINTL)
AC_CHECK_HEADER([libintl.h],
[NO_GETTEXT=],
[NO_GETTEXT=YesPlease])
-AC_SUBST(NO_GETTEXT)
+GIT_CONF_SUBST([NO_GETTEXT])
if test -z "$NO_GETTEXT"; then
test -n "$LIBC_CONTAINS_LIBINTL" || LIBS="$LIBS -lintl"
@@ -678,19 +691,19 @@ AC_MSG_NOTICE([CHECKS for header files])
AC_CHECK_HEADER([sys/select.h],
[NO_SYS_SELECT_H=],
[NO_SYS_SELECT_H=UnfortunatelyYes])
-AC_SUBST(NO_SYS_SELECT_H)
+GIT_CONF_SUBST([NO_SYS_SELECT_H])
#
# Define NO_SYS_POLL_H if you don't have sys/poll.h
AC_CHECK_HEADER([sys/poll.h],
[NO_SYS_POLL_H=],
[NO_SYS_POLL_H=UnfortunatelyYes])
-AC_SUBST(NO_SYS_POLL_H)
+GIT_CONF_SUBST([NO_SYS_POLL_H])
#
# Define NO_INTTYPES_H if you don't have inttypes.h
AC_CHECK_HEADER([inttypes.h],
[NO_INTTYPES_H=],
[NO_INTTYPES_H=UnfortunatelyYes])
-AC_SUBST(NO_INTTYPES_H)
+GIT_CONF_SUBST([NO_INTTYPES_H])
#
# Define OLD_ICONV if your library has an old iconv(), where the second
# (input buffer pointer) parameter is declared with type (const char **).
@@ -713,23 +726,24 @@ AC_COMPILE_IFELSE([OLDICONVTEST_SRC],
GIT_UNSTASH_FLAGS($ICONVDIR)
-AC_SUBST(OLD_ICONV)
+GIT_CONF_SUBST([OLD_ICONV])
## Checks for typedefs, structures, and compiler characteristics.
AC_MSG_NOTICE([CHECKS for typedefs, structures, and compiler characteristics])
#
TYPE_SOCKLEN_T
case $ac_cv_type_socklen_t in
- yes) ;;
- *) AC_SUBST([SOCKLEN_T], [$git_cv_socklen_t_equiv]) ;;
+ yes) SOCKLEN_T='';;
+ *) SOCKLEN_T=$git_cv_socklen_t_equiv;;
esac
+GIT_CONF_SUBST([SOCKLEN_T])
# Define NO_D_INO_IN_DIRENT if you don't have d_ino in your struct dirent.
AC_CHECK_MEMBER(struct dirent.d_ino,
[NO_D_INO_IN_DIRENT=],
[NO_D_INO_IN_DIRENT=YesPlease],
[#include <dirent.h>])
-AC_SUBST(NO_D_INO_IN_DIRENT)
+GIT_CONF_SUBST([NO_D_INO_IN_DIRENT])
#
# Define NO_D_TYPE_IN_DIRENT if your platform defines DT_UNKNOWN but lacks
# d_type in struct dirent (latest Cygwin -- will be fixed soonish).
@@ -737,7 +751,7 @@ AC_CHECK_MEMBER(struct dirent.d_type,
[NO_D_TYPE_IN_DIRENT=],
[NO_D_TYPE_IN_DIRENT=YesPlease],
[#include <dirent.h>])
-AC_SUBST(NO_D_TYPE_IN_DIRENT)
+GIT_CONF_SUBST([NO_D_TYPE_IN_DIRENT])
#
# Define NO_SOCKADDR_STORAGE if your platform does not have struct
# sockaddr_storage.
@@ -747,7 +761,7 @@ AC_CHECK_TYPE(struct sockaddr_storage,
#include <sys/types.h>
#include <sys/socket.h>
])
-AC_SUBST(NO_SOCKADDR_STORAGE)
+GIT_CONF_SUBST([NO_SOCKADDR_STORAGE])
#
# Define NO_IPV6 if you lack IPv6 support and getaddrinfo().
AC_CHECK_TYPE([struct addrinfo],[
@@ -759,7 +773,7 @@ AC_CHECK_TYPE([struct addrinfo],[
#include <sys/socket.h>
#include <netdb.h>
])
-AC_SUBST(NO_IPV6)
+GIT_CONF_SUBST([NO_IPV6])
#
# Define NO_REGEX if you have no or inferior regex support in your C library.
AC_CACHE_CHECK([whether the platform regex can handle null bytes],
@@ -780,7 +794,7 @@ if test $ac_cv_c_excellent_regex = yes; then
else
NO_REGEX=YesPlease
fi
-AC_SUBST(NO_REGEX)
+GIT_CONF_SUBST([NO_REGEX])
#
# Define FREAD_READS_DIRECTORIES if your are on a system which succeeds
# when attempting to read from an fopen'ed directory.
@@ -800,7 +814,7 @@ if test $ac_cv_fread_reads_directories = yes; then
else
FREAD_READS_DIRECTORIES=
fi
-AC_SUBST(FREAD_READS_DIRECTORIES)
+GIT_CONF_SUBST([FREAD_READS_DIRECTORIES])
#
# Define SNPRINTF_RETURNS_BOGUS if your are on a system which snprintf()
# or vsnprintf() return -1 instead of number of characters which would
@@ -834,7 +848,7 @@ if test $ac_cv_snprintf_returns_bogus = yes; then
else
SNPRINTF_RETURNS_BOGUS=
fi
-AC_SUBST(SNPRINTF_RETURNS_BOGUS)
+GIT_CONF_SUBST([SNPRINTF_RETURNS_BOGUS])
## Checks for library functions.
@@ -845,47 +859,45 @@ AC_MSG_NOTICE([CHECKS for library functions])
AC_CHECK_HEADER([libgen.h],
[NO_LIBGEN_H=],
[NO_LIBGEN_H=YesPlease])
-AC_SUBST(NO_LIBGEN_H)
+GIT_CONF_SUBST([NO_LIBGEN_H])
#
# Define HAVE_PATHS_H if you have paths.h.
AC_CHECK_HEADER([paths.h],
[HAVE_PATHS_H=YesPlease],
[HAVE_PATHS_H=])
-AC_SUBST(HAVE_PATHS_H)
+GIT_CONF_SUBST([HAVE_PATHS_H])
#
# Define HAVE_LIBCHARSET_H if have libcharset.h
AC_CHECK_HEADER([libcharset.h],
[HAVE_LIBCHARSET_H=YesPlease],
[HAVE_LIBCHARSET_H=])
-AC_SUBST(HAVE_LIBCHARSET_H)
+GIT_CONF_SUBST([HAVE_LIBCHARSET_H])
# Define CHARSET_LIB if libiconv does not export the locale_charset symbol
# and libcharset does
CHARSET_LIB=
AC_CHECK_LIB([iconv], [locale_charset],
[],
[AC_CHECK_LIB([charset], [locale_charset],
- [CHARSET_LIB=-lcharset])
- ]
-)
-AC_SUBST(CHARSET_LIB)
+ [CHARSET_LIB=-lcharset])])
+GIT_CONF_SUBST([CHARSET_LIB])
#
# Define NO_STRCASESTR if you don't have strcasestr.
GIT_CHECK_FUNC(strcasestr,
[NO_STRCASESTR=],
[NO_STRCASESTR=YesPlease])
-AC_SUBST(NO_STRCASESTR)
+GIT_CONF_SUBST([NO_STRCASESTR])
#
# Define NO_STRTOK_R if you don't have strtok_r
GIT_CHECK_FUNC(strtok_r,
[NO_STRTOK_R=],
[NO_STRTOK_R=YesPlease])
-AC_SUBST(NO_STRTOK_R)
+GIT_CONF_SUBST([NO_STRTOK_R])
#
# Define NO_FNMATCH if you don't have fnmatch
GIT_CHECK_FUNC(fnmatch,
[NO_FNMATCH=],
[NO_FNMATCH=YesPlease])
-AC_SUBST(NO_FNMATCH)
+GIT_CONF_SUBST([NO_FNMATCH])
#
# Define NO_FNMATCH_CASEFOLD if your fnmatch function doesn't have the
# FNM_CASEFOLD GNU extension.
@@ -907,19 +919,19 @@ if test $ac_cv_c_excellent_fnmatch = yes; then
else
NO_FNMATCH_CASEFOLD=YesPlease
fi
-AC_SUBST(NO_FNMATCH_CASEFOLD)
+GIT_CONF_SUBST([NO_FNMATCH_CASEFOLD])
#
# Define NO_MEMMEM if you don't have memmem.
GIT_CHECK_FUNC(memmem,
[NO_MEMMEM=],
[NO_MEMMEM=YesPlease])
-AC_SUBST(NO_MEMMEM)
+GIT_CONF_SUBST([NO_MEMMEM])
#
# Define NO_STRLCPY if you don't have strlcpy.
GIT_CHECK_FUNC(strlcpy,
[NO_STRLCPY=],
[NO_STRLCPY=YesPlease])
-AC_SUBST(NO_STRLCPY)
+GIT_CONF_SUBST([NO_STRLCPY])
#
# Define NO_UINTMAX_T if your platform does not have uintmax_t
AC_CHECK_TYPE(uintmax_t,
@@ -927,43 +939,43 @@ AC_CHECK_TYPE(uintmax_t,
[NO_UINTMAX_T=YesPlease],[
#include <inttypes.h>
])
-AC_SUBST(NO_UINTMAX_T)
+GIT_CONF_SUBST([NO_UINTMAX_T])
#
# Define NO_STRTOUMAX if you don't have strtoumax in the C library.
GIT_CHECK_FUNC(strtoumax,
[NO_STRTOUMAX=],
[NO_STRTOUMAX=YesPlease])
-AC_SUBST(NO_STRTOUMAX)
+GIT_CONF_SUBST([NO_STRTOUMAX])
#
# Define NO_SETENV if you don't have setenv in the C library.
GIT_CHECK_FUNC(setenv,
[NO_SETENV=],
[NO_SETENV=YesPlease])
-AC_SUBST(NO_SETENV)
+GIT_CONF_SUBST([NO_SETENV])
#
# Define NO_UNSETENV if you don't have unsetenv in the C library.
GIT_CHECK_FUNC(unsetenv,
[NO_UNSETENV=],
[NO_UNSETENV=YesPlease])
-AC_SUBST(NO_UNSETENV)
+GIT_CONF_SUBST([NO_UNSETENV])
#
# Define NO_MKDTEMP if you don't have mkdtemp in the C library.
GIT_CHECK_FUNC(mkdtemp,
[NO_MKDTEMP=],
[NO_MKDTEMP=YesPlease])
-AC_SUBST(NO_MKDTEMP)
+GIT_CONF_SUBST([NO_MKDTEMP])
#
# Define NO_MKSTEMPS if you don't have mkstemps in the C library.
GIT_CHECK_FUNC(mkstemps,
[NO_MKSTEMPS=],
[NO_MKSTEMPS=YesPlease])
-AC_SUBST(NO_MKSTEMPS)
+GIT_CONF_SUBST([NO_MKSTEMPS])
#
# Define NO_INITGROUPS if you don't have initgroups in the C library.
GIT_CHECK_FUNC(initgroups,
[NO_INITGROUPS=],
[NO_INITGROUPS=YesPlease])
-AC_SUBST(NO_INITGROUPS)
+GIT_CONF_SUBST([NO_INITGROUPS])
#
#
# Define NO_MMAP if you want to avoid mmap.
@@ -1045,14 +1057,10 @@ fi
CFLAGS="$old_CFLAGS"
-AC_SUBST(PTHREAD_CFLAGS)
-AC_SUBST(PTHREAD_LIBS)
-AC_SUBST(NO_PTHREADS)
+GIT_CONF_SUBST([PTHREAD_CFLAGS])
+GIT_CONF_SUBST([PTHREAD_LIBS])
+GIT_CONF_SUBST([NO_PTHREADS])
## Output files
-AC_CONFIG_FILES(["${config_file}":"${config_in}":"${config_append}"])
+AC_CONFIG_FILES(["${config_file}":"${config_in}"])
AC_OUTPUT
-
-
-## Cleanup
-rm -f "${config_append}"
diff --git a/connect.c b/connect.c
index 41b7400..49e56ba 100644
--- a/connect.c
+++ b/connect.c
@@ -49,6 +49,16 @@ static void add_extra_have(struct extra_have_objects *extra, unsigned char *sha1
extra->nr++;
}
+static void die_initial_contact(int got_at_least_one_head)
+{
+ if (got_at_least_one_head)
+ die("The remote end hung up upon initial contact");
+ else
+ die("Could not read from remote repository.\n\n"
+ "Please make sure you have the correct access rights\n"
+ "and the repository exists.");
+}
+
/*
* Read all the refs from the other end
*/
@@ -56,6 +66,8 @@ struct ref **get_remote_heads(int in, struct ref **list,
unsigned int flags,
struct extra_have_objects *extra_have)
{
+ int got_at_least_one_head = 0;
+
*list = NULL;
for (;;) {
struct ref *ref;
@@ -64,7 +76,10 @@ struct ref **get_remote_heads(int in, struct ref **list,
char *name;
int len, name_len;
- len = packet_read_line(in, buffer, sizeof(buffer));
+ len = packet_read(in, buffer, sizeof(buffer));
+ if (len < 0)
+ die_initial_contact(got_at_least_one_head);
+
if (!len)
break;
if (buffer[len-1] == '\n')
@@ -95,16 +110,12 @@ struct ref **get_remote_heads(int in, struct ref **list,
hashcpy(ref->old_sha1, old_sha1);
*list = ref;
list = &ref->next;
+ got_at_least_one_head = 1;
}
return list;
}
-int server_supports(const char *feature)
-{
- return !!parse_feature_request(server_capabilities, feature);
-}
-
-const char *parse_feature_request(const char *feature_list, const char *feature)
+const char *parse_feature_value(const char *feature_list, const char *feature, int *lenp)
{
int len;
@@ -116,14 +127,46 @@ const char *parse_feature_request(const char *feature_list, const char *feature)
const char *found = strstr(feature_list, feature);
if (!found)
return NULL;
- if ((feature_list == found || isspace(found[-1])) &&
- (!found[len] || isspace(found[len]) || found[len] == '='))
- return found;
+ if (feature_list == found || isspace(found[-1])) {
+ const char *value = found + len;
+ /* feature with no value (e.g., "thin-pack") */
+ if (!*value || isspace(*value)) {
+ if (lenp)
+ *lenp = 0;
+ return value;
+ }
+ /* feature with a value (e.g., "agent=git/1.2.3") */
+ else if (*value == '=') {
+ value++;
+ if (lenp)
+ *lenp = strcspn(value, " \t\n");
+ return value;
+ }
+ /*
+ * otherwise we matched a substring of another feature;
+ * keep looking
+ */
+ }
feature_list = found + 1;
}
return NULL;
}
+int parse_feature_request(const char *feature_list, const char *feature)
+{
+ return !!parse_feature_value(feature_list, feature, NULL);
+}
+
+const char *server_feature_value(const char *feature, int *len)
+{
+ return parse_feature_value(server_capabilities, feature, len);
+}
+
+int server_supports(const char *feature)
+{
+ return !!server_feature_value(feature, NULL);
+}
+
enum protocol {
PROTO_LOCAL = 1,
PROTO_SSH,
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 2e1b5e1..be800e0 100755..100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -20,46 +20,8 @@
# 1) Copy this file to somewhere (e.g. ~/.git-completion.sh).
# 2) Add the following line to your .bashrc/.zshrc:
# source ~/.git-completion.sh
-#
-# 3) Consider changing your PS1 to also show the current branch:
-# Bash: PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '
-# ZSH: PS1='[%n@%m %c$(__git_ps1 " (%s)")]\$ '
-#
-# The argument to __git_ps1 will be displayed only if you
-# are currently in a git repository. The %s token will be
-# the name of the current branch.
-#
-# In addition, if you set GIT_PS1_SHOWDIRTYSTATE to a nonempty
-# value, unstaged (*) and staged (+) changes will be shown next
-# to the branch name. You can configure this per-repository
-# with the bash.showDirtyState variable, which defaults to true
-# once GIT_PS1_SHOWDIRTYSTATE is enabled.
-#
-# You can also see if currently something is stashed, by setting
-# GIT_PS1_SHOWSTASHSTATE to a nonempty value. If something is stashed,
-# then a '$' will be shown next to the branch name.
-#
-# If you would like to see if there're untracked files, then you can
-# set GIT_PS1_SHOWUNTRACKEDFILES to a nonempty value. If there're
-# untracked files, then a '%' will be shown next to the branch name.
-#
-# If you would like to see the difference between HEAD and its
-# upstream, set GIT_PS1_SHOWUPSTREAM="auto". A "<" indicates
-# you are behind, ">" indicates you are ahead, and "<>"
-# indicates you have diverged. You can further control
-# behaviour by setting GIT_PS1_SHOWUPSTREAM to a space-separated
-# list of values:
-# verbose show number of commits ahead/behind (+/-) upstream
-# legacy don't use the '--count' option available in recent
-# versions of git-rev-list
-# git always compare HEAD to @{upstream}
-# svn always compare HEAD to your SVN upstream
-# By default, __git_ps1 will compare HEAD to your SVN upstream
-# if it can find one, or @{upstream} otherwise. Once you have
-# set GIT_PS1_SHOWUPSTREAM, you can override it on a
-# per-repository basis by setting the bash.showUpstream config
-# variable.
-#
+# 3) Consider changing your PS1 to also show the current branch,
+# see git-prompt.sh for details.
if [[ -n ${ZSH_VERSION-} ]]; then
autoload -U +X bashcompinit && bashcompinit
@@ -74,9 +36,14 @@ esac
# returns location of .git repo
__gitdir ()
{
+ # Note: this function is duplicated in git-prompt.sh
+ # When updating it, make sure you update the other one to match.
if [ -z "${1-}" ]; then
if [ -n "${__git_dir-}" ]; then
echo "$__git_dir"
+ elif [ -n "${GIT_DIR-}" ]; then
+ test -d "${GIT_DIR-}" || return 1
+ echo "$GIT_DIR"
elif [ -d .git ]; then
echo .git
else
@@ -89,221 +56,6 @@ __gitdir ()
fi
}
-# stores the divergence from upstream in $p
-# used by GIT_PS1_SHOWUPSTREAM
-__git_ps1_show_upstream ()
-{
- local key value
- local svn_remote svn_url_pattern count n
- local upstream=git legacy="" verbose=""
-
- svn_remote=()
- # get some config options from git-config
- local output="$(git config -z --get-regexp '^(svn-remote\..*\.url|bash\.showupstream)$' 2>/dev/null | tr '\0\n' '\n ')"
- while read -r key value; do
- case "$key" in
- bash.showupstream)
- GIT_PS1_SHOWUPSTREAM="$value"
- if [[ -z "${GIT_PS1_SHOWUPSTREAM}" ]]; then
- p=""
- return
- fi
- ;;
- svn-remote.*.url)
- svn_remote[ $((${#svn_remote[@]} + 1)) ]="$value"
- svn_url_pattern+="\\|$value"
- upstream=svn+git # default upstream is SVN if available, else git
- ;;
- esac
- done <<< "$output"
-
- # parse configuration values
- for option in ${GIT_PS1_SHOWUPSTREAM}; do
- case "$option" in
- git|svn) upstream="$option" ;;
- verbose) verbose=1 ;;
- legacy) legacy=1 ;;
- esac
- done
-
- # Find our upstream
- case "$upstream" in
- git) upstream="@{upstream}" ;;
- svn*)
- # get the upstream from the "git-svn-id: ..." in a commit message
- # (git-svn uses essentially the same procedure internally)
- local svn_upstream=($(git log --first-parent -1 \
- --grep="^git-svn-id: \(${svn_url_pattern#??}\)" 2>/dev/null))
- if [[ 0 -ne ${#svn_upstream[@]} ]]; then
- svn_upstream=${svn_upstream[ ${#svn_upstream[@]} - 2 ]}
- svn_upstream=${svn_upstream%@*}
- local n_stop="${#svn_remote[@]}"
- for ((n=1; n <= n_stop; n++)); do
- svn_upstream=${svn_upstream#${svn_remote[$n]}}
- done
-
- if [[ -z "$svn_upstream" ]]; then
- # default branch name for checkouts with no layout:
- upstream=${GIT_SVN_ID:-git-svn}
- else
- upstream=${svn_upstream#/}
- fi
- elif [[ "svn+git" = "$upstream" ]]; then
- upstream="@{upstream}"
- fi
- ;;
- esac
-
- # Find how many commits we are ahead/behind our upstream
- if [[ -z "$legacy" ]]; then
- count="$(git rev-list --count --left-right \
- "$upstream"...HEAD 2>/dev/null)"
- else
- # produce equivalent output to --count for older versions of git
- local commits
- if commits="$(git rev-list --left-right "$upstream"...HEAD 2>/dev/null)"
- then
- local commit behind=0 ahead=0
- for commit in $commits
- do
- case "$commit" in
- "<"*) ((behind++)) ;;
- *) ((ahead++)) ;;
- esac
- done
- count="$behind $ahead"
- else
- count=""
- fi
- fi
-
- # calculate the result
- if [[ -z "$verbose" ]]; then
- case "$count" in
- "") # no upstream
- p="" ;;
- "0 0") # equal to upstream
- p="=" ;;
- "0 "*) # ahead of upstream
- p=">" ;;
- *" 0") # behind upstream
- p="<" ;;
- *) # diverged from upstream
- p="<>" ;;
- esac
- else
- case "$count" in
- "") # no upstream
- p="" ;;
- "0 0") # equal to upstream
- p=" u=" ;;
- "0 "*) # ahead of upstream
- p=" u+${count#0 }" ;;
- *" 0") # behind upstream
- p=" u-${count% 0}" ;;
- *) # diverged from upstream
- p=" u+${count#* }-${count% *}" ;;
- esac
- fi
-
-}
-
-
-# __git_ps1 accepts 0 or 1 arguments (i.e., format string)
-# returns text to add to bash PS1 prompt (includes branch name)
-__git_ps1 ()
-{
- local g="$(__gitdir)"
- if [ -n "$g" ]; then
- local r=""
- local b=""
- if [ -f "$g/rebase-merge/interactive" ]; then
- r="|REBASE-i"
- b="$(cat "$g/rebase-merge/head-name")"
- elif [ -d "$g/rebase-merge" ]; then
- r="|REBASE-m"
- b="$(cat "$g/rebase-merge/head-name")"
- else
- if [ -d "$g/rebase-apply" ]; then
- if [ -f "$g/rebase-apply/rebasing" ]; then
- r="|REBASE"
- elif [ -f "$g/rebase-apply/applying" ]; then
- r="|AM"
- else
- r="|AM/REBASE"
- fi
- elif [ -f "$g/MERGE_HEAD" ]; then
- r="|MERGING"
- elif [ -f "$g/CHERRY_PICK_HEAD" ]; then
- r="|CHERRY-PICKING"
- elif [ -f "$g/BISECT_LOG" ]; then
- r="|BISECTING"
- fi
-
- b="$(git symbolic-ref HEAD 2>/dev/null)" || {
-
- b="$(
- case "${GIT_PS1_DESCRIBE_STYLE-}" in
- (contains)
- git describe --contains HEAD ;;
- (branch)
- git describe --contains --all HEAD ;;
- (describe)
- git describe HEAD ;;
- (* | default)
- git describe --tags --exact-match HEAD ;;
- esac 2>/dev/null)" ||
-
- b="$(cut -c1-7 "$g/HEAD" 2>/dev/null)..." ||
- b="unknown"
- b="($b)"
- }
- fi
-
- local w=""
- local i=""
- local s=""
- local u=""
- local c=""
- local p=""
-
- if [ "true" = "$(git rev-parse --is-inside-git-dir 2>/dev/null)" ]; then
- if [ "true" = "$(git rev-parse --is-bare-repository 2>/dev/null)" ]; then
- c="BARE:"
- else
- b="GIT_DIR!"
- fi
- elif [ "true" = "$(git rev-parse --is-inside-work-tree 2>/dev/null)" ]; then
- if [ -n "${GIT_PS1_SHOWDIRTYSTATE-}" ]; then
- if [ "$(git config --bool bash.showDirtyState)" != "false" ]; then
- git diff --no-ext-diff --quiet --exit-code || w="*"
- if git rev-parse --quiet --verify HEAD >/dev/null; then
- git diff-index --cached --quiet HEAD -- || i="+"
- else
- i="#"
- fi
- fi
- fi
- if [ -n "${GIT_PS1_SHOWSTASHSTATE-}" ]; then
- git rev-parse --verify refs/stash >/dev/null 2>&1 && s="$"
- fi
-
- if [ -n "${GIT_PS1_SHOWUNTRACKEDFILES-}" ]; then
- if [ -n "$(git ls-files --others --exclude-standard)" ]; then
- u="%"
- fi
- fi
-
- if [ -n "${GIT_PS1_SHOWUPSTREAM-}" ]; then
- __git_ps1_show_upstream
- fi
- fi
-
- local f="$w$i$s$u"
- printf -- "${1:- (%s)}" "$c${b##refs/heads/}${f:+ $f}$r$p"
- fi
-}
-
__gitcomp_1 ()
{
local c IFS=$' \t\n'
@@ -1123,11 +875,15 @@ _git_branch ()
done
case "$cur" in
+ --set-upstream-to=*)
+ __gitcomp "$(__git_refs)" "" "${cur##--set-upstream-to=}"
+ ;;
--*)
__gitcomp "
--color --no-color --verbose --abbrev= --no-abbrev
--track --no-track --contains --merged --no-merged
- --set-upstream --edit-description --list
+ --set-upstream-to= --edit-description --list
+ --unset-upstream
"
;;
*)
@@ -1262,7 +1018,8 @@ _git_commit ()
--*)
__gitcomp "
--all --author= --signoff --verify --no-verify
- --edit --amend --include --only --interactive
+ --edit --no-edit
+ --amend --include --only --interactive
--dry-run --reuse-message= --reedit-message=
--reset-author --file= --message= --template=
--cleanup= --untracked-files --untracked-files=
@@ -1319,7 +1076,7 @@ _git_diff ()
}
__git_mergetools_common="diffuse ecmerge emerge kdiff3 meld opendiff
- tkdiff vimdiff gvimdiff xxdiff araxis p4merge bc3
+ tkdiff vimdiff gvimdiff xxdiff araxis p4merge bc3 codecompare
"
_git_difftool ()
@@ -2280,7 +2037,7 @@ _git_config ()
_git_remote ()
{
- local subcommands="add rename rm set-head set-branches set-url show prune update"
+ local subcommands="add rename remove set-head set-branches set-url show prune update"
local subcommand="$(__git_find_on_cmdline "$subcommands")"
if [ -z "$subcommand" ]; then
__gitcomp "$subcommands"
@@ -2288,7 +2045,7 @@ _git_remote ()
fi
case "$subcommand" in
- rename|rm|set-url|show|prune)
+ rename|remove|set-url|show|prune)
__gitcomp_nl "$(__git_remotes)"
;;
set-head|set-branches)
diff --git a/contrib/completion/git-prompt.sh b/contrib/completion/git-prompt.sh
new file mode 100644
index 0000000..bf20491
--- /dev/null
+++ b/contrib/completion/git-prompt.sh
@@ -0,0 +1,290 @@
+# bash/zsh git prompt support
+#
+# Copyright (C) 2006,2007 Shawn O. Pearce <spearce@spearce.org>
+# Distributed under the GNU General Public License, version 2.0.
+#
+# This script allows you to see the current branch in your prompt.
+#
+# To enable:
+#
+# 1) Copy this file to somewhere (e.g. ~/.git-prompt.sh).
+# 2) Add the following line to your .bashrc/.zshrc:
+# source ~/.git-prompt.sh
+# 3) Change your PS1 to also show the current branch:
+# Bash: PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '
+# ZSH: PS1='[%n@%m %c$(__git_ps1 " (%s)")]\$ '
+#
+# The argument to __git_ps1 will be displayed only if you are currently
+# in a git repository. The %s token will be the name of the current
+# branch.
+#
+# In addition, if you set GIT_PS1_SHOWDIRTYSTATE to a nonempty value,
+# unstaged (*) and staged (+) changes will be shown next to the branch
+# name. You can configure this per-repository with the
+# bash.showDirtyState variable, which defaults to true once
+# GIT_PS1_SHOWDIRTYSTATE is enabled.
+#
+# You can also see if currently something is stashed, by setting
+# GIT_PS1_SHOWSTASHSTATE to a nonempty value. If something is stashed,
+# then a '$' will be shown next to the branch name.
+#
+# If you would like to see if there're untracked files, then you can set
+# GIT_PS1_SHOWUNTRACKEDFILES to a nonempty value. If there're untracked
+# files, then a '%' will be shown next to the branch name.
+#
+# If you would like to see the difference between HEAD and its upstream,
+# set GIT_PS1_SHOWUPSTREAM="auto". A "<" indicates you are behind, ">"
+# indicates you are ahead, "<>" indicates you have diverged and "="
+# indicates that there is no difference. You can further control
+# behaviour by setting GIT_PS1_SHOWUPSTREAM to a space-separated list
+# of values:
+#
+# verbose show number of commits ahead/behind (+/-) upstream
+# legacy don't use the '--count' option available in recent
+# versions of git-rev-list
+# git always compare HEAD to @{upstream}
+# svn always compare HEAD to your SVN upstream
+#
+# By default, __git_ps1 will compare HEAD to your SVN upstream if it can
+# find one, or @{upstream} otherwise. Once you have set
+# GIT_PS1_SHOWUPSTREAM, you can override it on a per-repository basis by
+# setting the bash.showUpstream config variable.
+
+# __gitdir accepts 0 or 1 arguments (i.e., location)
+# returns location of .git repo
+__gitdir ()
+{
+ # Note: this function is duplicated in git-completion.bash
+ # When updating it, make sure you update the other one to match.
+ if [ -z "${1-}" ]; then
+ if [ -n "${__git_dir-}" ]; then
+ echo "$__git_dir"
+ elif [ -n "${GIT_DIR-}" ]; then
+ test -d "${GIT_DIR-}" || return 1
+ echo "$GIT_DIR"
+ elif [ -d .git ]; then
+ echo .git
+ else
+ git rev-parse --git-dir 2>/dev/null
+ fi
+ elif [ -d "$1/.git" ]; then
+ echo "$1/.git"
+ else
+ echo "$1"
+ fi
+}
+
+# stores the divergence from upstream in $p
+# used by GIT_PS1_SHOWUPSTREAM
+__git_ps1_show_upstream ()
+{
+ local key value
+ local svn_remote svn_url_pattern count n
+ local upstream=git legacy="" verbose=""
+
+ svn_remote=()
+ # get some config options from git-config
+ local output="$(git config -z --get-regexp '^(svn-remote\..*\.url|bash\.showupstream)$' 2>/dev/null | tr '\0\n' '\n ')"
+ while read -r key value; do
+ case "$key" in
+ bash.showupstream)
+ GIT_PS1_SHOWUPSTREAM="$value"
+ if [[ -z "${GIT_PS1_SHOWUPSTREAM}" ]]; then
+ p=""
+ return
+ fi
+ ;;
+ svn-remote.*.url)
+ svn_remote[ $((${#svn_remote[@]} + 1)) ]="$value"
+ svn_url_pattern+="\\|$value"
+ upstream=svn+git # default upstream is SVN if available, else git
+ ;;
+ esac
+ done <<< "$output"
+
+ # parse configuration values
+ for option in ${GIT_PS1_SHOWUPSTREAM}; do
+ case "$option" in
+ git|svn) upstream="$option" ;;
+ verbose) verbose=1 ;;
+ legacy) legacy=1 ;;
+ esac
+ done
+
+ # Find our upstream
+ case "$upstream" in
+ git) upstream="@{upstream}" ;;
+ svn*)
+ # get the upstream from the "git-svn-id: ..." in a commit message
+ # (git-svn uses essentially the same procedure internally)
+ local svn_upstream=($(git log --first-parent -1 \
+ --grep="^git-svn-id: \(${svn_url_pattern#??}\)" 2>/dev/null))
+ if [[ 0 -ne ${#svn_upstream[@]} ]]; then
+ svn_upstream=${svn_upstream[ ${#svn_upstream[@]} - 2 ]}
+ svn_upstream=${svn_upstream%@*}
+ local n_stop="${#svn_remote[@]}"
+ for ((n=1; n <= n_stop; n++)); do
+ svn_upstream=${svn_upstream#${svn_remote[$n]}}
+ done
+
+ if [[ -z "$svn_upstream" ]]; then
+ # default branch name for checkouts with no layout:
+ upstream=${GIT_SVN_ID:-git-svn}
+ else
+ upstream=${svn_upstream#/}
+ fi
+ elif [[ "svn+git" = "$upstream" ]]; then
+ upstream="@{upstream}"
+ fi
+ ;;
+ esac
+
+ # Find how many commits we are ahead/behind our upstream
+ if [[ -z "$legacy" ]]; then
+ count="$(git rev-list --count --left-right \
+ "$upstream"...HEAD 2>/dev/null)"
+ else
+ # produce equivalent output to --count for older versions of git
+ local commits
+ if commits="$(git rev-list --left-right "$upstream"...HEAD 2>/dev/null)"
+ then
+ local commit behind=0 ahead=0
+ for commit in $commits
+ do
+ case "$commit" in
+ "<"*) ((behind++)) ;;
+ *) ((ahead++)) ;;
+ esac
+ done
+ count="$behind $ahead"
+ else
+ count=""
+ fi
+ fi
+
+ # calculate the result
+ if [[ -z "$verbose" ]]; then
+ case "$count" in
+ "") # no upstream
+ p="" ;;
+ "0 0") # equal to upstream
+ p="=" ;;
+ "0 "*) # ahead of upstream
+ p=">" ;;
+ *" 0") # behind upstream
+ p="<" ;;
+ *) # diverged from upstream
+ p="<>" ;;
+ esac
+ else
+ case "$count" in
+ "") # no upstream
+ p="" ;;
+ "0 0") # equal to upstream
+ p=" u=" ;;
+ "0 "*) # ahead of upstream
+ p=" u+${count#0 }" ;;
+ *" 0") # behind upstream
+ p=" u-${count% 0}" ;;
+ *) # diverged from upstream
+ p=" u+${count#* }-${count% *}" ;;
+ esac
+ fi
+
+}
+
+
+# __git_ps1 accepts 0 or 1 arguments (i.e., format string)
+# returns text to add to bash PS1 prompt (includes branch name)
+__git_ps1 ()
+{
+ local g="$(__gitdir)"
+ if [ -n "$g" ]; then
+ local r=""
+ local b=""
+ if [ -f "$g/rebase-merge/interactive" ]; then
+ r="|REBASE-i"
+ b="$(cat "$g/rebase-merge/head-name")"
+ elif [ -d "$g/rebase-merge" ]; then
+ r="|REBASE-m"
+ b="$(cat "$g/rebase-merge/head-name")"
+ else
+ if [ -d "$g/rebase-apply" ]; then
+ if [ -f "$g/rebase-apply/rebasing" ]; then
+ r="|REBASE"
+ elif [ -f "$g/rebase-apply/applying" ]; then
+ r="|AM"
+ else
+ r="|AM/REBASE"
+ fi
+ elif [ -f "$g/MERGE_HEAD" ]; then
+ r="|MERGING"
+ elif [ -f "$g/CHERRY_PICK_HEAD" ]; then
+ r="|CHERRY-PICKING"
+ elif [ -f "$g/BISECT_LOG" ]; then
+ r="|BISECTING"
+ fi
+
+ b="$(git symbolic-ref HEAD 2>/dev/null)" || {
+
+ b="$(
+ case "${GIT_PS1_DESCRIBE_STYLE-}" in
+ (contains)
+ git describe --contains HEAD ;;
+ (branch)
+ git describe --contains --all HEAD ;;
+ (describe)
+ git describe HEAD ;;
+ (* | default)
+ git describe --tags --exact-match HEAD ;;
+ esac 2>/dev/null)" ||
+
+ b="$(cut -c1-7 "$g/HEAD" 2>/dev/null)..." ||
+ b="unknown"
+ b="($b)"
+ }
+ fi
+
+ local w=""
+ local i=""
+ local s=""
+ local u=""
+ local c=""
+ local p=""
+
+ if [ "true" = "$(git rev-parse --is-inside-git-dir 2>/dev/null)" ]; then
+ if [ "true" = "$(git rev-parse --is-bare-repository 2>/dev/null)" ]; then
+ c="BARE:"
+ else
+ b="GIT_DIR!"
+ fi
+ elif [ "true" = "$(git rev-parse --is-inside-work-tree 2>/dev/null)" ]; then
+ if [ -n "${GIT_PS1_SHOWDIRTYSTATE-}" ]; then
+ if [ "$(git config --bool bash.showDirtyState)" != "false" ]; then
+ git diff --no-ext-diff --quiet --exit-code || w="*"
+ if git rev-parse --quiet --verify HEAD >/dev/null; then
+ git diff-index --cached --quiet HEAD -- || i="+"
+ else
+ i="#"
+ fi
+ fi
+ fi
+ if [ -n "${GIT_PS1_SHOWSTASHSTATE-}" ]; then
+ git rev-parse --verify refs/stash >/dev/null 2>&1 && s="$"
+ fi
+
+ if [ -n "${GIT_PS1_SHOWUNTRACKEDFILES-}" ]; then
+ if [ -n "$(git ls-files --others --exclude-standard)" ]; then
+ u="%"
+ fi
+ fi
+
+ if [ -n "${GIT_PS1_SHOWUPSTREAM-}" ]; then
+ __git_ps1_show_upstream
+ fi
+ fi
+
+ local f="$w$i$s$u"
+ printf -- "${1:- (%s)}" "$c${b##refs/heads/}${f:+ $f}$r$p"
+ fi
+}
diff --git a/contrib/credential/gnome-keyring/.gitignore b/contrib/credential/gnome-keyring/.gitignore
new file mode 100644
index 0000000..88d8fcd
--- /dev/null
+++ b/contrib/credential/gnome-keyring/.gitignore
@@ -0,0 +1 @@
+git-credential-gnome-keyring
diff --git a/contrib/credential/gnome-keyring/Makefile b/contrib/credential/gnome-keyring/Makefile
new file mode 100644
index 0000000..e6561d8
--- /dev/null
+++ b/contrib/credential/gnome-keyring/Makefile
@@ -0,0 +1,24 @@
+MAIN:=git-credential-gnome-keyring
+all:: $(MAIN)
+
+CC = gcc
+RM = rm -f
+CFLAGS = -g -O2 -Wall
+
+-include ../../../config.mak.autogen
+-include ../../../config.mak
+
+INCS:=$(shell pkg-config --cflags gnome-keyring-1)
+LIBS:=$(shell pkg-config --libs gnome-keyring-1)
+
+SRCS:=$(MAIN).c
+OBJS:=$(SRCS:.c=.o)
+
+%.o: %.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) $(INCS) -o $@ -c $<
+
+$(MAIN): $(OBJS)
+ $(CC) -o $@ $(LDFLAGS) $^ $(LIBS)
+
+clean:
+ @$(RM) $(MAIN) $(OBJS)
diff --git a/contrib/credential/gnome-keyring/git-credential-gnome-keyring.c b/contrib/credential/gnome-keyring/git-credential-gnome-keyring.c
new file mode 100644
index 0000000..41f61c5
--- /dev/null
+++ b/contrib/credential/gnome-keyring/git-credential-gnome-keyring.c
@@ -0,0 +1,445 @@
+/*
+ * Copyright (C) 2011 John Szakmeister <john@szakmeister.net>
+ * 2012 Philipp A. Hartmann <pah@qo.cx>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * Credits:
+ * - GNOME Keyring API handling originally written by John Szakmeister
+ * - ported to credential helper API by Philipp A. Hartmann
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <gnome-keyring.h>
+
+/*
+ * This credential struct and API is simplified from git's credential.{h,c}
+ */
+struct credential
+{
+ char *protocol;
+ char *host;
+ unsigned short port;
+ char *path;
+ char *username;
+ char *password;
+};
+
+#define CREDENTIAL_INIT \
+ { NULL,NULL,0,NULL,NULL,NULL }
+
+void credential_init(struct credential *c);
+void credential_clear(struct credential *c);
+int credential_read(struct credential *c);
+void credential_write(const struct credential *c);
+
+typedef int (*credential_op_cb)(struct credential*);
+
+struct credential_operation
+{
+ char *name;
+ credential_op_cb op;
+};
+
+#define CREDENTIAL_OP_END \
+ { NULL,NULL }
+
+/*
+ * Table with operation callbacks is defined in concrete
+ * credential helper implementation and contains entries
+ * like { "get", function_to_get_credential } terminated
+ * by CREDENTIAL_OP_END.
+ */
+struct credential_operation const credential_helper_ops[];
+
+/* ---------------- common helper functions ----------------- */
+
+static inline void free_password(char *password)
+{
+ char *c = password;
+ if (!password)
+ return;
+
+ while (*c) *c++ = '\0';
+ free(password);
+}
+
+static inline void warning(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ fprintf(stderr, "warning: ");
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n" );
+ va_end(ap);
+}
+
+static inline void error(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ fprintf(stderr, "error: ");
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n" );
+ va_end(ap);
+}
+
+static inline void die(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap,fmt);
+ error(fmt, ap);
+ va_end(ap);
+ exit(EXIT_FAILURE);
+}
+
+static inline void die_errno(int err)
+{
+ error("%s", strerror(err));
+ exit(EXIT_FAILURE);
+}
+
+static inline char *xstrdup(const char *str)
+{
+ char *ret = strdup(str);
+ if (!ret)
+ die_errno(errno);
+
+ return ret;
+}
+
+/* ----------------- GNOME Keyring functions ----------------- */
+
+/* create a special keyring option string, if path is given */
+static char* keyring_object(struct credential *c)
+{
+ char* object = NULL;
+
+ if (!c->path)
+ return object;
+
+ object = (char*) malloc(strlen(c->host)+strlen(c->path)+8);
+ if(!object)
+ die_errno(errno);
+
+ if(c->port)
+ sprintf(object,"%s:%hd/%s",c->host,c->port,c->path);
+ else
+ sprintf(object,"%s/%s",c->host,c->path);
+
+ return object;
+}
+
+int keyring_get(struct credential *c)
+{
+ char* object = NULL;
+ GList *entries;
+ GnomeKeyringNetworkPasswordData *password_data;
+ GnomeKeyringResult result;
+
+ if (!c->protocol || !(c->host || c->path))
+ return EXIT_FAILURE;
+
+ object = keyring_object(c);
+
+ result = gnome_keyring_find_network_password_sync(
+ c->username,
+ NULL /* domain */,
+ c->host,
+ object,
+ c->protocol,
+ NULL /* authtype */,
+ c->port,
+ &entries);
+
+ free(object);
+
+ if (result == GNOME_KEYRING_RESULT_NO_MATCH)
+ return EXIT_SUCCESS;
+
+ if (result == GNOME_KEYRING_RESULT_CANCELLED)
+ return EXIT_SUCCESS;
+
+ if (result != GNOME_KEYRING_RESULT_OK) {
+ error("%s",gnome_keyring_result_to_message(result));
+ return EXIT_FAILURE;
+ }
+
+ /* pick the first one from the list */
+ password_data = (GnomeKeyringNetworkPasswordData *) entries->data;
+
+ free_password(c->password);
+ c->password = xstrdup(password_data->password);
+
+ if (!c->username)
+ c->username = xstrdup(password_data->user);
+
+ gnome_keyring_network_password_list_free(entries);
+
+ return EXIT_SUCCESS;
+}
+
+
+int keyring_store(struct credential *c)
+{
+ guint32 item_id;
+ char *object = NULL;
+
+ /*
+ * Sanity check that what we are storing is actually sensible.
+ * In particular, we can't make a URL without a protocol field.
+ * Without either a host or pathname (depending on the scheme),
+ * we have no primary key. And without a username and password,
+ * we are not actually storing a credential.
+ */
+ if (!c->protocol || !(c->host || c->path) ||
+ !c->username || !c->password)
+ return EXIT_FAILURE;
+
+ object = keyring_object(c);
+
+ gnome_keyring_set_network_password_sync(
+ GNOME_KEYRING_DEFAULT,
+ c->username,
+ NULL /* domain */,
+ c->host,
+ object,
+ c->protocol,
+ NULL /* authtype */,
+ c->port,
+ c->password,
+ &item_id);
+
+ free(object);
+ return EXIT_SUCCESS;
+}
+
+int keyring_erase(struct credential *c)
+{
+ char *object = NULL;
+ GList *entries;
+ GnomeKeyringNetworkPasswordData *password_data;
+ GnomeKeyringResult result;
+
+ /*
+ * Sanity check that we actually have something to match
+ * against. The input we get is a restrictive pattern,
+ * so technically a blank credential means "erase everything".
+ * But it is too easy to accidentally send this, since it is equivalent
+ * to empty input. So explicitly disallow it, and require that the
+ * pattern have some actual content to match.
+ */
+ if (!c->protocol && !c->host && !c->path && !c->username)
+ return EXIT_FAILURE;
+
+ object = keyring_object(c);
+
+ result = gnome_keyring_find_network_password_sync(
+ c->username,
+ NULL /* domain */,
+ c->host,
+ object,
+ c->protocol,
+ NULL /* authtype */,
+ c->port,
+ &entries);
+
+ free(object);
+
+ if (result == GNOME_KEYRING_RESULT_NO_MATCH)
+ return EXIT_SUCCESS;
+
+ if (result == GNOME_KEYRING_RESULT_CANCELLED)
+ return EXIT_SUCCESS;
+
+ if (result != GNOME_KEYRING_RESULT_OK)
+ {
+ error("%s",gnome_keyring_result_to_message(result));
+ return EXIT_FAILURE;
+ }
+
+ /* pick the first one from the list (delete all matches?) */
+ password_data = (GnomeKeyringNetworkPasswordData *) entries->data;
+
+ result = gnome_keyring_item_delete_sync(
+ password_data->keyring, password_data->item_id);
+
+ gnome_keyring_network_password_list_free(entries);
+
+ if (result != GNOME_KEYRING_RESULT_OK)
+ {
+ error("%s",gnome_keyring_result_to_message(result));
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+/*
+ * Table with helper operation callbacks, used by generic
+ * credential helper main function.
+ */
+struct credential_operation const credential_helper_ops[] =
+{
+ { "get", keyring_get },
+ { "store", keyring_store },
+ { "erase", keyring_erase },
+ CREDENTIAL_OP_END
+};
+
+/* ------------------ credential functions ------------------ */
+
+void credential_init(struct credential *c)
+{
+ memset(c, 0, sizeof(*c));
+}
+
+void credential_clear(struct credential *c)
+{
+ free(c->protocol);
+ free(c->host);
+ free(c->path);
+ free(c->username);
+ free_password(c->password);
+
+ credential_init(c);
+}
+
+int credential_read(struct credential *c)
+{
+ char buf[1024];
+ ssize_t line_len = 0;
+ char *key = buf;
+ char *value;
+
+ while (fgets(buf, sizeof(buf), stdin))
+ {
+ line_len = strlen(buf);
+
+ if(buf[line_len-1]=='\n')
+ buf[--line_len]='\0';
+
+ if(!line_len)
+ break;
+
+ value = strchr(buf,'=');
+ if(!value) {
+ warning("invalid credential line: %s", key);
+ return -1;
+ }
+ *value++ = '\0';
+
+ if (!strcmp(key, "protocol")) {
+ free(c->protocol);
+ c->protocol = xstrdup(value);
+ } else if (!strcmp(key, "host")) {
+ free(c->host);
+ c->host = xstrdup(value);
+ value = strrchr(c->host,':');
+ if (value) {
+ *value++ = '\0';
+ c->port = atoi(value);
+ }
+ } else if (!strcmp(key, "path")) {
+ free(c->path);
+ c->path = xstrdup(value);
+ } else if (!strcmp(key, "username")) {
+ free(c->username);
+ c->username = xstrdup(value);
+ } else if (!strcmp(key, "password")) {
+ free_password(c->password);
+ c->password = xstrdup(value);
+ while (*value) *value++ = '\0';
+ }
+ /*
+ * Ignore other lines; we don't know what they mean, but
+ * this future-proofs us when later versions of git do
+ * learn new lines, and the helpers are updated to match.
+ */
+ }
+ return 0;
+}
+
+void credential_write_item(FILE *fp, const char *key, const char *value)
+{
+ if (!value)
+ return;
+ fprintf(fp, "%s=%s\n", key, value);
+}
+
+void credential_write(const struct credential *c)
+{
+ /* only write username/password, if set */
+ credential_write_item(stdout, "username", c->username);
+ credential_write_item(stdout, "password", c->password);
+}
+
+static void usage(const char *name)
+{
+ struct credential_operation const *try_op = credential_helper_ops;
+ const char *basename = strrchr(name,'/');
+
+ basename = (basename) ? basename + 1 : name;
+ fprintf(stderr, "Usage: %s <", basename);
+ while(try_op->name) {
+ fprintf(stderr,"%s",(try_op++)->name);
+ if(try_op->name)
+ fprintf(stderr,"%s","|");
+ }
+ fprintf(stderr,"%s",">\n");
+}
+
+int main(int argc, char *argv[])
+{
+ int ret = EXIT_SUCCESS;
+
+ struct credential_operation const *try_op = credential_helper_ops;
+ struct credential cred = CREDENTIAL_INIT;
+
+ if (!argv[1]) {
+ usage(argv[0]);
+ goto out;
+ }
+
+ /* lookup operation callback */
+ while(try_op->name && strcmp(argv[1], try_op->name))
+ try_op++;
+
+ /* unsupported operation given -- ignore silently */
+ if(!try_op->name || !try_op->op)
+ goto out;
+
+ ret = credential_read(&cred);
+ if(ret)
+ goto out;
+
+ /* perform credential operation */
+ ret = (*try_op->op)(&cred);
+
+ credential_write(&cred);
+
+out:
+ credential_clear(&cred);
+ return ret;
+}
diff --git a/contrib/credential/wincred/Makefile b/contrib/credential/wincred/Makefile
new file mode 100644
index 0000000..bad45ca
--- /dev/null
+++ b/contrib/credential/wincred/Makefile
@@ -0,0 +1,14 @@
+all: git-credential-wincred.exe
+
+CC = gcc
+RM = rm -f
+CFLAGS = -O2 -Wall
+
+-include ../../../config.mak.autogen
+-include ../../../config.mak
+
+git-credential-wincred.exe : git-credential-wincred.c
+ $(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@
+
+clean:
+ $(RM) git-credential-wincred.exe
diff --git a/contrib/credential/wincred/git-credential-wincred.c b/contrib/credential/wincred/git-credential-wincred.c
new file mode 100644
index 0000000..cbaec5f
--- /dev/null
+++ b/contrib/credential/wincred/git-credential-wincred.c
@@ -0,0 +1,357 @@
+/*
+ * A git credential helper that interface with Windows' Credential Manager
+ *
+ */
+#include <windows.h>
+#include <stdio.h>
+#include <io.h>
+#include <fcntl.h>
+
+/* common helpers */
+
+static void die(const char *err, ...)
+{
+ char msg[4096];
+ va_list params;
+ va_start(params, err);
+ vsnprintf(msg, sizeof(msg), err, params);
+ fprintf(stderr, "%s\n", msg);
+ va_end(params);
+ exit(1);
+}
+
+static void *xmalloc(size_t size)
+{
+ void *ret = malloc(size);
+ if (!ret && !size)
+ ret = malloc(1);
+ if (!ret)
+ die("Out of memory");
+ return ret;
+}
+
+static char *xstrdup(const char *str)
+{
+ char *ret = strdup(str);
+ if (!ret)
+ die("Out of memory");
+ return ret;
+}
+
+/* MinGW doesn't have wincred.h, so we need to define stuff */
+
+typedef struct _CREDENTIAL_ATTRIBUTEW {
+ LPWSTR Keyword;
+ DWORD Flags;
+ DWORD ValueSize;
+ LPBYTE Value;
+} CREDENTIAL_ATTRIBUTEW, *PCREDENTIAL_ATTRIBUTEW;
+
+typedef struct _CREDENTIALW {
+ DWORD Flags;
+ DWORD Type;
+ LPWSTR TargetName;
+ LPWSTR Comment;
+ FILETIME LastWritten;
+ DWORD CredentialBlobSize;
+ LPBYTE CredentialBlob;
+ DWORD Persist;
+ DWORD AttributeCount;
+ PCREDENTIAL_ATTRIBUTEW Attributes;
+ LPWSTR TargetAlias;
+ LPWSTR UserName;
+} CREDENTIALW, *PCREDENTIALW;
+
+#define CRED_TYPE_GENERIC 1
+#define CRED_PERSIST_LOCAL_MACHINE 2
+#define CRED_MAX_ATTRIBUTES 64
+
+typedef BOOL (WINAPI *CredWriteWT)(PCREDENTIALW, DWORD);
+typedef BOOL (WINAPI *CredUnPackAuthenticationBufferWT)(DWORD, PVOID, DWORD,
+ LPWSTR, DWORD *, LPWSTR, DWORD *, LPWSTR, DWORD *);
+typedef BOOL (WINAPI *CredEnumerateWT)(LPCWSTR, DWORD, DWORD *,
+ PCREDENTIALW **);
+typedef BOOL (WINAPI *CredPackAuthenticationBufferWT)(DWORD, LPWSTR, LPWSTR,
+ PBYTE, DWORD *);
+typedef VOID (WINAPI *CredFreeT)(PVOID);
+typedef BOOL (WINAPI *CredDeleteWT)(LPCWSTR, DWORD, DWORD);
+
+static HMODULE advapi, credui;
+static CredWriteWT CredWriteW;
+static CredUnPackAuthenticationBufferWT CredUnPackAuthenticationBufferW;
+static CredEnumerateWT CredEnumerateW;
+static CredPackAuthenticationBufferWT CredPackAuthenticationBufferW;
+static CredFreeT CredFree;
+static CredDeleteWT CredDeleteW;
+
+static void load_cred_funcs(void)
+{
+ /* load DLLs */
+ advapi = LoadLibrary("advapi32.dll");
+ credui = LoadLibrary("credui.dll");
+ if (!advapi || !credui)
+ die("failed to load DLLs");
+
+ /* get function pointers */
+ CredWriteW = (CredWriteWT)GetProcAddress(advapi, "CredWriteW");
+ CredUnPackAuthenticationBufferW = (CredUnPackAuthenticationBufferWT)
+ GetProcAddress(credui, "CredUnPackAuthenticationBufferW");
+ CredEnumerateW = (CredEnumerateWT)GetProcAddress(advapi,
+ "CredEnumerateW");
+ CredPackAuthenticationBufferW = (CredPackAuthenticationBufferWT)
+ GetProcAddress(credui, "CredPackAuthenticationBufferW");
+ CredFree = (CredFreeT)GetProcAddress(advapi, "CredFree");
+ CredDeleteW = (CredDeleteWT)GetProcAddress(advapi, "CredDeleteW");
+ if (!CredWriteW || !CredUnPackAuthenticationBufferW ||
+ !CredEnumerateW || !CredPackAuthenticationBufferW || !CredFree ||
+ !CredDeleteW)
+ die("failed to load functions");
+}
+
+static char target_buf[1024];
+static char *protocol, *host, *path, *username;
+static WCHAR *wusername, *password, *target;
+
+static void write_item(const char *what, WCHAR *wbuf)
+{
+ char *buf;
+ int len = WideCharToMultiByte(CP_UTF8, 0, wbuf, -1, NULL, 0, NULL,
+ FALSE);
+ buf = xmalloc(len);
+
+ if (!WideCharToMultiByte(CP_UTF8, 0, wbuf, -1, buf, len, NULL, FALSE))
+ die("WideCharToMultiByte failed!");
+
+ printf("%s=", what);
+ fwrite(buf, 1, len - 1, stdout);
+ putchar('\n');
+ free(buf);
+}
+
+static int match_attr(const CREDENTIALW *cred, const WCHAR *keyword,
+ const char *want)
+{
+ int i;
+ if (!want)
+ return 1;
+
+ for (i = 0; i < cred->AttributeCount; ++i)
+ if (!wcscmp(cred->Attributes[i].Keyword, keyword))
+ return !strcmp((const char *)cred->Attributes[i].Value,
+ want);
+
+ return 0; /* not found */
+}
+
+static int match_cred(const CREDENTIALW *cred)
+{
+ return (!wusername || !wcscmp(wusername, cred->UserName)) &&
+ match_attr(cred, L"git_protocol", protocol) &&
+ match_attr(cred, L"git_host", host) &&
+ match_attr(cred, L"git_path", path);
+}
+
+static void get_credential(void)
+{
+ WCHAR *user_buf, *pass_buf;
+ DWORD user_buf_size = 0, pass_buf_size = 0;
+ CREDENTIALW **creds, *cred = NULL;
+ DWORD num_creds;
+ int i;
+
+ if (!CredEnumerateW(L"git:*", 0, &num_creds, &creds))
+ return;
+
+ /* search for the first credential that matches username */
+ for (i = 0; i < num_creds; ++i)
+ if (match_cred(creds[i])) {
+ cred = creds[i];
+ break;
+ }
+ if (!cred)
+ return;
+
+ CredUnPackAuthenticationBufferW(0, cred->CredentialBlob,
+ cred->CredentialBlobSize, NULL, &user_buf_size, NULL, NULL,
+ NULL, &pass_buf_size);
+
+ user_buf = xmalloc(user_buf_size * sizeof(WCHAR));
+ pass_buf = xmalloc(pass_buf_size * sizeof(WCHAR));
+
+ if (!CredUnPackAuthenticationBufferW(0, cred->CredentialBlob,
+ cred->CredentialBlobSize, user_buf, &user_buf_size, NULL, NULL,
+ pass_buf, &pass_buf_size))
+ die("CredUnPackAuthenticationBuffer failed");
+
+ CredFree(creds);
+
+ /* zero-terminate (sizes include zero-termination) */
+ user_buf[user_buf_size - 1] = L'\0';
+ pass_buf[pass_buf_size - 1] = L'\0';
+
+ write_item("username", user_buf);
+ write_item("password", pass_buf);
+
+ free(user_buf);
+ free(pass_buf);
+}
+
+static void write_attr(CREDENTIAL_ATTRIBUTEW *attr, const WCHAR *keyword,
+ const char *value)
+{
+ attr->Keyword = (LPWSTR)keyword;
+ attr->Flags = 0;
+ attr->ValueSize = strlen(value) + 1; /* store zero-termination */
+ attr->Value = (LPBYTE)value;
+}
+
+static void store_credential(void)
+{
+ CREDENTIALW cred;
+ BYTE *auth_buf;
+ DWORD auth_buf_size = 0;
+ CREDENTIAL_ATTRIBUTEW attrs[CRED_MAX_ATTRIBUTES];
+
+ if (!wusername || !password)
+ return;
+
+ /* query buffer size */
+ CredPackAuthenticationBufferW(0, wusername, password,
+ NULL, &auth_buf_size);
+
+ auth_buf = xmalloc(auth_buf_size);
+
+ if (!CredPackAuthenticationBufferW(0, wusername, password,
+ auth_buf, &auth_buf_size))
+ die("CredPackAuthenticationBuffer failed");
+
+ cred.Flags = 0;
+ cred.Type = CRED_TYPE_GENERIC;
+ cred.TargetName = target;
+ cred.Comment = L"saved by git-credential-wincred";
+ cred.CredentialBlobSize = auth_buf_size;
+ cred.CredentialBlob = auth_buf;
+ cred.Persist = CRED_PERSIST_LOCAL_MACHINE;
+ cred.AttributeCount = 1;
+ cred.Attributes = attrs;
+ cred.TargetAlias = NULL;
+ cred.UserName = wusername;
+
+ write_attr(attrs, L"git_protocol", protocol);
+
+ if (host) {
+ write_attr(attrs + cred.AttributeCount, L"git_host", host);
+ cred.AttributeCount++;
+ }
+
+ if (path) {
+ write_attr(attrs + cred.AttributeCount, L"git_path", path);
+ cred.AttributeCount++;
+ }
+
+ if (!CredWriteW(&cred, 0))
+ die("CredWrite failed");
+}
+
+static void erase_credential(void)
+{
+ CREDENTIALW **creds;
+ DWORD num_creds;
+ int i;
+
+ if (!CredEnumerateW(L"git:*", 0, &num_creds, &creds))
+ return;
+
+ for (i = 0; i < num_creds; ++i) {
+ if (match_cred(creds[i]))
+ CredDeleteW(creds[i]->TargetName, creds[i]->Type, 0);
+ }
+
+ CredFree(creds);
+}
+
+static WCHAR *utf8_to_utf16_dup(const char *str)
+{
+ int wlen = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
+ WCHAR *wstr = xmalloc(sizeof(WCHAR) * wlen);
+ MultiByteToWideChar(CP_UTF8, 0, str, -1, wstr, wlen);
+ return wstr;
+}
+
+static void read_credential(void)
+{
+ char buf[1024];
+
+ while (fgets(buf, sizeof(buf), stdin)) {
+ char *v;
+
+ if (!strcmp(buf, "\n"))
+ break;
+ buf[strlen(buf)-1] = '\0';
+
+ v = strchr(buf, '=');
+ if (!v)
+ die("bad input: %s", buf);
+ *v++ = '\0';
+
+ if (!strcmp(buf, "protocol"))
+ protocol = xstrdup(v);
+ else if (!strcmp(buf, "host"))
+ host = xstrdup(v);
+ else if (!strcmp(buf, "path"))
+ path = xstrdup(v);
+ else if (!strcmp(buf, "username")) {
+ username = xstrdup(v);
+ wusername = utf8_to_utf16_dup(v);
+ } else if (!strcmp(buf, "password"))
+ password = utf8_to_utf16_dup(v);
+ else
+ die("unrecognized input");
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ const char *usage =
+ "Usage: git credential-wincred <get|store|erase>\n";
+
+ if (!argv[1])
+ die(usage);
+
+ /* git use binary pipes to avoid CRLF-issues */
+ _setmode(_fileno(stdin), _O_BINARY);
+ _setmode(_fileno(stdout), _O_BINARY);
+
+ read_credential();
+
+ load_cred_funcs();
+
+ if (!protocol || !(host || path))
+ return 0;
+
+ /* prepare 'target', the unique key for the credential */
+ strncat(target_buf, "git:", sizeof(target_buf));
+ strncat(target_buf, protocol, sizeof(target_buf));
+ strncat(target_buf, "://", sizeof(target_buf));
+ if (username) {
+ strncat(target_buf, username, sizeof(target_buf));
+ strncat(target_buf, "@", sizeof(target_buf));
+ }
+ if (host)
+ strncat(target_buf, host, sizeof(target_buf));
+ if (path) {
+ strncat(target_buf, "/", sizeof(target_buf));
+ strncat(target_buf, path, sizeof(target_buf));
+ }
+
+ target = utf8_to_utf16_dup(target_buf);
+
+ if (!strcmp(argv[1], "get"))
+ get_credential();
+ else if (!strcmp(argv[1], "store"))
+ store_credential();
+ else if (!strcmp(argv[1], "erase"))
+ erase_credential();
+ /* otherwise, ignore unknown action */
+ return 0;
+}
diff --git a/contrib/examples/builtin-fetch--tool.c b/contrib/examples/builtin-fetch--tool.c
index 0d54aa7..8bc8c75 100644
--- a/contrib/examples/builtin-fetch--tool.c
+++ b/contrib/examples/builtin-fetch--tool.c
@@ -96,7 +96,7 @@ static int update_local_ref(const char *name,
strcpy(oldh, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV));
strcpy(newh, find_unique_abbrev(sha1_new, DEFAULT_ABBREV));
- if (in_merge_bases(current, &updated, 1)) {
+ if (in_merge_bases(current, updated)) {
fprintf(stderr, "* %s: fast-forward to %s\n",
name, note);
fprintf(stderr, " old..new: %s..%s\n", oldh, newh);
diff --git a/contrib/git-jump/git-jump b/contrib/git-jump/git-jump
index a33674e..dc90cd6 100755
--- a/contrib/git-jump/git-jump
+++ b/contrib/git-jump/git-jump
@@ -21,9 +21,9 @@ open_editor() {
}
mode_diff() {
- git diff --relative "$@" |
+ git diff --no-prefix --relative "$@" |
perl -ne '
- if (m{^\+\+\+ b/(.*)}) { $file = $1; next }
+ if (m{^\+\+\+ (.*)}) { $file = $1; next }
defined($file) or next;
if (m/^@@ .*\+(\d+)/) { $line = $1; next }
defined($line) or next;
diff --git a/contrib/mw-to-git/Makefile b/contrib/mw-to-git/Makefile
new file mode 100644
index 0000000..3ed728b
--- /dev/null
+++ b/contrib/mw-to-git/Makefile
@@ -0,0 +1,47 @@
+#
+# Copyright (C) 2012
+# Charles Roussel <charles.roussel@ensimag.imag.fr>
+# Simon Cathebras <simon.cathebras@ensimag.imag.fr>
+# Julien Khayat <julien.khayat@ensimag.imag.fr>
+# Guillaume Sasdy <guillaume.sasdy@ensimag.imag.fr>
+# Simon Perrat <simon.perrat@ensimag.imag.fr>
+#
+## Build git-remote-mediawiki
+
+-include ../../config.mak.autogen
+-include ../../config.mak
+
+ifndef PERL_PATH
+ PERL_PATH = /usr/bin/perl
+endif
+ifndef gitexecdir
+ gitexecdir = $(shell git --exec-path)
+endif
+
+PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH))
+gitexecdir_SQ = $(subst ','\'',$(gitexecdir))
+SCRIPT = git-remote-mediawiki
+
+.PHONY: install help doc test clean
+
+help:
+ @echo 'This is the help target of the Makefile. Current configuration:'
+ @echo ' gitexecdir = $(gitexecdir_SQ)'
+ @echo ' PERL_PATH = $(PERL_PATH_SQ)'
+ @echo 'Run "$(MAKE) install" to install $(SCRIPT) in gitexecdir'
+ @echo 'Run "$(MAKE) test" to run the testsuite'
+
+install:
+ sed -e '1s|#!.*/perl|#!$(PERL_PATH_SQ)|' $(SCRIPT) \
+ > '$(gitexecdir_SQ)/$(SCRIPT)'
+ chmod +x '$(gitexecdir)/$(SCRIPT)'
+
+doc:
+ @echo 'Sorry, "make doc" is not implemented yet for $(SCRIPT)'
+
+test:
+ $(MAKE) -C t/ test
+
+clean:
+ $(RM) '$(gitexecdir)/$(SCRIPT)'
+ $(MAKE) -C t/ clean
diff --git a/contrib/mw-to-git/git-remote-mediawiki b/contrib/mw-to-git/git-remote-mediawiki
index c18bfa1..68555d4 100755
--- a/contrib/mw-to-git/git-remote-mediawiki
+++ b/contrib/mw-to-git/git-remote-mediawiki
@@ -9,40 +9,19 @@
# License: GPL v2 or later
# Gateway between Git and MediaWiki.
-# https://github.com/Bibzball/Git-Mediawiki/wiki
-#
-# Known limitations:
-#
-# - Only wiki pages are managed, no support for [[File:...]]
-# attachments.
-#
-# - Poor performance in the best case: it takes forever to check
-# whether we're up-to-date (on fetch or push) or to fetch a few
-# revisions from a large wiki, because we use exclusively a
-# page-based synchronization. We could switch to a wiki-wide
-# synchronization when the synchronization involves few revisions
-# but the wiki is large.
-#
-# - Git renames could be turned into MediaWiki renames (see TODO
-# below)
-#
-# - login/password support requires the user to write the password
-# cleartext in a file (see TODO below).
-#
-# - No way to import "one page, and all pages included in it"
-#
-# - Multiple remote MediaWikis have not been very well tested.
+# Documentation & bugtracker: https://github.com/moy/Git-Mediawiki/
use strict;
use MediaWiki::API;
use DateTime::Format::ISO8601;
-use encoding 'utf8';
-# use encoding 'utf8' doesn't change STDERROR
-# but we're going to output UTF-8 filenames to STDERR
+# By default, use UTF-8 to communicate with Git and the user
binmode STDERR, ":utf8";
+binmode STDOUT, ":utf8";
use URI::Escape;
+use IPC::Open2;
+
use warnings;
# Mediawiki filenames can contain forward slashes. This variable decides by which pattern they should be replaced
@@ -59,6 +38,9 @@ use constant EMPTY_CONTENT => "<!-- empty page -->\n";
# used to reflect file creation or deletion in diff.
use constant NULL_SHA1 => "0000000000000000000000000000000000000000";
+# Used on Git's side to reflect empty edit messages on the wiki
+use constant EMPTY_MESSAGE => '*Empty MediaWiki Message*';
+
my $remotename = $ARGV[0];
my $url = $ARGV[1];
@@ -71,10 +53,18 @@ chomp(@tracked_pages);
my @tracked_categories = split(/[ \n]/, run_git("config --get-all remote.". $remotename .".categories"));
chomp(@tracked_categories);
+# Import media files on pull
+my $import_media = run_git("config --get --bool remote.". $remotename .".mediaimport");
+chomp($import_media);
+$import_media = ($import_media eq "true");
+
+# Export media files on push
+my $export_media = run_git("config --get --bool remote.". $remotename .".mediaexport");
+chomp($export_media);
+$export_media = !($export_media eq "false");
+
my $wiki_login = run_git("config --get remote.". $remotename .".mwLogin");
-# TODO: ideally, this should be able to read from keyboard, but we're
-# inside a remote helper, so our stdin is connect to git, not to a
-# terminal.
+# Note: mwPassword is discourraged. Use the credential system instead.
my $wiki_passwd = run_git("config --get remote.". $remotename .".mwPassword");
my $wiki_domain = run_git("config --get remote.". $remotename .".mwDomain");
chomp($wiki_login);
@@ -86,6 +76,21 @@ my $shallow_import = run_git("config --get --bool remote.". $remotename .".shall
chomp($shallow_import);
$shallow_import = ($shallow_import eq "true");
+# Fetch (clone and pull) by revisions instead of by pages. This behavior
+# is more efficient when we have a wiki with lots of pages and we fetch
+# the revisions quite often so that they concern only few pages.
+# Possible values:
+# - by_rev: perform one query per new revision on the remote wiki
+# - by_page: query each tracked page for new revision
+my $fetch_strategy = run_git("config --get remote.$remotename.fetchStrategy");
+unless ($fetch_strategy) {
+ $fetch_strategy = run_git("config --get mediawiki.fetchStrategy");
+}
+chomp($fetch_strategy);
+unless ($fetch_strategy) {
+ $fetch_strategy = "by_page";
+}
+
# Dumb push: don't update notes and mediawiki ref to reflect the last push.
#
# Configurable with mediawiki.dumbPush, or per-remote with
@@ -151,32 +156,152 @@ while (<STDIN>) {
########################## Functions ##############################
+## credential API management (generic functions)
+
+sub credential_read {
+ my %credential;
+ my $reader = shift;
+ my $op = shift;
+ while (<$reader>) {
+ my ($key, $value) = /([^=]*)=(.*)/;
+ if (not defined $key) {
+ die "ERROR receiving response from git credential $op:\n$_\n";
+ }
+ $credential{$key} = $value;
+ }
+ return %credential;
+}
+
+sub credential_write {
+ my $credential = shift;
+ my $writer = shift;
+ # url overwrites other fields, so it must come first
+ print $writer "url=$credential->{url}\n" if exists $credential->{url};
+ while (my ($key, $value) = each(%$credential) ) {
+ if (length $value && $key ne 'url') {
+ print $writer "$key=$value\n";
+ }
+ }
+}
+
+sub credential_run {
+ my $op = shift;
+ my $credential = shift;
+ my $pid = open2(my $reader, my $writer, "git credential $op");
+ credential_write($credential, $writer);
+ print $writer "\n";
+ close($writer);
+
+ if ($op eq "fill") {
+ %$credential = credential_read($reader, $op);
+ } else {
+ if (<$reader>) {
+ die "ERROR while running git credential $op:\n$_";
+ }
+ }
+ close($reader);
+ waitpid($pid, 0);
+ my $child_exit_status = $? >> 8;
+ if ($child_exit_status != 0) {
+ die "'git credential $op' failed with code $child_exit_status.";
+ }
+}
+
# MediaWiki API instance, created lazily.
my $mediawiki;
sub mw_connect_maybe {
if ($mediawiki) {
- return;
+ return;
}
$mediawiki = MediaWiki::API->new;
$mediawiki->{config}->{api_url} = "$url/api.php";
if ($wiki_login) {
- if (!$mediawiki->login({
- lgname => $wiki_login,
- lgpassword => $wiki_passwd,
- lgdomain => $wiki_domain,
- })) {
- print STDERR "Failed to log in mediawiki user \"$wiki_login\" on $url\n";
- print STDERR "(error " .
- $mediawiki->{error}->{code} . ': ' .
- $mediawiki->{error}->{details} . ")\n";
- exit 1;
+ my %credential = (url => $url);
+ $credential{username} = $wiki_login;
+ $credential{password} = $wiki_passwd;
+ credential_run("fill", \%credential);
+ my $request = {lgname => $credential{username},
+ lgpassword => $credential{password},
+ lgdomain => $wiki_domain};
+ if ($mediawiki->login($request)) {
+ credential_run("approve", \%credential);
+ print STDERR "Logged in mediawiki user \"$credential{username}\".\n";
} else {
- print STDERR "Logged in with user \"$wiki_login\".\n";
+ print STDERR "Failed to log in mediawiki user \"$credential{username}\" on $url\n";
+ print STDERR " (error " .
+ $mediawiki->{error}->{code} . ': ' .
+ $mediawiki->{error}->{details} . ")\n";
+ credential_run("reject", \%credential);
+ exit 1;
+ }
+ }
+}
+
+## Functions for listing pages on the remote wiki
+sub get_mw_tracked_pages {
+ my $pages = shift;
+ get_mw_page_list(\@tracked_pages, $pages);
+}
+
+sub get_mw_page_list {
+ my $page_list = shift;
+ my $pages = shift;
+ my @some_pages = @$page_list;
+ while (@some_pages) {
+ my $last = 50;
+ if ($#some_pages < $last) {
+ $last = $#some_pages;
+ }
+ my @slice = @some_pages[0..$last];
+ get_mw_first_pages(\@slice, $pages);
+ @some_pages = @some_pages[51..$#some_pages];
+ }
+}
+
+sub get_mw_tracked_categories {
+ my $pages = shift;
+ foreach my $category (@tracked_categories) {
+ if (index($category, ':') < 0) {
+ # Mediawiki requires the Category
+ # prefix, but let's not force the user
+ # to specify it.
+ $category = "Category:" . $category;
+ }
+ my $mw_pages = $mediawiki->list( {
+ action => 'query',
+ list => 'categorymembers',
+ cmtitle => $category,
+ cmlimit => 'max' } )
+ || die $mediawiki->{error}->{code} . ': '
+ . $mediawiki->{error}->{details};
+ foreach my $page (@{$mw_pages}) {
+ $pages->{$page->{title}} = $page;
}
}
}
+sub get_mw_all_pages {
+ my $pages = shift;
+ # No user-provided list, get the list of pages from the API.
+ my $mw_pages = $mediawiki->list({
+ action => 'query',
+ list => 'allpages',
+ aplimit => 'max'
+ });
+ if (!defined($mw_pages)) {
+ print STDERR "fatal: could not get the list of wiki pages.\n";
+ print STDERR "fatal: '$url' does not appear to be a mediawiki\n";
+ print STDERR "fatal: make sure '$url/api.php' is a valid page.\n";
+ exit 1;
+ }
+ foreach my $page (@{$mw_pages}) {
+ $pages->{$page->{title}} = $page;
+ }
+}
+
+# queries the wiki for a set of pages. Meant to be used within a loop
+# querying the wiki for slices of page list.
sub get_mw_first_pages {
my $some_pages = shift;
my @some_pages = @{$some_pages};
@@ -205,70 +330,45 @@ sub get_mw_first_pages {
}
}
+# Get the list of pages to be fetched according to configuration.
sub get_mw_pages {
mw_connect_maybe();
+ print STDERR "Listing pages on remote wiki...\n";
+
my %pages; # hash on page titles to avoid duplicates
my $user_defined;
if (@tracked_pages) {
$user_defined = 1;
# The user provided a list of pages titles, but we
# still need to query the API to get the page IDs.
-
- my @some_pages = @tracked_pages;
- while (@some_pages) {
- my $last = 50;
- if ($#some_pages < $last) {
- $last = $#some_pages;
- }
- my @slice = @some_pages[0..$last];
- get_mw_first_pages(\@slice, \%pages);
- @some_pages = @some_pages[51..$#some_pages];
- }
+ get_mw_tracked_pages(\%pages);
}
if (@tracked_categories) {
$user_defined = 1;
- foreach my $category (@tracked_categories) {
- if (index($category, ':') < 0) {
- # Mediawiki requires the Category
- # prefix, but let's not force the user
- # to specify it.
- $category = "Category:" . $category;
- }
- my $mw_pages = $mediawiki->list( {
- action => 'query',
- list => 'categorymembers',
- cmtitle => $category,
- cmlimit => 'max' } )
- || die $mediawiki->{error}->{code} . ': ' . $mediawiki->{error}->{details};
- foreach my $page (@{$mw_pages}) {
- $pages{$page->{title}} = $page;
- }
- }
+ get_mw_tracked_categories(\%pages);
}
if (!$user_defined) {
- # No user-provided list, get the list of pages from
- # the API.
- my $mw_pages = $mediawiki->list({
- action => 'query',
- list => 'allpages',
- aplimit => 500,
- });
- if (!defined($mw_pages)) {
- print STDERR "fatal: could not get the list of wiki pages.\n";
- print STDERR "fatal: '$url' does not appear to be a mediawiki\n";
- print STDERR "fatal: make sure '$url/api.php' is a valid page.\n";
- exit 1;
- }
- foreach my $page (@{$mw_pages}) {
- $pages{$page->{title}} = $page;
+ get_mw_all_pages(\%pages);
+ }
+ if ($import_media) {
+ print STDERR "Getting media files for selected pages...\n";
+ if ($user_defined) {
+ get_linked_mediafiles(\%pages);
+ } else {
+ get_all_mediafiles(\%pages);
}
}
- return values(%pages);
+ print STDERR (scalar keys %pages) . " pages found.\n";
+ return %pages;
}
+# usage: $out = run_git("command args");
+# $out = run_git("command args", "raw"); # don't interpret output as UTF-8.
sub run_git {
- open(my $git, "-|:encoding(UTF-8)", "git " . $_[0]);
+ my $args = shift;
+ my $encoding = (shift || "encoding(UTF-8)");
+ open(my $git, "-|:$encoding", "git " . $args);
my $res = do { local $/; <$git> };
close($git);
@@ -276,6 +376,123 @@ sub run_git {
}
+sub get_all_mediafiles {
+ my $pages = shift;
+ # Attach list of all pages for media files from the API,
+ # they are in a different namespace, only one namespace
+ # can be queried at the same moment
+ my $mw_pages = $mediawiki->list({
+ action => 'query',
+ list => 'allpages',
+ apnamespace => get_mw_namespace_id("File"),
+ aplimit => 'max'
+ });
+ if (!defined($mw_pages)) {
+ print STDERR "fatal: could not get the list of pages for media files.\n";
+ print STDERR "fatal: '$url' does not appear to be a mediawiki\n";
+ print STDERR "fatal: make sure '$url/api.php' is a valid page.\n";
+ exit 1;
+ }
+ foreach my $page (@{$mw_pages}) {
+ $pages->{$page->{title}} = $page;
+ }
+}
+
+sub get_linked_mediafiles {
+ my $pages = shift;
+ my @titles = map $_->{title}, values(%{$pages});
+
+ # The query is split in small batches because of the MW API limit of
+ # the number of links to be returned (500 links max).
+ my $batch = 10;
+ while (@titles) {
+ if ($#titles < $batch) {
+ $batch = $#titles;
+ }
+ my @slice = @titles[0..$batch];
+
+ # pattern 'page1|page2|...' required by the API
+ my $mw_titles = join('|', @slice);
+
+ # Media files could be included or linked from
+ # a page, get all related
+ my $query = {
+ action => 'query',
+ prop => 'links|images',
+ titles => $mw_titles,
+ plnamespace => get_mw_namespace_id("File"),
+ pllimit => 'max'
+ };
+ my $result = $mediawiki->api($query);
+
+ while (my ($id, $page) = each(%{$result->{query}->{pages}})) {
+ my @media_titles;
+ if (defined($page->{links})) {
+ my @link_titles = map $_->{title}, @{$page->{links}};
+ push(@media_titles, @link_titles);
+ }
+ if (defined($page->{images})) {
+ my @image_titles = map $_->{title}, @{$page->{images}};
+ push(@media_titles, @image_titles);
+ }
+ if (@media_titles) {
+ get_mw_page_list(\@media_titles, $pages);
+ }
+ }
+
+ @titles = @titles[($batch+1)..$#titles];
+ }
+}
+
+sub get_mw_mediafile_for_page_revision {
+ # Name of the file on Wiki, with the prefix.
+ my $filename = shift;
+ my $timestamp = shift;
+ my %mediafile;
+
+ # Search if on a media file with given timestamp exists on
+ # MediaWiki. In that case download the file.
+ my $query = {
+ action => 'query',
+ prop => 'imageinfo',
+ titles => "File:" . $filename,
+ iistart => $timestamp,
+ iiend => $timestamp,
+ iiprop => 'timestamp|archivename|url',
+ iilimit => 1
+ };
+ my $result = $mediawiki->api($query);
+
+ my ($fileid, $file) = each( %{$result->{query}->{pages}} );
+ # If not defined it means there is no revision of the file for
+ # given timestamp.
+ if (defined($file->{imageinfo})) {
+ $mediafile{title} = $filename;
+
+ my $fileinfo = pop(@{$file->{imageinfo}});
+ $mediafile{timestamp} = $fileinfo->{timestamp};
+ # Mediawiki::API's download function doesn't support https URLs
+ # and can't download old versions of files.
+ print STDERR "\tDownloading file $mediafile{title}, version $mediafile{timestamp}\n";
+ $mediafile{content} = download_mw_mediafile($fileinfo->{url});
+ }
+ return %mediafile;
+}
+
+sub download_mw_mediafile {
+ my $url = shift;
+
+ my $response = $mediawiki->{ua}->get($url);
+ if ($response->code == 200) {
+ return $response->decoded_content;
+ } else {
+ print STDERR "Error downloading mediafile from :\n";
+ print STDERR "URL: $url\n";
+ print STDERR "Server response: " . $response->code . " " . $response->message . "\n";
+ exit 1;
+ }
+}
+
sub get_last_local_revision {
# Get note regarding last mediawiki revision
my $note = run_git("notes --ref=$remotename/mediawiki show refs/mediawiki/$remotename/master 2>/dev/null");
@@ -297,13 +514,36 @@ sub get_last_local_revision {
# Remember the timestamp corresponding to a revision id.
my %basetimestamps;
+# Get the last remote revision without taking in account which pages are
+# tracked or not. This function makes a single request to the wiki thus
+# avoid a loop onto all tracked pages. This is useful for the fetch-by-rev
+# option.
+sub get_last_global_remote_rev {
+ mw_connect_maybe();
+
+ my $query = {
+ action => 'query',
+ list => 'recentchanges',
+ prop => 'revisions',
+ rclimit => '1',
+ rcdir => 'older',
+ };
+ my $result = $mediawiki->api($query);
+ return $result->{query}->{recentchanges}[0]->{revid};
+}
+
+# Get the last remote revision concerning the tracked pages and the tracked
+# categories.
sub get_last_remote_revision {
mw_connect_maybe();
- my @pages = get_mw_pages();
+ my %pages_hash = get_mw_pages();
+ my @pages = values(%pages_hash);
my $max_rev_num = 0;
+ print STDERR "Getting last revision id on tracked pages...\n";
+
foreach my $page (@pages) {
my $id = $page->{pageid};
@@ -379,6 +619,16 @@ sub literal_data {
print STDOUT "data ", bytes::length($content), "\n", $content;
}
+sub literal_data_raw {
+ # Output possibly binary content.
+ my ($content) = @_;
+ # Avoid confusion between size in bytes and in characters
+ utf8::downgrade($content);
+ binmode STDOUT, ":raw";
+ print STDOUT "data ", bytes::length($content), "\n", $content;
+ binmode STDOUT, ":utf8";
+}
+
sub mw_capabilities {
# Revisions are imported to the private namespace
# refs/mediawiki/$remotename/ by the helper and fetched into
@@ -466,6 +716,11 @@ sub import_file_revision {
my %commit = %{$commit};
my $full_import = shift;
my $n = shift;
+ my $mediafile = shift;
+ my %mediafile;
+ if ($mediafile) {
+ %mediafile = %{$mediafile};
+ }
my $title = $commit{title};
my $comment = $commit{comment};
@@ -485,6 +740,10 @@ sub import_file_revision {
if ($content ne DELETED_CONTENT) {
print STDOUT "M 644 inline $title.mw\n";
literal_data($content);
+ if (%mediafile) {
+ print STDOUT "M 644 inline $mediafile{title}\n";
+ literal_data_raw($mediafile{content});
+ }
print STDOUT "\n\n";
} else {
print STDOUT "D $title.mw\n";
@@ -547,8 +806,6 @@ sub mw_import_ref {
mw_connect_maybe();
- my @pages = get_mw_pages();
-
print STDERR "Searching revisions...\n";
my $last_local = get_last_local_revision();
my $fetch_from = $last_local + 1;
@@ -557,36 +814,111 @@ sub mw_import_ref {
} else {
print STDERR ", fetching from here.\n";
}
+
+ my $n = 0;
+ if ($fetch_strategy eq "by_rev") {
+ print STDERR "Fetching & writing export data by revs...\n";
+ $n = mw_import_ref_by_revs($fetch_from);
+ } elsif ($fetch_strategy eq "by_page") {
+ print STDERR "Fetching & writing export data by pages...\n";
+ $n = mw_import_ref_by_pages($fetch_from);
+ } else {
+ print STDERR "fatal: invalid fetch strategy \"$fetch_strategy\".\n";
+ print STDERR "Check your configuration variables remote.$remotename.fetchStrategy and mediawiki.fetchStrategy\n";
+ exit 1;
+ }
+
+ if ($fetch_from == 1 && $n == 0) {
+ print STDERR "You appear to have cloned an empty MediaWiki.\n";
+ # Something has to be done remote-helper side. If nothing is done, an error is
+ # thrown saying that HEAD is refering to unknown object 0000000000000000000
+ # and the clone fails.
+ }
+}
+
+sub mw_import_ref_by_pages {
+
+ my $fetch_from = shift;
+ my %pages_hash = get_mw_pages();
+ my @pages = values(%pages_hash);
+
my ($n, @revisions) = fetch_mw_revisions(\@pages, $fetch_from);
- # Creation of the fast-import stream
- print STDERR "Fetching & writing export data...\n";
+ @revisions = sort {$a->{revid} <=> $b->{revid}} @revisions;
+ my @revision_ids = map $_->{revid}, @revisions;
- $n = 0;
+ return mw_import_revids($fetch_from, \@revision_ids, \%pages_hash);
+}
+
+sub mw_import_ref_by_revs {
+
+ my $fetch_from = shift;
+ my %pages_hash = get_mw_pages();
+
+ my $last_remote = get_last_global_remote_rev();
+ my @revision_ids = $fetch_from..$last_remote;
+ return mw_import_revids($fetch_from, \@revision_ids, \%pages_hash);
+}
+
+# Import revisions given in second argument (array of integers).
+# Only pages appearing in the third argument (hash indexed by page titles)
+# will be imported.
+sub mw_import_revids {
+ my $fetch_from = shift;
+ my $revision_ids = shift;
+ my $pages = shift;
+
+ my $n = 0;
+ my $n_actual = 0;
my $last_timestamp = 0; # Placeholer in case $rev->timestamp is undefined
- foreach my $pagerevid (sort {$a->{revid} <=> $b->{revid}} @revisions) {
+ foreach my $pagerevid (@$revision_ids) {
+ # Count page even if we skip it, since we display
+ # $n/$total and $total includes skipped pages.
+ $n++;
+
# fetch the content of the pages
my $query = {
action => 'query',
prop => 'revisions',
rvprop => 'content|timestamp|comment|user|ids',
- revids => $pagerevid->{revid},
+ revids => $pagerevid,
};
my $result = $mediawiki->api($query);
- my $rev = pop(@{$result->{query}->{pages}->{$pagerevid->{pageid}}->{revisions}});
+ if (!$result) {
+ die "Failed to retrieve modified page for revision $pagerevid";
+ }
- $n++;
+ if (defined($result->{query}->{badrevids}->{$pagerevid})) {
+ # The revision id does not exist on the remote wiki.
+ next;
+ }
+
+ if (!defined($result->{query}->{pages})) {
+ die "Invalid revision $pagerevid.";
+ }
+
+ my @result_pages = values(%{$result->{query}->{pages}});
+ my $result_page = $result_pages[0];
+ my $rev = $result_pages[0]->{revisions}->[0];
+
+ my $page_title = $result_page->{title};
+
+ if (!exists($pages->{$page_title})) {
+ print STDERR "$n/", scalar(@$revision_ids),
+ ": Skipping revision #$rev->{revid} of $page_title\n";
+ next;
+ }
+
+ $n_actual++;
my %commit;
$commit{author} = $rev->{user} || 'Anonymous';
- $commit{comment} = $rev->{comment} || '*Empty MediaWiki Message*';
- $commit{title} = mediawiki_smudge_filename(
- $result->{query}->{pages}->{$pagerevid->{pageid}}->{title}
- );
- $commit{mw_revision} = $pagerevid->{revid};
+ $commit{comment} = $rev->{comment} || EMPTY_MESSAGE;
+ $commit{title} = mediawiki_smudge_filename($page_title);
+ $commit{mw_revision} = $rev->{revid};
$commit{content} = mediawiki_smudge($rev->{'*'});
if (!defined($rev->{timestamp})) {
@@ -596,17 +928,23 @@ sub mw_import_ref {
}
$commit{date} = DateTime::Format::ISO8601->parse_datetime($last_timestamp);
- print STDERR "$n/", scalar(@revisions), ": Revision #$pagerevid->{revid} of $commit{title}\n";
-
- import_file_revision(\%commit, ($fetch_from == 1), $n);
+ # Differentiates classic pages and media files.
+ my ($namespace, $filename) = $page_title =~ /^([^:]*):(.*)$/;
+ my %mediafile;
+ if ($namespace) {
+ my $id = get_mw_namespace_id($namespace);
+ if ($id && $id == get_mw_namespace_id("File")) {
+ %mediafile = get_mw_mediafile_for_page_revision($filename, $rev->{timestamp});
+ }
+ }
+ # If this is a revision of the media page for new version
+ # of a file do one common commit for both file and media page.
+ # Else do commit only for that page.
+ print STDERR "$n/", scalar(@$revision_ids), ": Revision #$rev->{revid} of $commit{title}\n";
+ import_file_revision(\%commit, ($fetch_from == 1), $n_actual, \%mediafile);
}
- if ($fetch_from == 1 && $n == 0) {
- print STDERR "You appear to have cloned an empty MediaWiki.\n";
- # Something has to be done remote-helper side. If nothing is done, an error is
- # thrown saying that HEAD is refering to unknown object 0000000000000000000
- # and the clone fails.
- }
+ return $n_actual;
}
sub error_non_fast_forward {
@@ -624,6 +962,63 @@ sub error_non_fast_forward {
return 0;
}
+sub mw_upload_file {
+ my $complete_file_name = shift;
+ my $new_sha1 = shift;
+ my $extension = shift;
+ my $file_deleted = shift;
+ my $summary = shift;
+ my $newrevid;
+ my $path = "File:" . $complete_file_name;
+ my %hashFiles = get_allowed_file_extensions();
+ if (!exists($hashFiles{$extension})) {
+ print STDERR "$complete_file_name is not a permitted file on this wiki.\n";
+ print STDERR "Check the configuration of file uploads in your mediawiki.\n";
+ return $newrevid;
+ }
+ # Deleting and uploading a file requires a priviledged user
+ if ($file_deleted) {
+ mw_connect_maybe();
+ my $query = {
+ action => 'delete',
+ title => $path,
+ reason => $summary
+ };
+ if (!$mediawiki->edit($query)) {
+ print STDERR "Failed to delete file on remote wiki\n";
+ print STDERR "Check your permissions on the remote site. Error code:\n";
+ print STDERR $mediawiki->{error}->{code} . ':' . $mediawiki->{error}->{details};
+ exit 1;
+ }
+ } else {
+ # Don't let perl try to interpret file content as UTF-8 => use "raw"
+ my $content = run_git("cat-file blob $new_sha1", "raw");
+ if ($content ne "") {
+ mw_connect_maybe();
+ $mediawiki->{config}->{upload_url} =
+ "$url/index.php/Special:Upload";
+ $mediawiki->edit({
+ action => 'upload',
+ filename => $complete_file_name,
+ comment => $summary,
+ file => [undef,
+ $complete_file_name,
+ Content => $content],
+ ignorewarnings => 1,
+ }, {
+ skip_encoding => 1
+ } ) || die $mediawiki->{error}->{code} . ':'
+ . $mediawiki->{error}->{details};
+ my $last_file_page = $mediawiki->get_page({title => $path});
+ $newrevid = $last_file_page->{revid};
+ print STDERR "Pushed file: $new_sha1 - $complete_file_name.\n";
+ } else {
+ print STDERR "Empty file $complete_file_name not pushed.\n";
+ }
+ }
+ return $newrevid;
+}
+
sub mw_push_file {
my $diff_info = shift;
# $diff_info contains a string in this format:
@@ -636,7 +1031,12 @@ sub mw_push_file {
my $summary = shift;
# MediaWiki revision number. Keep the previous one by default,
# in case there's no edit to perform.
- my $newrevid = shift;
+ my $oldrevid = shift;
+ my $newrevid;
+
+ if ($summary eq EMPTY_MESSAGE) {
+ $summary = '';
+ }
my $new_sha1 = $diff_info_split[3];
my $old_sha1 = $diff_info_split[2];
@@ -644,9 +1044,16 @@ sub mw_push_file {
my $page_deleted = ($new_sha1 eq NULL_SHA1);
$complete_file_name = mediawiki_clean_filename($complete_file_name);
- if (substr($complete_file_name,-3) eq ".mw") {
- my $title = substr($complete_file_name,0,-3);
-
+ my ($title, $extension) = $complete_file_name =~ /^(.*)\.([^\.]*)$/;
+ if (!defined($extension)) {
+ $extension = "";
+ }
+ if ($extension eq "mw") {
+ my $ns = get_mw_namespace_id_for_page($complete_file_name);
+ if ($ns && $ns == get_mw_namespace_id("File") && (!$export_media)) {
+ print STDERR "Ignoring media file related page: $complete_file_name\n";
+ return ($oldrevid, "ok");
+ }
my $file_content;
if ($page_deleted) {
# Deleting a page usually requires
@@ -664,7 +1071,7 @@ sub mw_push_file {
action => 'edit',
summary => $summary,
title => $title,
- basetimestamp => $basetimestamps{$newrevid},
+ basetimestamp => $basetimestamps{$oldrevid},
text => mediawiki_clean($file_content, $page_created),
}, {
skip_encoding => 1 # Helps with names with accentuated characters
@@ -676,7 +1083,7 @@ sub mw_push_file {
$mediawiki->{error}->{code} .
' from mediwiki: ' . $mediawiki->{error}->{details} .
".\n";
- return ($newrevid, "non-fast-forward");
+ return ($oldrevid, "non-fast-forward");
} else {
# Other errors. Shouldn't happen => just die()
die 'Fatal: Error ' .
@@ -686,9 +1093,14 @@ sub mw_push_file {
}
$newrevid = $result->{edit}->{newrevid};
print STDERR "Pushed file: $new_sha1 - $title\n";
+ } elsif ($export_media) {
+ $newrevid = mw_upload_file($complete_file_name, $new_sha1,
+ $extension, $page_deleted,
+ $summary);
} else {
- print STDERR "$complete_file_name not a mediawiki file (Not pushable on this version of git-remote-mediawiki).\n"
+ print STDERR "Ignoring media file $title\n";
}
+ $newrevid = ($newrevid or $oldrevid);
return ($newrevid, "ok");
}
@@ -760,16 +1172,26 @@ sub mw_push_revision {
if ($last_local_revid > 0) {
my $parsed_sha1 = $remoteorigin_sha1;
# Find a path from last MediaWiki commit to pushed commit
+ print STDERR "Computing path from local to remote ...\n";
+ my @local_ancestry = split(/\n/, run_git("rev-list --boundary --parents $local ^$parsed_sha1"));
+ my %local_ancestry;
+ foreach my $line (@local_ancestry) {
+ if (my ($child, $parents) = $line =~ m/^-?([a-f0-9]+) ([a-f0-9 ]+)/) {
+ foreach my $parent (split(' ', $parents)) {
+ $local_ancestry{$parent} = $child;
+ }
+ } elsif (!$line =~ m/^([a-f0-9]+)/) {
+ die "Unexpected output from git rev-list: $line";
+ }
+ }
while ($parsed_sha1 ne $HEAD_sha1) {
- my @commit_info = grep(/^$parsed_sha1/, split(/\n/, run_git("rev-list --children $local")));
- if (!@commit_info) {
+ my $child = $local_ancestry{$parsed_sha1};
+ if (!$child) {
+ printf STDERR "Cannot find a path in history from remote commit to last commit\n";
return error_non_fast_forward($remote);
}
- my @commit_info_split = split(/ |\n/, $commit_info[0]);
- # $commit_info_split[1] is the sha1 of the commit to export
- # $commit_info_split[0] is the sha1 of its direct child
- push(@commit_pairs, \@commit_info_split);
- $parsed_sha1 = $commit_info_split[1];
+ push(@commit_pairs, [$parsed_sha1, $child]);
+ $parsed_sha1 = $child;
}
} else {
# No remote mediawiki revision. Export the whole
@@ -791,8 +1213,8 @@ sub mw_push_revision {
# TODO: we could detect rename, and encode them with a #redirect on the wiki.
# TODO: for now, it's just a delete+add
my @diff_info_list = split(/\0/, $diff_infos);
- # Keep the first line of the commit message as mediawiki comment for the revision
- my $commit_msg = (split(/\n/, run_git("show --pretty=format:\"%s\" $sha1_commit")))[0];
+ # Keep the subject line of the commit message as mediawiki comment for the revision
+ my $commit_msg = run_git("log --no-walk --format=\"%s\" $sha1_commit");
chomp($commit_msg);
# Push every blob
while (@diff_info_list) {
@@ -817,7 +1239,7 @@ sub mw_push_revision {
}
}
unless ($dumb_push) {
- run_git("notes --ref=$remotename/mediawiki add -m \"mediawiki_revision: $mw_revision\" $sha1_commit");
+ run_git("notes --ref=$remotename/mediawiki add -f -m \"mediawiki_revision: $mw_revision\" $sha1_commit");
run_git("update-ref -m \"Git-MediaWiki push\" refs/mediawiki/$remotename/master $sha1_commit $sha1_child");
}
}
@@ -825,3 +1247,104 @@ sub mw_push_revision {
print STDOUT "ok $remote\n";
return 1;
}
+
+sub get_allowed_file_extensions {
+ mw_connect_maybe();
+
+ my $query = {
+ action => 'query',
+ meta => 'siteinfo',
+ siprop => 'fileextensions'
+ };
+ my $result = $mediawiki->api($query);
+ my @file_extensions= map $_->{ext},@{$result->{query}->{fileextensions}};
+ my %hashFile = map {$_ => 1}@file_extensions;
+
+ return %hashFile;
+}
+
+# In memory cache for MediaWiki namespace ids.
+my %namespace_id;
+
+# Namespaces whose id is cached in the configuration file
+# (to avoid duplicates)
+my %cached_mw_namespace_id;
+
+# Return MediaWiki id for a canonical namespace name.
+# Ex.: "File", "Project".
+sub get_mw_namespace_id {
+ mw_connect_maybe();
+ my $name = shift;
+
+ if (!exists $namespace_id{$name}) {
+ # Look at configuration file, if the record for that namespace is
+ # already cached. Namespaces are stored in form:
+ # "Name_of_namespace:Id_namespace", ex.: "File:6".
+ my @temp = split(/[\n]/, run_git("config --get-all remote."
+ . $remotename .".namespaceCache"));
+ chomp(@temp);
+ foreach my $ns (@temp) {
+ my ($n, $id) = split(/:/, $ns);
+ if ($id eq 'notANameSpace') {
+ $namespace_id{$n} = {is_namespace => 0};
+ } else {
+ $namespace_id{$n} = {is_namespace => 1, id => $id};
+ }
+ $cached_mw_namespace_id{$n} = 1;
+ }
+ }
+
+ if (!exists $namespace_id{$name}) {
+ print STDERR "Namespace $name not found in cache, querying the wiki ...\n";
+ # NS not found => get namespace id from MW and store it in
+ # configuration file.
+ my $query = {
+ action => 'query',
+ meta => 'siteinfo',
+ siprop => 'namespaces'
+ };
+ my $result = $mediawiki->api($query);
+
+ while (my ($id, $ns) = each(%{$result->{query}->{namespaces}})) {
+ if (defined($ns->{id}) && defined($ns->{canonical})) {
+ $namespace_id{$ns->{canonical}} = {is_namespace => 1, id => $ns->{id}};
+ if ($ns->{'*'}) {
+ # alias (e.g. french Fichier: as alias for canonical File:)
+ $namespace_id{$ns->{'*'}} = {is_namespace => 1, id => $ns->{id}};
+ }
+ }
+ }
+ }
+
+ my $ns = $namespace_id{$name};
+ my $id;
+
+ unless (defined $ns) {
+ print STDERR "No such namespace $name on MediaWiki.\n";
+ $ns = {is_namespace => 0};
+ $namespace_id{$name} = $ns;
+ }
+
+ if ($ns->{is_namespace}) {
+ $id = $ns->{id};
+ }
+
+ # Store "notANameSpace" as special value for inexisting namespaces
+ my $store_id = ($id || 'notANameSpace');
+
+ # Store explicitely requested namespaces on disk
+ if (!exists $cached_mw_namespace_id{$name}) {
+ run_git("config --add remote.". $remotename
+ .".namespaceCache \"". $name .":". $store_id ."\"");
+ $cached_mw_namespace_id{$name} = 1;
+ }
+ return $id;
+}
+
+sub get_mw_namespace_id_for_page {
+ if (my ($namespace) = $_[0] =~ /^([^:]*):/) {
+ return get_mw_namespace_id($namespace);
+ } else {
+ return;
+ }
+}
diff --git a/contrib/mw-to-git/t/.gitignore b/contrib/mw-to-git/t/.gitignore
new file mode 100644
index 0000000..a7a40b4
--- /dev/null
+++ b/contrib/mw-to-git/t/.gitignore
@@ -0,0 +1,4 @@
+WEB/
+wiki/
+trash directory.t*/
+test-results/
diff --git a/contrib/mw-to-git/t/Makefile b/contrib/mw-to-git/t/Makefile
new file mode 100644
index 0000000..f422203
--- /dev/null
+++ b/contrib/mw-to-git/t/Makefile
@@ -0,0 +1,31 @@
+#
+# Copyright (C) 2012
+# Charles Roussel <charles.roussel@ensimag.imag.fr>
+# Simon Cathebras <simon.cathebras@ensimag.imag.fr>
+# Julien Khayat <julien.khayat@ensimag.imag.fr>
+# Guillaume Sasdy <guillaume.sasdy@ensimag.imag.fr>
+# Simon Perrat <simon.perrat@ensimag.imag.fr>
+#
+## Test git-remote-mediawiki
+
+all: test
+
+-include ../../../config.mak.autogen
+-include ../../../config.mak
+
+T = $(wildcard t[0-9][0-9][0-9][0-9]-*.sh)
+
+.PHONY: help test clean all
+
+help:
+ @echo 'Run "$(MAKE) test" to launch test scripts'
+ @echo 'Run "$(MAKE) clean" to remove trash folders'
+
+test:
+ @for t in $(T); do \
+ echo "$$t"; \
+ "./$$t" || exit 1; \
+ done
+
+clean:
+ $(RM) -r 'trash directory'.*
diff --git a/contrib/mw-to-git/t/README b/contrib/mw-to-git/t/README
new file mode 100644
index 0000000..96e9739
--- /dev/null
+++ b/contrib/mw-to-git/t/README
@@ -0,0 +1,124 @@
+Tests for Mediawiki-to-Git
+==========================
+
+Introduction
+------------
+This manual describes how to install the git-remote-mediawiki test
+environment on a machine with git installed on it.
+
+Prerequisite
+------------
+
+In order to run this test environment correctly, you will need to
+install the following packages (Debian/Ubuntu names, may need to be
+adapted for another distribution):
+
+* lighttpd
+* php5
+* php5-cgi
+* php5-cli
+* php5-curl
+* php5-sqlite
+
+Principles and Technical Choices
+--------------------------------
+
+The test environment makes it easy to install and manipulate one or
+several MediaWiki instances. To allow developers to run the testsuite
+easily, the environment does not require root priviledge (except to
+install the required packages if needed). It starts a webserver
+instance on the user's account (using lighttpd greatly helps for
+that), and does not need a separate database daemon (thanks to the use
+of sqlite).
+
+Run the test environment
+------------------------
+
+Install a new wiki
+~~~~~~~~~~~~~~~~~~
+
+Once you have all the prerequisite, you need to install a MediaWiki
+instance on your machine. If you already have one, it is still
+strongly recommended to install one with the script provided. Here's
+how to work it:
+
+a. change directory to contrib/mw-to-git/t/
+b. if needed, edit test.config to choose your installation parameters
+c. run `./install-wiki.sh install`
+d. check on your favourite web browser if your wiki is correctly
+ installed.
+
+Remove an existing wiki
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Edit the file test.config to fit the wiki you want to delete, and then
+execute the command `./install-wiki.sh delete` from the
+contrib/mw-to-git/t directory.
+
+Run the existing tests
+~~~~~~~~~~~~~~~~~~~~~~
+
+The provided tests are currently in the `contrib/mw-to-git/t` directory.
+The files are all the t936[0-9]-*.sh shell scripts.
+
+a. Run all tests:
+To do so, run "make test" from the contrib/mw-to-git/ directory.
+
+b. Run a specific test:
+To run a given test <test_name>, run ./<test_name> from the
+contrib/mw-to-git/t directory.
+
+How to create new tests
+-----------------------
+
+Available functions
+~~~~~~~~~~~~~~~~~~~
+
+The test environment of git-remote-mediawiki provides some functions
+useful to test its behaviour. for more details about the functions'
+parameters, please refer to the `test-gitmw-lib.sh` and
+`test-gitmw.pl` files.
+
+** `test_check_wiki_precond`:
+Check if the tests must be skipped or not. Please use this function
+at the beggining of each new test file.
+
+** `wiki_getpage`:
+Fetch a given page from the wiki and puts its content in the
+directory in parameter.
+
+** `wiki_delete_page`:
+Delete a given page from the wiki.
+
+** `wiki_edit_page`:
+Create or modify a given page in the wiki. You can specify several
+parameters like a summary for the page edition, or add the page to a
+given category.
+See test-gitmw.pl for more details.
+
+** `wiki_getallpage`:
+Fetch all pages from the wiki into a given directory. The directory
+is created if it does not exists.
+
+** `test_diff_directories`:
+Compare the content of two directories. The content must be the same.
+Use this function to compare the content of a git directory and a wiki
+one created by wiki_getallpage.
+
+** `test_contains_N_files`:
+Check if the given directory contains a given number of file.
+
+** `wiki_page_exists`:
+Tests if a given page exists on the wiki.
+
+** `wiki_reset`:
+Reset the wiki, i.e. flush the database. Use this function at the
+begining of each new test, except if the test re-uses the same wiki
+(and history) as the previous test.
+
+How to write a new test
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Please, follow the standards given by git. See git/t/README.
+New file should be named as t936[0-9]-*.sh.
+Be sure to reset your wiki regulary with the function `wiki_reset`.
diff --git a/contrib/mw-to-git/t/install-wiki.sh b/contrib/mw-to-git/t/install-wiki.sh
new file mode 100755
index 0000000..c6d6fa3
--- /dev/null
+++ b/contrib/mw-to-git/t/install-wiki.sh
@@ -0,0 +1,45 @@
+#!/bin/sh
+
+# This script installs or deletes a MediaWiki on your computer.
+# It requires a web server with PHP and SQLite running. In addition, if you
+# do not have MediaWiki sources on your computer, the option 'install'
+# downloads them for you.
+# Please set the CONFIGURATION VARIABLES in ./test-gitmw-lib.sh
+
+WIKI_TEST_DIR=$(cd "$(dirname "$0")" && pwd)
+
+if test -z "$WIKI_TEST_DIR"
+then
+ WIKI_TEST_DIR=.
+fi
+
+. "$WIKI_TEST_DIR"/test-gitmw-lib.sh
+usage () {
+ echo "Usage: "
+ echo " ./install-wiki.sh <install | delete | --help>"
+ echo " install | -i : Install a wiki on your computer."
+ echo " delete | -d : Delete the wiki and all its pages and "
+ echo " content."
+}
+
+
+# Argument: install, delete, --help | -h
+case "$1" in
+ "install" | "-i")
+ wiki_install
+ exit 0
+ ;;
+ "delete" | "-d")
+ wiki_delete
+ exit 0
+ ;;
+ "--help" | "-h")
+ usage
+ exit 0
+ ;;
+ *)
+ echo "Invalid argument: $1"
+ usage
+ exit 1
+ ;;
+esac
diff --git a/contrib/mw-to-git/t/install-wiki/.gitignore b/contrib/mw-to-git/t/install-wiki/.gitignore
new file mode 100644
index 0000000..b5a2a44
--- /dev/null
+++ b/contrib/mw-to-git/t/install-wiki/.gitignore
@@ -0,0 +1 @@
+wikidb.sqlite
diff --git a/contrib/mw-to-git/t/install-wiki/LocalSettings.php b/contrib/mw-to-git/t/install-wiki/LocalSettings.php
new file mode 100644
index 0000000..29f1251
--- /dev/null
+++ b/contrib/mw-to-git/t/install-wiki/LocalSettings.php
@@ -0,0 +1,129 @@
+<?php
+# This file was automatically generated by the MediaWiki 1.19.0
+# installer. If you make manual changes, please keep track in case you
+# need to recreate them later.
+#
+# See includes/DefaultSettings.php for all configurable settings
+# and their default values, but don't forget to make changes in _this_
+# file, not there.
+#
+# Further documentation for configuration settings may be found at:
+# http://www.mediawiki.org/wiki/Manual:Configuration_settings
+
+# Protect against web entry
+if ( !defined( 'MEDIAWIKI' ) ) {
+ exit;
+}
+
+## Uncomment this to disable output compression
+# $wgDisableOutputCompression = true;
+
+$wgSitename = "Git-MediaWiki-Test";
+$wgMetaNamespace = "Git-MediaWiki-Test";
+
+## The URL base path to the directory containing the wiki;
+## defaults for all runtime URL paths are based off of this.
+## For more information on customizing the URLs please see:
+## http://www.mediawiki.org/wiki/Manual:Short_URL
+$wgScriptPath = "@WG_SCRIPT_PATH@";
+$wgScriptExtension = ".php";
+
+## The protocol and server name to use in fully-qualified URLs
+$wgServer = "@WG_SERVER@";
+
+## The relative URL path to the skins directory
+$wgStylePath = "$wgScriptPath/skins";
+
+## The relative URL path to the logo. Make sure you change this from the default,
+## or else you'll overwrite your logo when you upgrade!
+$wgLogo = "$wgStylePath/common/images/wiki.png";
+
+## UPO means: this is also a user preference option
+
+$wgEnableEmail = true;
+$wgEnableUserEmail = true; # UPO
+
+$wgEmergencyContact = "apache@localhost";
+$wgPasswordSender = "apache@localhost";
+
+$wgEnotifUserTalk = false; # UPO
+$wgEnotifWatchlist = false; # UPO
+$wgEmailAuthentication = true;
+
+## Database settings
+$wgDBtype = "sqlite";
+$wgDBserver = "";
+$wgDBname = "@WG_SQLITE_DATAFILE@";
+$wgDBuser = "";
+$wgDBpassword = "";
+
+# SQLite-specific settings
+$wgSQLiteDataDir = "@WG_SQLITE_DATADIR@";
+
+
+## Shared memory settings
+$wgMainCacheType = CACHE_NONE;
+$wgMemCachedServers = array();
+
+## To enable image uploads, make sure the 'images' directory
+## is writable, then set this to true:
+$wgEnableUploads = true;
+$wgUseImageMagick = true;
+$wgImageMagickConvertCommand ="@CONVERT@";
+$wgFileExtensions[] = 'txt';
+
+# InstantCommons allows wiki to use images from http://commons.wikimedia.org
+$wgUseInstantCommons = false;
+
+## If you use ImageMagick (or any other shell command) on a
+## Linux server, this will need to be set to the name of an
+## available UTF-8 locale
+$wgShellLocale = "en_US.utf8";
+
+## If you want to use image uploads under safe mode,
+## create the directories images/archive, images/thumb and
+## images/temp, and make them all writable. Then uncomment
+## this, if it's not already uncommented:
+#$wgHashedUploadDirectory = false;
+
+## Set $wgCacheDirectory to a writable directory on the web server
+## to make your wiki go slightly faster. The directory should not
+## be publically accessible from the web.
+#$wgCacheDirectory = "$IP/cache";
+
+# Site language code, should be one of the list in ./languages/Names.php
+$wgLanguageCode = "en";
+
+$wgSecretKey = "1c912bfe3519fb70f5dc523ecc698111cd43d81a11c585b3eefb28f29c2699b7";
+#$wgSecretKey = "@SECRETKEY@";
+
+
+# Site upgrade key. Must be set to a string (default provided) to turn on the
+# web installer while LocalSettings.php is in place
+$wgUpgradeKey = "ddae7dc87cd0a645";
+
+## Default skin: you can change the default skin. Use the internal symbolic
+## names, ie 'standard', 'nostalgia', 'cologneblue', 'monobook', 'vector':
+$wgDefaultSkin = "vector";
+
+## For attaching licensing metadata to pages, and displaying an
+## appropriate copyright notice / icon. GNU Free Documentation
+## License and Creative Commons licenses are supported so far.
+$wgRightsPage = ""; # Set to the title of a wiki page that describes your license/copyright
+$wgRightsUrl = "";
+$wgRightsText = "";
+$wgRightsIcon = "";
+
+# Path to the GNU diff3 utility. Used for conflict resolution.
+$wgDiff3 = "/usr/bin/diff3";
+
+# Query string length limit for ResourceLoader. You should only set this if
+# your web server has a query string length limit (then set it to that limit),
+# or if you have suhosin.get.max_value_length set in php.ini (then set it to
+# that value)
+$wgResourceLoaderMaxQueryLength = -1;
+
+
+
+# End of automatically generated settings.
+# Add more configuration options below.
diff --git a/contrib/mw-to-git/t/install-wiki/db_install.php b/contrib/mw-to-git/t/install-wiki/db_install.php
new file mode 100644
index 0000000..0f3f4e0
--- /dev/null
+++ b/contrib/mw-to-git/t/install-wiki/db_install.php
@@ -0,0 +1,120 @@
+<?php
+/**
+ * This script generates a SQLite database for a MediaWiki version 1.19.0
+ * You must specify the login of the admin (argument 1) and its
+ * password (argument 2) and the folder where the database file
+ * is located (absolute path in argument 3).
+ * It is used by the script install-wiki.sh in order to make easy the
+ * installation of a MediaWiki.
+ *
+ * In order to generate a SQLite database file, MediaWiki ask the user
+ * to submit some forms in its web browser. This script simulates this
+ * behavior though the functions <get> and <submit>
+ *
+ */
+$argc = $_SERVER['argc'];
+$argv = $_SERVER['argv'];
+
+$login = $argv[2];
+$pass = $argv[3];
+$tmp = $argv[4];
+$port = $argv[5];
+
+$url = 'http://localhost:'.$port.'/wiki/mw-config/index.php';
+$db_dir = urlencode($tmp);
+$tmp_cookie = tempnam($tmp, "COOKIE_");
+/*
+ * Fetchs a page with cURL.
+ */
+function get($page_name = "") {
+ $curl = curl_init();
+ $page_name_add = "";
+ if ($page_name != "") {
+ $page_name_add = '?page='.$page_name;
+ }
+ $url = $GLOBALS['url'].$page_name_add;
+ $tmp_cookie = $GLOBALS['tmp_cookie'];
+ curl_setopt($curl, CURLOPT_COOKIEJAR, $tmp_cookie);
+ curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
+ curl_setopt($curl, CURLOPT_COOKIEFILE, $tmp_cookie);
+ curl_setopt($curl, CURLOPT_HEADER, true);
+ curl_setopt($curl, CURLOPT_URL, $url);
+
+ $page = curl_exec($curl);
+ if (!$page) {
+ die("Could not get page: $url\n");
+ }
+ curl_close($curl);
+ return $page;
+}
+
+/*
+ * Submits a form with cURL.
+ */
+function submit($page_name, $option = "") {
+ $curl = curl_init();
+ $datapost = 'submit-continue=Continue+%E2%86%92';
+ if ($option != "") {
+ $datapost = $option.'&'.$datapost;
+ }
+ $url = $GLOBALS['url'].'?page='.$page_name;
+ $tmp_cookie = $GLOBALS['tmp_cookie'];
+ curl_setopt($curl, CURLOPT_URL, $url);
+ curl_setopt($curl, CURLOPT_POST, true);
+ curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
+ curl_setopt($curl, CURLOPT_POSTFIELDS, $datapost);
+ curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($curl, CURLOPT_COOKIEJAR, $tmp_cookie);
+ curl_setopt($curl, CURLOPT_COOKIEFILE, $tmp_cookie);
+
+ $page = curl_exec($curl);
+ if (!$page) {
+ die("Could not get page: $url\n");
+ }
+ curl_close($curl);
+ return "$page";
+}
+
+/*
+ * Here starts this script: simulates the behavior of the user
+ * submitting forms to generates the database file.
+ * Note this simulation was made for the MediaWiki version 1.19.0,
+ * we can't assume it works with other versions.
+ *
+ */
+
+$page = get();
+if (!preg_match('/input type="hidden" value="([0-9]+)" name="LanguageRequestTime"/',
+ $page, $matches)) {
+ echo "Unexpected content for page downloaded:\n";
+ echo "$page";
+ die;
+};
+$timestamp = $matches[1];
+$language = "LanguageRequestTime=$timestamp&uselang=en&ContLang=en";
+$page = submit('Language', $language);
+
+submit('Welcome');
+
+$db_config = 'DBType=sqlite';
+$db_config = $db_config.'&sqlite_wgSQLiteDataDir='.$db_dir;
+$db_config = $db_config.'&sqlite_wgDBname='.$argv[1];
+submit('DBConnect', $db_config);
+
+$wiki_config = 'config_wgSitename=TEST';
+$wiki_config = $wiki_config.'&config__NamespaceType=site-name';
+$wiki_config = $wiki_config.'&config_wgMetaNamespace=MyWiki';
+$wiki_config = $wiki_config.'&config__AdminName='.$login;
+
+$wiki_config = $wiki_config.'&config__AdminPassword='.$pass;
+$wiki_config = $wiki_config.'&config__AdminPassword2='.$pass;
+
+$wiki_config = $wiki_config.'&wiki__configEmail=email%40email.org';
+$wiki_config = $wiki_config.'&config__SkipOptional=skip';
+submit('Name', $wiki_config);
+submit('Install');
+submit('Install');
+
+unlink($tmp_cookie);
+?>
diff --git a/contrib/mw-to-git/t/push-pull-tests.sh b/contrib/mw-to-git/t/push-pull-tests.sh
new file mode 100644
index 0000000..9da2dc5
--- /dev/null
+++ b/contrib/mw-to-git/t/push-pull-tests.sh
@@ -0,0 +1,144 @@
+test_push_pull () {
+
+ test_expect_success 'Git pull works after adding a new wiki page' '
+ wiki_reset &&
+
+ git clone mediawiki::'"$WIKI_URL"' mw_dir_1 &&
+ wiki_editpage Foo "page created after the git clone" false &&
+
+ (
+ cd mw_dir_1 &&
+ git pull
+ ) &&
+
+ wiki_getallpage ref_page_1 &&
+ test_diff_directories mw_dir_1 ref_page_1
+ '
+
+ test_expect_success 'Git pull works after editing a wiki page' '
+ wiki_reset &&
+
+ wiki_editpage Foo "page created before the git clone" false &&
+ git clone mediawiki::'"$WIKI_URL"' mw_dir_2 &&
+ wiki_editpage Foo "new line added on the wiki" true &&
+
+ (
+ cd mw_dir_2 &&
+ git pull
+ ) &&
+
+ wiki_getallpage ref_page_2 &&
+ test_diff_directories mw_dir_2 ref_page_2
+ '
+
+ test_expect_success 'git pull works on conflict handled by auto-merge' '
+ wiki_reset &&
+
+ wiki_editpage Foo "1 init
+3
+5
+ " false &&
+ git clone mediawiki::'"$WIKI_URL"' mw_dir_3 &&
+
+ wiki_editpage Foo "1 init
+2 content added on wiki after clone
+3
+5
+ " false &&
+
+ (
+ cd mw_dir_3 &&
+ echo "1 init
+3
+4 content added on git after clone
+5
+" >Foo.mw &&
+ git commit -am "conflicting change on foo" &&
+ git pull &&
+ git push
+ )
+ '
+
+ test_expect_success 'Git push works after adding a file .mw' '
+ wiki_reset &&
+ git clone mediawiki::'"$WIKI_URL"' mw_dir_4 &&
+ wiki_getallpage ref_page_4 &&
+ (
+ cd mw_dir_4 &&
+ test_path_is_missing Foo.mw &&
+ touch Foo.mw &&
+ echo "hello world" >>Foo.mw &&
+ git add Foo.mw &&
+ git commit -m "Foo" &&
+ git push
+ ) &&
+ wiki_getallpage ref_page_4 &&
+ test_diff_directories mw_dir_4 ref_page_4
+ '
+
+ test_expect_success 'Git push works after editing a file .mw' '
+ wiki_reset &&
+ wiki_editpage "Foo" "page created before the git clone" false &&
+ git clone mediawiki::'"$WIKI_URL"' mw_dir_5 &&
+
+ (
+ cd mw_dir_5 &&
+ echo "new line added in the file Foo.mw" >>Foo.mw &&
+ git commit -am "edit file Foo.mw" &&
+ git push
+ ) &&
+
+ wiki_getallpage ref_page_5 &&
+ test_diff_directories mw_dir_5 ref_page_5
+ '
+
+ test_expect_failure 'Git push works after deleting a file' '
+ wiki_reset &&
+ wiki_editpage Foo "wiki page added before git clone" false &&
+ git clone mediawiki::'"$WIKI_URL"' mw_dir_6 &&
+
+ (
+ cd mw_dir_6 &&
+ git rm Foo.mw &&
+ git commit -am "page Foo.mw deleted" &&
+ git push
+ ) &&
+
+ test_must_fail wiki_page_exist Foo
+ '
+
+ test_expect_success 'Merge conflict expected and solving it' '
+ wiki_reset &&
+
+ git clone mediawiki::'"$WIKI_URL"' mw_dir_7 &&
+ wiki_editpage Foo "1 conflict
+3 wiki
+4" false &&
+
+ (
+ cd mw_dir_7 &&
+ echo "1 conflict
+2 git
+4" >Foo.mw &&
+ git add Foo.mw &&
+ git commit -m "conflict created" &&
+ test_must_fail git pull &&
+ "$PERL_PATH" -pi -e "s/[<=>].*//g" Foo.mw &&
+ git commit -am "merge conflict solved" &&
+ git push
+ )
+ '
+
+ test_expect_failure 'git pull works after deleting a wiki page' '
+ wiki_reset &&
+ wiki_editpage Foo "wiki page added before the git clone" false &&
+ git clone mediawiki::'"$WIKI_URL"' mw_dir_8 &&
+
+ wiki_delete_page Foo &&
+ (
+ cd mw_dir_8 &&
+ git pull &&
+ test_path_is_missing Foo.mw
+ )
+ '
+}
diff --git a/contrib/mw-to-git/t/t9360-mw-to-git-clone.sh b/contrib/mw-to-git/t/t9360-mw-to-git-clone.sh
new file mode 100755
index 0000000..811a90c
--- /dev/null
+++ b/contrib/mw-to-git/t/t9360-mw-to-git-clone.sh
@@ -0,0 +1,257 @@
+#!/bin/sh
+#
+# Copyright (C) 2012
+# Charles Roussel <charles.roussel@ensimag.imag.fr>
+# Simon Cathebras <simon.cathebras@ensimag.imag.fr>
+# Julien Khayat <julien.khayat@ensimag.imag.fr>
+# Guillaume Sasdy <guillaume.sasdy@ensimag.imag.fr>
+# Simon Perrat <simon.perrat@ensimag.imag.fr>
+#
+# License: GPL v2 or later
+
+
+test_description='Test the Git Mediawiki remote helper: git clone'
+
+. ./test-gitmw-lib.sh
+. $TEST_DIRECTORY/test-lib.sh
+
+
+test_check_precond
+
+
+test_expect_success 'Git clone creates the expected git log with one file' '
+ wiki_reset &&
+ wiki_editpage foo "this is not important" false -c cat -s "this must be the same" &&
+ git clone mediawiki::'"$WIKI_URL"' mw_dir_1 &&
+ (
+ cd mw_dir_1 &&
+ git log --format=%s HEAD^..HEAD >log.tmp
+ ) &&
+ echo "this must be the same" >msg.tmp &&
+ diff -b mw_dir_1/log.tmp msg.tmp
+'
+
+
+test_expect_success 'Git clone creates the expected git log with multiple files' '
+ wiki_reset &&
+ wiki_editpage daddy "this is not important" false -s="this must be the same" &&
+ wiki_editpage daddy "neither is this" true -s="this must also be the same" &&
+ wiki_editpage daddy "neither is this" true -s="same same same" &&
+ wiki_editpage dj "dont care" false -s="identical" &&
+ wiki_editpage dj "dont care either" true -s="identical too" &&
+ git clone mediawiki::'"$WIKI_URL"' mw_dir_2 &&
+ (
+ cd mw_dir_2 &&
+ git log --format=%s Daddy.mw >logDaddy.tmp &&
+ git log --format=%s Dj.mw >logDj.tmp
+ ) &&
+ echo "same same same" >msgDaddy.tmp &&
+ echo "this must also be the same" >>msgDaddy.tmp &&
+ echo "this must be the same" >>msgDaddy.tmp &&
+ echo "identical too" >msgDj.tmp &&
+ echo "identical" >>msgDj.tmp &&
+ diff -b mw_dir_2/logDaddy.tmp msgDaddy.tmp &&
+ diff -b mw_dir_2/logDj.tmp msgDj.tmp
+'
+
+
+test_expect_success 'Git clone creates only Main_Page.mw with an empty wiki' '
+ wiki_reset &&
+ git clone mediawiki::'"$WIKI_URL"' mw_dir_3 &&
+ test_contains_N_files mw_dir_3 1 &&
+ test_path_is_file mw_dir_3/Main_Page.mw
+'
+
+test_expect_success 'Git clone does not fetch a deleted page' '
+ wiki_reset &&
+ wiki_editpage foo "this page must be deleted before the clone" false &&
+ wiki_delete_page foo &&
+ git clone mediawiki::'"$WIKI_URL"' mw_dir_4 &&
+ test_contains_N_files mw_dir_4 1 &&
+ test_path_is_file mw_dir_4/Main_Page.mw &&
+ test_path_is_missing mw_dir_4/Foo.mw
+'
+
+test_expect_success 'Git clone works with page added' '
+ wiki_reset &&
+ wiki_editpage foo " I will be cloned" false &&
+ wiki_editpage bar "I will be cloned" false &&
+ git clone mediawiki::'"$WIKI_URL"' mw_dir_5 &&
+ wiki_getallpage ref_page_5 &&
+ test_diff_directories mw_dir_5 ref_page_5 &&
+ wiki_delete_page foo &&
+ wiki_delete_page bar
+'
+
+test_expect_success 'Git clone works with an edited page ' '
+ wiki_reset &&
+ wiki_editpage foo "this page will be edited" \
+ false -s "first edition of page foo"&&
+ wiki_editpage foo "this page has been edited and must be on the clone " true &&
+ git clone mediawiki::'"$WIKI_URL"' mw_dir_6 &&
+ test_path_is_file mw_dir_6/Foo.mw &&
+ test_path_is_file mw_dir_6/Main_Page.mw &&
+ wiki_getallpage mw_dir_6/page_ref_6 &&
+ test_diff_directories mw_dir_6 mw_dir_6/page_ref_6 &&
+ (
+ cd mw_dir_6 &&
+ git log --format=%s HEAD^ Foo.mw > ../Foo.log
+ ) &&
+ echo "first edition of page foo" > FooExpect.log &&
+ diff FooExpect.log Foo.log
+'
+
+
+test_expect_success 'Git clone works with several pages and some deleted ' '
+ wiki_reset &&
+ wiki_editpage foo "this page will not be deleted" false &&
+ wiki_editpage bar "I must not be erased" false &&
+ wiki_editpage namnam "I will not be there at the end" false &&
+ wiki_editpage nyancat "nyan nyan nyan delete me" false &&
+ wiki_delete_page namnam &&
+ wiki_delete_page nyancat &&
+ git clone mediawiki::'"$WIKI_URL"' mw_dir_7 &&
+ test_path_is_file mw_dir_7/Foo.mw &&
+ test_path_is_file mw_dir_7/Bar.mw &&
+ test_path_is_missing mw_dir_7/Namnam.mw &&
+ test_path_is_missing mw_dir_7/Nyancat.mw &&
+ wiki_getallpage mw_dir_7/page_ref_7 &&
+ test_diff_directories mw_dir_7 mw_dir_7/page_ref_7
+'
+
+
+test_expect_success 'Git clone works with one specific page cloned ' '
+ wiki_reset &&
+ wiki_editpage foo "I will not be cloned" false &&
+ wiki_editpage bar "Do not clone me" false &&
+ wiki_editpage namnam "I will be cloned :)" false -s="this log must stay" &&
+ wiki_editpage nyancat "nyan nyan nyan you cant clone me" false &&
+ git clone -c remote.origin.pages=namnam \
+ mediawiki::'"$WIKI_URL"' mw_dir_8 &&
+ test_contains_N_files mw_dir_8 1 &&
+ test_path_is_file mw_dir_8/Namnam.mw &&
+ test_path_is_missing mw_dir_8/Main_Page.mw &&
+ (
+ cd mw_dir_8 &&
+ echo "this log must stay" >msg.tmp &&
+ git log --format=%s >log.tmp &&
+ diff -b msg.tmp log.tmp
+ ) &&
+ wiki_check_content mw_dir_8/Namnam.mw Namnam
+'
+
+test_expect_success 'Git clone works with multiple specific page cloned ' '
+ wiki_reset &&
+ wiki_editpage foo "I will be there" false &&
+ wiki_editpage bar "I will not disapear" false &&
+ wiki_editpage namnam "I be erased" false &&
+ wiki_editpage nyancat "nyan nyan nyan you will not erase me" false &&
+ wiki_delete_page namnam &&
+ git clone -c remote.origin.pages="foo bar nyancat namnam" \
+ mediawiki::'"$WIKI_URL"' mw_dir_9 &&
+ test_contains_N_files mw_dir_9 3 &&
+ test_path_is_missing mw_dir_9/Namnam.mw &&
+ test_path_is_file mw_dir_9/Foo.mw &&
+ test_path_is_file mw_dir_9/Nyancat.mw &&
+ test_path_is_file mw_dir_9/Bar.mw &&
+ wiki_check_content mw_dir_9/Foo.mw Foo &&
+ wiki_check_content mw_dir_9/Bar.mw Bar &&
+ wiki_check_content mw_dir_9/Nyancat.mw Nyancat
+'
+
+test_expect_success 'Mediawiki-clone of several specific pages on wiki' '
+ wiki_reset &&
+ wiki_editpage foo "foo 1" false &&
+ wiki_editpage bar "bar 1" false &&
+ wiki_editpage dummy "dummy 1" false &&
+ wiki_editpage cloned_1 "cloned_1 1" false &&
+ wiki_editpage cloned_2 "cloned_2 2" false &&
+ wiki_editpage cloned_3 "cloned_3 3" false &&
+ mkdir -p ref_page_10 &&
+ wiki_getpage cloned_1 ref_page_10 &&
+ wiki_getpage cloned_2 ref_page_10 &&
+ wiki_getpage cloned_3 ref_page_10 &&
+ git clone -c remote.origin.pages="cloned_1 cloned_2 cloned_3" \
+ mediawiki::'"$WIKI_URL"' mw_dir_10 &&
+ test_diff_directories mw_dir_10 ref_page_10
+'
+
+test_expect_success 'Git clone works with the shallow option' '
+ wiki_reset &&
+ wiki_editpage foo "1st revision, should be cloned" false &&
+ wiki_editpage bar "1st revision, should be cloned" false &&
+ wiki_editpage nyan "1st revision, should not be cloned" false &&
+ wiki_editpage nyan "2nd revision, should be cloned" false &&
+ git -c remote.origin.shallow=true clone \
+ mediawiki::'"$WIKI_URL"' mw_dir_11 &&
+ test_contains_N_files mw_dir_11 4 &&
+ test_path_is_file mw_dir_11/Nyan.mw &&
+ test_path_is_file mw_dir_11/Foo.mw &&
+ test_path_is_file mw_dir_11/Bar.mw &&
+ test_path_is_file mw_dir_11/Main_Page.mw &&
+ (
+ cd mw_dir_11 &&
+ test `git log --oneline Nyan.mw | wc -l` -eq 1 &&
+ test `git log --oneline Foo.mw | wc -l` -eq 1 &&
+ test `git log --oneline Bar.mw | wc -l` -eq 1 &&
+ test `git log --oneline Main_Page.mw | wc -l ` -eq 1
+ ) &&
+ wiki_check_content mw_dir_11/Nyan.mw Nyan &&
+ wiki_check_content mw_dir_11/Foo.mw Foo &&
+ wiki_check_content mw_dir_11/Bar.mw Bar &&
+ wiki_check_content mw_dir_11/Main_Page.mw Main_Page
+'
+
+test_expect_success 'Git clone works with the shallow option with a delete page' '
+ wiki_reset &&
+ wiki_editpage foo "1st revision, will be deleted" false &&
+ wiki_editpage bar "1st revision, should be cloned" false &&
+ wiki_editpage nyan "1st revision, should not be cloned" false &&
+ wiki_editpage nyan "2nd revision, should be cloned" false &&
+ wiki_delete_page foo &&
+ git -c remote.origin.shallow=true clone \
+ mediawiki::'"$WIKI_URL"' mw_dir_12 &&
+ test_contains_N_files mw_dir_12 3 &&
+ test_path_is_file mw_dir_12/Nyan.mw &&
+ test_path_is_missing mw_dir_12/Foo.mw &&
+ test_path_is_file mw_dir_12/Bar.mw &&
+ test_path_is_file mw_dir_12/Main_Page.mw &&
+ (
+ cd mw_dir_12 &&
+ test `git log --oneline Nyan.mw | wc -l` -eq 1 &&
+ test `git log --oneline Bar.mw | wc -l` -eq 1 &&
+ test `git log --oneline Main_Page.mw | wc -l ` -eq 1
+ ) &&
+ wiki_check_content mw_dir_12/Nyan.mw Nyan &&
+ wiki_check_content mw_dir_12/Bar.mw Bar &&
+ wiki_check_content mw_dir_12/Main_Page.mw Main_Page
+'
+
+test_expect_success 'Test of fetching a category' '
+ wiki_reset &&
+ wiki_editpage Foo "I will be cloned" false -c=Category &&
+ wiki_editpage Bar "Meet me on the repository" false -c=Category &&
+ wiki_editpage Dummy "I will not come" false &&
+ wiki_editpage BarWrong "I will stay online only" false -c=NotCategory &&
+ git clone -c remote.origin.categories="Category" \
+ mediawiki::'"$WIKI_URL"' mw_dir_13 &&
+ wiki_getallpage ref_page_13 Category &&
+ test_diff_directories mw_dir_13 ref_page_13
+'
+
+test_expect_success 'Test of resistance to modification of category on wiki for clone' '
+ wiki_reset &&
+ wiki_editpage Tobedeleted "this page will be deleted" false -c=Catone &&
+ wiki_editpage Tobeedited "this page will be modified" false -c=Catone &&
+ wiki_editpage Normalone "this page wont be modified and will be on git" false -c=Catone &&
+ wiki_editpage Notconsidered "this page will not appear on local" false &&
+ wiki_editpage Othercategory "this page will not appear on local" false -c=Cattwo &&
+ wiki_editpage Tobeedited "this page have been modified" true -c=Catone &&
+ wiki_delete_page Tobedeleted
+ git clone -c remote.origin.categories="Catone" \
+ mediawiki::'"$WIKI_URL"' mw_dir_14 &&
+ wiki_getallpage ref_page_14 Catone &&
+ test_diff_directories mw_dir_14 ref_page_14
+'
+
+test_done
diff --git a/contrib/mw-to-git/t/t9361-mw-to-git-push-pull.sh b/contrib/mw-to-git/t/t9361-mw-to-git-push-pull.sh
new file mode 100755
index 0000000..9ea2014
--- /dev/null
+++ b/contrib/mw-to-git/t/t9361-mw-to-git-push-pull.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+#
+# Copyright (C) 2012
+# Charles Roussel <charles.roussel@ensimag.imag.fr>
+# Simon Cathebras <simon.cathebras@ensimag.imag.fr>
+# Julien Khayat <julien.khayat@ensimag.imag.fr>
+# Guillaume Sasdy <guillaume.sasdy@ensimag.imag.fr>
+# Simon Perrat <simon.perrat@ensimag.imag.fr>
+#
+# License: GPL v2 or later
+
+# tests for git-remote-mediawiki
+
+test_description='Test the Git Mediawiki remote helper: git push and git pull simple test cases'
+
+. ./test-gitmw-lib.sh
+. ./push-pull-tests.sh
+. $TEST_DIRECTORY/test-lib.sh
+
+test_check_precond
+
+test_push_pull
+
+test_done
diff --git a/contrib/mw-to-git/t/t9362-mw-to-git-utf8.sh b/contrib/mw-to-git/t/t9362-mw-to-git-utf8.sh
new file mode 100755
index 0000000..246d47d
--- /dev/null
+++ b/contrib/mw-to-git/t/t9362-mw-to-git-utf8.sh
@@ -0,0 +1,321 @@
+#!/bin/sh
+#
+# Copyright (C) 2012
+# Charles Roussel <charles.roussel@ensimag.imag.fr>
+# Simon Cathebras <simon.cathebras@ensimag.imag.fr>
+# Julien Khayat <julien.khayat@ensimag.imag.fr>
+# Guillaume Sasdy <guillaume.sasdy@ensimag.imag.fr>
+# Simon Perrat <simon.perrat@ensimag.imag.fr>
+#
+# License: GPL v2 or later
+
+# tests for git-remote-mediawiki
+
+test_description='Test git-mediawiki with special characters in filenames'
+
+. ./test-gitmw-lib.sh
+. $TEST_DIRECTORY/test-lib.sh
+
+
+test_check_precond
+
+
+test_expect_success 'Git clone works for a wiki with accents in the page names' '
+ wiki_reset &&
+ wiki_editpage féé "This page must be délétéd before clone" false &&
+ wiki_editpage kèè "This page must be deleted before clone" false &&
+ wiki_editpage hàà "This page must be deleted before clone" false &&
+ wiki_editpage kîî "This page must be deleted before clone" false &&
+ wiki_editpage foo "This page must be deleted before clone" false &&
+ git clone mediawiki::'"$WIKI_URL"' mw_dir_1 &&
+ wiki_getallpage ref_page_1 &&
+ test_diff_directories mw_dir_1 ref_page_1
+'
+
+
+test_expect_success 'Git pull works with a wiki with accents in the pages names' '
+ wiki_reset &&
+ wiki_editpage kîî "this page must be cloned" false &&
+ wiki_editpage foo "this page must be cloned" false &&
+ git clone mediawiki::'"$WIKI_URL"' mw_dir_2 &&
+ wiki_editpage éàîôû "This page must be pulled" false &&
+ (
+ cd mw_dir_2 &&
+ git pull
+ ) &&
+ wiki_getallpage ref_page_2 &&
+ test_diff_directories mw_dir_2 ref_page_2
+'
+
+
+test_expect_success 'Cloning a chosen page works with accents' '
+ wiki_reset &&
+ wiki_editpage kîî "this page must be cloned" false &&
+ git clone -c remote.origin.pages=kîî \
+ mediawiki::'"$WIKI_URL"' mw_dir_3 &&
+ wiki_check_content mw_dir_3/Kîî.mw Kîî &&
+ test_path_is_file mw_dir_3/Kîî.mw &&
+ rm -rf mw_dir_3
+'
+
+
+test_expect_success 'The shallow option works with accents' '
+ wiki_reset &&
+ wiki_editpage néoà "1st revision, should not be cloned" false &&
+ wiki_editpage néoà "2nd revision, should be cloned" false &&
+ git -c remote.origin.shallow=true clone \
+ mediawiki::'"$WIKI_URL"' mw_dir_4 &&
+ test_contains_N_files mw_dir_4 2 &&
+ test_path_is_file mw_dir_4/Néoà.mw &&
+ test_path_is_file mw_dir_4/Main_Page.mw &&
+ (
+ cd mw_dir_4 &&
+ test `git log --oneline Néoà.mw | wc -l` -eq 1 &&
+ test `git log --oneline Main_Page.mw | wc -l ` -eq 1
+ ) &&
+ wiki_check_content mw_dir_4/Néoà.mw Néoà &&
+ wiki_check_content mw_dir_4/Main_Page.mw Main_Page
+'
+
+
+test_expect_success 'Cloning works when page name first letter has an accent' '
+ wiki_reset &&
+ wiki_editpage îî "this page must be cloned" false &&
+ git clone -c remote.origin.pages=îî \
+ mediawiki::'"$WIKI_URL"' mw_dir_5 &&
+ test_path_is_file mw_dir_5/Îî.mw &&
+ wiki_check_content mw_dir_5/Îî.mw Îî
+'
+
+
+test_expect_success 'Git push works with a wiki with accents' '
+ wiki_reset &&
+ wiki_editpage féé "lots of accents : éèàÖ" false &&
+ wiki_editpage foo "this page must be cloned" false &&
+ git clone mediawiki::'"$WIKI_URL"' mw_dir_6 &&
+ (
+ cd mw_dir_6 &&
+ echo "A wild Pîkächû appears on the wiki" >Pîkächû.mw &&
+ git add Pîkächû.mw &&
+ git commit -m "A new page appears" &&
+ git push
+ ) &&
+ wiki_getallpage ref_page_6 &&
+ test_diff_directories mw_dir_6 ref_page_6
+'
+
+test_expect_success 'Git clone works with accentsand spaces' '
+ wiki_reset &&
+ wiki_editpage "é à î" "this page must be délété before the clone" false &&
+ git clone mediawiki::'"$WIKI_URL"' mw_dir_7 &&
+ wiki_getallpage ref_page_7 &&
+ test_diff_directories mw_dir_7 ref_page_7
+'
+
+test_expect_success 'character $ in page name (mw -> git)' '
+ wiki_reset &&
+ wiki_editpage file_\$_foo "expect to be called file_$_foo" false &&
+ git clone mediawiki::'"$WIKI_URL"' mw_dir_8 &&
+ test_path_is_file mw_dir_8/File_\$_foo.mw &&
+ wiki_getallpage ref_page_8 &&
+ test_diff_directories mw_dir_8 ref_page_8
+'
+
+
+
+test_expect_success 'character $ in file name (git -> mw) ' '
+ wiki_reset &&
+ git clone mediawiki::'"$WIKI_URL"' mw_dir_9 &&
+ (
+ cd mw_dir_9 &&
+ echo "this file is called File_\$_foo.mw" >File_\$_foo.mw &&
+ git add . &&
+ git commit -am "file File_\$_foo.mw" &&
+ git pull &&
+ git push
+ ) &&
+ wiki_getallpage ref_page_9 &&
+ test_diff_directories mw_dir_9 ref_page_9
+'
+
+
+test_expect_failure 'capital at the begining of file names' '
+ wiki_reset &&
+ git clone mediawiki::'"$WIKI_URL"' mw_dir_10 &&
+ (
+ cd mw_dir_10 &&
+ echo "my new file foo" >foo.mw &&
+ echo "my new file Foo... Finger crossed" >Foo.mw &&
+ git add . &&
+ git commit -am "file foo.mw" &&
+ git pull &&
+ git push
+ ) &&
+ wiki_getallpage ref_page_10 &&
+ test_diff_directories mw_dir_10 ref_page_10
+'
+
+
+test_expect_failure 'special character at the begining of file name from mw to git' '
+ wiki_reset &&
+ git clone mediawiki::'"$WIKI_URL"' mw_dir_11 &&
+ wiki_editpage {char_1 "expect to be renamed {char_1" false &&
+ wiki_editpage [char_2 "expect to be renamed [char_2" false &&
+ (
+ cd mw_dir_11 &&
+ git pull
+ ) &&
+ test_path_is_file mw_dir_11/{char_1 &&
+ test_path_is_file mw_dir_11/[char_2
+'
+
+test_expect_success 'Pull page with title containing ":" other than namespace separator' '
+ wiki_editpage Foo:Bar content false &&
+ (
+ cd mw_dir_11 &&
+ git pull
+ ) &&
+ test_path_is_file mw_dir_11/Foo:Bar.mw
+'
+
+test_expect_success 'Push page with title containing ":" other than namespace separator' '
+ (
+ cd mw_dir_11 &&
+ echo content >NotANameSpace:Page.mw &&
+ git add NotANameSpace:Page.mw &&
+ git commit -m "add page with colon" &&
+ git push
+ ) &&
+ wiki_page_exist NotANameSpace:Page
+'
+
+test_expect_success 'test of correct formating for file name from mw to git' '
+ wiki_reset &&
+ git clone mediawiki::'"$WIKI_URL"' mw_dir_12 &&
+ wiki_editpage char_%_7b_1 "expect to be renamed char{_1" false &&
+ wiki_editpage char_%_5b_2 "expect to be renamed char{_2" false &&
+ (
+ cd mw_dir_12 &&
+ git pull
+ ) &&
+ test_path_is_file mw_dir_12/Char\{_1.mw &&
+ test_path_is_file mw_dir_12/Char\[_2.mw &&
+ wiki_getallpage ref_page_12 &&
+ mv ref_page_12/Char_%_7b_1.mw ref_page_12/Char\{_1.mw &&
+ mv ref_page_12/Char_%_5b_2.mw ref_page_12/Char\[_2.mw &&
+ test_diff_directories mw_dir_12 ref_page_12
+'
+
+
+test_expect_failure 'test of correct formating for file name begining with special character' '
+ wiki_reset &&
+ git clone mediawiki::'"$WIKI_URL"' mw_dir_13 &&
+ (
+ cd mw_dir_13 &&
+ echo "my new file {char_1" >\{char_1.mw &&
+ echo "my new file [char_2" >\[char_2.mw &&
+ git add . &&
+ git commit -am "commiting some exotic file name..." &&
+ git push &&
+ git pull
+ ) &&
+ wiki_getallpage ref_page_13 &&
+ test_path_is_file ref_page_13/{char_1.mw &&
+ test_path_is_file ref_page_13/[char_2.mw &&
+ test_diff_directories mw_dir_13 ref_page_13
+'
+
+
+test_expect_success 'test of correct formating for file name from git to mw' '
+ wiki_reset &&
+ git clone mediawiki::'"$WIKI_URL"' mw_dir_14 &&
+ (
+ cd mw_dir_14 &&
+ echo "my new file char{_1" >Char\{_1.mw &&
+ echo "my new file char[_2" >Char\[_2.mw &&
+ git add . &&
+ git commit -m "commiting some exotic file name..." &&
+ git push
+ ) &&
+ wiki_getallpage ref_page_14 &&
+ mv mw_dir_14/Char\{_1.mw mw_dir_14/Char_%_7b_1.mw &&
+ mv mw_dir_14/Char\[_2.mw mw_dir_14/Char_%_5b_2.mw &&
+ test_diff_directories mw_dir_14 ref_page_14
+'
+
+
+test_expect_success 'git clone with /' '
+ wiki_reset &&
+ wiki_editpage \/fo\/o "this is not important" false -c=Deleted &&
+ git clone mediawiki::'"$WIKI_URL"' mw_dir_15 &&
+ test_path_is_file mw_dir_15/%2Ffo%2Fo.mw &&
+ wiki_check_content mw_dir_15/%2Ffo%2Fo.mw \/fo\/o
+'
+
+
+test_expect_success 'git push with /' '
+ wiki_reset &&
+ git clone mediawiki::'"$WIKI_URL"' mw_dir_16 &&
+ echo "I will be on the wiki" >mw_dir_16/%2Ffo%2Fo.mw &&
+ (
+ cd mw_dir_16 &&
+ git add %2Ffo%2Fo.mw &&
+ git commit -m " %2Ffo%2Fo added" &&
+ git push
+ ) &&
+ wiki_page_exist \/fo\/o &&
+ wiki_check_content mw_dir_16/%2Ffo%2Fo.mw \/fo\/o
+
+'
+
+
+test_expect_success 'git clone with \' '
+ wiki_reset &&
+ wiki_editpage \\ko\\o "this is not important" false -c=Deleted &&
+ git clone mediawiki::'"$WIKI_URL"' mw_dir_17 &&
+ test_path_is_file mw_dir_17/\\ko\\o.mw &&
+ wiki_check_content mw_dir_17/\\ko\\o.mw \\ko\\o
+'
+
+
+test_expect_success 'git push with \' '
+ wiki_reset &&
+ git clone mediawiki::'"$WIKI_URL"' mw_dir_18 &&
+ echo "I will be on the wiki" >mw_dir_18/\\ko\\o.mw &&
+ (
+ cd mw_dir_18 &&
+ git add \\ko\\o.mw &&
+ git commit -m " \\ko\\o added" &&
+ git push
+ )&&
+ wiki_page_exist \\ko\\o &&
+ wiki_check_content mw_dir_18/\\ko\\o.mw \\ko\\o
+
+'
+
+test_expect_success 'git clone with \ in format control' '
+ wiki_reset &&
+ wiki_editpage \\no\\o "this is not important" false &&
+ git clone mediawiki::'"$WIKI_URL"' mw_dir_19 &&
+ test_path_is_file mw_dir_19/\\no\\o.mw &&
+ wiki_check_content mw_dir_19/\\no\\o.mw \\no\\o
+'
+
+
+test_expect_success 'git push with \ in format control' '
+ wiki_reset &&
+ git clone mediawiki::'"$WIKI_URL"' mw_dir_20 &&
+ echo "I will be on the wiki" >mw_dir_20/\\fo\\o.mw &&
+ (
+ cd mw_dir_20 &&
+ git add \\fo\\o.mw &&
+ git commit -m " \\fo\\o added" &&
+ git push
+ )&&
+ wiki_page_exist \\fo\\o &&
+ wiki_check_content mw_dir_20/\\fo\\o.mw \\fo\\o
+
+'
+
+
+test_done
diff --git a/contrib/mw-to-git/t/t9363-mw-to-git-export-import.sh b/contrib/mw-to-git/t/t9363-mw-to-git-export-import.sh
new file mode 100755
index 0000000..5a03739
--- /dev/null
+++ b/contrib/mw-to-git/t/t9363-mw-to-git-export-import.sh
@@ -0,0 +1,198 @@
+#!/bin/sh
+#
+# Copyright (C) 2012
+# Charles Roussel <charles.roussel@ensimag.imag.fr>
+# Simon Cathebras <simon.cathebras@ensimag.imag.fr>
+# Julien Khayat <julien.khayat@ensimag.imag.fr>
+# Guillaume Sasdy <guillaume.sasdy@ensimag.imag.fr>
+# Simon Perrat <simon.perrat@ensimag.imag.fr>
+#
+# License: GPL v2 or later
+
+# tests for git-remote-mediawiki
+
+test_description='Test the Git Mediawiki remote helper: git push and git pull simple test cases'
+
+. ./test-gitmw-lib.sh
+. $TEST_DIRECTORY/test-lib.sh
+
+
+test_check_precond
+
+
+test_git_reimport () {
+ git -c remote.origin.dumbPush=true push &&
+ git -c remote.origin.mediaImport=true pull --rebase
+}
+
+# Don't bother with permissions, be administrator by default
+test_expect_success 'setup config' '
+ git config --global remote.origin.mwLogin WikiAdmin &&
+ git config --global remote.origin.mwPassword AdminPass &&
+ test_might_fail git config --global --unset remote.origin.mediaImport
+'
+
+test_expect_success 'git push can upload media (File:) files' '
+ wiki_reset &&
+ git clone mediawiki::'"$WIKI_URL"' mw_dir &&
+ (
+ cd mw_dir &&
+ echo "hello world" >Foo.txt &&
+ git add Foo.txt &&
+ git commit -m "add a text file" &&
+ git push &&
+ "$PERL_PATH" -e "print STDOUT \"binary content: \".chr(255);" >Foo.txt &&
+ git add Foo.txt &&
+ git commit -m "add a text file with binary content" &&
+ git push
+ )
+'
+
+test_expect_success 'git clone works on previously created wiki with media files' '
+ test_when_finished "rm -rf mw_dir mw_dir_clone" &&
+ git clone -c remote.origin.mediaimport=true \
+ mediawiki::'"$WIKI_URL"' mw_dir_clone &&
+ test_cmp mw_dir_clone/Foo.txt mw_dir/Foo.txt &&
+ (cd mw_dir_clone && git checkout HEAD^) &&
+ (cd mw_dir && git checkout HEAD^) &&
+ test_cmp mw_dir_clone/Foo.txt mw_dir/Foo.txt
+'
+
+test_expect_success 'git push & pull work with locally renamed media files' '
+ wiki_reset &&
+ git clone mediawiki::'"$WIKI_URL"' mw_dir &&
+ test_when_finished "rm -fr mw_dir" &&
+ (
+ cd mw_dir &&
+ echo "A File" >Foo.txt &&
+ git add Foo.txt &&
+ git commit -m "add a file" &&
+ git mv Foo.txt Bar.txt &&
+ git commit -m "Rename a file" &&
+ test_git_reimport &&
+ echo "A File" >expect &&
+ test_cmp expect Bar.txt &&
+ test_path_is_missing Foo.txt
+ )
+'
+
+test_expect_success 'git push can propagate local page deletion' '
+ wiki_reset &&
+ git clone mediawiki::'"$WIKI_URL"' mw_dir &&
+ test_when_finished "rm -fr mw_dir" &&
+ (
+ cd mw_dir &&
+ test_path_is_missing Foo.mw &&
+ echo "hello world" >Foo.mw &&
+ git add Foo.mw &&
+ git commit -m "Add the page Foo" &&
+ git push &&
+ rm -f Foo.mw &&
+ git commit -am "Delete the page Foo" &&
+ test_git_reimport &&
+ test_path_is_missing Foo.mw
+ )
+'
+
+test_expect_success 'git push can propagate local media file deletion' '
+ wiki_reset &&
+ git clone mediawiki::'"$WIKI_URL"' mw_dir &&
+ test_when_finished "rm -fr mw_dir" &&
+ (
+ cd mw_dir &&
+ echo "hello world" >Foo.txt &&
+ git add Foo.txt &&
+ git commit -m "Add the text file Foo" &&
+ git rm Foo.txt &&
+ git commit -m "Delete the file Foo" &&
+ test_git_reimport &&
+ test_path_is_missing Foo.txt
+ )
+'
+
+# test failure: the file is correctly uploaded, and then deleted but
+# as no page link to it, the import (which looks at page revisions)
+# doesn't notice the file deletion on the wiki. We fetch the list of
+# files from the wiki, but as the file is deleted, it doesn't appear.
+test_expect_failure 'git pull correctly imports media file deletion when no page link to it' '
+ wiki_reset &&
+ git clone mediawiki::'"$WIKI_URL"' mw_dir &&
+ test_when_finished "rm -fr mw_dir" &&
+ (
+ cd mw_dir &&
+ echo "hello world" >Foo.txt &&
+ git add Foo.txt &&
+ git commit -m "Add the text file Foo" &&
+ git push &&
+ git rm Foo.txt &&
+ git commit -m "Delete the file Foo" &&
+ test_git_reimport &&
+ test_path_is_missing Foo.txt
+ )
+'
+
+test_expect_success 'git push properly warns about insufficient permissions' '
+ wiki_reset &&
+ git clone mediawiki::'"$WIKI_URL"' mw_dir &&
+ test_when_finished "rm -fr mw_dir" &&
+ (
+ cd mw_dir &&
+ echo "A File" >foo.forbidden &&
+ git add foo.forbidden &&
+ git commit -m "add a file" &&
+ git push 2>actual &&
+ test_i18ngrep "foo.forbidden is not a permitted file" actual
+ )
+'
+
+test_expect_success 'setup a repository with media files' '
+ wiki_reset &&
+ wiki_editpage testpage "I am linking a file [[File:File.txt]]" false &&
+ echo "File content" >File.txt &&
+ wiki_upload_file File.txt &&
+ echo "Another file content" >AnotherFile.txt &&
+ wiki_upload_file AnotherFile.txt
+'
+
+test_expect_success 'git clone works with one specific page cloned and mediaimport=true' '
+ git clone -c remote.origin.pages=testpage \
+ -c remote.origin.mediaimport=true \
+ mediawiki::'"$WIKI_URL"' mw_dir_15 &&
+ test_when_finished "rm -rf mw_dir_15" &&
+ test_contains_N_files mw_dir_15 3 &&
+ test_path_is_file mw_dir_15/Testpage.mw &&
+ test_path_is_file mw_dir_15/File:File.txt.mw &&
+ test_path_is_file mw_dir_15/File.txt &&
+ test_path_is_missing mw_dir_15/Main_Page.mw &&
+ test_path_is_missing mw_dir_15/File:AnotherFile.txt.mw &&
+ test_path_is_missing mw_dir_15/AnothetFile.txt &&
+ wiki_check_content mw_dir_15/Testpage.mw Testpage &&
+ test_cmp mw_dir_15/File.txt File.txt
+'
+
+test_expect_success 'git clone works with one specific page cloned and mediaimport=false' '
+ test_when_finished "rm -rf mw_dir_16" &&
+ git clone -c remote.origin.pages=testpage \
+ mediawiki::'"$WIKI_URL"' mw_dir_16 &&
+ test_contains_N_files mw_dir_16 1 &&
+ test_path_is_file mw_dir_16/Testpage.mw &&
+ test_path_is_missing mw_dir_16/File:File.txt.mw &&
+ test_path_is_missing mw_dir_16/File.txt &&
+ test_path_is_missing mw_dir_16/Main_Page.mw &&
+ wiki_check_content mw_dir_16/Testpage.mw Testpage
+'
+
+# should behave like mediaimport=false
+test_expect_success 'git clone works with one specific page cloned and mediaimport unset' '
+ test_when_finished "rm -fr mw_dir_17" &&
+ git clone -c remote.origin.pages=testpage \
+ mediawiki::'"$WIKI_URL"' mw_dir_17 &&
+ test_contains_N_files mw_dir_17 1 &&
+ test_path_is_file mw_dir_17/Testpage.mw &&
+ test_path_is_missing mw_dir_17/File:File.txt.mw &&
+ test_path_is_missing mw_dir_17/File.txt &&
+ test_path_is_missing mw_dir_17/Main_Page.mw &&
+ wiki_check_content mw_dir_17/Testpage.mw Testpage
+'
+
+test_done
diff --git a/contrib/mw-to-git/t/t9364-pull-by-rev.sh b/contrib/mw-to-git/t/t9364-pull-by-rev.sh
new file mode 100755
index 0000000..5c22457
--- /dev/null
+++ b/contrib/mw-to-git/t/t9364-pull-by-rev.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+test_description='Test the Git Mediawiki remote helper: git pull by revision'
+
+. ./test-gitmw-lib.sh
+. ./push-pull-tests.sh
+. $TEST_DIRECTORY/test-lib.sh
+
+test_check_precond
+
+test_expect_success 'configuration' '
+ git config --global mediawiki.fetchStrategy by_rev
+'
+
+test_push_pull
+
+test_done
diff --git a/contrib/mw-to-git/t/test-gitmw-lib.sh b/contrib/mw-to-git/t/test-gitmw-lib.sh
new file mode 100755
index 0000000..3b2cfac
--- /dev/null
+++ b/contrib/mw-to-git/t/test-gitmw-lib.sh
@@ -0,0 +1,435 @@
+# Copyright (C) 2012
+# Charles Roussel <charles.roussel@ensimag.imag.fr>
+# Simon Cathebras <simon.cathebras@ensimag.imag.fr>
+# Julien Khayat <julien.khayat@ensimag.imag.fr>
+# Guillaume Sasdy <guillaume.sasdy@ensimag.imag.fr>
+# Simon Perrat <simon.perrat@ensimag.imag.fr>
+# License: GPL v2 or later
+
+#
+# CONFIGURATION VARIABLES
+# You might want to change these ones
+#
+
+. ./test.config
+
+WIKI_URL=http://"$SERVER_ADDR:$PORT/$WIKI_DIR_NAME"
+CURR_DIR=$(pwd)
+TEST_OUTPUT_DIRECTORY=$(pwd)
+TEST_DIRECTORY="$CURR_DIR"/../../../t
+
+export TEST_OUTPUT_DIRECTORY TEST_DIRECTORY CURR_DIR
+
+if test "$LIGHTTPD" = "false" ; then
+ PORT=80
+else
+ WIKI_DIR_INST="$CURR_DIR/$WEB_WWW"
+fi
+
+wiki_upload_file () {
+ "$CURR_DIR"/test-gitmw.pl upload_file "$@"
+}
+
+wiki_getpage () {
+ "$CURR_DIR"/test-gitmw.pl get_page "$@"
+}
+
+wiki_delete_page () {
+ "$CURR_DIR"/test-gitmw.pl delete_page "$@"
+}
+
+wiki_editpage () {
+ "$CURR_DIR"/test-gitmw.pl edit_page "$@"
+}
+
+die () {
+ die_with_status 1 "$@"
+}
+
+die_with_status () {
+ status=$1
+ shift
+ echo >&2 "$*"
+ exit "$status"
+}
+
+
+# Check the preconditions to run git-remote-mediawiki's tests
+test_check_precond () {
+ if ! test_have_prereq PERL
+ then
+ skip_all='skipping gateway git-mw tests, perl not available'
+ test_done
+ fi
+
+ if [ ! -f "$GIT_BUILD_DIR"/git-remote-mediawiki ];
+ then
+ echo "No remote mediawiki for git found. Copying it in git"
+ echo "cp $GIT_BUILD_DIR/contrib/mw-to-git/git-remote-mediawiki $GIT_BUILD_DIR/"
+ ln -s "$GIT_BUILD_DIR"/contrib/mw-to-git/git-remote-mediawiki "$GIT_BUILD_DIR"
+ fi
+
+ if [ ! -d "$WIKI_DIR_INST/$WIKI_DIR_NAME" ];
+ then
+ skip_all='skipping gateway git-mw tests, no mediawiki found'
+ test_done
+ fi
+}
+
+# test_diff_directories <dir_git> <dir_wiki>
+#
+# Compare the contents of directories <dir_git> and <dir_wiki> with diff
+# and errors if they do not match. The program will
+# not look into .git in the process.
+# Warning: the first argument MUST be the directory containing the git data
+test_diff_directories () {
+ rm -rf "$1_tmp"
+ mkdir -p "$1_tmp"
+ cp "$1"/*.mw "$1_tmp"
+ diff -r -b "$1_tmp" "$2"
+}
+
+# $1=<dir>
+# $2=<N>
+#
+# Check that <dir> contains exactly <N> files
+test_contains_N_files () {
+ if test `ls -- "$1" | wc -l` -ne "$2"; then
+ echo "directory $1 sould contain $2 files"
+ echo "it contains these files:"
+ ls "$1"
+ false
+ fi
+}
+
+
+# wiki_check_content <file_name> <page_name>
+#
+# Compares the contents of the file <file_name> and the wiki page
+# <page_name> and exits with error 1 if they do not match.
+wiki_check_content () {
+ mkdir -p wiki_tmp
+ wiki_getpage "$2" wiki_tmp
+ # replacement of forbidden character in file name
+ page_name=$(printf "%s\n" "$2" | sed -e "s/\//%2F/g")
+
+ diff -b "$1" wiki_tmp/"$page_name".mw
+ if test $? -ne 0
+ then
+ rm -rf wiki_tmp
+ error "ERROR: file $2 not found on wiki"
+ fi
+ rm -rf wiki_tmp
+}
+
+# wiki_page_exist <page_name>
+#
+# Check the existence of the page <page_name> on the wiki and exits
+# with error if it is absent from it.
+wiki_page_exist () {
+ mkdir -p wiki_tmp
+ wiki_getpage "$1" wiki_tmp
+ page_name=$(printf "%s\n" "$1" | sed "s/\//%2F/g")
+ if test -f wiki_tmp/"$page_name".mw ; then
+ rm -rf wiki_tmp
+ else
+ rm -rf wiki_tmp
+ error "test failed: file $1 not found on wiki"
+ fi
+}
+
+# wiki_getallpagename
+#
+# Fetch the name of each page on the wiki.
+wiki_getallpagename () {
+ "$CURR_DIR"/test-gitmw.pl getallpagename
+}
+
+# wiki_getallpagecategory <category>
+#
+# Fetch the name of each page belonging to <category> on the wiki.
+wiki_getallpagecategory () {
+ "$CURR_DIR"/test-gitmw.pl getallpagename "$@"
+}
+
+# wiki_getallpage <dest_dir> [<category>]
+#
+# Fetch all the pages from the wiki and place them in the directory
+# <dest_dir>.
+# If <category> is define, then wiki_getallpage fetch the pages included
+# in <category>.
+wiki_getallpage () {
+ if test -z "$2";
+ then
+ wiki_getallpagename
+ else
+ wiki_getallpagecategory "$2"
+ fi
+ mkdir -p "$1"
+ while read -r line; do
+ wiki_getpage "$line" $1;
+ done < all.txt
+}
+
+# ================= Install part =================
+
+error () {
+ echo "$@" >&2
+ exit 1
+}
+
+# config_lighttpd
+#
+# Create the configuration files and the folders necessary to start lighttpd.
+# Overwrite any existing file.
+config_lighttpd () {
+ mkdir -p $WEB
+ mkdir -p $WEB_TMP
+ mkdir -p $WEB_WWW
+ cat > $WEB/lighttpd.conf <<EOF
+ server.document-root = "$CURR_DIR/$WEB_WWW"
+ server.port = $PORT
+ server.pid-file = "$CURR_DIR/$WEB_TMP/pid"
+
+ server.modules = (
+ "mod_rewrite",
+ "mod_redirect",
+ "mod_access",
+ "mod_accesslog",
+ "mod_fastcgi"
+ )
+
+ index-file.names = ("index.php" , "index.html")
+
+ mimetype.assign = (
+ ".pdf" => "application/pdf",
+ ".sig" => "application/pgp-signature",
+ ".spl" => "application/futuresplash",
+ ".class" => "application/octet-stream",
+ ".ps" => "application/postscript",
+ ".torrent" => "application/x-bittorrent",
+ ".dvi" => "application/x-dvi",
+ ".gz" => "application/x-gzip",
+ ".pac" => "application/x-ns-proxy-autoconfig",
+ ".swf" => "application/x-shockwave-flash",
+ ".tar.gz" => "application/x-tgz",
+ ".tgz" => "application/x-tgz",
+ ".tar" => "application/x-tar",
+ ".zip" => "application/zip",
+ ".mp3" => "audio/mpeg",
+ ".m3u" => "audio/x-mpegurl",
+ ".wma" => "audio/x-ms-wma",
+ ".wax" => "audio/x-ms-wax",
+ ".ogg" => "application/ogg",
+ ".wav" => "audio/x-wav",
+ ".gif" => "image/gif",
+ ".jpg" => "image/jpeg",
+ ".jpeg" => "image/jpeg",
+ ".png" => "image/png",
+ ".xbm" => "image/x-xbitmap",
+ ".xpm" => "image/x-xpixmap",
+ ".xwd" => "image/x-xwindowdump",
+ ".css" => "text/css",
+ ".html" => "text/html",
+ ".htm" => "text/html",
+ ".js" => "text/javascript",
+ ".asc" => "text/plain",
+ ".c" => "text/plain",
+ ".cpp" => "text/plain",
+ ".log" => "text/plain",
+ ".conf" => "text/plain",
+ ".text" => "text/plain",
+ ".txt" => "text/plain",
+ ".dtd" => "text/xml",
+ ".xml" => "text/xml",
+ ".mpeg" => "video/mpeg",
+ ".mpg" => "video/mpeg",
+ ".mov" => "video/quicktime",
+ ".qt" => "video/quicktime",
+ ".avi" => "video/x-msvideo",
+ ".asf" => "video/x-ms-asf",
+ ".asx" => "video/x-ms-asf",
+ ".wmv" => "video/x-ms-wmv",
+ ".bz2" => "application/x-bzip",
+ ".tbz" => "application/x-bzip-compressed-tar",
+ ".tar.bz2" => "application/x-bzip-compressed-tar",
+ "" => "text/plain"
+ )
+
+ fastcgi.server = ( ".php" =>
+ ("localhost" =>
+ ( "socket" => "$CURR_DIR/$WEB_TMP/php.socket",
+ "bin-path" => "$PHP_DIR/php-cgi -c $CURR_DIR/$WEB/php.ini"
+
+ )
+ )
+ )
+EOF
+
+ cat > $WEB/php.ini <<EOF
+ session.save_path ='$CURR_DIR/$WEB_TMP'
+EOF
+}
+
+# start_lighttpd
+#
+# Start or restart daemon lighttpd. If restart, rewrite configuration files.
+start_lighttpd () {
+ if test -f "$WEB_TMP/pid"; then
+ echo "Instance already running. Restarting..."
+ stop_lighttpd
+ fi
+ config_lighttpd
+ "$LIGHTTPD_DIR"/lighttpd -f "$WEB"/lighttpd.conf
+
+ if test $? -ne 0 ; then
+ echo "Could not execute http deamon lighttpd"
+ exit 1
+ fi
+}
+
+# stop_lighttpd
+#
+# Kill daemon lighttpd and removes files and folders associated.
+stop_lighttpd () {
+ test -f "$WEB_TMP/pid" && kill $(cat "$WEB_TMP/pid")
+ rm -rf "$WEB"
+}
+
+# Create the SQLite database of the MediaWiki. If the database file already
+# exists, it will be deleted.
+# This script should be runned from the directory where $FILES_FOLDER is
+# located.
+create_db () {
+ rm -f "$TMP/$DB_FILE"
+
+ echo "Generating the SQLite database file. It can take some time ..."
+ # Run the php script to generate the SQLite database file
+ # with cURL calls.
+ php "$FILES_FOLDER/$DB_INSTALL_SCRIPT" $(basename "$DB_FILE" .sqlite) \
+ "$WIKI_ADMIN" "$WIKI_PASSW" "$TMP" "$PORT"
+
+ if [ ! -f "$TMP/$DB_FILE" ] ; then
+ error "Can't create database file $TMP/$DB_FILE. Try to run ./install-wiki.sh delete first."
+ fi
+
+ # Copy the generated database file into the directory the
+ # user indicated.
+ cp "$TMP/$DB_FILE" "$FILES_FOLDER" ||
+ error "Unable to copy $TMP/$DB_FILE to $FILES_FOLDER"
+}
+
+# Install a wiki in your web server directory.
+wiki_install () {
+ if test $LIGHTTPD = "true" ; then
+ start_lighttpd
+ fi
+
+ SERVER_ADDR=$SERVER_ADDR:$PORT
+ # In this part, we change directory to $TMP in order to download,
+ # unpack and copy the files of MediaWiki
+ (
+ mkdir -p "$WIKI_DIR_INST/$WIKI_DIR_NAME"
+ if [ ! -d "$WIKI_DIR_INST/$WIKI_DIR_NAME" ] ; then
+ error "Folder $WIKI_DIR_INST/$WIKI_DIR_NAME doesn't exist.
+ Please create it and launch the script again."
+ fi
+
+ # Fetch MediaWiki's archive if not already present in the TMP directory
+ cd "$TMP"
+ if [ ! -f "$MW_VERSION.tar.gz" ] ; then
+ echo "Downloading $MW_VERSION sources ..."
+ wget "http://download.wikimedia.org/mediawiki/1.19/mediawiki-1.19.0.tar.gz" ||
+ error "Unable to download "\
+ "http://download.wikimedia.org/mediawiki/1.19/"\
+ "mediawiki-1.19.0.tar.gz. "\
+ "Please fix your connection and launch the script again."
+ echo "$MW_VERSION.tar.gz downloaded in `pwd`. "\
+ "You can delete it later if you want."
+ else
+ echo "Reusing existing $MW_VERSION.tar.gz downloaded in `pwd`."
+ fi
+ archive_abs_path=$(pwd)/"$MW_VERSION.tar.gz"
+ cd "$WIKI_DIR_INST/$WIKI_DIR_NAME/" ||
+ error "can't cd to $WIKI_DIR_INST/$WIKI_DIR_NAME/"
+ tar xzf "$archive_abs_path" --strip-components=1 ||
+ error "Unable to extract WikiMedia's files from $archive_abs_path to "\
+ "$WIKI_DIR_INST/$WIKI_DIR_NAME"
+ ) || exit 1
+
+ create_db
+
+ # Copy the generic LocalSettings.php in the web server's directory
+ # And modify parameters according to the ones set at the top
+ # of this script.
+ # Note that LocalSettings.php is never modified.
+ if [ ! -f "$FILES_FOLDER/LocalSettings.php" ] ; then
+ error "Can't find $FILES_FOLDER/LocalSettings.php " \
+ "in the current folder. "\
+ "Please run the script inside its folder."
+ fi
+ cp "$FILES_FOLDER/LocalSettings.php" \
+ "$FILES_FOLDER/LocalSettings-tmp.php" ||
+ error "Unable to copy $FILES_FOLDER/LocalSettings.php " \
+ "to $FILES_FOLDER/LocalSettings-tmp.php"
+
+ # Parse and set the LocalSettings file of the user according to the
+ # CONFIGURATION VARIABLES section at the beginning of this script
+ file_swap="$FILES_FOLDER/LocalSettings-swap.php"
+ sed "s,@WG_SCRIPT_PATH@,/$WIKI_DIR_NAME," \
+ "$FILES_FOLDER/LocalSettings-tmp.php" > "$file_swap"
+ mv "$file_swap" "$FILES_FOLDER/LocalSettings-tmp.php"
+ sed "s,@WG_SERVER@,http://$SERVER_ADDR," \
+ "$FILES_FOLDER/LocalSettings-tmp.php" > "$file_swap"
+ mv "$file_swap" "$FILES_FOLDER/LocalSettings-tmp.php"
+ sed "s,@WG_SQLITE_DATADIR@,$TMP," \
+ "$FILES_FOLDER/LocalSettings-tmp.php" > "$file_swap"
+ mv "$file_swap" "$FILES_FOLDER/LocalSettings-tmp.php"
+ sed "s,@WG_SQLITE_DATAFILE@,$( basename $DB_FILE .sqlite)," \
+ "$FILES_FOLDER/LocalSettings-tmp.php" > "$file_swap"
+ mv "$file_swap" "$FILES_FOLDER/LocalSettings-tmp.php"
+
+ mv "$FILES_FOLDER/LocalSettings-tmp.php" \
+ "$WIKI_DIR_INST/$WIKI_DIR_NAME/LocalSettings.php" ||
+ error "Unable to move $FILES_FOLDER/LocalSettings-tmp.php" \
+ "in $WIKI_DIR_INST/$WIKI_DIR_NAME"
+ echo "File $FILES_FOLDER/LocalSettings.php is set in" \
+ " $WIKI_DIR_INST/$WIKI_DIR_NAME"
+
+ echo "Your wiki has been installed. You can check it at
+ http://$SERVER_ADDR/$WIKI_DIR_NAME"
+}
+
+# Reset the database of the wiki and the password of the admin
+#
+# Warning: This function must be called only in a subdirectory of t/ directory
+wiki_reset () {
+ # Copy initial database of the wiki
+ if [ ! -f "../$FILES_FOLDER/$DB_FILE" ] ; then
+ error "Can't find ../$FILES_FOLDER/$DB_FILE in the current folder."
+ fi
+ cp "../$FILES_FOLDER/$DB_FILE" "$TMP" ||
+ error "Can't copy ../$FILES_FOLDER/$DB_FILE in $TMP"
+ echo "File $FILES_FOLDER/$DB_FILE is set in $TMP"
+}
+
+# Delete the wiki created in the web server's directory and all its content
+# saved in the database.
+wiki_delete () {
+ if test $LIGHTTPD = "true"; then
+ stop_lighttpd
+ else
+ # Delete the wiki's directory.
+ rm -rf "$WIKI_DIR_INST/$WIKI_DIR_NAME" ||
+ error "Wiki's directory $WIKI_DIR_INST/" \
+ "$WIKI_DIR_NAME could not be deleted"
+ # Delete the wiki's SQLite database.
+ rm -f "$TMP/$DB_FILE" ||
+ error "Database $TMP/$DB_FILE could not be deleted."
+ fi
+
+ # Delete the wiki's SQLite database
+ rm -f "$TMP/$DB_FILE" || error "Database $TMP/$DB_FILE could not be deleted."
+ rm -f "$FILES_FOLDER/$DB_FILE"
+ rm -rf "$TMP/$MW_VERSION"
+}
diff --git a/contrib/mw-to-git/t/test-gitmw.pl b/contrib/mw-to-git/t/test-gitmw.pl
new file mode 100755
index 0000000..0ff7625
--- /dev/null
+++ b/contrib/mw-to-git/t/test-gitmw.pl
@@ -0,0 +1,225 @@
+#!/usr/bin/perl -w -s
+# Copyright (C) 2012
+# Charles Roussel <charles.roussel@ensimag.imag.fr>
+# Simon Cathebras <simon.cathebras@ensimag.imag.fr>
+# Julien Khayat <julien.khayat@ensimag.imag.fr>
+# Guillaume Sasdy <guillaume.sasdy@ensimag.imag.fr>
+# Simon Perrat <simon.perrat@ensimag.imag.fr>
+# License: GPL v2 or later
+
+# Usage:
+# ./test-gitmw.pl <command> [argument]*
+# Execute in terminal using the name of the function to call as first
+# parameter, and the function's arguments as following parameters
+#
+# Example:
+# ./test-gitmw.pl "get_page" foo .
+# will call <wiki_getpage> with arguments <foo> and <.>
+#
+# Available functions are:
+# "get_page"
+# "delete_page"
+# "edit_page"
+# "getallpagename"
+
+use MediaWiki::API;
+use Getopt::Long;
+use encoding 'utf8';
+use DateTime::Format::ISO8601;
+use open ':encoding(utf8)';
+use constant SLASH_REPLACEMENT => "%2F";
+
+#Parsing of the config file
+
+my $configfile = "$ENV{'CURR_DIR'}/test.config";
+my %config;
+open my $CONFIG, "<", $configfile or die "can't open $configfile: $!";
+while (<$CONFIG>)
+{
+ chomp;
+ s/#.*//;
+ s/^\s+//;
+ s/\s+$//;
+ next unless length;
+ my ($key, $value) = split (/\s*=\s*/,$_, 2);
+ $config{$key} = $value;
+ last if ($key eq 'LIGHTTPD' and $value eq 'false');
+ last if ($key eq 'PORT');
+}
+close $CONFIG or die "can't close $configfile: $!";
+
+my $wiki_address = "http://$config{'SERVER_ADDR'}".":"."$config{'PORT'}";
+my $wiki_url = "$wiki_address/$config{'WIKI_DIR_NAME'}/api.php";
+my $wiki_admin = "$config{'WIKI_ADMIN'}";
+my $wiki_admin_pass = "$config{'WIKI_PASSW'}";
+my $mw = MediaWiki::API->new;
+$mw->{config}->{api_url} = $wiki_url;
+
+
+# wiki_login <name> <password>
+#
+# Logs the user with <name> and <password> in the global variable
+# of the mediawiki $mw
+sub wiki_login {
+ $mw->login( { lgname => "$_[0]",lgpassword => "$_[1]" } )
+ || die "getpage: login failed";
+}
+
+# wiki_getpage <wiki_page> <dest_path>
+#
+# fetch a page <wiki_page> from the wiki referenced in the global variable
+# $mw and copies its content in directory dest_path
+sub wiki_getpage {
+ my $pagename = $_[0];
+ my $destdir = $_[1];
+
+ my $page = $mw->get_page( { title => $pagename } );
+ if (!defined($page)) {
+ die "getpage: wiki does not exist";
+ }
+
+ my $content = $page->{'*'};
+ if (!defined($content)) {
+ die "getpage: page does not exist";
+ }
+
+ $pagename=$page->{'title'};
+ # Replace spaces by underscore in the page name
+ $pagename =~ s/ /_/g;
+ $pagename =~ s/\//%2F/g;
+ open(my $file, ">$destdir/$pagename.mw");
+ print $file "$content";
+ close ($file);
+
+}
+
+# wiki_delete_page <page_name>
+#
+# delete the page with name <page_name> from the wiki referenced
+# in the global variable $mw
+sub wiki_delete_page {
+ my $pagename = $_[0];
+
+ my $exist=$mw->get_page({title => $pagename});
+
+ if (defined($exist->{'*'})){
+ $mw->edit({ action => 'delete',
+ title => $pagename})
+ || die $mw->{error}->{code} . ": " . $mw->{error}->{details};
+ } else {
+ die "no page with such name found: $pagename\n";
+ }
+}
+
+# wiki_editpage <wiki_page> <wiki_content> <wiki_append> [-c=<category>] [-s=<summary>]
+#
+# Edit a page named <wiki_page> with content <wiki_content> on the wiki
+# referenced with the global variable $mw
+# If <wiki_append> == true : append <wiki_content> at the end of the actual
+# content of the page <wiki_page>
+# If <wik_page> doesn't exist, that page is created with the <wiki_content>
+sub wiki_editpage {
+ my $wiki_page = $_[0];
+ my $wiki_content = $_[1];
+ my $wiki_append = $_[2];
+ my $summary = "";
+ my ($summ, $cat) = ();
+ GetOptions('s=s' => \$summ, 'c=s' => \$cat);
+
+ my $append = 0;
+ if (defined($wiki_append) && $wiki_append eq 'true') {
+ $append=1;
+ }
+
+ my $previous_text ="";
+
+ if ($append) {
+ my $ref = $mw->get_page( { title => $wiki_page } );
+ $previous_text = $ref->{'*'};
+ }
+
+ my $text = $wiki_content;
+ if (defined($previous_text)) {
+ $text="$previous_text$text";
+ }
+
+ # Eventually, add this page to a category.
+ if (defined($cat)) {
+ my $category_name="[[Category:$cat]]";
+ $text="$text\n $category_name";
+ }
+ if(defined($summ)){
+ $summary=$summ;
+ }
+
+ $mw->edit( { action => 'edit', title => $wiki_page, summary => $summary, text => "$text"} );
+}
+
+# wiki_getallpagename [<category>]
+#
+# Fetch all pages of the wiki referenced by the global variable $mw
+# and print the names of each one in the file all.txt with a new line
+# ("\n") between these.
+# If the argument <category> is defined, then this function get only the pages
+# belonging to <category>.
+sub wiki_getallpagename {
+ # fetch the pages of the wiki
+ if (defined($_[0])) {
+ my $mw_pages = $mw->list ( { action => 'query',
+ list => 'categorymembers',
+ cmtitle => "Category:$_[0]",
+ cmnamespace => 0,
+ cmlimit => 500 },
+ )
+ || die $mw->{error}->{code}.": ".$mw->{error}->{details};
+ open(my $file, ">all.txt");
+ foreach my $page (@{$mw_pages}) {
+ print $file "$page->{title}\n";
+ }
+ close ($file);
+
+ } else {
+ my $mw_pages = $mw->list({
+ action => 'query',
+ list => 'allpages',
+ aplimit => 500,
+ })
+ || die $mw->{error}->{code}.": ".$mw->{error}->{details};
+ open(my $file, ">all.txt");
+ foreach my $page (@{$mw_pages}) {
+ print $file "$page->{title}\n";
+ }
+ close ($file);
+ }
+}
+
+sub wiki_upload_file {
+ my $file_name = $_[0];
+ my $resultat = $mw->edit ( {
+ action => 'upload',
+ filename => $file_name,
+ comment => 'upload a file',
+ file => [ $file_name ],
+ ignorewarnings=>1,
+ }, {
+ skip_encoding => 1
+ } ) || die $mw->{error}->{code} . ' : ' . $mw->{error}->{details};
+}
+
+
+
+# Main part of this script: parse the command line arguments
+# and select which function to execute
+my $fct_to_call = shift;
+
+wiki_login($wiki_admin, $wiki_admin_pass);
+
+my %functions_to_call = qw(
+ upload_file wiki_upload_file
+ get_page wiki_getpage
+ delete_page wiki_delete_page
+ edit_page wiki_editpage
+ getallpagename wiki_getallpagename
+);
+die "$0 ERROR: wrong argument" unless exists $functions_to_call{$fct_to_call};
+&{$functions_to_call{$fct_to_call}}(@ARGV);
diff --git a/contrib/mw-to-git/t/test.config b/contrib/mw-to-git/t/test.config
new file mode 100644
index 0000000..958b37b
--- /dev/null
+++ b/contrib/mw-to-git/t/test.config
@@ -0,0 +1,35 @@
+# Name of the web server's directory dedicated to the wiki is WIKI_DIR_NAME
+WIKI_DIR_NAME=wiki
+
+# Login and password of the wiki's admin
+WIKI_ADMIN=WikiAdmin
+WIKI_PASSW=AdminPass
+
+# Address of the web server
+SERVER_ADDR=localhost
+
+# SQLite database of the wiki, named DB_FILE, is located in TMP
+TMP=/tmp
+DB_FILE=wikidb.sqlite
+
+# If LIGHTTPD is not set to true, the script will use the defaut
+# web server running in WIKI_DIR_INST.
+WIKI_DIR_INST=/var/www
+
+# If LIGHTTPD is set to true, the script will use Lighttpd to run
+# the wiki.
+LIGHTTPD=true
+
+# The variables below are useful only if LIGHTTPD is set to true.
+PORT=1234
+PHP_DIR=/usr/bin
+LIGHTTPD_DIR=/usr/sbin
+WEB=WEB
+WEB_TMP=$WEB/tmp
+WEB_WWW=$WEB/www
+
+# The variables below are used by the script to install a wiki.
+# You should not modify these unless you are modifying the script itself.
+MW_VERSION=mediawiki-1.19.0
+FILES_FOLDER=install-wiki
+DB_INSTALL_SCRIPT=db_install.php
diff --git a/credential.c b/credential.c
index 62d1c56..e54753c 100644
--- a/credential.c
+++ b/credential.c
@@ -172,6 +172,8 @@ int credential_read(struct credential *c, FILE *fp)
} else if (!strcmp(key, "path")) {
free(c->path);
c->path = xstrdup(value);
+ } else if (!strcmp(key, "url")) {
+ credential_from_url(c, value);
}
/*
* Ignore other lines; we don't know what they mean, but
@@ -191,7 +193,7 @@ static void credential_write_item(FILE *fp, const char *key, const char *value)
fprintf(fp, "%s=%s\n", key, value);
}
-static void credential_write(const struct credential *c, FILE *fp)
+void credential_write(const struct credential *c, FILE *fp)
{
credential_write_item(fp, "protocol", c->protocol);
credential_write_item(fp, "host", c->host);
diff --git a/credential.h b/credential.h
index 96ea41b..0c3e85e 100644
--- a/credential.h
+++ b/credential.h
@@ -26,6 +26,7 @@ void credential_approve(struct credential *);
void credential_reject(struct credential *);
int credential_read(struct credential *, FILE *);
+void credential_write(const struct credential *, FILE *);
void credential_from_url(struct credential *, const char *url);
int credential_match(const struct credential *have,
const struct credential *want);
diff --git a/daemon.c b/daemon.c
index ab21e66..4602b46 100644
--- a/daemon.c
+++ b/daemon.c
@@ -30,6 +30,7 @@ static const char daemon_usage[] =
" [--interpolated-path=<path>]\n"
" [--reuseaddr] [--pid-file=<file>]\n"
" [--(enable|disable|allow-override|forbid-override)=<service>]\n"
+" [--access-hook=<path>]\n"
" [--inetd | [--listen=<host_or_ipaddr>] [--port=<n>]\n"
" [--detach] [--user=<user> [--group=<group>]]\n"
" [<directory>...]";
@@ -256,6 +257,71 @@ static int daemon_error(const char *dir, const char *msg)
return -1;
}
+static char *access_hook;
+
+static int run_access_hook(struct daemon_service *service, const char *dir, const char *path)
+{
+ struct child_process child;
+ struct strbuf buf = STRBUF_INIT;
+ const char *argv[8];
+ const char **arg = argv;
+ char *eol;
+ int seen_errors = 0;
+
+#define STRARG(x) ((x) ? (x) : "")
+ *arg++ = access_hook;
+ *arg++ = service->name;
+ *arg++ = path;
+ *arg++ = STRARG(hostname);
+ *arg++ = STRARG(canon_hostname);
+ *arg++ = STRARG(ip_address);
+ *arg++ = STRARG(tcp_port);
+ *arg = NULL;
+#undef STRARG
+
+ memset(&child, 0, sizeof(child));
+ child.use_shell = 1;
+ child.argv = argv;
+ child.no_stdin = 1;
+ child.no_stderr = 1;
+ child.out = -1;
+ if (start_command(&child)) {
+ logerror("daemon access hook '%s' failed to start",
+ access_hook);
+ goto error_return;
+ }
+ if (strbuf_read(&buf, child.out, 0) < 0) {
+ logerror("failed to read from pipe to daemon access hook '%s'",
+ access_hook);
+ strbuf_reset(&buf);
+ seen_errors = 1;
+ }
+ if (close(child.out) < 0) {
+ logerror("failed to close pipe to daemon access hook '%s'",
+ access_hook);
+ seen_errors = 1;
+ }
+ if (finish_command(&child))
+ seen_errors = 1;
+
+ if (!seen_errors) {
+ strbuf_release(&buf);
+ return 0;
+ }
+
+error_return:
+ strbuf_ltrim(&buf);
+ if (!buf.len)
+ strbuf_addstr(&buf, "service rejected");
+ eol = strchr(buf.buf, '\n');
+ if (eol)
+ *eol = '\0';
+ errno = EACCES;
+ daemon_error(dir, buf.buf);
+ strbuf_release(&buf);
+ return -1;
+}
+
static int run_service(char *dir, struct daemon_service *service)
{
const char *path;
@@ -304,6 +370,13 @@ static int run_service(char *dir, struct daemon_service *service)
}
/*
+ * Optionally, a hook can choose to deny access to the
+ * repository depending on the phase of the moon.
+ */
+ if (access_hook && run_access_hook(service, dir, path))
+ return -1;
+
+ /*
* We'll ignore SIGTERM from now on, we have a
* good client.
*/
@@ -1142,6 +1215,10 @@ int main(int argc, char **argv)
export_all_trees = 1;
continue;
}
+ if (!prefixcmp(arg, "--access-hook=")) {
+ access_hook = arg + 14;
+ continue;
+ }
if (!prefixcmp(arg, "--timeout=")) {
timeout = atoi(arg+10);
continue;
diff --git a/diff.c b/diff.c
index f1b0447..35d3f07 100644
--- a/diff.c
+++ b/diff.c
@@ -25,7 +25,7 @@
static int diff_detect_rename_default;
static int diff_rename_limit_default = 400;
static int diff_suppress_blank_empty;
-int diff_use_color_default = -1;
+static int diff_use_color_default = -1;
static const char *diff_word_regex_cfg;
static const char *external_diff_cmd_cfg;
int diff_auto_refresh_index = 1;
@@ -1398,11 +1398,11 @@ int print_stat_summary(FILE *fp, int files, int insertions, int deletions)
if (!files) {
assert(insertions == 0 && deletions == 0);
- return fputs(_(" 0 files changed\n"), fp);
+ return fprintf(fp, "%s\n", " 0 files changed");
}
strbuf_addf(&sb,
- Q_(" %d file changed", " %d files changed", files),
+ (files == 1) ? " %d file changed" : " %d files changed",
files);
/*
@@ -1419,8 +1419,7 @@ int print_stat_summary(FILE *fp, int files, int insertions, int deletions)
* do not translate it.
*/
strbuf_addf(&sb,
- Q_(", %d insertion(+)", ", %d insertions(+)",
- insertions),
+ (insertions == 1) ? ", %d insertion(+)" : ", %d insertions(+)",
insertions);
}
@@ -1430,8 +1429,7 @@ int print_stat_summary(FILE *fp, int files, int insertions, int deletions)
* do not translate it.
*/
strbuf_addf(&sb,
- Q_(", %d deletion(-)", ", %d deletions(-)",
- deletions),
+ (deletions == 1) ? ", %d deletion(-)" : ", %d deletions(-)",
deletions);
}
strbuf_addch(&sb, '\n');
diff --git a/diff.h b/diff.h
index e25addb..a658f85 100644
--- a/diff.h
+++ b/diff.h
@@ -243,7 +243,6 @@ extern int parse_long_opt(const char *opt, const char **argv,
extern int git_diff_basic_config(const char *var, const char *value, void *cb);
extern int git_diff_ui_config(const char *var, const char *value, void *cb);
-extern int diff_use_color_default;
extern void diff_setup(struct diff_options *);
extern int diff_opt_parse(struct diff_options *, const char **, int);
extern void diff_setup_done(struct diff_options *);
diff --git a/dir.c b/dir.c
index 2c02b31..4868339 100644
--- a/dir.c
+++ b/dir.c
@@ -288,9 +288,24 @@ int match_pathspec_depth(const struct pathspec *ps,
return retval;
}
+/*
+ * Return the length of the "simple" part of a path match limiter.
+ */
+static int simple_length(const char *match)
+{
+ int len = -1;
+
+ for (;;) {
+ unsigned char c = *match++;
+ len++;
+ if (c == '\0' || is_glob_special(c))
+ return len;
+ }
+}
+
static int no_wildcard(const char *string)
{
- return string[strcspn(string, "*?[{\\")] == '\0';
+ return string[simple_length(string)] == '\0';
}
void add_exclude(const char *string, const char *base,
@@ -326,8 +341,7 @@ void add_exclude(const char *string, const char *base,
x->flags = flags;
if (!strchr(string, '/'))
x->flags |= EXC_FLAG_NODIR;
- if (no_wildcard(string))
- x->flags |= EXC_FLAG_NOWILDCARD;
+ x->nowildcardlen = simple_length(string);
if (*string == '*' && no_wildcard(string+1))
x->flags |= EXC_FLAG_ENDSWITH;
ALLOC_GROW(which->excludes, which->nr + 1, which->alloc);
@@ -383,6 +397,8 @@ int add_excludes_from_file_to_list(const char *fname,
fd = open(fname, O_RDONLY);
if (fd < 0 || fstat(fd, &st) < 0) {
+ if (errno != ENOENT)
+ warn_on_inaccessible(fname);
if (0 <= fd)
close(fd);
if (!check_index ||
@@ -498,57 +514,69 @@ int excluded_from_list(const char *pathname,
{
int i;
- if (el->nr) {
- for (i = el->nr - 1; 0 <= i; i--) {
- struct exclude *x = el->excludes[i];
- const char *exclude = x->pattern;
- int to_exclude = x->to_exclude;
-
- if (x->flags & EXC_FLAG_MUSTBEDIR) {
- if (*dtype == DT_UNKNOWN)
- *dtype = get_dtype(NULL, pathname, pathlen);
- if (*dtype != DT_DIR)
- continue;
- }
+ if (!el->nr)
+ return -1; /* undefined */
- if (x->flags & EXC_FLAG_NODIR) {
- /* match basename */
- if (x->flags & EXC_FLAG_NOWILDCARD) {
- if (!strcmp_icase(exclude, basename))
- return to_exclude;
- } else if (x->flags & EXC_FLAG_ENDSWITH) {
- if (x->patternlen - 1 <= pathlen &&
- !strcmp_icase(exclude + 1, pathname + pathlen - x->patternlen + 1))
- return to_exclude;
- } else {
- if (fnmatch_icase(exclude, basename, 0) == 0)
- return to_exclude;
- }
- }
- else {
- /* match with FNM_PATHNAME:
- * exclude has base (baselen long) implicitly
- * in front of it.
- */
- int baselen = x->baselen;
- if (*exclude == '/')
- exclude++;
-
- if (pathlen < baselen ||
- (baselen && pathname[baselen-1] != '/') ||
- strncmp_icase(pathname, x->base, baselen))
- continue;
-
- if (x->flags & EXC_FLAG_NOWILDCARD) {
- if (!strcmp_icase(exclude, pathname + baselen))
- return to_exclude;
- } else {
- if (fnmatch_icase(exclude, pathname+baselen,
- FNM_PATHNAME) == 0)
- return to_exclude;
- }
+ for (i = el->nr - 1; 0 <= i; i--) {
+ struct exclude *x = el->excludes[i];
+ const char *name, *exclude = x->pattern;
+ int to_exclude = x->to_exclude;
+ int namelen, prefix = x->nowildcardlen;
+
+ if (x->flags & EXC_FLAG_MUSTBEDIR) {
+ if (*dtype == DT_UNKNOWN)
+ *dtype = get_dtype(NULL, pathname, pathlen);
+ if (*dtype != DT_DIR)
+ continue;
+ }
+
+ if (x->flags & EXC_FLAG_NODIR) {
+ /* match basename */
+ if (prefix == x->patternlen) {
+ if (!strcmp_icase(exclude, basename))
+ return to_exclude;
+ } else if (x->flags & EXC_FLAG_ENDSWITH) {
+ if (x->patternlen - 1 <= pathlen &&
+ !strcmp_icase(exclude + 1, pathname + pathlen - x->patternlen + 1))
+ return to_exclude;
+ } else {
+ if (fnmatch_icase(exclude, basename, 0) == 0)
+ return to_exclude;
}
+ continue;
+ }
+
+ /* match with FNM_PATHNAME:
+ * exclude has base (baselen long) implicitly in front of it.
+ */
+ if (*exclude == '/') {
+ exclude++;
+ prefix--;
}
+
+ if (pathlen < x->baselen ||
+ (x->baselen && pathname[x->baselen-1] != '/') ||
+ strncmp_icase(pathname, x->base, x->baselen))
+ continue;
+
+ namelen = x->baselen ? pathlen - x->baselen : pathlen;
+ name = pathname + pathlen - namelen;
+
+ /* if the non-wildcard part is longer than the
+ remaining pathname, surely it cannot match */
+ if (prefix > namelen)
+ continue;
+
+ if (prefix) {
+ if (strncmp_icase(exclude, name, prefix))
+ continue;
+ exclude += prefix;
+ name += prefix;
+ namelen -= prefix;
+ }
+
+ if (!namelen || !fnmatch_icase(exclude, name, FNM_PATHNAME))
+ return to_exclude;
}
return -1; /* undecided */
}
@@ -1055,21 +1083,6 @@ static int cmp_name(const void *p1, const void *p2)
e2->name, e2->len);
}
-/*
- * Return the length of the "simple" part of a path match limiter.
- */
-static int simple_length(const char *match)
-{
- int len = -1;
-
- for (;;) {
- unsigned char c = *match++;
- len++;
- if (c == '\0' || is_glob_special(c))
- return len;
- }
-}
-
static struct path_simplify *create_simplify(const char **pathspec)
{
int nr, alloc = 0;
@@ -1292,12 +1305,17 @@ int remove_dir_recursively(struct strbuf *path, int flag)
void setup_standard_excludes(struct dir_struct *dir)
{
const char *path;
+ char *xdg_path;
dir->exclude_per_dir = ".gitignore";
path = git_path("info/exclude");
- if (!access(path, R_OK))
+ if (!excludes_file) {
+ home_config_paths(NULL, &xdg_path, "ignore");
+ excludes_file = xdg_path;
+ }
+ if (!access_or_warn(path, R_OK))
add_excludes_from_file(dir, path);
- if (excludes_file && !access(excludes_file, R_OK))
+ if (excludes_file && !access_or_warn(excludes_file, R_OK))
add_excludes_from_file(dir, excludes_file);
}
diff --git a/dir.h b/dir.h
index 6c73e41..893465a 100644
--- a/dir.h
+++ b/dir.h
@@ -9,7 +9,6 @@ struct dir_entry {
};
#define EXC_FLAG_NODIR 1
-#define EXC_FLAG_NOWILDCARD 2
#define EXC_FLAG_ENDSWITH 4
#define EXC_FLAG_MUSTBEDIR 8
@@ -19,6 +18,7 @@ struct exclude_list {
struct exclude {
const char *pattern;
int patternlen;
+ int nowildcardlen;
const char *base;
int baselen;
int to_exclude;
diff --git a/environment.c b/environment.c
index 669e498..85edd7f 100644
--- a/environment.c
+++ b/environment.c
@@ -58,6 +58,7 @@ char *notes_ref_name;
int grafts_replace_parents = 1;
int core_apply_sparse_checkout;
int merge_log_config = -1;
+int precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */
struct startup_info *startup_info;
unsigned long pack_size_limit_cfg;
diff --git a/fast-import.c b/fast-import.c
index eed97c8..c2a814e 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -1691,7 +1691,7 @@ static int update_branch(struct branch *b)
return error("Branch %s is missing commits.", b->name);
}
- if (!in_merge_bases(old_cmit, &new_cmit, 1)) {
+ if (!in_merge_bases(old_cmit, new_cmit)) {
unlock_ref(lock);
warning("Not updating %s"
" (new tip %s does not contain %s)",
diff --git a/fetch-pack.h b/fetch-pack.h
index 7c2069c..cb14871 100644
--- a/fetch-pack.h
+++ b/fetch-pack.h
@@ -1,6 +1,8 @@
#ifndef FETCH_PACK_H
#define FETCH_PACK_H
+#include "string-list.h"
+
struct fetch_pack_args {
const char *uploadpack;
int unpacklimit;
@@ -17,12 +19,18 @@ struct fetch_pack_args {
stateless_rpc:1;
};
+/*
+ * sought contains the full names of remote references that should be
+ * updated from. On return, the names that were found on the remote
+ * will have been removed from the list. The util members of the
+ * string_list_items are used internally; they must be NULL on entry
+ * (and will be NULL on exit).
+ */
struct ref *fetch_pack(struct fetch_pack_args *args,
- int fd[], struct child_process *conn,
- const struct ref *ref,
- const char *dest,
- int nr_heads,
- char **heads,
- char **pack_lockfile);
+ int fd[], struct child_process *conn,
+ const struct ref *ref,
+ const char *dest,
+ struct string_list *sought,
+ char **pack_lockfile);
#endif
diff --git a/gettext.c b/gettext.c
index f75bca7..71e9545 100644
--- a/gettext.c
+++ b/gettext.c
@@ -4,6 +4,8 @@
#include "git-compat-util.h"
#include "gettext.h"
+#include "strbuf.h"
+#include "utf8.h"
#ifndef NO_GETTEXT
# include <locale.h>
@@ -27,10 +29,9 @@ int use_gettext_poison(void)
#endif
#ifndef NO_GETTEXT
+static const char *charset;
static void init_gettext_charset(const char *domain)
{
- const char *charset;
-
/*
This trick arranges for messages to be emitted in the user's
requested encoding, but avoids setting LC_CTYPE from the
@@ -128,4 +129,14 @@ void git_setup_gettext(void)
init_gettext_charset("git");
textdomain("git");
}
+
+/* return the number of columns of string 's' in current locale */
+int gettext_width(const char *s)
+{
+ static int is_utf8 = -1;
+ if (is_utf8 == -1)
+ is_utf8 = !strcmp(charset, "UTF-8");
+
+ return is_utf8 ? utf8_strwidth(s) : strlen(s);
+}
#endif
diff --git a/gettext.h b/gettext.h
index 57ba8bb..7671d09 100644
--- a/gettext.h
+++ b/gettext.h
@@ -30,10 +30,15 @@
#ifndef NO_GETTEXT
extern void git_setup_gettext(void);
+extern int gettext_width(const char *s);
#else
static inline void git_setup_gettext(void)
{
}
+static inline int gettext_width(const char *s)
+{
+ return strlen(s);
+}
#endif
#ifdef GETTEXT_POISON
@@ -44,6 +49,8 @@ extern int use_gettext_poison(void);
static inline FORMAT_PRESERVING(1) const char *_(const char *msgid)
{
+ if (!*msgid)
+ return "";
return use_gettext_poison() ? "# GETTEXT POISON #" : gettext(msgid);
}
diff --git a/git-am.sh b/git-am.sh
index 9abad36..c682d34 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -92,7 +92,7 @@ safe_to_abort () {
then
return 0
fi
- gettextln "You seem to have moved HEAD since the last 'am' failure.
+ gettextln "You seem to have moved HEAD since the last 'am' failure.
Not rewinding to ORIG_HEAD" >&2
return 1
}
@@ -102,9 +102,9 @@ stop_here_user_resolve () {
printf '%s\n' "$resolvemsg"
stop_here $1
fi
- eval_gettextln "When you have resolved this problem run \"\$cmdline --resolved\".
-If you would prefer to skip this patch, instead run \"\$cmdline --skip\".
-To restore the original branch and stop patching run \"\$cmdline --abort\"."
+ eval_gettextln "When you have resolved this problem, run \"\$cmdline --resolved\".
+If you prefer to skip this patch, run \"\$cmdline --skip\" instead.
+To restore the original branch and stop patching, run \"\$cmdline --abort\"."
stop_here $1
}
@@ -136,7 +136,7 @@ fall_back_3way () {
git write-tree >"$dotest/patch-merge-base+" ||
cannot_fallback "$(gettext "Repository lacks necessary blobs to fall back on 3-way merge.")"
- say Using index info to reconstruct a base tree...
+ say "$(gettext "Using index info to reconstruct a base tree...")"
cmd='GIT_INDEX_FILE="$dotest/patch-merge-tmp-index"'
@@ -176,8 +176,7 @@ It does not apply to blobs recorded in its index.")"
fi
git-merge-recursive $orig_tree -- HEAD $his_tree || {
git rerere $allow_rerere_autoupdate
- echo Failed to merge in the changes.
- exit 1
+ die "$(gettext "Failed to merge in the changes.")"
}
unset GITHEAD_$his_tree
}
@@ -260,7 +259,7 @@ check_patch_format () {
split_patches () {
case "$patch_format" in
mbox)
- if test -n "$rebasing" || test t = "$keepcr"
+ if test t = "$keepcr"
then
keep_cr=--keep-cr
else
@@ -387,8 +386,8 @@ do
-i|--interactive)
interactive=t ;;
-b|--binary)
- echo >&2 "The $1 option has been a no-op for long time, and"
- echo >&2 "it will be removed. Please do not use it anymore."
+ gettextln >&2 "The -b/--binary option has been a no-op for long time, and
+it will be removed. Please do not use it anymore."
;;
-3|--3way)
threeway=t ;;
@@ -413,10 +412,7 @@ do
--abort)
abort=t ;;
--rebasing)
- rebasing=t threeway=t keep=t scissors=f no_inbody_headers=t ;;
- -d|--dotest)
- die "$(gettext "-d option is no longer supported. Do not use.")"
- ;;
+ rebasing=t threeway=t ;;
--resolvemsg)
shift; resolvemsg=$1 ;;
--whitespace|--directory|--exclude|--include)
@@ -658,32 +654,34 @@ do
# by the user, or the user can tell us to do so by --resolved flag.
case "$resume" in
'')
- git mailinfo $keep $no_inbody_headers $scissors $utf8 "$dotest/msg" "$dotest/patch" \
- <"$dotest/$msgnum" >"$dotest/info" ||
- stop_here $this
-
- # skip pine's internal folder data
- sane_grep '^Author: Mail System Internal Data$' \
- <"$dotest"/info >/dev/null &&
- go_next && continue
-
- test -s "$dotest/patch" || {
- eval_gettextln "Patch is empty. Was it split wrong?
-If you would prefer to skip this patch, instead run \"\$cmdline --skip\".
-To restore the original branch and stop patching run \"\$cmdline --abort\"."
- stop_here $this
- }
- rm -f "$dotest/original-commit" "$dotest/author-script"
- if test -f "$dotest/rebasing" &&
+ if test -f "$dotest/rebasing"
+ then
commit=$(sed -e 's/^From \([0-9a-f]*\) .*/\1/' \
-e q "$dotest/$msgnum") &&
- test "$(git cat-file -t "$commit")" = commit
- then
+ test "$(git cat-file -t "$commit")" = commit ||
+ stop_here $this
git cat-file commit "$commit" |
sed -e '1,/^$/d' >"$dotest/msg-clean"
- echo "$commit" > "$dotest/original-commit"
- get_author_ident_from_commit "$commit" > "$dotest/author-script"
+ echo "$commit" >"$dotest/original-commit"
+ get_author_ident_from_commit "$commit" >"$dotest/author-script"
+ git diff-tree --root --binary "$commit" >"$dotest/patch"
else
+ git mailinfo $keep $no_inbody_headers $scissors $utf8 "$dotest/msg" "$dotest/patch" \
+ <"$dotest/$msgnum" >"$dotest/info" ||
+ stop_here $this
+
+ # skip pine's internal folder data
+ sane_grep '^Author: Mail System Internal Data$' \
+ <"$dotest"/info >/dev/null &&
+ go_next && continue
+
+ test -s "$dotest/patch" || {
+ eval_gettextln "Patch is empty. Was it split wrong?
+If you would prefer to skip this patch, instead run \"\$cmdline --skip\".
+To restore the original branch and stop patching run \"\$cmdline --abort\"."
+ stop_here $this
+ }
+ rm -f "$dotest/original-commit" "$dotest/author-script"
{
sed -n '/^Subject/ s/Subject: //p' "$dotest/info"
echo
@@ -857,8 +855,8 @@ did you forget to use 'git add'?"
eval_gettextln 'Patch failed at $msgnum $FIRSTLINE'
if test "$(git config --bool advice.amworkdir)" != false
then
- eval_gettextln "The copy of the patch that failed is found in:
- $dotest/patch"
+ eval_gettextln 'The copy of the patch that failed is found in:
+ $dotest/patch'
fi
stop_here_user_resolve $this
fi
diff --git a/git-compat-util.h b/git-compat-util.h
index 5bd9ad7..2fbf1fd 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -74,7 +74,8 @@
# define _XOPEN_SOURCE 500
# endif
#elif !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__USLC__) && \
- !defined(_M_UNIX) && !defined(__sgi) && !defined(__DragonFly__)
+ !defined(_M_UNIX) && !defined(__sgi) && !defined(__DragonFly__) && \
+ !defined(__TANDEM)
#define _XOPEN_SOURCE 600 /* glibc2 and AIX 5.3L need 500, OpenBSD needs 600 for S_ISLNK() */
#define _XOPEN_SOURCE_EXTENDED 1 /* AIX 5.3L needs this */
#endif
@@ -98,6 +99,9 @@
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
+#ifdef __TANDEM /* or HAVE_STRINGS_H or !NO_STRINGS_H? */
+#include <strings.h> /* for strcasecmp() */
+#endif
#include <errno.h>
#include <limits.h>
#include <sys/param.h>
@@ -141,6 +145,17 @@
#else
#include <stdint.h>
#endif
+#ifdef NO_INTPTR_T
+/*
+ * On I16LP32, ILP32 and LP64 "long" is the save bet, however
+ * on LLP86, IL33LLP64 and P64 it needs to be "long long",
+ * while on IP16 and IP16L32 it is "int" (resp. "short")
+ * Size needs to match (or exceed) 'sizeof(void *)'.
+ * We can't take "long long" here as not everybody has it.
+ */
+typedef long intptr_t;
+typedef unsigned long uintptr_t;
+#endif
#if defined(__CYGWIN__)
#undef _XOPEN_SOURCE
#include <grp.h>
@@ -153,6 +168,31 @@
#endif
#endif
+/* used on Mac OS X */
+#ifdef PRECOMPOSE_UNICODE
+#include "compat/precompose_utf8.h"
+#else
+#define precompose_str(in,i_nfd2nfc)
+#define precompose_argv(c,v)
+#define probe_utf8_pathname_composition(a,b)
+#endif
+
+#ifdef MKDIR_WO_TRAILING_SLASH
+#define mkdir(a,b) compat_mkdir_wo_trailing_slash((a),(b))
+extern int compat_mkdir_wo_trailing_slash(const char*, mode_t);
+#endif
+
+#ifdef NO_STRUCT_ITIMERVAL
+struct itimerval {
+ struct timeval it_interval;
+ struct timeval it_value;
+}
+#endif
+
+#ifdef NO_SETITIMER
+#define setitimer(which,value,ovalue)
+#endif
+
#ifndef NO_LIBGEN_H
#include <libgen.h>
#else
@@ -595,6 +635,12 @@ int rmdir_or_warn(const char *path);
*/
int remove_or_warn(unsigned int mode, const char *path);
+/* Call access(2), but warn for any error besides ENOENT. */
+int access_or_warn(const char *path, int mode);
+
+/* Warn on an inaccessible file that ought to be accessible */
+void warn_on_inaccessible(const char *path);
+
/* Get the passwd entry for the UID of the current process. */
struct passwd *xgetpwuid_self(void);
diff --git a/git-cvsimport.perl b/git-cvsimport.perl
index 8d41610..8032f23 100755
--- a/git-cvsimport.perl
+++ b/git-cvsimport.perl
@@ -889,10 +889,37 @@ sub commit {
$xtag =~ s/\s+\*\*.*$//; # Remove stuff like ** INVALID ** and ** FUNKY **
$xtag =~ tr/_/\./ if ( $opt_u );
$xtag =~ s/[\/]/$opt_s/g;
- $xtag =~ s/\[//g;
- system('git' , 'tag', '-f', $xtag, $cid) == 0
- or die "Cannot create tag $xtag: $!\n";
+ # See refs.c for these rules.
+ # Tag cannot contain bad chars. (See bad_ref_char in refs.c.)
+ $xtag =~ s/[ ~\^:\\\*\?\[]//g;
+ # Other bad strings for tags:
+ # (See check_refname_component in refs.c.)
+ 1 while $xtag =~ s/
+ (?: \.\. # Tag cannot contain '..'.
+ | \@{ # Tag cannot contain '@{'.
+ | ^ - # Tag cannot begin with '-'.
+ | \.lock $ # Tag cannot end with '.lock'.
+ | ^ \. # Tag cannot begin...
+ | \. $ # ...or end with '.'
+ )//xg;
+ # Tag cannot be empty.
+ if ($xtag eq '') {
+ warn("warning: ignoring tag '$tag'",
+ " with invalid tagname\n");
+ return;
+ }
+
+ if (system('git' , 'tag', '-f', $xtag, $cid) != 0) {
+ # We did our best to sanitize the tag, but still failed
+ # for whatever reason. Bail out, and give the user
+ # enough information to understand if/how we should
+ # improve the translation in the future.
+ if ($tag ne $xtag) {
+ print "Translated '$tag' tag to '$xtag'\n";
+ }
+ die "Cannot create tag $xtag: $!\n";
+ }
print "Created tag '$xtag' on '$branch'\n" if $opt_v;
}
diff --git a/git-difftool.perl b/git-difftool.perl
index ae1e052..edd0493 100755
--- a/git-difftool.perl
+++ b/git-difftool.perl
@@ -15,19 +15,14 @@ use strict;
use warnings;
use File::Basename qw(dirname);
use File::Copy;
+use File::Compare;
use File::Find;
use File::stat;
-use File::Path qw(mkpath);
+use File::Path qw(mkpath rmtree);
use File::Temp qw(tempdir);
use Getopt::Long qw(:config pass_through);
use Git;
-my @tools;
-my @working_tree;
-my $rc;
-my $repo = Git->repository();
-my $repo_path = $repo->repo_path();
-
sub usage
{
my $exitcode = shift;
@@ -44,6 +39,8 @@ USAGE
sub find_worktree
{
+ my ($repo) = @_;
+
# Git->repository->wc_path() does not honor changes to the working
# tree location made by $ENV{GIT_WORK_TREE} or the 'core.worktree'
# config variable.
@@ -62,10 +59,9 @@ sub find_worktree
return $worktree;
}
-my $workdir = find_worktree();
-
sub filter_tool_scripts
{
+ my ($tools) = @_;
if (-d $_) {
if ($_ ne ".") {
# Ignore files in subdirectories
@@ -73,17 +69,17 @@ sub filter_tool_scripts
}
} else {
if ((-f $_) && ($_ ne "defaults")) {
- push(@tools, $_);
+ push(@$tools, $_);
}
}
}
sub print_tool_help
{
- my ($cmd, @found, @notfound);
+ my ($cmd, @found, @notfound, @tools);
my $gitpath = Git::exec_path();
- find(\&filter_tool_scripts, "$gitpath/mergetools");
+ find(sub { filter_tool_scripts(\@tools) }, "$gitpath/mergetools");
foreach my $tool (@tools) {
$cmd = "TOOL_MODE=diff";
@@ -97,34 +93,52 @@ sub print_tool_help
}
}
- print "'git difftool --tool=<tool>' may be set to one of the following:\n";
+ print << 'EOF';
+'git difftool --tool=<tool>' may be set to one of the following:
+EOF
print "\t$_\n" for (sort(@found));
- print "\nThe following tools are valid, but not currently available:\n";
+ print << 'EOF';
+
+The following tools are valid, but not currently available:
+EOF
print "\t$_\n" for (sort(@notfound));
- print "\nNOTE: Some of the tools listed above only work in a windowed\n";
- print "environment. If run in a terminal-only session, they will fail.\n";
+ print << 'EOF';
+NOTE: Some of the tools listed above only work in a windowed
+environment. If run in a terminal-only session, they will fail.
+EOF
exit(0);
}
+sub exit_cleanup
+{
+ my ($tmpdir, $status) = @_;
+ my $errno = $!;
+ rmtree($tmpdir);
+ if ($status and $errno) {
+ my ($package, $file, $line) = caller();
+ warn "$file line $line: $errno\n";
+ }
+ exit($status | ($status >> 8));
+}
+
sub setup_dir_diff
{
+ my ($repo, $workdir, $symlinks) = @_;
+
# Run the diff; exit immediately if no diff found
# 'Repository' and 'WorkingCopy' must be explicitly set to insure that
# if $GIT_DIR and $GIT_WORK_TREE are set in ENV, they are actually used
# by Git->repository->command*.
- my $diffrepo = Git->repository(Repository => $repo_path, WorkingCopy => $workdir);
- my $diffrtn = $diffrepo->command_oneline('diff', '--raw', '--no-abbrev', '-z', @ARGV);
- exit(0) if (length($diffrtn) == 0);
+ my $repo_path = $repo->repo_path();
+ my %repo_args = (Repository => $repo_path, WorkingCopy => $workdir);
+ my $diffrepo = Git->repository(%repo_args);
- # Setup temp directories
- my $tmpdir = tempdir('git-diffall.XXXXX', CLEANUP => 1, TMPDIR => 1);
- my $ldir = "$tmpdir/left";
- my $rdir = "$tmpdir/right";
- mkpath($ldir) or die $!;
- mkpath($rdir) or die $!;
+ my @gitargs = ('diff', '--raw', '--no-abbrev', '-z', @ARGV);
+ my $diffrtn = $diffrepo->command_oneline(@gitargs);
+ exit(0) unless defined($diffrtn);
# Build index info for left and right sides of the diff
my $submodule_mode = '160000';
@@ -135,16 +149,21 @@ sub setup_dir_diff
my $rindex = '';
my %submodule;
my %symlink;
+ my @working_tree = ();
my @rawdiff = split('\0', $diffrtn);
my $i = 0;
while ($i < $#rawdiff) {
if ($rawdiff[$i] =~ /^::/) {
- print "Combined diff formats ('-c' and '--cc') are not supported in directory diff mode.\n";
+ warn << 'EOF';
+Combined diff formats ('-c' and '--cc') are not supported in
+directory diff mode ('-d' and '--dir-diff').
+EOF
exit(1);
}
- my ($lmode, $rmode, $lsha1, $rsha1, $status) = split(' ', substr($rawdiff[$i], 1));
+ my ($lmode, $rmode, $lsha1, $rsha1, $status) =
+ split(' ', substr($rawdiff[$i], 1));
my $src_path = $rawdiff[$i + 1];
my $dst_path;
@@ -156,7 +175,7 @@ sub setup_dir_diff
$i += 2;
}
- if (($lmode eq $submodule_mode) or ($rmode eq $submodule_mode)) {
+ if ($lmode eq $submodule_mode or $rmode eq $submodule_mode) {
$submodule{$src_path}{left} = $lsha1;
if ($lsha1 ne $rsha1) {
$submodule{$dst_path}{right} = $rsha1;
@@ -167,14 +186,16 @@ sub setup_dir_diff
}
if ($lmode eq $symlink_mode) {
- $symlink{$src_path}{left} = $diffrepo->command_oneline('show', "$lsha1");
+ $symlink{$src_path}{left} =
+ $diffrepo->command_oneline('show', "$lsha1");
}
if ($rmode eq $symlink_mode) {
- $symlink{$dst_path}{right} = $diffrepo->command_oneline('show', "$rsha1");
+ $symlink{$dst_path}{right} =
+ $diffrepo->command_oneline('show', "$rsha1");
}
- if (($lmode ne $null_mode) and ($status !~ /^C/)) {
+ if ($lmode ne $null_mode and $status !~ /^C/) {
$lindex .= "$lmode $lsha1\t$src_path\0";
}
@@ -187,6 +208,13 @@ sub setup_dir_diff
}
}
+ # Setup temp directories
+ my $tmpdir = tempdir('git-difftool.XXXXX', CLEANUP => 0, TMPDIR => 1);
+ my $ldir = "$tmpdir/left";
+ my $rdir = "$tmpdir/right";
+ mkpath($ldir) or exit_cleanup($tmpdir, 1);
+ mkpath($rdir) or exit_cleanup($tmpdir, 1);
+
# If $GIT_DIR is not set prior to calling 'git update-index' and
# 'git checkout-index', then those commands will fail if difftool
# is called from a directory other than the repo root.
@@ -199,18 +227,22 @@ sub setup_dir_diff
# Populate the left and right directories based on each index file
my ($inpipe, $ctx);
$ENV{GIT_INDEX_FILE} = "$tmpdir/lindex";
- ($inpipe, $ctx) = $repo->command_input_pipe(qw/update-index -z --index-info/);
+ ($inpipe, $ctx) =
+ $repo->command_input_pipe(qw(update-index -z --index-info));
print($inpipe $lindex);
$repo->command_close_pipe($inpipe, $ctx);
- $rc = system('git', 'checkout-index', '--all', "--prefix=$ldir/");
- exit($rc | ($rc >> 8)) if ($rc != 0);
+
+ my $rc = system('git', 'checkout-index', '--all', "--prefix=$ldir/");
+ exit_cleanup($tmpdir, $rc) if $rc != 0;
$ENV{GIT_INDEX_FILE} = "$tmpdir/rindex";
- ($inpipe, $ctx) = $repo->command_input_pipe(qw/update-index -z --index-info/);
+ ($inpipe, $ctx) =
+ $repo->command_input_pipe(qw(update-index -z --index-info));
print($inpipe $rindex);
$repo->command_close_pipe($inpipe, $ctx);
+
$rc = system('git', 'checkout-index', '--all', "--prefix=$rdir/");
- exit($rc | ($rc >> 8)) if ($rc != 0);
+ exit_cleanup($tmpdir, $rc) if $rc != 0;
# If $GIT_DIR was explicitly set just for the update/checkout
# commands, then it should be unset before continuing.
@@ -222,37 +254,55 @@ sub setup_dir_diff
for my $file (@working_tree) {
my $dir = dirname($file);
unless (-d "$rdir/$dir") {
- mkpath("$rdir/$dir") or die $!;
+ mkpath("$rdir/$dir") or
+ exit_cleanup($tmpdir, 1);
+ }
+ if ($symlinks) {
+ symlink("$workdir/$file", "$rdir/$file") or
+ exit_cleanup($tmpdir, 1);
+ } else {
+ copy("$workdir/$file", "$rdir/$file") or
+ exit_cleanup($tmpdir, 1);
+
+ my $mode = stat("$workdir/$file")->mode;
+ chmod($mode, "$rdir/$file") or
+ exit_cleanup($tmpdir, 1);
}
- copy("$workdir/$file", "$rdir/$file") or die $!;
- chmod(stat("$workdir/$file")->mode, "$rdir/$file") or die $!;
}
# Changes to submodules require special treatment. This loop writes a
# temporary file to both the left and right directories to show the
# change in the recorded SHA1 for the submodule.
for my $path (keys %submodule) {
+ my $ok;
if (defined($submodule{$path}{left})) {
- write_to_file("$ldir/$path", "Subproject commit $submodule{$path}{left}");
+ $ok = write_to_file("$ldir/$path",
+ "Subproject commit $submodule{$path}{left}");
}
if (defined($submodule{$path}{right})) {
- write_to_file("$rdir/$path", "Subproject commit $submodule{$path}{right}");
+ $ok = write_to_file("$rdir/$path",
+ "Subproject commit $submodule{$path}{right}");
}
+ exit_cleanup($tmpdir, 1) if not $ok;
}
# Symbolic links require special treatment. The standard "git diff"
# shows only the link itself, not the contents of the link target.
# This loop replicates that behavior.
for my $path (keys %symlink) {
+ my $ok;
if (defined($symlink{$path}{left})) {
- write_to_file("$ldir/$path", $symlink{$path}{left});
+ $ok = write_to_file("$ldir/$path",
+ $symlink{$path}{left});
}
if (defined($symlink{$path}{right})) {
- write_to_file("$rdir/$path", $symlink{$path}{right});
+ $ok = write_to_file("$rdir/$path",
+ $symlink{$path}{right});
}
+ exit_cleanup($tmpdir, 1) if not $ok;
}
- return ($ldir, $rdir);
+ return ($ldir, $rdir, $tmpdir, @working_tree);
}
sub write_to_file
@@ -263,83 +313,141 @@ sub write_to_file
# Make sure the path to the file exists
my $dir = dirname($path);
unless (-d "$dir") {
- mkpath("$dir") or die $!;
+ mkpath("$dir") or return 0;
}
# If the file already exists in that location, delete it. This
# is required in the case of symbolic links.
- unlink("$path");
+ unlink($path);
- open(my $fh, '>', "$path") or die $!;
+ open(my $fh, '>', $path) or return 0;
print($fh $value);
close($fh);
-}
-# parse command-line options. all unrecognized options and arguments
-# are passed through to the 'git diff' command.
-my ($difftool_cmd, $dirdiff, $extcmd, $gui, $help, $prompt, $tool_help);
-GetOptions('g|gui!' => \$gui,
- 'd|dir-diff' => \$dirdiff,
- 'h' => \$help,
- 'prompt!' => \$prompt,
- 'y' => sub { $prompt = 0; },
- 't|tool:s' => \$difftool_cmd,
- 'tool-help' => \$tool_help,
- 'x|extcmd:s' => \$extcmd);
-
-if (defined($help)) {
- usage(0);
-}
-if (defined($tool_help)) {
- print_tool_help();
+ return 1;
}
-if (defined($difftool_cmd)) {
- if (length($difftool_cmd) > 0) {
- $ENV{GIT_DIFF_TOOL} = $difftool_cmd;
- } else {
- print "No <tool> given for --tool=<tool>\n";
- usage(1);
+
+sub main
+{
+ # parse command-line options. all unrecognized options and arguments
+ # are passed through to the 'git diff' command.
+ my %opts = (
+ difftool_cmd => undef,
+ dirdiff => undef,
+ extcmd => undef,
+ gui => undef,
+ help => undef,
+ prompt => undef,
+ symlinks => $^O ne 'cygwin' &&
+ $^O ne 'MSWin32' && $^O ne 'msys',
+ tool_help => undef,
+ );
+ GetOptions('g|gui!' => \$opts{gui},
+ 'd|dir-diff' => \$opts{dirdiff},
+ 'h' => \$opts{help},
+ 'prompt!' => \$opts{prompt},
+ 'y' => sub { $opts{prompt} = 0; },
+ 'symlinks' => \$opts{symlinks},
+ 'no-symlinks' => sub { $opts{symlinks} = 0; },
+ 't|tool:s' => \$opts{difftool_cmd},
+ 'tool-help' => \$opts{tool_help},
+ 'x|extcmd:s' => \$opts{extcmd});
+
+ if (defined($opts{help})) {
+ usage(0);
}
-}
-if (defined($extcmd)) {
- if (length($extcmd) > 0) {
- $ENV{GIT_DIFFTOOL_EXTCMD} = $extcmd;
- } else {
- print "No <cmd> given for --extcmd=<cmd>\n";
- usage(1);
+ if (defined($opts{tool_help})) {
+ print_tool_help();
}
-}
-if ($gui) {
- my $guitool = '';
- $guitool = Git::config('diff.guitool');
- if (length($guitool) > 0) {
- $ENV{GIT_DIFF_TOOL} = $guitool;
+ if (defined($opts{difftool_cmd})) {
+ if (length($opts{difftool_cmd}) > 0) {
+ $ENV{GIT_DIFF_TOOL} = $opts{difftool_cmd};
+ } else {
+ print "No <tool> given for --tool=<tool>\n";
+ usage(1);
+ }
+ }
+ if (defined($opts{extcmd})) {
+ if (length($opts{extcmd}) > 0) {
+ $ENV{GIT_DIFFTOOL_EXTCMD} = $opts{extcmd};
+ } else {
+ print "No <cmd> given for --extcmd=<cmd>\n";
+ usage(1);
+ }
+ }
+ if ($opts{gui}) {
+ my $guitool = Git::config('diff.guitool');
+ if (length($guitool) > 0) {
+ $ENV{GIT_DIFF_TOOL} = $guitool;
+ }
+ }
+
+ # In directory diff mode, 'git-difftool--helper' is called once
+ # to compare the a/b directories. In file diff mode, 'git diff'
+ # will invoke a separate instance of 'git-difftool--helper' for
+ # each file that changed.
+ if (defined($opts{dirdiff})) {
+ dir_diff($opts{extcmd}, $opts{symlinks});
+ } else {
+ file_diff($opts{prompt});
}
}
-# In directory diff mode, 'git-difftool--helper' is called once
-# to compare the a/b directories. In file diff mode, 'git diff'
-# will invoke a separate instance of 'git-difftool--helper' for
-# each file that changed.
-if (defined($dirdiff)) {
- my ($a, $b) = setup_dir_diff();
+sub dir_diff
+{
+ my ($extcmd, $symlinks) = @_;
+ my $rc;
+ my $error = 0;
+ my $repo = Git->repository();
+ my $workdir = find_worktree($repo);
+ my ($a, $b, $tmpdir, @worktree) =
+ setup_dir_diff($repo, $workdir, $symlinks);
+
if (defined($extcmd)) {
$rc = system($extcmd, $a, $b);
} else {
$ENV{GIT_DIFFTOOL_DIRDIFF} = 'true';
$rc = system('git', 'difftool--helper', $a, $b);
}
-
- exit($rc | ($rc >> 8)) if ($rc != 0);
-
# If the diff including working copy files and those
# files were modified during the diff, then the changes
- # should be copied back to the working tree
- for my $file (@working_tree) {
- copy("$b/$file", "$workdir/$file") or die $!;
- chmod(stat("$b/$file")->mode, "$workdir/$file") or die $!;
+ # should be copied back to the working tree.
+ # Do not copy back files when symlinks are used and the
+ # external tool did not replace the original link with a file.
+ for my $file (@worktree) {
+ next if $symlinks && -l "$b/$file";
+ next if ! -f "$b/$file";
+
+ my $diff = compare("$b/$file", "$workdir/$file");
+ if ($diff == 0) {
+ next;
+ } elsif ($diff == -1) {
+ my $errmsg = "warning: Could not compare ";
+ $errmsg += "'$b/$file' with '$workdir/$file'\n";
+ warn $errmsg;
+ $error = 1;
+ } elsif ($diff == 1) {
+ my $mode = stat("$b/$file")->mode;
+ copy("$b/$file", "$workdir/$file") or
+ exit_cleanup($tmpdir, 1);
+
+ chmod($mode, "$workdir/$file") or
+ exit_cleanup($tmpdir, 1);
+ }
}
-} else {
+ if ($error) {
+ warn "warning: Temporary files exist in '$tmpdir'.\n";
+ warn "warning: You may want to cleanup or recover these.\n";
+ exit(1);
+ } else {
+ exit_cleanup($tmpdir, $rc);
+ }
+}
+
+sub file_diff
+{
+ my ($prompt) = @_;
+
if (defined($prompt)) {
if ($prompt) {
$ENV{GIT_DIFFTOOL_PROMPT} = 'true';
@@ -359,3 +467,5 @@ if (defined($dirdiff)) {
my $rc = system('git', 'diff', @ARGV);
exit($rc | ($rc >> 8));
}
+
+main();
diff --git a/git-mergetool--lib.sh b/git-mergetool--lib.sh
index f730253..f013a03 100644
--- a/git-mergetool--lib.sh
+++ b/git-mergetool--lib.sh
@@ -104,13 +104,49 @@ run_merge_tool () {
if merge_mode
then
- merge_cmd "$1"
+ run_merge_cmd "$1"
else
- diff_cmd "$1"
+ run_diff_cmd "$1"
fi
return $status
}
+# Run a either a configured or built-in diff tool
+run_diff_cmd () {
+ merge_tool_cmd="$(get_merge_tool_cmd "$1")"
+ if test -n "$merge_tool_cmd"
+ then
+ ( eval $merge_tool_cmd )
+ status=$?
+ return $status
+ else
+ diff_cmd "$1"
+ fi
+}
+
+# Run a either a configured or built-in merge tool
+run_merge_cmd () {
+ merge_tool_cmd="$(get_merge_tool_cmd "$1")"
+ if test -n "$merge_tool_cmd"
+ then
+ trust_exit_code="$(git config --bool \
+ mergetool."$1".trustExitCode || echo false)"
+ if test "$trust_exit_code" = "false"
+ then
+ touch "$BACKUP"
+ ( eval $merge_tool_cmd )
+ status=$?
+ check_unchanged
+ else
+ ( eval $merge_tool_cmd )
+ status=$?
+ fi
+ return $status
+ else
+ merge_cmd "$1"
+ fi
+}
+
list_merge_tool_candidates () {
if merge_mode
then
@@ -126,7 +162,7 @@ list_merge_tool_candidates () {
else
tools="opendiff kdiff3 tkdiff xxdiff meld $tools"
fi
- tools="$tools gvimdiff diffuse ecmerge p4merge araxis bc3"
+ tools="$tools gvimdiff diffuse ecmerge p4merge araxis bc3 codecompare"
fi
case "${VISUAL:-$EDITOR}" in
*vim*)
diff --git a/git-p4.py b/git-p4.py
index f895a24..882b1bb 100755
--- a/git-p4.py
+++ b/git-p4.py
@@ -120,6 +120,15 @@ def p4_read_pipe_lines(c):
real_cmd = p4_build_cmd(c)
return read_pipe_lines(real_cmd)
+def p4_has_command(cmd):
+ """Ask p4 for help on this command. If it returns an error, the
+ command does not exist in this version of p4."""
+ real_cmd = p4_build_cmd(["help", cmd])
+ p = subprocess.Popen(real_cmd, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ p.communicate()
+ return p.returncode == 0
+
def system(cmd):
expand = isinstance(cmd,basestring)
if verbose:
@@ -157,6 +166,9 @@ def p4_revert(f):
def p4_reopen(type, f):
p4_system(["reopen", "-t", type, wildcard_encode(f)])
+def p4_move(src, dest):
+ p4_system(["move", "-k", wildcard_encode(src), wildcard_encode(dest)])
+
#
# Canonicalize the p4 type and return a tuple of the
# base type, plus any modifiers. See "p4 help filetypes"
@@ -832,6 +844,9 @@ class P4RollBack(Command):
return True
class P4Submit(Command, P4UserMap):
+
+ conflict_behavior_choices = ("ask", "skip", "quit")
+
def __init__(self):
Command.__init__(self)
P4UserMap.__init__(self)
@@ -841,23 +856,55 @@ class P4Submit(Command, P4UserMap):
# preserve the user, requires relevant p4 permissions
optparse.make_option("--preserve-user", dest="preserveUser", action="store_true"),
optparse.make_option("--export-labels", dest="exportLabels", action="store_true"),
+ optparse.make_option("--dry-run", "-n", dest="dry_run", action="store_true"),
+ optparse.make_option("--prepare-p4-only", dest="prepare_p4_only", action="store_true"),
+ optparse.make_option("--conflict", dest="conflict_behavior",
+ choices=self.conflict_behavior_choices)
]
self.description = "Submit changes from git to the perforce depot."
self.usage += " [name of git branch to submit into perforce depot]"
- self.interactive = True
self.origin = ""
self.detectRenames = False
self.preserveUser = gitConfig("git-p4.preserveUser").lower() == "true"
+ self.dry_run = False
+ self.prepare_p4_only = False
+ self.conflict_behavior = None
self.isWindows = (platform.system() == "Windows")
self.exportLabels = False
+ self.p4HasMoveCommand = p4_has_command("move")
def check(self):
if len(p4CmdList("opened ...")) > 0:
die("You have files opened with perforce! Close them before starting the sync.")
- # replaces everything between 'Description:' and the next P4 submit template field with the
- # commit message
- def prepareLogMessage(self, template, message):
+ def separate_jobs_from_description(self, message):
+ """Extract and return a possible Jobs field in the commit
+ message. It goes into a separate section in the p4 change
+ specification.
+
+ A jobs line starts with "Jobs:" and looks like a new field
+ in a form. Values are white-space separated on the same
+ line or on following lines that start with a tab.
+
+ This does not parse and extract the full git commit message
+ like a p4 form. It just sees the Jobs: line as a marker
+ to pass everything from then on directly into the p4 form,
+ but outside the description section.
+
+ Return a tuple (stripped log message, jobs string)."""
+
+ m = re.search(r'^Jobs:', message, re.MULTILINE)
+ if m is None:
+ return (message, None)
+
+ jobtext = message[m.start():]
+ stripped_message = message[:m.start()].rstrip()
+ return (stripped_message, jobtext)
+
+ def prepareLogMessage(self, template, message, jobs):
+ """Edits the template returned from "p4 change -o" to insert
+ the message in the Description field, and the jobs text in
+ the Jobs field."""
result = ""
inDescriptionSection = False
@@ -870,6 +917,9 @@ class P4Submit(Command, P4UserMap):
if inDescriptionSection:
if line.startswith("Files:") or line.startswith("Jobs:"):
inDescriptionSection = False
+ # insert Jobs section
+ if jobs:
+ result += jobs + "\n"
else:
continue
else:
@@ -981,7 +1031,13 @@ class P4Submit(Command, P4UserMap):
return 0
def prepareSubmitTemplate(self):
- # remove lines in the Files section that show changes to files outside the depot path we're committing into
+ """Run "p4 change -o" to grab a change specification template.
+ This does not use "p4 -G", as it is nice to keep the submission
+ template in original order, since a human might edit it.
+
+ Remove lines in the Files section that show changes to files
+ outside the depot path we're committing into."""
+
template = ""
inFilesSection = False
for line in p4_read_pipe_lines(['change', '-o']):
@@ -1042,31 +1098,14 @@ class P4Submit(Command, P4UserMap):
return False
def applyCommit(self, id):
- print "Applying %s" % (read_pipe("git log --max-count=1 --pretty=oneline %s" % id))
+ """Apply one commit, return True if it succeeded."""
- (p4User, gitEmail) = self.p4UserForCommit(id)
-
- if not self.detectRenames:
- # If not explicitly set check the config variable
- self.detectRenames = gitConfig("git-p4.detectRenames")
-
- if self.detectRenames.lower() == "false" or self.detectRenames == "":
- diffOpts = ""
- elif self.detectRenames.lower() == "true":
- diffOpts = "-M"
- else:
- diffOpts = "-M%s" % self.detectRenames
-
- detectCopies = gitConfig("git-p4.detectCopies")
- if detectCopies.lower() == "true":
- diffOpts += " -C"
- elif detectCopies != "" and detectCopies.lower() != "false":
- diffOpts += " -C%s" % detectCopies
+ print "Applying", read_pipe(["git", "show", "-s",
+ "--format=format:%h %s", id])
- if gitConfig("git-p4.detectCopiesHarder", "--bool") == "true":
- diffOpts += " --find-copies-harder"
+ (p4User, gitEmail) = self.p4UserForCommit(id)
- diff = read_pipe_lines("git diff-tree -r %s \"%s^\" \"%s\"" % (diffOpts, id, id))
+ diff = read_pipe_lines("git diff-tree -r %s \"%s^\" \"%s\"" % (self.diffOpts, id, id))
filesToAdd = set()
filesToDelete = set()
editedFiles = set()
@@ -1106,17 +1145,23 @@ class P4Submit(Command, P4UserMap):
editedFiles.add(dest)
elif modifier == "R":
src, dest = diff['src'], diff['dst']
- p4_integrate(src, dest)
- if diff['src_sha1'] != diff['dst_sha1']:
- p4_edit(dest)
+ if self.p4HasMoveCommand:
+ p4_edit(src) # src must be open before move
+ p4_move(src, dest) # opens for (move/delete, move/add)
else:
- pureRenameCopy.add(dest)
+ p4_integrate(src, dest)
+ if diff['src_sha1'] != diff['dst_sha1']:
+ p4_edit(dest)
+ else:
+ pureRenameCopy.add(dest)
if isModeExecChanged(diff['src_mode'], diff['dst_mode']):
- p4_edit(dest)
+ if not self.p4HasMoveCommand:
+ p4_edit(dest) # with move: already open, writable
filesToChangeExecBit[dest] = diff['dst_mode']
- os.unlink(dest)
+ if not self.p4HasMoveCommand:
+ os.unlink(dest)
+ filesToDelete.add(src)
editedFiles.add(dest)
- filesToDelete.add(src)
else:
die("unknown modifier %s for %s" % (modifier, path))
@@ -1163,34 +1208,13 @@ class P4Submit(Command, P4UserMap):
patch_succeeded = True
if not patch_succeeded:
- print "What do you want to do?"
- response = "x"
- while response != "s" and response != "a" and response != "w":
- response = raw_input("[s]kip this patch / [a]pply the patch forcibly "
- "and with .rej files / [w]rite the patch to a file (patch.txt) ")
- if response == "s":
- print "Skipping! Good luck with the next patches..."
- for f in editedFiles:
- p4_revert(f)
- for f in filesToAdd:
- os.remove(f)
- return
- elif response == "a":
- os.system(applyPatchCmd)
- if len(filesToAdd) > 0:
- print "You may also want to call p4 add on the following files:"
- print " ".join(filesToAdd)
- if len(filesToDelete):
- print "The following files should be scheduled for deletion with p4 delete:"
- print " ".join(filesToDelete)
- die("Please resolve and submit the conflict manually and "
- + "continue afterwards with git p4 submit --continue")
- elif response == "w":
- system(diffcmd + " > patch.txt")
- print "Patch saved to patch.txt in %s !" % self.clientPath
- die("Please resolve and submit the conflict manually and "
- "continue afterwards with git p4 submit --continue")
+ for f in editedFiles:
+ p4_revert(f)
+ return False
+ #
+ # Apply the patch for real, and do add/delete/+x handling.
+ #
system(applyPatchCmd)
for f in filesToAdd:
@@ -1204,91 +1228,132 @@ class P4Submit(Command, P4UserMap):
mode = filesToChangeExecBit[f]
setP4ExecBit(f, mode)
+ #
+ # Build p4 change description, starting with the contents
+ # of the git commit message.
+ #
logMessage = extractLogMessageFromGitCommit(id)
logMessage = logMessage.strip()
+ (logMessage, jobs) = self.separate_jobs_from_description(logMessage)
template = self.prepareSubmitTemplate()
+ submitTemplate = self.prepareLogMessage(template, logMessage, jobs)
- if self.interactive:
- submitTemplate = self.prepareLogMessage(template, logMessage)
-
- if self.preserveUser:
- submitTemplate = submitTemplate + ("\n######## Actual user %s, modified after commit\n" % p4User)
-
- if os.environ.has_key("P4DIFF"):
- del(os.environ["P4DIFF"])
- diff = ""
- for editedFile in editedFiles:
- diff += p4_read_pipe(['diff', '-du',
- wildcard_encode(editedFile)])
-
- newdiff = ""
- for newFile in filesToAdd:
- newdiff += "==== new file ====\n"
- newdiff += "--- /dev/null\n"
- newdiff += "+++ %s\n" % newFile
- f = open(newFile, "r")
- for line in f.readlines():
- newdiff += "+" + line
- f.close()
-
- if self.checkAuthorship and not self.p4UserIsMe(p4User):
- submitTemplate += "######## git author %s does not match your p4 account.\n" % gitEmail
- submitTemplate += "######## Use option --preserve-user to modify authorship.\n"
- submitTemplate += "######## Variable git-p4.skipUserNameCheck hides this message.\n"
-
- separatorLine = "######## everything below this line is just the diff #######\n"
-
- (handle, fileName) = tempfile.mkstemp()
- tmpFile = os.fdopen(handle, "w+")
- if self.isWindows:
- submitTemplate = submitTemplate.replace("\n", "\r\n")
- separatorLine = separatorLine.replace("\n", "\r\n")
- newdiff = newdiff.replace("\n", "\r\n")
- tmpFile.write(submitTemplate + separatorLine + diff + newdiff)
- tmpFile.close()
-
- if self.edit_template(fileName):
- # read the edited message and submit
- tmpFile = open(fileName, "rb")
- message = tmpFile.read()
- tmpFile.close()
- submitTemplate = message[:message.index(separatorLine)]
- if self.isWindows:
- submitTemplate = submitTemplate.replace("\r\n", "\n")
- p4_write_pipe(['submit', '-i'], submitTemplate)
-
- if self.preserveUser:
- if p4User:
- # Get last changelist number. Cannot easily get it from
- # the submit command output as the output is
- # unmarshalled.
- changelist = self.lastP4Changelist()
- self.modifyChangelistUser(changelist, p4User)
-
- # The rename/copy happened by applying a patch that created a
- # new file. This leaves it writable, which confuses p4.
+ if self.preserveUser:
+ submitTemplate += "\n######## Actual user %s, modified after commit\n" % p4User
+
+ if self.checkAuthorship and not self.p4UserIsMe(p4User):
+ submitTemplate += "######## git author %s does not match your p4 account.\n" % gitEmail
+ submitTemplate += "######## Use option --preserve-user to modify authorship.\n"
+ submitTemplate += "######## Variable git-p4.skipUserNameCheck hides this message.\n"
+
+ separatorLine = "######## everything below this line is just the diff #######\n"
+
+ # diff
+ if os.environ.has_key("P4DIFF"):
+ del(os.environ["P4DIFF"])
+ diff = ""
+ for editedFile in editedFiles:
+ diff += p4_read_pipe(['diff', '-du',
+ wildcard_encode(editedFile)])
+
+ # new file diff
+ newdiff = ""
+ for newFile in filesToAdd:
+ newdiff += "==== new file ====\n"
+ newdiff += "--- /dev/null\n"
+ newdiff += "+++ %s\n" % newFile
+ f = open(newFile, "r")
+ for line in f.readlines():
+ newdiff += "+" + line
+ f.close()
+
+ # change description file: submitTemplate, separatorLine, diff, newdiff
+ (handle, fileName) = tempfile.mkstemp()
+ tmpFile = os.fdopen(handle, "w+")
+ if self.isWindows:
+ submitTemplate = submitTemplate.replace("\n", "\r\n")
+ separatorLine = separatorLine.replace("\n", "\r\n")
+ newdiff = newdiff.replace("\n", "\r\n")
+ tmpFile.write(submitTemplate + separatorLine + diff + newdiff)
+ tmpFile.close()
+
+ if self.prepare_p4_only:
+ #
+ # Leave the p4 tree prepared, and the submit template around
+ # and let the user decide what to do next
+ #
+ print
+ print "P4 workspace prepared for submission."
+ print "To submit or revert, go to client workspace"
+ print " " + self.clientPath
+ print
+ print "To submit, use \"p4 submit\" to write a new description,"
+ print "or \"p4 submit -i %s\" to use the one prepared by" \
+ " \"git p4\"." % fileName
+ print "You can delete the file \"%s\" when finished." % fileName
+
+ if self.preserveUser and p4User and not self.p4UserIsMe(p4User):
+ print "To preserve change ownership by user %s, you must\n" \
+ "do \"p4 change -f <change>\" after submitting and\n" \
+ "edit the User field."
+ if pureRenameCopy:
+ print "After submitting, renamed files must be re-synced."
+ print "Invoke \"p4 sync -f\" on each of these files:"
for f in pureRenameCopy:
- p4_sync(f, "-f")
+ print " " + f
- else:
- # skip this patch
- print "Submission cancelled, undoing p4 changes."
- for f in editedFiles:
- p4_revert(f)
+ print
+ print "To revert the changes, use \"p4 revert ...\", and delete"
+ print "the submit template file \"%s\"" % fileName
+ if filesToAdd:
+ print "Since the commit adds new files, they must be deleted:"
for f in filesToAdd:
- p4_revert(f)
- os.remove(f)
+ print " " + f
+ print
+ return True
+
+ #
+ # Let the user edit the change description, then submit it.
+ #
+ if self.edit_template(fileName):
+ # read the edited message and submit
+ ret = True
+ tmpFile = open(fileName, "rb")
+ message = tmpFile.read()
+ tmpFile.close()
+ submitTemplate = message[:message.index(separatorLine)]
+ if self.isWindows:
+ submitTemplate = submitTemplate.replace("\r\n", "\n")
+ p4_write_pipe(['submit', '-i'], submitTemplate)
+
+ if self.preserveUser:
+ if p4User:
+ # Get last changelist number. Cannot easily get it from
+ # the submit command output as the output is
+ # unmarshalled.
+ changelist = self.lastP4Changelist()
+ self.modifyChangelistUser(changelist, p4User)
+
+ # The rename/copy happened by applying a patch that created a
+ # new file. This leaves it writable, which confuses p4.
+ for f in pureRenameCopy:
+ p4_sync(f, "-f")
- os.remove(fileName)
else:
- fileName = "submit.txt"
- file = open(fileName, "w+")
- file.write(self.prepareLogMessage(template, logMessage))
- file.close()
- print ("Perforce submit template written as %s. "
- + "Please review/edit and then use p4 submit -i < %s to submit directly!"
- % (fileName, fileName))
+ # skip this patch
+ ret = False
+ print "Submission cancelled, undoing p4 changes."
+ for f in editedFiles:
+ p4_revert(f)
+ for f in filesToAdd:
+ p4_revert(f)
+ os.remove(f)
+ for f in filesToDelete:
+ p4_revert(f)
+
+ os.remove(fileName)
+ return ret
# Export git tags as p4 labels. Create a p4 label and then tag
# with that.
@@ -1346,14 +1411,20 @@ class P4Submit(Command, P4UserMap):
for mapping in clientSpec.mappings:
labelTemplate += "\t%s\n" % mapping.depot_side.path
- p4_write_pipe(["label", "-i"], labelTemplate)
+ if self.dry_run:
+ print "Would create p4 label %s for tag" % name
+ elif self.prepare_p4_only:
+ print "Not creating p4 label %s for tag due to option" \
+ " --prepare-p4-only" % name
+ else:
+ p4_write_pipe(["label", "-i"], labelTemplate)
- # Use the label
- p4_system(["tag", "-l", name] +
- ["%s@%s" % (mapping.depot_side.path, changelist) for mapping in clientSpec.mappings])
+ # Use the label
+ p4_system(["tag", "-l", name] +
+ ["%s@%s" % (mapping.depot_side.path, changelist) for mapping in clientSpec.mappings])
- if verbose:
- print "created p4 label for tag %s" % name
+ if verbose:
+ print "created p4 label for tag %s" % name
def run(self, args):
if len(args) == 0:
@@ -1380,6 +1451,16 @@ class P4Submit(Command, P4UserMap):
if not self.canChangeChangelists():
die("Cannot preserve user names without p4 super-user or admin permissions")
+ # if not set from the command line, try the config file
+ if self.conflict_behavior is None:
+ val = gitConfig("git-p4.conflict")
+ if val:
+ if val not in self.conflict_behavior_choices:
+ die("Invalid value '%s' for config git-p4.conflict" % val)
+ else:
+ val = "ask"
+ self.conflict_behavior = val
+
if self.verbose:
print "Origin branch is " + self.origin
@@ -1412,12 +1493,15 @@ class P4Submit(Command, P4UserMap):
os.makedirs(self.clientPath)
chdir(self.clientPath)
- print "Synchronizing p4 checkout..."
- if new_client_dir:
- # old one was destroyed, and maybe nobody told p4
- p4_sync("...", "-f")
+ if self.dry_run:
+ print "Would synchronize p4 checkout in %s" % self.clientPath
else:
- p4_sync("...")
+ print "Synchronizing p4 checkout..."
+ if new_client_dir:
+ # old one was destroyed, and maybe nobody told p4
+ p4_sync("...", "-f")
+ else:
+ p4_sync("...")
self.check()
commits = []
@@ -1433,16 +1517,95 @@ class P4Submit(Command, P4UserMap):
if self.preserveUser:
self.checkValidP4Users(commits)
- while len(commits) > 0:
- commit = commits[0]
- commits = commits[1:]
- self.applyCommit(commit)
- if not self.interactive:
- break
+ #
+ # Build up a set of options to be passed to diff when
+ # submitting each commit to p4.
+ #
+ if self.detectRenames:
+ # command-line -M arg
+ self.diffOpts = "-M"
+ else:
+ # If not explicitly set check the config variable
+ detectRenames = gitConfig("git-p4.detectRenames")
+
+ if detectRenames.lower() == "false" or detectRenames == "":
+ self.diffOpts = ""
+ elif detectRenames.lower() == "true":
+ self.diffOpts = "-M"
+ else:
+ self.diffOpts = "-M%s" % detectRenames
+
+ # no command-line arg for -C or --find-copies-harder, just
+ # config variables
+ detectCopies = gitConfig("git-p4.detectCopies")
+ if detectCopies.lower() == "false" or detectCopies == "":
+ pass
+ elif detectCopies.lower() == "true":
+ self.diffOpts += " -C"
+ else:
+ self.diffOpts += " -C%s" % detectCopies
+
+ if gitConfig("git-p4.detectCopiesHarder", "--bool") == "true":
+ self.diffOpts += " --find-copies-harder"
+
+ #
+ # Apply the commits, one at a time. On failure, ask if should
+ # continue to try the rest of the patches, or quit.
+ #
+ if self.dry_run:
+ print "Would apply"
+ applied = []
+ last = len(commits) - 1
+ for i, commit in enumerate(commits):
+ if self.dry_run:
+ print " ", read_pipe(["git", "show", "-s",
+ "--format=format:%h %s", commit])
+ ok = True
+ else:
+ ok = self.applyCommit(commit)
+ if ok:
+ applied.append(commit)
+ else:
+ if self.prepare_p4_only and i < last:
+ print "Processing only the first commit due to option" \
+ " --prepare-p4-only"
+ break
+ if i < last:
+ quit = False
+ while True:
+ # prompt for what to do, or use the option/variable
+ if self.conflict_behavior == "ask":
+ print "What do you want to do?"
+ response = raw_input("[s]kip this commit but apply"
+ " the rest, or [q]uit? ")
+ if not response:
+ continue
+ elif self.conflict_behavior == "skip":
+ response = "s"
+ elif self.conflict_behavior == "quit":
+ response = "q"
+ else:
+ die("Unknown conflict_behavior '%s'" %
+ self.conflict_behavior)
+
+ if response[0] == "s":
+ print "Skipping this commit, but applying the rest"
+ break
+ if response[0] == "q":
+ print "Quitting"
+ quit = True
+ break
+ if quit:
+ break
+
+ chdir(self.oldWorkingDirectory)
- if len(commits) == 0:
- print "All changes applied!"
- chdir(self.oldWorkingDirectory)
+ if self.dry_run:
+ pass
+ elif self.prepare_p4_only:
+ pass
+ elif len(commits) == len(applied):
+ print "All commits applied!"
sync = P4Sync()
sync.run([])
@@ -1450,6 +1613,20 @@ class P4Submit(Command, P4UserMap):
rebase = P4Rebase()
rebase.rebase()
+ else:
+ if len(applied) == 0:
+ print "No commits applied."
+ else:
+ print "Applied only the commits marked with '*':"
+ for c in commits:
+ if c in applied:
+ star = "*"
+ else:
+ star = " "
+ print star, read_pipe(["git", "show", "-s",
+ "--format=format:%h %s", c])
+ print "You will have to do 'git p4 sync' and rebase."
+
if gitConfig("git-p4.exportLabels", "--bool") == "true":
self.exportLabels = True
@@ -1460,6 +1637,10 @@ class P4Submit(Command, P4UserMap):
missingGitTags = gitTags - p4Labels
self.exportGitTags(missingGitTags)
+ # exit with error unless everything applied perfecly
+ if len(commits) != len(applied):
+ sys.exit(1)
+
return True
class View(object):
@@ -1766,19 +1947,41 @@ class P4Sync(Command, P4UserMap):
return files
def stripRepoPath(self, path, prefixes):
- if self.useClientSpec:
- return self.clientSpecDirs.map_in_client(path)
+ """When streaming files, this is called to map a p4 depot path
+ to where it should go in git. The prefixes are either
+ self.depotPaths, or self.branchPrefixes in the case of
+ branch detection."""
- if self.keepRepoPath:
- prefixes = [re.sub("^(//[^/]+/).*", r'\1', prefixes[0])]
+ if self.useClientSpec:
+ # branch detection moves files up a level (the branch name)
+ # from what client spec interpretation gives
+ path = self.clientSpecDirs.map_in_client(path)
+ if self.detectBranches:
+ for b in self.knownBranches:
+ if path.startswith(b + "/"):
+ path = path[len(b)+1:]
+
+ elif self.keepRepoPath:
+ # Preserve everything in relative path name except leading
+ # //depot/; just look at first prefix as they all should
+ # be in the same depot.
+ depot = re.sub("^(//[^/]+/).*", r'\1', prefixes[0])
+ if p4PathStartsWith(path, depot):
+ path = path[len(depot):]
- for p in prefixes:
- if p4PathStartsWith(path, p):
- path = path[len(p):]
+ else:
+ for p in prefixes:
+ if p4PathStartsWith(path, p):
+ path = path[len(p):]
+ break
+ path = wildcard_decode(path)
return path
def splitFilesIntoBranches(self, commit):
+ """Look at each depotFile in the commit to figure out to what
+ branch it belongs."""
+
branches = {}
fnum = 0
while commit.has_key("depotFile%s" % fnum):
@@ -1796,12 +1999,16 @@ class P4Sync(Command, P4UserMap):
file["type"] = commit["type%s" % fnum]
fnum = fnum + 1
- relPath = self.stripRepoPath(path, self.depotPaths)
- relPath = wildcard_decode(relPath)
+ # start with the full relative path where this file would
+ # go in a p4 client
+ if self.useClientSpec:
+ relPath = self.clientSpecDirs.map_in_client(path)
+ else:
+ relPath = self.stripRepoPath(path, self.depotPaths)
for branch in self.knownBranches.keys():
-
- # add a trailing slash so that a commit into qt/4.2foo doesn't end up in qt/4.2
+ # add a trailing slash so that a commit into qt/4.2foo
+ # doesn't end up in qt/4.2, e.g.
if relPath.startswith(branch + "/"):
if branch not in branches:
branches[branch] = []
@@ -1815,7 +2022,6 @@ class P4Sync(Command, P4UserMap):
def streamOneP4File(self, file, contents):
relPath = self.stripRepoPath(file['depotFile'], self.branchPrefixes)
- relPath = wildcard_decode(relPath)
if verbose:
sys.stderr.write("%s\n" % relPath)
@@ -1884,7 +2090,6 @@ class P4Sync(Command, P4UserMap):
def streamOneP4Deletion(self, file):
relPath = self.stripRepoPath(file['path'], self.branchPrefixes)
- relPath = wildcard_decode(relPath)
if verbose:
sys.stderr.write("delete %s\n" % relPath)
self.gitStream.write("D %s\n" % relPath)
@@ -1989,10 +2194,9 @@ class P4Sync(Command, P4UserMap):
gitStream.write(description)
gitStream.write("\n")
- def commit(self, details, files, branch, branchPrefixes, parent = ""):
+ def commit(self, details, files, branch, parent = ""):
epoch = details["time"]
author = details["user"]
- self.branchPrefixes = branchPrefixes
if self.verbose:
print "commit into %s" % branch
@@ -2001,7 +2205,7 @@ class P4Sync(Command, P4UserMap):
# create a commit.
new_files = []
for f in files:
- if [p for p in branchPrefixes if p4PathStartsWith(f['path'], p)]:
+ if [p for p in self.branchPrefixes if p4PathStartsWith(f['path'], p)]:
new_files.append (f)
else:
sys.stderr.write("Ignoring file outside of prefix: %s\n" % f['path'])
@@ -2018,8 +2222,8 @@ class P4Sync(Command, P4UserMap):
self.gitStream.write("data <<EOT\n")
self.gitStream.write(details["desc"])
- self.gitStream.write("\n[git-p4: depot-paths = \"%s\": change = %s"
- % (','.join (branchPrefixes), details["change"]))
+ self.gitStream.write("\n[git-p4: depot-paths = \"%s\": change = %s" %
+ (','.join(self.branchPrefixes), details["change"]))
if len(details['options']) > 0:
self.gitStream.write(": options = %s" % details['options'])
self.gitStream.write("]\nEOT\n\n")
@@ -2042,7 +2246,7 @@ class P4Sync(Command, P4UserMap):
print "Change %s is labelled %s" % (change, labelDetails)
files = p4CmdList(["files"] + ["%s...@%s" % (p, change)
- for p in branchPrefixes])
+ for p in self.branchPrefixes])
if len(files) == len(labelRevisions):
@@ -2353,6 +2557,7 @@ class P4Sync(Command, P4UserMap):
for branch in branches.keys():
## HACK --hwn
branchPrefix = self.depotPaths[0] + branch + "/"
+ self.branchPrefixes = [ branchPrefix ]
parent = ""
@@ -2397,19 +2602,19 @@ class P4Sync(Command, P4UserMap):
tempBranch = os.path.join(self.tempBranchLocation, "%d" % (change))
if self.verbose:
print "Creating temporary branch: " + tempBranch
- self.commit(description, filesForCommit, tempBranch, [branchPrefix])
+ self.commit(description, filesForCommit, tempBranch)
self.tempBranches.append(tempBranch)
self.checkpoint()
blob = self.searchParent(parent, branch, tempBranch)
if blob:
- self.commit(description, filesForCommit, branch, [branchPrefix], blob)
+ self.commit(description, filesForCommit, branch, blob)
else:
if self.verbose:
print "Parent of %s not found. Committing into head of %s" % (branch, parent)
- self.commit(description, filesForCommit, branch, [branchPrefix], parent)
+ self.commit(description, filesForCommit, branch, parent)
else:
files = self.extractFilesFromCommit(description)
- self.commit(description, files, self.branch, self.depotPaths,
+ self.commit(description, files, self.branch,
self.initialParent)
self.initialParent = ""
except IOError:
@@ -2473,7 +2678,7 @@ class P4Sync(Command, P4UserMap):
self.updateOptionDict(details)
try:
- self.commit(details, self.extractFilesFromCommit(details), self.branch, self.depotPaths)
+ self.commit(details, self.extractFilesFromCommit(details), self.branch)
except IOError:
print "IO error with git fast-import. Is your git version recent enough?"
print self.gitError.read()
@@ -2631,6 +2836,9 @@ class P4Sync(Command, P4UserMap):
self.depotPaths = newPaths
+ # --detect-branches may change this for each branch
+ self.branchPrefixes = self.depotPaths
+
self.loadUserMapFromCache()
self.labels = {}
if self.detectLabels:
@@ -2936,7 +3144,7 @@ def main():
args = sys.argv[2:]
- options.append(optparse.make_option("--verbose", dest="verbose", action="store_true"))
+ options.append(optparse.make_option("--verbose", "-v", dest="verbose", action="store_true"))
if cmd.needsGit:
options.append(optparse.make_option("--git-dir", dest="gitdir"))
diff --git a/git-rebase--am.sh b/git-rebase--am.sh
index 04d8941..392ebc9 100644
--- a/git-rebase--am.sh
+++ b/git-rebase--am.sh
@@ -3,8 +3,6 @@
# Copyright (c) 2010 Junio C Hamano.
#
-. git-sh-setup
-
case "$action" in
continue)
git am --resolved --resolvemsg="$resolvemsg" &&
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 8492678..44901d5 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -9,9 +9,7 @@
#
# The original idea comes from Eric W. Biederman, in
# http://article.gmane.org/gmane.comp.version-control.git/22407
-
-. git-sh-setup
-
+#
# The file containing rebase commands, comments, and empty lines.
# This file is created by "git rebase -i" then edited by the user. As
# the lines are processed, they are removed from the front of this
@@ -117,6 +115,23 @@ mark_action_done () {
fi
}
+append_todo_help () {
+ cat >> "$todo" << EOF
+#
+# Commands:
+# p, pick = use commit
+# r, reword = use commit, but edit the commit message
+# e, edit = use commit, but stop for amending
+# s, squash = use commit, but meld into previous commit
+# f, fixup = like "squash", but discard this commit's log message
+# x, exec = run command (the rest of the line) using shell
+#
+# These lines can be re-ordered; they are executed from top to bottom.
+#
+# If you remove a line here THAT COMMIT WILL BE LOST.
+EOF
+}
+
make_patch () {
sha1_and_parents="$(git rev-list --parents -1 "$1")"
case "$sha1_and_parents" in
@@ -417,6 +432,29 @@ record_in_rewritten() {
esac
}
+do_pick () {
+ if test "$(git rev-parse HEAD)" = "$squash_onto"
+ then
+ # Set the correct commit message and author info on the
+ # sentinel root before cherry-picking the original changes
+ # without committing (-n). Finally, update the sentinel again
+ # to include these changes. If the cherry-pick results in a
+ # conflict, this means our behaviour is similar to a standard
+ # failed cherry-pick during rebase, with a dirty index to
+ # resolve before manually running git commit --amend then git
+ # rebase --continue.
+ git commit --allow-empty --allow-empty-message --amend \
+ --no-post-rewrite -n -q -C $1 &&
+ pick_one -n $1 &&
+ git commit --allow-empty --allow-empty-message \
+ --amend --no-post-rewrite -n -q -C $1 ||
+ die_with_patch $1 "Could not apply $1... $2"
+ else
+ pick_one $1 ||
+ die_with_patch $1 "Could not apply $1... $2"
+ fi
+}
+
do_next () {
rm -f "$msg" "$author_script" "$amend" || exit
read -r command sha1 rest < "$todo"
@@ -428,16 +466,14 @@ do_next () {
comment_for_reflog pick
mark_action_done
- pick_one $sha1 ||
- die_with_patch $sha1 "Could not apply $sha1... $rest"
+ do_pick $sha1 "$rest"
record_in_rewritten $sha1
;;
reword|r)
comment_for_reflog reword
mark_action_done
- pick_one $sha1 ||
- die_with_patch $sha1 "Could not apply $sha1... $rest"
+ do_pick $sha1 "$rest"
git commit --amend --no-post-rewrite || {
warn "Could not amend commit after successfully picking $sha1... $rest"
warn "This is most likely due to an empty commit message, or the pre-commit hook"
@@ -451,8 +487,7 @@ do_next () {
comment_for_reflog edit
mark_action_done
- pick_one $sha1 ||
- die_with_patch $sha1 "Could not apply $sha1... $rest"
+ do_pick $sha1 "$rest"
warn "Stopped at $sha1... $rest"
exit_with_patch $sha1 0
;;
@@ -475,25 +510,28 @@ do_next () {
author_script_content=$(get_author_ident_from_commit HEAD)
echo "$author_script_content" > "$author_script"
eval "$author_script_content"
- output git reset --soft HEAD^
- pick_one -n $sha1 || die_failed_squash $sha1 "$rest"
+ if ! pick_one -n $sha1
+ then
+ git rev-parse --verify HEAD >"$amend"
+ die_failed_squash $sha1 "$rest"
+ fi
case "$(peek_next_command)" in
squash|s|fixup|f)
# This is an intermediate commit; its message will only be
# used in case of trouble. So use the long version:
- do_with_author output git commit --no-verify -F "$squash_msg" ||
+ do_with_author output git commit --amend --no-verify -F "$squash_msg" ||
die_failed_squash $sha1 "$rest"
;;
*)
# This is the final command of this squash/fixup group
if test -f "$fixup_msg"
then
- do_with_author git commit --no-verify -F "$fixup_msg" ||
+ do_with_author git commit --amend --no-verify -F "$fixup_msg" ||
die_failed_squash $sha1 "$rest"
else
cp "$squash_msg" "$GIT_DIR"/SQUASH_MSG || exit
rm -f "$GIT_DIR"/MERGE_MSG
- do_with_author git commit --no-verify -e ||
+ do_with_author git commit --amend --no-verify -F "$GIT_DIR"/SQUASH_MSG -e ||
die_failed_squash $sha1 "$rest"
fi
rm -f "$squash_msg" "$fixup_msg"
@@ -523,6 +561,10 @@ do_next () {
warn
warn " git rebase --continue"
warn
+ if test $status -eq 127 # command not found
+ then
+ status=1
+ fi
exit "$status"
elif test "$dirty" = t
then
@@ -537,11 +579,12 @@ do_next () {
;;
*)
warn "Unknown command: $command $sha1 $rest"
+ fixtodo="Please fix this using 'git rebase --edit-todo'."
if git rev-parse --verify -q "$sha1" >/dev/null
then
- die_with_patch $sha1 "Please fix this in the file $todo."
+ die_with_patch $sha1 "$fixtodo"
else
- die "Please fix this in the file $todo."
+ die "$fixtodo"
fi
;;
esac
@@ -683,6 +726,27 @@ rearrange_squash () {
rm -f "$1.sq" "$1.rearranged"
}
+# Add commands after a pick or after a squash/fixup serie
+# in the todo list.
+add_exec_commands () {
+ {
+ first=t
+ while read -r insn rest
+ do
+ case $insn in
+ pick)
+ test -n "$first" ||
+ printf "%s" "$cmd"
+ ;;
+ esac
+ printf "%s %s\n" "$insn" "$rest"
+ first=
+ done
+ printf "%s" "$cmd"
+ } <"$1" >"$1.new" &&
+ mv "$1.new" "$1"
+}
+
case "$action" in
continue)
# do we have anything to commit?
@@ -708,7 +772,6 @@ In both case, once you're done, continue with:
fi
. "$author_script" ||
die "Error trying to find the author identity to amend commit"
- current_head=
if test -f "$amend"
then
current_head=$(git rev-parse --verify HEAD)
@@ -716,13 +779,12 @@ In both case, once you're done, continue with:
die "\
You have uncommitted changes in your working tree. Please, commit them
first and then run 'git rebase --continue' again."
- git reset --soft HEAD^ ||
- die "Cannot rewind the HEAD"
+ do_with_author git commit --amend --no-verify -F "$msg" -e ||
+ die "Could not commit staged changes."
+ else
+ do_with_author git commit --no-verify -F "$msg" -e ||
+ die "Could not commit staged changes."
fi
- do_with_author git commit --no-verify -F "$msg" -e || {
- test -n "$current_head" && git reset --soft $current_head
- die "Could not commit staged changes."
- }
fi
record_in_rewritten "$(cat "$state_dir"/stopped-sha)"
@@ -735,6 +797,23 @@ skip)
do_rest
;;
+edit-todo)
+ sed -e '/^#/d' < "$todo" > "$todo".new
+ mv -f "$todo".new "$todo"
+ append_todo_help
+ cat >> "$todo" << EOF
+#
+# You are editing the todo file of an ongoing interactive rebase.
+# To continue rebase after editing, run:
+# git rebase --continue
+#
+EOF
+
+ git_sequence_editor "$todo" ||
+ die "Could not execute editor"
+
+ exit
+ ;;
esac
git var GIT_COMMITTER_IDENT >/dev/null ||
@@ -856,21 +935,15 @@ fi
test -s "$todo" || echo noop >> "$todo"
test -n "$autosquash" && rearrange_squash "$todo"
+test -n "$cmd" && add_exec_commands "$todo"
+
cat >> "$todo" << EOF
# Rebase $shortrevisions onto $shortonto
+EOF
+append_todo_help
+cat >> "$todo" << EOF
#
-# Commands:
-# p, pick = use commit
-# r, reword = use commit, but edit the commit message
-# e, edit = use commit, but stop for amending
-# s, squash = use commit, but meld into previous commit
-# f, fixup = like "squash", but discard this commit's log message
-# x, exec = run command (the rest of the line) using shell
-#
-# These lines can be re-ordered; they are executed from top to bottom.
-#
-# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#
EOF
diff --git a/git-rebase--merge.sh b/git-rebase--merge.sh
index dc59907..b10f2cf 100644
--- a/git-rebase--merge.sh
+++ b/git-rebase--merge.sh
@@ -3,8 +3,6 @@
# Copyright (c) 2010 Junio C Hamano.
#
-. git-sh-setup
-
prec=4
read_state () {
diff --git a/git-rebase.sh b/git-rebase.sh
index e616737..b2f1c76 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -3,36 +3,12 @@
# Copyright (c) 2005 Junio C Hamano.
#
-USAGE='[--interactive | -i] [-v] [--force-rebase | -f] [--no-ff] [--onto <newbase>] [<upstream>|--root] [<branch>] [--quiet | -q]'
-LONG_USAGE='git-rebase replaces <branch> with a new branch of the
-same name. When the --onto option is provided the new branch starts
-out with a HEAD equal to <newbase>, otherwise it is equal to <upstream>
-It then attempts to create a new commit for each commit from the original
-<branch> that does not exist in the <upstream> branch.
-
-It is possible that a merge failure will prevent this process from being
-completely automatic. You will have to resolve any such merge failure
-and run git rebase --continue. Another option is to bypass the commit
-that caused the merge failure with git rebase --skip. To check out the
-original <branch> and remove the .git/rebase-apply working files, use the
-command git rebase --abort instead.
-
-Note that if <branch> is not specified on the command line, the
-currently checked out branch is used.
-
-Example: git-rebase master~1 topic
-
- A---B---C topic A'\''--B'\''--C'\'' topic
- / --> /
- D---E---F---G master D---E---F---G master
-'
-
SUBDIRECTORY_OK=Yes
OPTIONS_KEEPDASHDASH=
OPTIONS_SPEC="\
-git rebase [-i] [options] [--onto <newbase>] [<upstream>] [<branch>]
-git rebase [-i] [options] --onto <newbase> --root [<branch>]
-git-rebase [-i] --continue | --abort | --skip
+git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] [<upstream>] [<branch>]
+git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] --root [<branch>]
+git-rebase --continue | --abort | --skip | --edit-todo
--
Available options are
v,verbose! display a diffstat of what changed upstream
@@ -43,6 +19,7 @@ s,strategy=! use the given merge strategy
no-ff! cherry-pick all commits, even if unchanged
m,merge! use merging strategies to rebase
i,interactive! let the user edit the list of commits to rebase
+x,exec=! add exec lines after each commit of the editable list
k,keep-empty preserve empty commits during rebase
f,force-rebase! force rebase even if branch is up to date
X,strategy-option=! pass the argument through to the merge strategy
@@ -61,8 +38,10 @@ C=! passed to 'git apply'
continue! continue
abort! abort and check out the original branch
skip! skip current patch and continue
+edit-todo! edit the todo list during an interactive rebase
"
. git-sh-setup
+. git-sh-i18n
set_reflog_action rebase
require_work_tree_exists
cd_to_toplevel
@@ -71,11 +50,12 @@ LF='
'
ok_to_skip_pre_rebase=
resolvemsg="
-When you have resolved this problem run \"git rebase --continue\".
-If you would prefer to skip this patch, instead run \"git rebase --skip\".
-To check out the original branch and stop rebasing run \"git rebase --abort\".
+$(gettext 'When you have resolved this problem, run "git rebase --continue".
+If you prefer to skip this patch, run "git rebase --skip" instead.
+To check out the original branch and stop rebasing, run "git rebase --abort".')
"
unset onto
+cmd=
strategy=
strategy_opts=
do_merge=
@@ -158,7 +138,7 @@ move_to_original_branch () {
git symbolic-ref \
-m "rebase finished: returning to $head_name" \
HEAD $head_name ||
- die "Could not move back to $head_name"
+ die "$(gettext "Could not move back to $head_name")"
;;
esac
}
@@ -177,12 +157,12 @@ run_pre_rebase_hook () {
test -x "$GIT_DIR/hooks/pre-rebase"
then
"$GIT_DIR/hooks/pre-rebase" ${1+"$@"} ||
- die "The pre-rebase hook refused to rebase."
+ die "$(gettext "The pre-rebase hook refused to rebase.")"
fi
}
test -f "$apply_dir"/applying &&
- die 'It looks like git-am is in progress. Cannot rebase.'
+ die "$(gettext "It looks like git-am is in progress. Cannot rebase.")"
if test -d "$apply_dir"
then
@@ -211,7 +191,7 @@ do
--verify)
ok_to_skip_pre_rebase=
;;
- --continue|--skip|--abort)
+ --continue|--skip|--abort|--edit-todo)
test $total_argc -eq 2 || usage
action=${1##--}
;;
@@ -220,6 +200,11 @@ do
onto="$2"
shift
;;
+ -x)
+ test 2 -le "$#" || usage
+ cmd="${cmd}exec $2${LF}"
+ shift
+ ;;
-i)
interactive_rebase=explicit
;;
@@ -305,9 +290,15 @@ do
done
test $# -gt 2 && usage
+if test -n "$cmd" &&
+ test "$interactive_rebase" != explicit
+then
+ die "$(gettext "The --exec option must be used with the --interactive option")"
+fi
+
if test -n "$action"
then
- test -z "$in_progress" && die "No rebase in progress?"
+ test -z "$in_progress" && die "$(gettext "No rebase in progress?")"
# Only interactive rebase uses detailed reflog messages
if test "$type" = interactive && test "$GIT_REFLOG_ACTION" = rebase
then
@@ -316,15 +307,20 @@ then
fi
fi
+if test "$action" = "edit-todo" && test "$type" != "interactive"
+then
+ die "$(gettext "The --edit-todo action can only be used during interactive rebase.")"
+fi
+
case "$action" in
continue)
# Sanity check
git rev-parse --verify HEAD >/dev/null ||
- die "Cannot read HEAD"
+ die "$(gettext "Cannot read HEAD")"
git update-index --ignore-submodules --refresh &&
git diff-files --quiet --ignore-submodules || {
- echo "You must edit all merge conflicts and then"
- echo "mark them as resolved using git add"
+ echo "$(gettext "You must edit all merge conflicts and then
+mark them as resolved using git add")"
exit 1
}
read_basic_state
@@ -341,27 +337,38 @@ abort)
case "$head_name" in
refs/*)
git symbolic-ref -m "rebase: aborting" HEAD $head_name ||
- die "Could not move back to $head_name"
+ die "$(eval_gettext "Could not move back to \$head_name")"
;;
esac
output git reset --hard $orig_head
rm -r "$state_dir"
exit
;;
+edit-todo)
+ run_specific_rebase
+ ;;
esac
# Make sure no rebase is in progress
if test -n "$in_progress"
then
- die '
-It seems that there is already a '"${state_dir##*/}"' directory, and
+ state_dir_base=${state_dir##*/}
+ cmd_live_rebase="git rebase (--continue | --abort | --skip)"
+ cmd_clear_stale_rebase="rm -fr \"$state_dir\""
+ die "
+$(eval_gettext 'It seems that there is already a $state_dir_base directory, and
I wonder if you are in the middle of another rebase. If that is the
case, please try
- git rebase (--continue | --abort | --skip)
+ $cmd_live_rebase
If that is not the case, please
- rm -fr '"$state_dir"'
+ $cmd_clear_stale_rebase
and run me again. I am stopping in case you still have something
-valuable there.'
+valuable there.')"
+fi
+
+if test -n "$rebase_root" && test -z "$onto"
+then
+ test -z "$interactive_rebase" && interactive_rebase=implied
fi
if test -n "$interactive_rebase"
@@ -394,12 +401,18 @@ then
;;
esac
upstream=`git rev-parse --verify "${upstream_name}^0"` ||
- die "invalid upstream $upstream_name"
+ die "$(eval_gettext "invalid upstream \$upstream_name")"
upstream_arg="$upstream_name"
else
- test -z "$onto" && die "You must specify --onto when using --root"
+ if test -z "$onto"
+ then
+ empty_tree=`git hash-object -t tree /dev/null`
+ onto=`git commit-tree $empty_tree </dev/null`
+ squash_onto="$onto"
+ fi
unset upstream_name
unset upstream
+ test $# -gt 1 && usage
upstream_arg=--root
fi
@@ -412,19 +425,19 @@ case "$onto_name" in
then
case "$onto" in
?*"$LF"?*)
- die "$onto_name: there are more than one merge bases"
+ die "$(eval_gettext "\$onto_name: there are more than one merge bases")"
;;
'')
- die "$onto_name: there is no merge base"
+ die "$(eval_gettext "\$onto_name: there is no merge base")"
;;
esac
else
- die "$onto_name: there is no merge base"
+ die "$(eval_gettext "\$onto_name: there is no merge base")"
fi
;;
*)
onto=$(git rev-parse --verify "${onto_name}^0") ||
- die "Does not point to a valid commit: $onto_name"
+ die "$(eval_gettext "Does not point to a valid commit: \$onto_name")"
;;
esac
@@ -447,10 +460,10 @@ case "$#" in
then
head_name="detached HEAD"
else
- die "fatal: no such branch: $1"
+ die "$(eval_gettext "fatal: no such branch: \$branch_name")"
fi
;;
-*)
+0)
# Do not need to switch branches, we are already on it.
if branch_name=`git symbolic-ref -q HEAD`
then
@@ -462,9 +475,12 @@ case "$#" in
fi
orig_head=$(git rev-parse --verify "${branch_name}^0") || exit
;;
+*)
+ die "BUG: unexpected number of arguments left to parse"
+ ;;
esac
-require_clean_work_tree "rebase" "Please commit or stash them."
+require_clean_work_tree "rebase" "$(gettext "Please commit or stash them.")"
# Now we are rebasing commits $upstream..$orig_head (or with --root,
# everything leading up to $orig_head) on top of $onto
@@ -482,10 +498,10 @@ then
then
# Lazily switch to the target branch if needed...
test -z "$switch_to" || git checkout "$switch_to" --
- say "Current branch $branch_name is up to date."
+ say "$(eval_gettext "Current branch \$branch_name is up to date.")"
exit 0
else
- say "Current branch $branch_name is up to date, rebase forced."
+ say "$(eval_gettext "Current branch \$branch_name is up to date, rebase forced.")"
fi
fi
@@ -496,7 +512,7 @@ if test -n "$diffstat"
then
if test -n "$verbose"
then
- echo "Changes from $mb to $onto:"
+ echo "$(eval_gettext "Changes from \$mb to \$onto:")"
fi
# We want color (if set), but no pager
GIT_PAGER='' git diff --stat --summary "$mb" "$onto"
@@ -505,7 +521,7 @@ fi
test "$type" = interactive && run_specific_rebase
# Detach HEAD and reset the tree
-say "First, rewinding head to replay your work on top of it..."
+say "$(gettext "First, rewinding head to replay your work on top of it...")"
git checkout -q "$onto^0" || die "could not detach HEAD"
git update-ref ORIG_HEAD $orig_head
@@ -513,7 +529,7 @@ git update-ref ORIG_HEAD $orig_head
# we just fast-forwarded.
if test "$mb" = "$orig_head"
then
- say "Fast-forwarded $branch_name to $onto_name."
+ say "$(eval_gettext "Fast-forwarded \$branch_name to \$onto_name.")"
move_to_original_branch
exit 0
fi
diff --git a/git-send-email.perl b/git-send-email.perl
index 6647137..aea66a0 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -681,6 +681,7 @@ sub ask {
my ($prompt, %arg) = @_;
my $valid_re = $arg{valid_re};
my $default = $arg{default};
+ my $confirm_only = $arg{confirm_only};
my $resp;
my $i = 0;
return defined $default ? $default : undef
@@ -698,6 +699,12 @@ sub ask {
if (!defined $valid_re or $resp =~ /$valid_re/) {
return $resp;
}
+ if ($confirm_only) {
+ my $yesno = $term->readline("Are you sure you want to use <$resp> [y/N]? ");
+ if (defined $yesno && $yesno =~ /y/i) {
+ return $resp;
+ }
+ }
}
return undef;
}
@@ -745,13 +752,16 @@ my $prompting = 0;
if (!defined $sender) {
$sender = $repoauthor || $repocommitter || '';
$sender = ask("Who should the emails appear to be from? [$sender] ",
- default => $sender);
+ default => $sender,
+ valid_re => qr/\@.*\./, confirm_only => 1);
print "Emails will be sent from: ", $sender, "\n";
$prompting++;
}
if (!@initial_to && !defined $to_cmd) {
- my $to = ask("Who should the emails be sent to? ");
+ my $to = ask("Who should the emails be sent to (if any)? ",
+ default => "",
+ valid_re => qr/\@.*\./, confirm_only => 1);
push @initial_to, parse_address_line($to) if defined $to; # sanitized/validated later
$prompting++;
}
@@ -777,7 +787,9 @@ sub expand_one_alias {
if ($thread && !defined $initial_reply_to && $prompting) {
$initial_reply_to = ask(
- "Message-ID to be used as In-Reply-To for the first email? ");
+ "Message-ID to be used as In-Reply-To for the first email (if any)? ",
+ default => "",
+ valid_re => qr/\@.*\./, confirm_only => 1);
}
if (defined $initial_reply_to) {
$initial_reply_to =~ s/^\s*<?//;
diff --git a/git-submodule.sh b/git-submodule.sh
index e89b516..ab6b110 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -30,7 +30,22 @@ nofetch=
update=
prefix=
-# Resolve relative url by appending to parent's url
+# The function takes at most 2 arguments. The first argument is the
+# URL that navigates to the submodule origin repo. When relative, this URL
+# is relative to the superproject origin URL repo. The second up_path
+# argument, if specified, is the relative path that navigates
+# from the submodule working tree to the superproject working tree.
+#
+# The output of the function is the origin URL of the submodule.
+#
+# The output will either be an absolute URL or filesystem path (if the
+# superproject origin URL is an absolute URL or filesystem path,
+# respectively) or a relative file system path (if the superproject
+# origin URL is a relative file system path).
+#
+# When the output is a relative file system path, the path is either
+# relative to the submodule working tree, if up_path is specified, or to
+# the superproject working tree otherwise.
resolve_relative_url ()
{
remote=$(get_default_remote)
@@ -39,6 +54,21 @@ resolve_relative_url ()
url="$1"
remoteurl=${remoteurl%/}
sep=/
+ up_path="$2"
+
+ case "$remoteurl" in
+ *:*|/*)
+ is_relative=
+ ;;
+ ./*|../*)
+ is_relative=t
+ ;;
+ *)
+ is_relative=t
+ remoteurl="./$remoteurl"
+ ;;
+ esac
+
while test -n "$url"
do
case "$url" in
@@ -53,7 +83,12 @@ resolve_relative_url ()
sep=:
;;
*)
- die "$(eval_gettext "cannot strip one component off url '\$remoteurl'")"
+ if test -z "$is_relative" || test "." = "$remoteurl"
+ then
+ die "$(eval_gettext "cannot strip one component off url '\$remoteurl'")"
+ else
+ remoteurl=.
+ fi
;;
esac
;;
@@ -64,7 +99,8 @@ resolve_relative_url ()
break;;
esac
done
- echo "$remoteurl$sep${url%/}"
+ remoteurl="$remoteurl$sep${url%/}"
+ echo "${is_relative:+${up_path}}${remoteurl#./}"
}
#
@@ -167,8 +203,11 @@ module_clone()
rm -f "$gitdir/index"
else
mkdir -p "$gitdir_base"
- git clone $quiet -n ${reference:+"$reference"} \
- --separate-git-dir "$gitdir" "$url" "$sm_path" ||
+ (
+ clear_local_git_env
+ git clone $quiet -n ${reference:+"$reference"} \
+ --separate-git-dir "$gitdir" "$url" "$sm_path"
+ ) ||
die "$(eval_gettext "Clone of '\$url' into submodule path '\$sm_path' failed")"
fi
@@ -737,7 +776,7 @@ cmd_summary() {
if [ -n "$files" ]
then
test -n "$cached" &&
- die "$(gettext -- "--cached cannot be used with --files")"
+ die "$(gettext "The --cached option cannot be used with the --files option")"
diff_cmd=diff-files
head=
fi
@@ -994,14 +1033,26 @@ cmd_sync()
# Possibly a url relative to parent
case "$url" in
./*|../*)
- url=$(resolve_relative_url "$url") || exit
+ # rewrite foo/bar as ../.. to find path from
+ # submodule work tree to superproject work tree
+ up_path="$(echo "$sm_path" | sed "s/[^/][^/]*/../g")" &&
+ # guarantee a trailing /
+ up_path=${up_path%/}/ &&
+ # path from submodule work tree to submodule origin repo
+ sub_origin_url=$(resolve_relative_url "$url" "$up_path") &&
+ # path from superproject work tree to submodule origin repo
+ super_config_url=$(resolve_relative_url "$url") || exit
+ ;;
+ *)
+ sub_origin_url="$url"
+ super_config_url="$url"
;;
esac
if git config "submodule.$name.url" >/dev/null 2>/dev/null
then
say "$(eval_gettext "Synchronizing submodule url for '\$name'")"
- git config submodule."$name".url "$url"
+ git config submodule."$name".url "$super_config_url"
if test -e "$sm_path"/.git
then
@@ -1009,7 +1060,7 @@ cmd_sync()
clear_local_git_env
cd "$sm_path"
remote=$(get_default_remote)
- git config remote."$remote".url "$url"
+ git config remote."$remote".url "$sub_origin_url"
)
fi
fi
@@ -1056,7 +1107,15 @@ do
done
# No command word defaults to "status"
-test -n "$command" || command=status
+if test -z "$command"
+then
+ if test $# = 0
+ then
+ command=status
+ else
+ usage
+ fi
+fi
# "-b branch" is accepted only by "add"
if test -n "$branch" && test "$command" != add
diff --git a/git-svn.perl b/git-svn.perl
index 0b074c4..bd5266c 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -10,6 +10,52 @@ use vars qw/ $AUTHOR $VERSION
$AUTHOR = 'Eric Wong <normalperson@yhbt.net>';
$VERSION = '@@GIT_VERSION@@';
+use Carp qw/croak/;
+use Digest::MD5;
+use IO::File qw//;
+use File::Basename qw/dirname basename/;
+use File::Path qw/mkpath/;
+use File::Spec;
+use File::Find;
+use Getopt::Long qw/:config gnu_getopt no_ignore_case auto_abbrev/;
+use IPC::Open3;
+use Memoize;
+
+use Git::SVN;
+use Git::SVN::Editor;
+use Git::SVN::Fetcher;
+use Git::SVN::Ra;
+use Git::SVN::Prompt;
+use Git::SVN::Log;
+use Git::SVN::Migration;
+
+use Git::SVN::Utils qw(
+ fatal
+ can_compress
+ canonicalize_path
+ canonicalize_url
+ join_paths
+ add_path_to_url
+ join_paths
+);
+
+use Git qw(
+ git_cmd_try
+ command
+ command_oneline
+ command_noisy
+ command_output_pipe
+ command_close_pipe
+ command_bidi_pipe
+ command_close_bidi_pipe
+);
+
+BEGIN {
+ Memoize::memoize 'Git::config';
+ Memoize::memoize 'Git::config_bool';
+}
+
+
# From which subdir have we been invoked?
my $cmd_dir_prefix = eval {
command_oneline([qw/rev-parse --show-prefix/], STDERR => 0)
@@ -17,10 +63,7 @@ my $cmd_dir_prefix = eval {
my $git_dir_user_set = 1 if defined $ENV{GIT_DIR};
$ENV{GIT_DIR} ||= '.git';
-$Git::SVN::default_repo_id = 'svn';
-$Git::SVN::default_ref_id = $ENV{GIT_SVN_ID} || 'git-svn';
$Git::SVN::Ra::_log_window_size = 100;
-$Git::SVN::_minimize_url = 'unset';
if (! exists $ENV{SVN_SSH} && exists $ENV{GIT_SSH}) {
$ENV{SVN_SSH} = $ENV{GIT_SSH};
@@ -35,8 +78,6 @@ $Git::SVN::Log::TZ = $ENV{TZ};
$ENV{TZ} = 'UTC';
$| = 1; # unbuffer STDOUT
-sub fatal (@) { print STDERR "@_\n"; exit 1 }
-
# All SVN commands do it. Otherwise we may die on SIGPIPE when the remote
# repository decides to close the connection which we expect to be kept alive.
$SIG{PIPE} = 'IGNORE';
@@ -66,39 +107,6 @@ sub _req_svn {
fatal "Need SVN::Core 1.1.0 or better (got $SVN::Core::VERSION)";
}
}
-my $can_compress = eval { require Compress::Zlib; 1};
-use Carp qw/croak/;
-use Digest::MD5;
-use IO::File qw//;
-use File::Basename qw/dirname basename/;
-use File::Path qw/mkpath/;
-use File::Spec;
-use File::Find;
-use Getopt::Long qw/:config gnu_getopt no_ignore_case auto_abbrev/;
-use IPC::Open3;
-use Git;
-use Git::SVN::Editor qw//;
-use Git::SVN::Fetcher qw//;
-use Git::SVN::Ra qw//;
-use Git::SVN::Prompt qw//;
-use Memoize; # core since 5.8.0, Jul 2002
-
-BEGIN {
- # import functions from Git into our packages, en masse
- no strict 'refs';
- foreach (qw/command command_oneline command_noisy command_output_pipe
- command_input_pipe command_close_pipe
- command_bidi_pipe command_close_bidi_pipe/) {
- for my $package ( qw(Git::SVN::Migration Git::SVN::Log Git::SVN),
- __PACKAGE__) {
- *{"${package}::$_"} = \&{"Git::$_"};
- }
- }
- Memoize::memoize 'Git::config';
- Memoize::memoize 'Git::config_bool';
-}
-
-my ($SVN);
$sha1 = qr/[a-f\d]{40}/;
$sha1_short = qr/[a-f\d]{4,40}/;
@@ -108,8 +116,11 @@ my ($_stdin, $_help, $_edit,
$_version, $_fetch_all, $_no_rebase, $_fetch_parent,
$_merge, $_strategy, $_preserve_merges, $_dry_run, $_local,
$_prefix, $_no_checkout, $_url, $_verbose,
- $_git_format, $_commit_url, $_tag, $_merge_info, $_interactive);
-$Git::SVN::_follow_parent = 1;
+ $_commit_url, $_tag, $_merge_info, $_interactive);
+
+# This is a refactoring artifact so Git::SVN can get at this git-svn switch.
+sub opt_prefix { return $_prefix || '' }
+
$Git::SVN::Fetcher::_placeholder_filename = ".gitignore";
$_q ||= 0;
my %remote_opts = ( 'username=s' => \$Git::SVN::Prompt::_username,
@@ -269,7 +280,7 @@ my %cmd = (
{ 'url' => \$_url, } ],
'blame' => [ \&Git::SVN::Log::cmd_blame,
"Show what revision and author last modified each line of a file",
- { 'git-format' => \$_git_format } ],
+ { 'git-format' => \$Git::SVN::Log::_git_format } ],
'reset' => [ \&cmd_reset,
"Undo fetches back to the specified SVN revision",
{ 'revision|r=s' => \$_revision,
@@ -367,9 +378,9 @@ Git::SVN::init_vars();
eval {
Git::SVN::verify_remotes_sanity();
$cmd{$cmd}->[0]->(@ARGV);
+ post_fetch_checkout();
};
fatal $@ if $@;
-post_fetch_checkout();
exit 0;
####################### primary functions ######################
@@ -775,6 +786,44 @@ sub populate_merge_info {
return undef;
}
+sub dcommit_rebase {
+ my ($is_last, $current, $fetched_ref, $svn_error) = @_;
+ my @diff;
+
+ if ($svn_error) {
+ print STDERR "\nERROR from SVN:\n",
+ $svn_error->expanded_message, "\n";
+ }
+ unless ($_no_rebase) {
+ # we always want to rebase against the current HEAD,
+ # not any head that was passed to us
+ @diff = command('diff-tree', $current,
+ $fetched_ref, '--');
+ my @finish;
+ if (@diff) {
+ @finish = rebase_cmd();
+ print STDERR "W: $current and ", $fetched_ref,
+ " differ, using @finish:\n",
+ join("\n", @diff), "\n";
+ } elsif ($is_last) {
+ print "No changes between ", $current, " and ",
+ $fetched_ref,
+ "\nResetting to the latest ",
+ $fetched_ref, "\n";
+ @finish = qw/reset --mixed/;
+ }
+ command_noisy(@finish, $fetched_ref) if @finish;
+ }
+ if ($svn_error) {
+ die "ERROR: Not all changes have been committed into SVN"
+ .($_no_rebase ? ".\n" : ", however the committed\n"
+ ."ones (if any) seem to be successfully integrated "
+ ."into the working tree.\n")
+ ."Please see the above messages for details.\n";
+ }
+ return @diff;
+}
+
sub cmd_dcommit {
my $head = shift;
command_noisy(qw/update-index --refresh/);
@@ -902,6 +951,7 @@ sub cmd_dcommit {
}
my $rewritten_parent;
+ my $current_head = command_oneline(qw/rev-parse HEAD/);
Git::SVN::remove_username($expect_url);
if (defined($_merge_info)) {
$_merge_info =~ tr{ }{\n};
@@ -941,6 +991,14 @@ sub cmd_dcommit {
},
mergeinfo => $_merge_info,
svn_path => '');
+
+ my $err_handler = $SVN::Error::handler;
+ $SVN::Error::handler = sub {
+ my $err = shift;
+ dcommit_rebase(1, $current_head, $gs->refname,
+ $err);
+ };
+
if (!Git::SVN::Editor->new(\%ed_opts)->apply_diff) {
print "No changes\n$d~1 == $d\n";
} elsif ($parents->{$d} && @{$parents->{$d}}) {
@@ -948,31 +1006,19 @@ sub cmd_dcommit {
$parents->{$d};
}
$_fetch_all ? $gs->fetch_all : $gs->fetch;
+ $SVN::Error::handler = $err_handler;
$last_rev = $cmt_rev;
next if $_no_rebase;
- # we always want to rebase against the current HEAD,
- # not any head that was passed to us
- my @diff = command('diff-tree', $d,
- $gs->refname, '--');
- my @finish;
- if (@diff) {
- @finish = rebase_cmd();
- print STDERR "W: $d and ", $gs->refname,
- " differ, using @finish:\n",
- join("\n", @diff), "\n";
- } else {
- print "No changes between current HEAD and ",
- $gs->refname,
- "\nResetting to the latest ",
- $gs->refname, "\n";
- @finish = qw/reset --mixed/;
- }
- command_noisy(@finish, $gs->refname);
+ my @diff = dcommit_rebase(@$linear_refs == 0, $d,
+ $gs->refname, undef);
- $rewritten_parent = command_oneline(qw/rev-parse HEAD/);
+ $rewritten_parent = command_oneline(qw/rev-parse/,
+ $gs->refname);
if (@diff) {
+ $current_head = command_oneline(qw/rev-parse
+ HEAD/);
@refs = ();
my ($url_, $rev_, $uuid_, $gs_) =
working_head_info('HEAD', \@refs);
@@ -1017,6 +1063,7 @@ sub cmd_dcommit {
}
$parents = \%p;
$linear_refs = \@l;
+ undef $last_rev;
}
}
}
@@ -1193,7 +1240,7 @@ sub cmd_show_ignore {
my ($url, $rev, $uuid, $gs) = working_head_info('HEAD');
$gs ||= Git::SVN->new;
my $r = (defined $_revision ? $_revision : $gs->ra->get_latest_revnum);
- $gs->prop_walk($gs->{path}, $r, sub {
+ $gs->prop_walk($gs->path, $r, sub {
my ($gs, $path, $props) = @_;
print STDOUT "\n# $path\n";
my $s = $props->{'svn:ignore'} or return;
@@ -1209,7 +1256,7 @@ sub cmd_show_externals {
my ($url, $rev, $uuid, $gs) = working_head_info('HEAD');
$gs ||= Git::SVN->new;
my $r = (defined $_revision ? $_revision : $gs->ra->get_latest_revnum);
- $gs->prop_walk($gs->{path}, $r, sub {
+ $gs->prop_walk($gs->path, $r, sub {
my ($gs, $path, $props) = @_;
print STDOUT "\n# $path\n";
my $s = $props->{'svn:externals'} or return;
@@ -1224,7 +1271,7 @@ sub cmd_create_ignore {
my ($url, $rev, $uuid, $gs) = working_head_info('HEAD');
$gs ||= Git::SVN->new;
my $r = (defined $_revision ? $_revision : $gs->ra->get_latest_revnum);
- $gs->prop_walk($gs->{path}, $r, sub {
+ $gs->prop_walk($gs->path, $r, sub {
my ($gs, $path, $props) = @_;
# $path is of the form /path/to/dir/
$path = '.' . $path;
@@ -1254,31 +1301,6 @@ sub cmd_mkdirs {
$gs->mkemptydirs($_revision);
}
-sub canonicalize_path {
- my ($path) = @_;
- my $dot_slash_added = 0;
- if (substr($path, 0, 1) ne "/") {
- $path = "./" . $path;
- $dot_slash_added = 1;
- }
- # File::Spec->canonpath doesn't collapse x/../y into y (for a
- # good reason), so let's do this manually.
- $path =~ s#/+#/#g;
- $path =~ s#/\.(?:/|$)#/#g;
- $path =~ s#/[^/]+/\.\.##g;
- $path =~ s#/$##g;
- $path =~ s#^\./## if $dot_slash_added;
- $path =~ s#^/##;
- $path =~ s#^\.$##;
- return $path;
-}
-
-sub canonicalize_url {
- my ($url) = @_;
- $url =~ s#^([^:]+://[^/]*/)(.*)$#$1 . canonicalize_path($2)#e;
- return $url;
-}
-
# get_svnprops(PATH)
# ------------------
# Helper for cmd_propget and cmd_proplist below.
@@ -1292,7 +1314,7 @@ sub get_svnprops {
$path = $cmd_dir_prefix . $path;
fatal("No such file or directory: $path") unless -e $path;
my $is_dir = -d $path ? 1 : 0;
- $path = $gs->{path} . '/' . $path;
+ $path = join_paths($gs->path, $path);
# canonicalize the path (otherwise libsvn will abort or fail to
# find the file)
@@ -1393,8 +1415,8 @@ sub cmd_commit_diff {
fatal("Needed URL or usable git-svn --id in ",
"the command-line\n", $usage);
}
- $url = $gs->{url};
- $svn_path = $gs->{path};
+ $url = $gs->url;
+ $svn_path = $gs->path;
}
unless (defined $_revision) {
fatal("-r|--revision is a required argument\n", $usage);
@@ -1428,24 +1450,6 @@ sub cmd_commit_diff {
}
}
-sub escape_uri_only {
- my ($uri) = @_;
- my @tmp;
- foreach (split m{/}, $uri) {
- s/([^~\w.%+-]|%(?![a-fA-F0-9]{2}))/sprintf("%%%02X",ord($1))/eg;
- push @tmp, $_;
- }
- join('/', @tmp);
-}
-
-sub escape_url {
- my ($url) = @_;
- if ($url =~ m#^([^:]+)://([^/]*)(.*)$#) {
- my ($scheme, $domain, $uri) = ($1, $2, escape_uri_only($3));
- $url = "$scheme://$domain$uri";
- }
- $url;
-}
sub cmd_info {
my $path = canonicalize_path(defined($_[0]) ? $_[0] : ".");
@@ -1470,21 +1474,21 @@ sub cmd_info {
# canonicalize_path() will return "" to make libsvn 1.5.x happy,
$path = "." if $path eq "";
- my $full_url = $url . ($fullpath eq "" ? "" : "/$fullpath");
+ my $full_url = canonicalize_url( add_path_to_url( $url, $fullpath ) );
if ($_url) {
- print escape_url($full_url), "\n";
+ print "$full_url\n";
return;
}
my $result = "Path: $path\n";
$result .= "Name: " . basename($path) . "\n" if $file_type ne "dir";
- $result .= "URL: " . escape_url($full_url) . "\n";
+ $result .= "URL: $full_url\n";
eval {
my $repos_root = $gs->repos_root;
Git::SVN::remove_username($repos_root);
- $result .= "Repository Root: " . escape_url($repos_root) . "\n";
+ $result .= "Repository Root: " . canonicalize_url($repos_root) . "\n";
};
if ($@) {
$result .= "Repository Root: (offline)\n";
@@ -1578,7 +1582,7 @@ sub cmd_reset {
}
sub cmd_gc {
- if (!$can_compress) {
+ if (!can_compress()) {
warn "Compress::Zlib could not be found; unhandled.log " .
"files will not be compressed.\n";
}
@@ -1598,8 +1602,8 @@ sub rebase_cmd {
sub post_fetch_checkout {
return if $_no_checkout;
+ return if verify_ref('HEAD^0');
my $gs = $Git::SVN::_head or return;
- return if verify_ref('refs/heads/master^0');
# look for "trunk" ref if it exists
my $remote = Git::SVN::read_all_remotes()->{$gs->{repo_id}};
@@ -1612,9 +1616,8 @@ sub post_fetch_checkout {
}
}
- my $valid_head = verify_ref('HEAD^0');
- command_noisy(qw(update-ref refs/heads/master), $gs->refname);
- return if ($valid_head || !verify_ref('HEAD^0'));
+ command_noisy(qw(update-ref HEAD), $gs->refname);
+ return unless verify_ref('HEAD^0');
return if $ENV{GIT_DIR} !~ m#^(?:.*/)?\.git$#;
my $index = $ENV{GIT_INDEX_FILE} || "$ENV{GIT_DIR}/index";
@@ -1632,7 +1635,9 @@ sub post_fetch_checkout {
sub complete_svn_url {
my ($url, $path) = @_;
- $path =~ s#/+$##;
+ $path = canonicalize_path($path);
+
+ # If the path is not a URL...
if ($path !~ m#^[a-z\+]+://#) {
if (!defined $url || $url !~ m#^[a-z\+]+://#) {
fatal("E: '$path' is not a complete URL ",
@@ -1649,7 +1654,7 @@ sub complete_url_ls_init {
print STDERR "W: $switch not specified\n";
return;
}
- $repo_path =~ s#/+$##;
+ $repo_path = canonicalize_path($repo_path);
if ($repo_path =~ m#^[a-z\+]+://#) {
$ra = Git::SVN::Ra->new($repo_path);
$repo_path = '';
@@ -1660,18 +1665,18 @@ sub complete_url_ls_init {
"and a separate URL is not specified");
}
}
- my $url = $ra->{url};
+ my $url = $ra->url;
my $gs = Git::SVN->init($url, undef, undef, undef, 1);
my $k = "svn-remote.$gs->{repo_id}.url";
my $orig_url = eval { command_oneline(qw/config --get/, $k) };
- if ($orig_url && ($orig_url ne $gs->{url})) {
+ if ($orig_url && ($orig_url ne $gs->url)) {
die "$k already set: $orig_url\n",
- "wanted to set to: $gs->{url}\n";
+ "wanted to set to: $gs->url\n";
}
- command_oneline('config', $k, $gs->{url}) unless $orig_url;
- my $remote_path = "$gs->{path}/$repo_path";
+ command_oneline('config', $k, $gs->url) unless $orig_url;
+
+ my $remote_path = join_paths( $gs->path, $repo_path );
$remote_path =~ s{%([0-9A-F]{2})}{chr hex($1)}ieg;
- $remote_path =~ s#/+#/#g;
$remote_path =~ s#^/##g;
$remote_path .= "/*" if $remote_path !~ /\*/;
my ($n) = ($switch =~ /^--(\w+)/);
@@ -2014,13 +2019,13 @@ sub md5sum {
} elsif (!$ref) {
$md5->add($arg) or croak $!;
} else {
- ::fatal "Can't provide MD5 hash for unknown ref type: '", $ref, "'";
+ fatal "Can't provide MD5 hash for unknown ref type: '", $ref, "'";
}
return $md5->hexdigest();
}
sub gc_directory {
- if ($can_compress && -f $_ && basename($_) eq "unhandled.log") {
+ if (can_compress() && -f $_ && basename($_) eq "unhandled.log") {
my $out_filename = $_ . ".gz";
open my $in_fh, "<", $_ or die "Unable to open $_: $!\n";
binmode $in_fh;
@@ -2038,3035 +2043,6 @@ sub gc_directory {
}
}
-package Git::SVN;
-use strict;
-use warnings;
-use Fcntl qw/:DEFAULT :seek/;
-use constant rev_map_fmt => 'NH40';
-use vars qw/$default_repo_id $default_ref_id $_no_metadata $_follow_parent
- $_repack $_repack_flags $_use_svm_props $_head
- $_use_svnsync_props $no_reuse_existing $_minimize_url
- $_use_log_author $_add_author_from $_localtime/;
-use Carp qw/croak/;
-use File::Path qw/mkpath/;
-use File::Copy qw/copy/;
-use IPC::Open3;
-use Time::Local;
-use Memoize; # core since 5.8.0, Jul 2002
-use Memoize::Storable;
-use POSIX qw(:signal_h);
-my $can_use_yaml;
-BEGIN {
- $can_use_yaml = eval { require Git::SVN::Memoize::YAML; 1};
-}
-
-my ($_gc_nr, $_gc_period);
-
-# properties that we do not log:
-my %SKIP_PROP;
-BEGIN {
- %SKIP_PROP = map { $_ => 1 } qw/svn:wc:ra_dav:version-url
- svn:special svn:executable
- svn:entry:committed-rev
- svn:entry:last-author
- svn:entry:uuid
- svn:entry:committed-date/;
-
- # some options are read globally, but can be overridden locally
- # per [svn-remote "..."] section. Command-line options will *NOT*
- # override options set in an [svn-remote "..."] section
- no strict 'refs';
- for my $option (qw/follow_parent no_metadata use_svm_props
- use_svnsync_props/) {
- my $key = $option;
- $key =~ tr/_//d;
- my $prop = "-$option";
- *$option = sub {
- my ($self) = @_;
- return $self->{$prop} if exists $self->{$prop};
- my $k = "svn-remote.$self->{repo_id}.$key";
- eval { command_oneline(qw/config --get/, $k) };
- if ($@) {
- $self->{$prop} = ${"Git::SVN::_$option"};
- } else {
- my $v = command_oneline(qw/config --bool/,$k);
- $self->{$prop} = $v eq 'false' ? 0 : 1;
- }
- return $self->{$prop};
- }
- }
-}
-
-
-my (%LOCKFILES, %INDEX_FILES);
-END {
- unlink keys %LOCKFILES if %LOCKFILES;
- unlink keys %INDEX_FILES if %INDEX_FILES;
-}
-
-sub resolve_local_globs {
- my ($url, $fetch, $glob_spec) = @_;
- return unless defined $glob_spec;
- my $ref = $glob_spec->{ref};
- my $path = $glob_spec->{path};
- foreach (command(qw#for-each-ref --format=%(refname) refs/#)) {
- next unless m#^$ref->{regex}$#;
- my $p = $1;
- my $pathname = desanitize_refname($path->full_path($p));
- my $refname = desanitize_refname($ref->full_path($p));
- if (my $existing = $fetch->{$pathname}) {
- if ($existing ne $refname) {
- die "Refspec conflict:\n",
- "existing: $existing\n",
- " globbed: $refname\n";
- }
- my $u = (::cmt_metadata("$refname"))[0];
- $u =~ s!^\Q$url\E(/|$)!! or die
- "$refname: '$url' not found in '$u'\n";
- if ($pathname ne $u) {
- warn "W: Refspec glob conflict ",
- "(ref: $refname):\n",
- "expected path: $pathname\n",
- " real path: $u\n",
- "Continuing ahead with $u\n";
- next;
- }
- } else {
- $fetch->{$pathname} = $refname;
- }
- }
-}
-
-sub parse_revision_argument {
- my ($base, $head) = @_;
- if (!defined $::_revision || $::_revision eq 'BASE:HEAD') {
- return ($base, $head);
- }
- return ($1, $2) if ($::_revision =~ /^(\d+):(\d+)$/);
- return ($::_revision, $::_revision) if ($::_revision =~ /^\d+$/);
- return ($head, $head) if ($::_revision eq 'HEAD');
- return ($base, $1) if ($::_revision =~ /^BASE:(\d+)$/);
- return ($1, $head) if ($::_revision =~ /^(\d+):HEAD$/);
- die "revision argument: $::_revision not understood by git-svn\n";
-}
-
-sub fetch_all {
- my ($repo_id, $remotes) = @_;
- if (ref $repo_id) {
- my $gs = $repo_id;
- $repo_id = undef;
- $repo_id = $gs->{repo_id};
- }
- $remotes ||= read_all_remotes();
- my $remote = $remotes->{$repo_id} or
- die "[svn-remote \"$repo_id\"] unknown\n";
- my $fetch = $remote->{fetch};
- my $url = $remote->{url} or die "svn-remote.$repo_id.url not defined\n";
- my (@gs, @globs);
- my $ra = Git::SVN::Ra->new($url);
- my $uuid = $ra->get_uuid;
- my $head = $ra->get_latest_revnum;
-
- # ignore errors, $head revision may not even exist anymore
- eval { $ra->get_log("", $head, 0, 1, 0, 1, sub { $head = $_[1] }) };
- warn "W: $@\n" if $@;
-
- my $base = defined $fetch ? $head : 0;
-
- # read the max revs for wildcard expansion (branches/*, tags/*)
- foreach my $t (qw/branches tags/) {
- defined $remote->{$t} or next;
- push @globs, @{$remote->{$t}};
-
- my $max_rev = eval { tmp_config(qw/--int --get/,
- "svn-remote.$repo_id.${t}-maxRev") };
- if (defined $max_rev && ($max_rev < $base)) {
- $base = $max_rev;
- } elsif (!defined $max_rev) {
- $base = 0;
- }
- }
-
- if ($fetch) {
- foreach my $p (sort keys %$fetch) {
- my $gs = Git::SVN->new($fetch->{$p}, $repo_id, $p);
- my $lr = $gs->rev_map_max;
- if (defined $lr) {
- $base = $lr if ($lr < $base);
- }
- push @gs, $gs;
- }
- }
-
- ($base, $head) = parse_revision_argument($base, $head);
- $ra->gs_fetch_loop_common($base, $head, \@gs, \@globs);
-}
-
-sub read_all_remotes {
- my $r = {};
- my $use_svm_props = eval { command_oneline(qw/config --bool
- svn.useSvmProps/) };
- $use_svm_props = $use_svm_props eq 'true' if $use_svm_props;
- my $svn_refspec = qr{\s*(.*?)\s*:\s*(.+?)\s*};
- foreach (grep { s/^svn-remote\.// } command(qw/config -l/)) {
- if (m!^(.+)\.fetch=$svn_refspec$!) {
- my ($remote, $local_ref, $remote_ref) = ($1, $2, $3);
- die("svn-remote.$remote: remote ref '$remote_ref' "
- . "must start with 'refs/'\n")
- unless $remote_ref =~ m{^refs/};
- $local_ref = uri_decode($local_ref);
- $r->{$remote}->{fetch}->{$local_ref} = $remote_ref;
- $r->{$remote}->{svm} = {} if $use_svm_props;
- } elsif (m!^(.+)\.usesvmprops=\s*(.*)\s*$!) {
- $r->{$1}->{svm} = {};
- } elsif (m!^(.+)\.url=\s*(.*)\s*$!) {
- $r->{$1}->{url} = $2;
- } elsif (m!^(.+)\.pushurl=\s*(.*)\s*$!) {
- $r->{$1}->{pushurl} = $2;
- } elsif (m!^(.+)\.ignore-refs=\s*(.*)\s*$!) {
- $r->{$1}->{ignore_refs_regex} = $2;
- } elsif (m!^(.+)\.(branches|tags)=$svn_refspec$!) {
- my ($remote, $t, $local_ref, $remote_ref) =
- ($1, $2, $3, $4);
- die("svn-remote.$remote: remote ref '$remote_ref' ($t) "
- . "must start with 'refs/'\n")
- unless $remote_ref =~ m{^refs/};
- $local_ref = uri_decode($local_ref);
- my $rs = {
- t => $t,
- remote => $remote,
- path => Git::SVN::GlobSpec->new($local_ref, 1),
- ref => Git::SVN::GlobSpec->new($remote_ref, 0) };
- if (length($rs->{ref}->{right}) != 0) {
- die "The '*' glob character must be the last ",
- "character of '$remote_ref'\n";
- }
- push @{ $r->{$remote}->{$t} }, $rs;
- }
- }
-
- map {
- if (defined $r->{$_}->{svm}) {
- my $svm;
- eval {
- my $section = "svn-remote.$_";
- $svm = {
- source => tmp_config('--get',
- "$section.svm-source"),
- replace => tmp_config('--get',
- "$section.svm-replace"),
- }
- };
- $r->{$_}->{svm} = $svm;
- }
- } keys %$r;
-
- foreach my $remote (keys %$r) {
- foreach ( grep { defined $_ }
- map { $r->{$remote}->{$_} } qw(branches tags) ) {
- foreach my $rs ( @$_ ) {
- $rs->{ignore_refs_regex} =
- $r->{$remote}->{ignore_refs_regex};
- }
- }
- }
-
- $r;
-}
-
-sub init_vars {
- $_gc_nr = $_gc_period = 1000;
- if (defined $_repack || defined $_repack_flags) {
- warn "Repack options are obsolete; they have no effect.\n";
- }
-}
-
-sub verify_remotes_sanity {
- return unless -d $ENV{GIT_DIR};
- my %seen;
- foreach (command(qw/config -l/)) {
- if (m!^svn-remote\.(?:.+)\.fetch=.*:refs/remotes/(\S+)\s*$!) {
- if ($seen{$1}) {
- die "Remote ref refs/remote/$1 is tracked by",
- "\n \"$_\"\nand\n \"$seen{$1}\"\n",
- "Please resolve this ambiguity in ",
- "your git configuration file before ",
- "continuing\n";
- }
- $seen{$1} = $_;
- }
- }
-}
-
-sub find_existing_remote {
- my ($url, $remotes) = @_;
- return undef if $no_reuse_existing;
- my $existing;
- foreach my $repo_id (keys %$remotes) {
- my $u = $remotes->{$repo_id}->{url} or next;
- next if $u ne $url;
- $existing = $repo_id;
- last;
- }
- $existing;
-}
-
-sub init_remote_config {
- my ($self, $url, $no_write) = @_;
- $url =~ s!/+$!!; # strip trailing slash
- my $r = read_all_remotes();
- my $existing = find_existing_remote($url, $r);
- if ($existing) {
- unless ($no_write) {
- print STDERR "Using existing ",
- "[svn-remote \"$existing\"]\n";
- }
- $self->{repo_id} = $existing;
- } elsif ($_minimize_url) {
- my $min_url = Git::SVN::Ra->new($url)->minimize_url;
- $existing = find_existing_remote($min_url, $r);
- if ($existing) {
- unless ($no_write) {
- print STDERR "Using existing ",
- "[svn-remote \"$existing\"]\n";
- }
- $self->{repo_id} = $existing;
- }
- if ($min_url ne $url) {
- unless ($no_write) {
- print STDERR "Using higher level of URL: ",
- "$url => $min_url\n";
- }
- my $old_path = $self->{path};
- $self->{path} = $url;
- $self->{path} =~ s!^\Q$min_url\E(/|$)!!;
- if (length $old_path) {
- $self->{path} .= "/$old_path";
- }
- $url = $min_url;
- }
- }
- my $orig_url;
- if (!$existing) {
- # verify that we aren't overwriting anything:
- $orig_url = eval {
- command_oneline('config', '--get',
- "svn-remote.$self->{repo_id}.url")
- };
- if ($orig_url && ($orig_url ne $url)) {
- die "svn-remote.$self->{repo_id}.url already set: ",
- "$orig_url\nwanted to set to: $url\n";
- }
- }
- my ($xrepo_id, $xpath) = find_ref($self->refname);
- if (!$no_write && defined $xpath) {
- die "svn-remote.$xrepo_id.fetch already set to track ",
- "$xpath:", $self->refname, "\n";
- }
- unless ($no_write) {
- command_noisy('config',
- "svn-remote.$self->{repo_id}.url", $url);
- $self->{path} =~ s{^/}{};
- $self->{path} =~ s{%([0-9A-F]{2})}{chr hex($1)}ieg;
- command_noisy('config', '--add',
- "svn-remote.$self->{repo_id}.fetch",
- "$self->{path}:".$self->refname);
- }
- $self->{url} = $url;
-}
-
-sub find_by_url { # repos_root and, path are optional
- my ($class, $full_url, $repos_root, $path) = @_;
-
- return undef unless defined $full_url;
- remove_username($full_url);
- remove_username($repos_root) if defined $repos_root;
- my $remotes = read_all_remotes();
- if (defined $full_url && defined $repos_root && !defined $path) {
- $path = $full_url;
- $path =~ s#^\Q$repos_root\E(?:/|$)##;
- }
- foreach my $repo_id (keys %$remotes) {
- my $u = $remotes->{$repo_id}->{url} or next;
- remove_username($u);
- next if defined $repos_root && $repos_root ne $u;
-
- my $fetch = $remotes->{$repo_id}->{fetch} || {};
- foreach my $t (qw/branches tags/) {
- foreach my $globspec (@{$remotes->{$repo_id}->{$t}}) {
- resolve_local_globs($u, $fetch, $globspec);
- }
- }
- my $p = $path;
- my $rwr = rewrite_root({repo_id => $repo_id});
- my $svm = $remotes->{$repo_id}->{svm}
- if defined $remotes->{$repo_id}->{svm};
- unless (defined $p) {
- $p = $full_url;
- my $z = $u;
- my $prefix = '';
- if ($rwr) {
- $z = $rwr;
- remove_username($z);
- } elsif (defined $svm) {
- $z = $svm->{source};
- $prefix = $svm->{replace};
- $prefix =~ s#^\Q$u\E(?:/|$)##;
- $prefix =~ s#/$##;
- }
- $p =~ s#^\Q$z\E(?:/|$)#$prefix# or next;
- }
- foreach my $f (keys %$fetch) {
- next if $f ne $p;
- return Git::SVN->new($fetch->{$f}, $repo_id, $f);
- }
- }
- undef;
-}
-
-sub init {
- my ($class, $url, $path, $repo_id, $ref_id, $no_write) = @_;
- my $self = _new($class, $repo_id, $ref_id, $path);
- if (defined $url) {
- $self->init_remote_config($url, $no_write);
- }
- $self;
-}
-
-sub find_ref {
- my ($ref_id) = @_;
- foreach (command(qw/config -l/)) {
- next unless m!^svn-remote\.(.+)\.fetch=
- \s*(.*?)\s*:\s*(.+?)\s*$!x;
- my ($repo_id, $path, $ref) = ($1, $2, $3);
- if ($ref eq $ref_id) {
- $path = '' if ($path =~ m#^\./?#);
- return ($repo_id, $path);
- }
- }
- (undef, undef, undef);
-}
-
-sub new {
- my ($class, $ref_id, $repo_id, $path) = @_;
- if (defined $ref_id && !defined $repo_id && !defined $path) {
- ($repo_id, $path) = find_ref($ref_id);
- if (!defined $repo_id) {
- die "Could not find a \"svn-remote.*.fetch\" key ",
- "in the repository configuration matching: ",
- "$ref_id\n";
- }
- }
- my $self = _new($class, $repo_id, $ref_id, $path);
- if (!defined $self->{path} || !length $self->{path}) {
- my $fetch = command_oneline('config', '--get',
- "svn-remote.$repo_id.fetch",
- ":$ref_id\$") or
- die "Failed to read \"svn-remote.$repo_id.fetch\" ",
- "\":$ref_id\$\" in config\n";
- ($self->{path}, undef) = split(/\s*:\s*/, $fetch);
- }
- $self->{path} =~ s{/+}{/}g;
- $self->{path} =~ s{\A/}{};
- $self->{path} =~ s{/\z}{};
- $self->{url} = command_oneline('config', '--get',
- "svn-remote.$repo_id.url") or
- die "Failed to read \"svn-remote.$repo_id.url\" in config\n";
- $self->{pushurl} = eval { command_oneline('config', '--get',
- "svn-remote.$repo_id.pushurl") };
- $self->rebuild;
- $self;
-}
-
-sub refname {
- my ($refname) = $_[0]->{ref_id} ;
-
- # It cannot end with a slash /, we'll throw up on this because
- # SVN can't have directories with a slash in their name, either:
- if ($refname =~ m{/$}) {
- die "ref: '$refname' ends with a trailing slash, this is ",
- "not permitted by git nor Subversion\n";
- }
-
- # It cannot have ASCII control character space, tilde ~, caret ^,
- # colon :, question-mark ?, asterisk *, space, or open bracket [
- # anywhere.
- #
- # Additionally, % must be escaped because it is used for escaping
- # and we want our escaped refname to be reversible
- $refname =~ s{([ \%~\^:\?\*\[\t])}{uc sprintf('%%%02x',ord($1))}eg;
-
- # no slash-separated component can begin with a dot .
- # /.* becomes /%2E*
- $refname =~ s{/\.}{/%2E}g;
-
- # It cannot have two consecutive dots .. anywhere
- # .. becomes %2E%2E
- $refname =~ s{\.\.}{%2E%2E}g;
-
- # trailing dots and .lock are not allowed
- # .$ becomes %2E and .lock becomes %2Elock
- $refname =~ s{\.(?=$|lock$)}{%2E};
-
- # the sequence @{ is used to access the reflog
- # @{ becomes %40{
- $refname =~ s{\@\{}{%40\{}g;
-
- return $refname;
-}
-
-sub desanitize_refname {
- my ($refname) = @_;
- $refname =~ s{%(?:([0-9A-F]{2}))}{chr hex($1)}eg;
- return $refname;
-}
-
-sub svm_uuid {
- my ($self) = @_;
- return $self->{svm}->{uuid} if $self->svm;
- $self->ra;
- unless ($self->{svm}) {
- die "SVM UUID not cached, and reading remotely failed\n";
- }
- $self->{svm}->{uuid};
-}
-
-sub svm {
- my ($self) = @_;
- return $self->{svm} if $self->{svm};
- my $svm;
- # see if we have it in our config, first:
- eval {
- my $section = "svn-remote.$self->{repo_id}";
- $svm = {
- source => tmp_config('--get', "$section.svm-source"),
- uuid => tmp_config('--get', "$section.svm-uuid"),
- replace => tmp_config('--get', "$section.svm-replace"),
- }
- };
- if ($svm && $svm->{source} && $svm->{uuid} && $svm->{replace}) {
- $self->{svm} = $svm;
- }
- $self->{svm};
-}
-
-sub _set_svm_vars {
- my ($self, $ra) = @_;
- return $ra if $self->svm;
-
- my @err = ( "useSvmProps set, but failed to read SVM properties\n",
- "(svm:source, svm:uuid) ",
- "from the following URLs:\n" );
- sub read_svm_props {
- my ($self, $ra, $path, $r) = @_;
- my $props = ($ra->get_dir($path, $r))[2];
- my $src = $props->{'svm:source'};
- my $uuid = $props->{'svm:uuid'};
- return undef if (!$src || !$uuid);
-
- chomp($src, $uuid);
-
- $uuid =~ m{^[0-9a-f\-]{30,}$}i
- or die "doesn't look right - svm:uuid is '$uuid'\n";
-
- # the '!' is used to mark the repos_root!/relative/path
- $src =~ s{/?!/?}{/};
- $src =~ s{/+$}{}; # no trailing slashes please
- # username is of no interest
- $src =~ s{(^[a-z\+]*://)[^/@]*@}{$1};
-
- my $replace = $ra->{url};
- $replace .= "/$path" if length $path;
-
- my $section = "svn-remote.$self->{repo_id}";
- tmp_config("$section.svm-source", $src);
- tmp_config("$section.svm-replace", $replace);
- tmp_config("$section.svm-uuid", $uuid);
- $self->{svm} = {
- source => $src,
- uuid => $uuid,
- replace => $replace
- };
- }
-
- my $r = $ra->get_latest_revnum;
- my $path = $self->{path};
- my %tried;
- while (length $path) {
- unless ($tried{"$self->{url}/$path"}) {
- return $ra if $self->read_svm_props($ra, $path, $r);
- $tried{"$self->{url}/$path"} = 1;
- }
- $path =~ s#/?[^/]+$##;
- }
- die "Path: '$path' should be ''\n" if $path ne '';
- return $ra if $self->read_svm_props($ra, $path, $r);
- $tried{"$self->{url}/$path"} = 1;
-
- if ($ra->{repos_root} eq $self->{url}) {
- die @err, (map { " $_\n" } keys %tried), "\n";
- }
-
- # nope, make sure we're connected to the repository root:
- my $ok;
- my @tried_b;
- $path = $ra->{svn_path};
- $ra = Git::SVN::Ra->new($ra->{repos_root});
- while (length $path) {
- unless ($tried{"$ra->{url}/$path"}) {
- $ok = $self->read_svm_props($ra, $path, $r);
- last if $ok;
- $tried{"$ra->{url}/$path"} = 1;
- }
- $path =~ s#/?[^/]+$##;
- }
- die "Path: '$path' should be ''\n" if $path ne '';
- $ok ||= $self->read_svm_props($ra, $path, $r);
- $tried{"$ra->{url}/$path"} = 1;
- if (!$ok) {
- die @err, (map { " $_\n" } keys %tried), "\n";
- }
- Git::SVN::Ra->new($self->{url});
-}
-
-sub svnsync {
- my ($self) = @_;
- return $self->{svnsync} if $self->{svnsync};
-
- if ($self->no_metadata) {
- die "Can't have both 'noMetadata' and ",
- "'useSvnsyncProps' options set!\n";
- }
- if ($self->rewrite_root) {
- die "Can't have both 'useSvnsyncProps' and 'rewriteRoot' ",
- "options set!\n";
- }
- if ($self->rewrite_uuid) {
- die "Can't have both 'useSvnsyncProps' and 'rewriteUUID' ",
- "options set!\n";
- }
-
- my $svnsync;
- # see if we have it in our config, first:
- eval {
- my $section = "svn-remote.$self->{repo_id}";
-
- my $url = tmp_config('--get', "$section.svnsync-url");
- ($url) = ($url =~ m{^([a-z\+]+://\S+)$}) or
- die "doesn't look right - svn:sync-from-url is '$url'\n";
-
- my $uuid = tmp_config('--get', "$section.svnsync-uuid");
- ($uuid) = ($uuid =~ m{^([0-9a-f\-]{30,})$}i) or
- die "doesn't look right - svn:sync-from-uuid is '$uuid'\n";
-
- $svnsync = { url => $url, uuid => $uuid }
- };
- if ($svnsync && $svnsync->{url} && $svnsync->{uuid}) {
- return $self->{svnsync} = $svnsync;
- }
-
- my $err = "useSvnsyncProps set, but failed to read " .
- "svnsync property: svn:sync-from-";
- my $rp = $self->ra->rev_proplist(0);
-
- my $url = $rp->{'svn:sync-from-url'} or die $err . "url\n";
- ($url) = ($url =~ m{^([a-z\+]+://\S+)$}) or
- die "doesn't look right - svn:sync-from-url is '$url'\n";
-
- my $uuid = $rp->{'svn:sync-from-uuid'} or die $err . "uuid\n";
- ($uuid) = ($uuid =~ m{^([0-9a-f\-]{30,})$}i) or
- die "doesn't look right - svn:sync-from-uuid is '$uuid'\n";
-
- my $section = "svn-remote.$self->{repo_id}";
- tmp_config('--add', "$section.svnsync-uuid", $uuid);
- tmp_config('--add', "$section.svnsync-url", $url);
- return $self->{svnsync} = { url => $url, uuid => $uuid };
-}
-
-# this allows us to memoize our SVN::Ra UUID locally and avoid a
-# remote lookup (useful for 'git svn log').
-sub ra_uuid {
- my ($self) = @_;
- unless ($self->{ra_uuid}) {
- my $key = "svn-remote.$self->{repo_id}.uuid";
- my $uuid = eval { tmp_config('--get', $key) };
- if (!$@ && $uuid && $uuid =~ /^([a-f\d\-]{30,})$/i) {
- $self->{ra_uuid} = $uuid;
- } else {
- die "ra_uuid called without URL\n" unless $self->{url};
- $self->{ra_uuid} = $self->ra->get_uuid;
- tmp_config('--add', $key, $self->{ra_uuid});
- }
- }
- $self->{ra_uuid};
-}
-
-sub _set_repos_root {
- my ($self, $repos_root) = @_;
- my $k = "svn-remote.$self->{repo_id}.reposRoot";
- $repos_root ||= $self->ra->{repos_root};
- tmp_config($k, $repos_root);
- $repos_root;
-}
-
-sub repos_root {
- my ($self) = @_;
- my $k = "svn-remote.$self->{repo_id}.reposRoot";
- eval { tmp_config('--get', $k) } || $self->_set_repos_root;
-}
-
-sub ra {
- my ($self) = shift;
- my $ra = Git::SVN::Ra->new($self->{url});
- $self->_set_repos_root($ra->{repos_root});
- if ($self->use_svm_props && !$self->{svm}) {
- if ($self->no_metadata) {
- die "Can't have both 'noMetadata' and ",
- "'useSvmProps' options set!\n";
- } elsif ($self->use_svnsync_props) {
- die "Can't have both 'useSvnsyncProps' and ",
- "'useSvmProps' options set!\n";
- }
- $ra = $self->_set_svm_vars($ra);
- $self->{-want_revprops} = 1;
- }
- $ra;
-}
-
-# prop_walk(PATH, REV, SUB)
-# -------------------------
-# Recursively traverse PATH at revision REV and invoke SUB for each
-# directory that contains a SVN property. SUB will be invoked as
-# follows: &SUB(gs, path, props); where `gs' is this instance of
-# Git::SVN, `path' the path to the directory where the properties
-# `props' were found. The `path' will be relative to point of checkout,
-# that is, if url://repo/trunk is the current Git branch, and that
-# directory contains a sub-directory `d', SUB will be invoked with `/d/'
-# as `path' (note the trailing `/').
-sub prop_walk {
- my ($self, $path, $rev, $sub) = @_;
-
- $path =~ s#^/##;
- my ($dirent, undef, $props) = $self->ra->get_dir($path, $rev);
- $path =~ s#^/*#/#g;
- my $p = $path;
- # Strip the irrelevant part of the path.
- $p =~ s#^/+\Q$self->{path}\E(/|$)#/#;
- # Ensure the path is terminated by a `/'.
- $p =~ s#/*$#/#;
-
- # The properties contain all the internal SVN stuff nobody
- # (usually) cares about.
- my $interesting_props = 0;
- foreach (keys %{$props}) {
- # If it doesn't start with `svn:', it must be a
- # user-defined property.
- ++$interesting_props and next if $_ !~ /^svn:/;
- # FIXME: Fragile, if SVN adds new public properties,
- # this needs to be updated.
- ++$interesting_props if /^svn:(?:ignore|keywords|executable
- |eol-style|mime-type
- |externals|needs-lock)$/x;
- }
- &$sub($self, $p, $props) if $interesting_props;
-
- foreach (sort keys %$dirent) {
- next if $dirent->{$_}->{kind} != $SVN::Node::dir;
- $self->prop_walk($self->{path} . $p . $_, $rev, $sub);
- }
-}
-
-sub last_rev { ($_[0]->last_rev_commit)[0] }
-sub last_commit { ($_[0]->last_rev_commit)[1] }
-
-# returns the newest SVN revision number and newest commit SHA1
-sub last_rev_commit {
- my ($self) = @_;
- if (defined $self->{last_rev} && defined $self->{last_commit}) {
- return ($self->{last_rev}, $self->{last_commit});
- }
- my $c = ::verify_ref($self->refname.'^0');
- if ($c && !$self->use_svm_props && !$self->no_metadata) {
- my $rev = (::cmt_metadata($c))[1];
- if (defined $rev) {
- ($self->{last_rev}, $self->{last_commit}) = ($rev, $c);
- return ($rev, $c);
- }
- }
- my $map_path = $self->map_path;
- unless (-e $map_path) {
- ($self->{last_rev}, $self->{last_commit}) = (undef, undef);
- return (undef, undef);
- }
- my ($rev, $commit) = $self->rev_map_max(1);
- ($self->{last_rev}, $self->{last_commit}) = ($rev, $commit);
- return ($rev, $commit);
-}
-
-sub get_fetch_range {
- my ($self, $min, $max) = @_;
- $max ||= $self->ra->get_latest_revnum;
- $min ||= $self->rev_map_max;
- (++$min, $max);
-}
-
-sub tmp_config {
- my (@args) = @_;
- my $old_def_config = "$ENV{GIT_DIR}/svn/config";
- my $config = "$ENV{GIT_DIR}/svn/.metadata";
- if (! -f $config && -f $old_def_config) {
- rename $old_def_config, $config or
- die "Failed rename $old_def_config => $config: $!\n";
- }
- my $old_config = $ENV{GIT_CONFIG};
- $ENV{GIT_CONFIG} = $config;
- $@ = undef;
- my @ret = eval {
- unless (-f $config) {
- mkfile($config);
- open my $fh, '>', $config or
- die "Can't open $config: $!\n";
- print $fh "; This file is used internally by ",
- "git-svn\n" or die
- "Couldn't write to $config: $!\n";
- print $fh "; You should not have to edit it\n" or
- die "Couldn't write to $config: $!\n";
- close $fh or die "Couldn't close $config: $!\n";
- }
- command('config', @args);
- };
- my $err = $@;
- if (defined $old_config) {
- $ENV{GIT_CONFIG} = $old_config;
- } else {
- delete $ENV{GIT_CONFIG};
- }
- die $err if $err;
- wantarray ? @ret : $ret[0];
-}
-
-sub tmp_index_do {
- my ($self, $sub) = @_;
- my $old_index = $ENV{GIT_INDEX_FILE};
- $ENV{GIT_INDEX_FILE} = $self->{index};
- $@ = undef;
- my @ret = eval {
- my ($dir, $base) = ($self->{index} =~ m#^(.*?)/?([^/]+)$#);
- mkpath([$dir]) unless -d $dir;
- &$sub;
- };
- my $err = $@;
- if (defined $old_index) {
- $ENV{GIT_INDEX_FILE} = $old_index;
- } else {
- delete $ENV{GIT_INDEX_FILE};
- }
- die $err if $err;
- wantarray ? @ret : $ret[0];
-}
-
-sub assert_index_clean {
- my ($self, $treeish) = @_;
-
- $self->tmp_index_do(sub {
- command_noisy('read-tree', $treeish) unless -e $self->{index};
- my $x = command_oneline('write-tree');
- my ($y) = (command(qw/cat-file commit/, $treeish) =~
- /^tree ($::sha1)/mo);
- return if $y eq $x;
-
- warn "Index mismatch: $y != $x\nrereading $treeish\n";
- unlink $self->{index} or die "unlink $self->{index}: $!\n";
- command_noisy('read-tree', $treeish);
- $x = command_oneline('write-tree');
- if ($y ne $x) {
- ::fatal "trees ($treeish) $y != $x\n",
- "Something is seriously wrong...";
- }
- });
-}
-
-sub get_commit_parents {
- my ($self, $log_entry) = @_;
- my (%seen, @ret, @tmp);
- # legacy support for 'set-tree'; this is only used by set_tree_cb:
- if (my $ip = $self->{inject_parents}) {
- if (my $commit = delete $ip->{$log_entry->{revision}}) {
- push @tmp, $commit;
- }
- }
- if (my $cur = ::verify_ref($self->refname.'^0')) {
- push @tmp, $cur;
- }
- if (my $ipd = $self->{inject_parents_dcommit}) {
- if (my $commit = delete $ipd->{$log_entry->{revision}}) {
- push @tmp, @$commit;
- }
- }
- push @tmp, $_ foreach (@{$log_entry->{parents}}, @tmp);
- while (my $p = shift @tmp) {
- next if $seen{$p};
- $seen{$p} = 1;
- push @ret, $p;
- }
- @ret;
-}
-
-sub rewrite_root {
- my ($self) = @_;
- return $self->{-rewrite_root} if exists $self->{-rewrite_root};
- my $k = "svn-remote.$self->{repo_id}.rewriteRoot";
- my $rwr = eval { command_oneline(qw/config --get/, $k) };
- if ($rwr) {
- $rwr =~ s#/+$##;
- if ($rwr !~ m#^[a-z\+]+://#) {
- die "$rwr is not a valid URL (key: $k)\n";
- }
- }
- $self->{-rewrite_root} = $rwr;
-}
-
-sub rewrite_uuid {
- my ($self) = @_;
- return $self->{-rewrite_uuid} if exists $self->{-rewrite_uuid};
- my $k = "svn-remote.$self->{repo_id}.rewriteUUID";
- my $rwid = eval { command_oneline(qw/config --get/, $k) };
- if ($rwid) {
- $rwid =~ s#/+$##;
- if ($rwid !~ m#^[a-f0-9]{8}-(?:[a-f0-9]{4}-){3}[a-f0-9]{12}$#) {
- die "$rwid is not a valid UUID (key: $k)\n";
- }
- }
- $self->{-rewrite_uuid} = $rwid;
-}
-
-sub metadata_url {
- my ($self) = @_;
- ($self->rewrite_root || $self->{url}) .
- (length $self->{path} ? '/' . $self->{path} : '');
-}
-
-sub full_url {
- my ($self) = @_;
- $self->{url} . (length $self->{path} ? '/' . $self->{path} : '');
-}
-
-sub full_pushurl {
- my ($self) = @_;
- if ($self->{pushurl}) {
- return $self->{pushurl} . (length $self->{path} ? '/' .
- $self->{path} : '');
- } else {
- return $self->full_url;
- }
-}
-
-sub set_commit_header_env {
- my ($log_entry) = @_;
- my %env;
- foreach my $ned (qw/NAME EMAIL DATE/) {
- foreach my $ac (qw/AUTHOR COMMITTER/) {
- $env{"GIT_${ac}_${ned}"} = $ENV{"GIT_${ac}_${ned}"};
- }
- }
-
- $ENV{GIT_AUTHOR_NAME} = $log_entry->{name};
- $ENV{GIT_AUTHOR_EMAIL} = $log_entry->{email};
- $ENV{GIT_AUTHOR_DATE} = $ENV{GIT_COMMITTER_DATE} = $log_entry->{date};
-
- $ENV{GIT_COMMITTER_NAME} = (defined $log_entry->{commit_name})
- ? $log_entry->{commit_name}
- : $log_entry->{name};
- $ENV{GIT_COMMITTER_EMAIL} = (defined $log_entry->{commit_email})
- ? $log_entry->{commit_email}
- : $log_entry->{email};
- \%env;
-}
-
-sub restore_commit_header_env {
- my ($env) = @_;
- foreach my $ned (qw/NAME EMAIL DATE/) {
- foreach my $ac (qw/AUTHOR COMMITTER/) {
- my $k = "GIT_${ac}_${ned}";
- if (defined $env->{$k}) {
- $ENV{$k} = $env->{$k};
- } else {
- delete $ENV{$k};
- }
- }
- }
-}
-
-sub gc {
- command_noisy('gc', '--auto');
-};
-
-sub do_git_commit {
- my ($self, $log_entry) = @_;
- my $lr = $self->last_rev;
- if (defined $lr && $lr >= $log_entry->{revision}) {
- die "Last fetched revision of ", $self->refname,
- " was r$lr, but we are about to fetch: ",
- "r$log_entry->{revision}!\n";
- }
- if (my $c = $self->rev_map_get($log_entry->{revision})) {
- croak "$log_entry->{revision} = $c already exists! ",
- "Why are we refetching it?\n";
- }
- my $old_env = set_commit_header_env($log_entry);
- my $tree = $log_entry->{tree};
- if (!defined $tree) {
- $tree = $self->tmp_index_do(sub {
- command_oneline('write-tree') });
- }
- die "Tree is not a valid sha1: $tree\n" if $tree !~ /^$::sha1$/o;
-
- my @exec = ('git', 'commit-tree', $tree);
- foreach ($self->get_commit_parents($log_entry)) {
- push @exec, '-p', $_;
- }
- defined(my $pid = open3(my $msg_fh, my $out_fh, '>&STDERR', @exec))
- or croak $!;
- binmode $msg_fh;
-
- # we always get UTF-8 from SVN, but we may want our commits in
- # a different encoding.
- if (my $enc = Git::config('i18n.commitencoding')) {
- require Encode;
- Encode::from_to($log_entry->{log}, 'UTF-8', $enc);
- }
- print $msg_fh $log_entry->{log} or croak $!;
- restore_commit_header_env($old_env);
- unless ($self->no_metadata) {
- print $msg_fh "\ngit-svn-id: $log_entry->{metadata}\n"
- or croak $!;
- }
- $msg_fh->flush == 0 or croak $!;
- close $msg_fh or croak $!;
- chomp(my $commit = do { local $/; <$out_fh> });
- close $out_fh or croak $!;
- waitpid $pid, 0;
- croak $? if $?;
- if ($commit !~ /^$::sha1$/o) {
- die "Failed to commit, invalid sha1: $commit\n";
- }
-
- $self->rev_map_set($log_entry->{revision}, $commit, 1);
-
- $self->{last_rev} = $log_entry->{revision};
- $self->{last_commit} = $commit;
- print "r$log_entry->{revision}" unless $::_q > 1;
- if (defined $log_entry->{svm_revision}) {
- print " (\@$log_entry->{svm_revision})" unless $::_q > 1;
- $self->rev_map_set($log_entry->{svm_revision}, $commit,
- 0, $self->svm_uuid);
- }
- print " = $commit ($self->{ref_id})\n" unless $::_q > 1;
- if (--$_gc_nr == 0) {
- $_gc_nr = $_gc_period;
- gc();
- }
- return $commit;
-}
-
-sub match_paths {
- my ($self, $paths, $r) = @_;
- return 1 if $self->{path} eq '';
- if (my $path = $paths->{"/$self->{path}"}) {
- return ($path->{action} eq 'D') ? 0 : 1;
- }
- $self->{path_regex} ||= qr/^\/\Q$self->{path}\E\//;
- if (grep /$self->{path_regex}/, keys %$paths) {
- return 1;
- }
- my $c = '';
- foreach (split m#/#, $self->{path}) {
- $c .= "/$_";
- next unless ($paths->{$c} &&
- ($paths->{$c}->{action} =~ /^[AR]$/));
- if ($self->ra->check_path($self->{path}, $r) ==
- $SVN::Node::dir) {
- return 1;
- }
- }
- return 0;
-}
-
-sub find_parent_branch {
- my ($self, $paths, $rev) = @_;
- return undef unless $self->follow_parent;
- unless (defined $paths) {
- my $err_handler = $SVN::Error::handler;
- $SVN::Error::handler = \&Git::SVN::Ra::skip_unknown_revs;
- $self->ra->get_log([$self->{path}], $rev, $rev, 0, 1, 1,
- sub { $paths = $_[0] });
- $SVN::Error::handler = $err_handler;
- }
- return undef unless defined $paths;
-
- # look for a parent from another branch:
- my @b_path_components = split m#/#, $self->{path};
- my @a_path_components;
- my $i;
- while (@b_path_components) {
- $i = $paths->{'/'.join('/', @b_path_components)};
- last if $i && defined $i->{copyfrom_path};
- unshift(@a_path_components, pop(@b_path_components));
- }
- return undef unless defined $i && defined $i->{copyfrom_path};
- my $branch_from = $i->{copyfrom_path};
- if (@a_path_components) {
- print STDERR "branch_from: $branch_from => ";
- $branch_from .= '/'.join('/', @a_path_components);
- print STDERR $branch_from, "\n";
- }
- my $r = $i->{copyfrom_rev};
- my $repos_root = $self->ra->{repos_root};
- my $url = $self->ra->{url};
- my $new_url = $url . $branch_from;
- print STDERR "Found possible branch point: ",
- "$new_url => ", $self->full_url, ", $r\n"
- unless $::_q > 1;
- $branch_from =~ s#^/##;
- my $gs = $self->other_gs($new_url, $url,
- $branch_from, $r, $self->{ref_id});
- my ($r0, $parent) = $gs->find_rev_before($r, 1);
- {
- my ($base, $head);
- if (!defined $r0 || !defined $parent) {
- ($base, $head) = parse_revision_argument(0, $r);
- } else {
- if ($r0 < $r) {
- $gs->ra->get_log([$gs->{path}], $r0 + 1, $r, 1,
- 0, 1, sub { $base = $_[1] - 1 });
- }
- }
- if (defined $base && $base <= $r) {
- $gs->fetch($base, $r);
- }
- ($r0, $parent) = $gs->find_rev_before($r, 1);
- }
- if (defined $r0 && defined $parent) {
- print STDERR "Found branch parent: ($self->{ref_id}) $parent\n"
- unless $::_q > 1;
- my $ed;
- if ($self->ra->can_do_switch) {
- $self->assert_index_clean($parent);
- print STDERR "Following parent with do_switch\n"
- unless $::_q > 1;
- # do_switch works with svn/trunk >= r22312, but that
- # is not included with SVN 1.4.3 (the latest version
- # at the moment), so we can't rely on it
- $self->{last_rev} = $r0;
- $self->{last_commit} = $parent;
- $ed = Git::SVN::Fetcher->new($self, $gs->{path});
- $gs->ra->gs_do_switch($r0, $rev, $gs,
- $self->full_url, $ed)
- or die "SVN connection failed somewhere...\n";
- } elsif ($self->ra->trees_match($new_url, $r0,
- $self->full_url, $rev)) {
- print STDERR "Trees match:\n",
- " $new_url\@$r0\n",
- " ${\$self->full_url}\@$rev\n",
- "Following parent with no changes\n"
- unless $::_q > 1;
- $self->tmp_index_do(sub {
- command_noisy('read-tree', $parent);
- });
- $self->{last_commit} = $parent;
- } else {
- print STDERR "Following parent with do_update\n"
- unless $::_q > 1;
- $ed = Git::SVN::Fetcher->new($self);
- $self->ra->gs_do_update($rev, $rev, $self, $ed)
- or die "SVN connection failed somewhere...\n";
- }
- print STDERR "Successfully followed parent\n" unless $::_q > 1;
- return $self->make_log_entry($rev, [$parent], $ed);
- }
- return undef;
-}
-
-sub do_fetch {
- my ($self, $paths, $rev) = @_;
- my $ed;
- my ($last_rev, @parents);
- if (my $lc = $self->last_commit) {
- # we can have a branch that was deleted, then re-added
- # under the same name but copied from another path, in
- # which case we'll have multiple parents (we don't
- # want to break the original ref, nor lose copypath info):
- if (my $log_entry = $self->find_parent_branch($paths, $rev)) {
- push @{$log_entry->{parents}}, $lc;
- return $log_entry;
- }
- $ed = Git::SVN::Fetcher->new($self);
- $last_rev = $self->{last_rev};
- $ed->{c} = $lc;
- @parents = ($lc);
- } else {
- $last_rev = $rev;
- if (my $log_entry = $self->find_parent_branch($paths, $rev)) {
- return $log_entry;
- }
- $ed = Git::SVN::Fetcher->new($self);
- }
- unless ($self->ra->gs_do_update($last_rev, $rev, $self, $ed)) {
- die "SVN connection failed somewhere...\n";
- }
- $self->make_log_entry($rev, \@parents, $ed);
-}
-
-sub mkemptydirs {
- my ($self, $r) = @_;
-
- sub scan {
- my ($r, $empty_dirs, $line) = @_;
- if (defined $r && $line =~ /^r(\d+)$/) {
- return 0 if $1 > $r;
- } elsif ($line =~ /^ \+empty_dir: (.+)$/) {
- $empty_dirs->{$1} = 1;
- } elsif ($line =~ /^ \-empty_dir: (.+)$/) {
- my @d = grep {m[^\Q$1\E(/|$)]} (keys %$empty_dirs);
- delete @$empty_dirs{@d};
- }
- 1; # continue
- };
-
- my %empty_dirs = ();
- my $gz_file = "$self->{dir}/unhandled.log.gz";
- if (-f $gz_file) {
- if (!$can_compress) {
- warn "Compress::Zlib could not be found; ",
- "empty directories in $gz_file will not be read\n";
- } else {
- my $gz = Compress::Zlib::gzopen($gz_file, "rb") or
- die "Unable to open $gz_file: $!\n";
- my $line;
- while ($gz->gzreadline($line) > 0) {
- scan($r, \%empty_dirs, $line) or last;
- }
- $gz->gzclose;
- }
- }
-
- if (open my $fh, '<', "$self->{dir}/unhandled.log") {
- binmode $fh or croak "binmode: $!";
- while (<$fh>) {
- scan($r, \%empty_dirs, $_) or last;
- }
- close $fh;
- }
-
- my $strip = qr/\A\Q$self->{path}\E(?:\/|$)/;
- foreach my $d (sort keys %empty_dirs) {
- $d = uri_decode($d);
- $d =~ s/$strip//;
- next unless length($d);
- next if -d $d;
- if (-e $d) {
- warn "$d exists but is not a directory\n";
- } else {
- print "creating empty directory: $d\n";
- mkpath([$d]);
- }
- }
-}
-
-sub get_untracked {
- my ($self, $ed) = @_;
- my @out;
- my $h = $ed->{empty};
- foreach (sort keys %$h) {
- my $act = $h->{$_} ? '+empty_dir' : '-empty_dir';
- push @out, " $act: " . uri_encode($_);
- warn "W: $act: $_\n";
- }
- foreach my $t (qw/dir_prop file_prop/) {
- $h = $ed->{$t} or next;
- foreach my $path (sort keys %$h) {
- my $ppath = $path eq '' ? '.' : $path;
- foreach my $prop (sort keys %{$h->{$path}}) {
- next if $SKIP_PROP{$prop};
- my $v = $h->{$path}->{$prop};
- my $t_ppath_prop = "$t: " .
- uri_encode($ppath) . ' ' .
- uri_encode($prop);
- if (defined $v) {
- push @out, " +$t_ppath_prop " .
- uri_encode($v);
- } else {
- push @out, " -$t_ppath_prop";
- }
- }
- }
- }
- foreach my $t (qw/absent_file absent_directory/) {
- $h = $ed->{$t} or next;
- foreach my $parent (sort keys %$h) {
- foreach my $path (sort @{$h->{$parent}}) {
- push @out, " $t: " .
- uri_encode("$parent/$path");
- warn "W: $t: $parent/$path ",
- "Insufficient permissions?\n";
- }
- }
- }
- \@out;
-}
-
-sub get_tz {
- # some systmes don't handle or mishandle %z, so be creative.
- my $t = shift || time;
- my $gm = timelocal(gmtime($t));
- my $sign = qw( + + - )[ $t <=> $gm ];
- return sprintf("%s%02d%02d", $sign, (gmtime(abs($t - $gm)))[2,1]);
-}
-
-# parse_svn_date(DATE)
-# --------------------
-# Given a date (in UTC) from Subversion, return a string in the format
-# "<TZ Offset> <local date/time>" that Git will use.
-#
-# By default the parsed date will be in UTC; if $Git::SVN::_localtime
-# is true we'll convert it to the local timezone instead.
-sub parse_svn_date {
- my $date = shift || return '+0000 1970-01-01 00:00:00';
- my ($Y,$m,$d,$H,$M,$S) = ($date =~ /^(\d{4})\-(\d\d)\-(\d\d)T
- (\d\d)\:(\d\d)\:(\d\d)\.\d*Z$/x) or
- croak "Unable to parse date: $date\n";
- my $parsed_date; # Set next.
-
- if ($Git::SVN::_localtime) {
- # Translate the Subversion datetime to an epoch time.
- # Begin by switching ourselves to $date's timezone, UTC.
- my $old_env_TZ = $ENV{TZ};
- $ENV{TZ} = 'UTC';
-
- my $epoch_in_UTC =
- POSIX::strftime('%s', $S, $M, $H, $d, $m - 1, $Y - 1900);
-
- # Determine our local timezone (including DST) at the
- # time of $epoch_in_UTC. $Git::SVN::Log::TZ stored the
- # value of TZ, if any, at the time we were run.
- if (defined $Git::SVN::Log::TZ) {
- $ENV{TZ} = $Git::SVN::Log::TZ;
- } else {
- delete $ENV{TZ};
- }
-
- my $our_TZ = get_tz();
-
- # This converts $epoch_in_UTC into our local timezone.
- my ($sec, $min, $hour, $mday, $mon, $year,
- $wday, $yday, $isdst) = localtime($epoch_in_UTC);
-
- $parsed_date = sprintf('%s %04d-%02d-%02d %02d:%02d:%02d',
- $our_TZ, $year + 1900, $mon + 1,
- $mday, $hour, $min, $sec);
-
- # Reset us to the timezone in effect when we entered
- # this routine.
- if (defined $old_env_TZ) {
- $ENV{TZ} = $old_env_TZ;
- } else {
- delete $ENV{TZ};
- }
- } else {
- $parsed_date = "+0000 $Y-$m-$d $H:$M:$S";
- }
-
- return $parsed_date;
-}
-
-sub other_gs {
- my ($self, $new_url, $url,
- $branch_from, $r, $old_ref_id) = @_;
- my $gs = Git::SVN->find_by_url($new_url, $url, $branch_from);
- unless ($gs) {
- my $ref_id = $old_ref_id;
- $ref_id =~ s/\@\d+-*$//;
- $ref_id .= "\@$r";
- # just grow a tail if we're not unique enough :x
- $ref_id .= '-' while find_ref($ref_id);
- my ($u, $p, $repo_id) = ($new_url, '', $ref_id);
- if ($u =~ s#^\Q$url\E(/|$)##) {
- $p = $u;
- $u = $url;
- $repo_id = $self->{repo_id};
- }
- while (1) {
- # It is possible to tag two different subdirectories at
- # the same revision. If the url for an existing ref
- # does not match, we must either find a ref with a
- # matching url or create a new ref by growing a tail.
- $gs = Git::SVN->init($u, $p, $repo_id, $ref_id, 1);
- my (undef, $max_commit) = $gs->rev_map_max(1);
- last if (!$max_commit);
- my ($url) = ::cmt_metadata($max_commit);
- last if ($url eq $gs->metadata_url);
- $ref_id .= '-';
- }
- print STDERR "Initializing parent: $ref_id\n" unless $::_q > 1;
- }
- $gs
-}
-
-sub call_authors_prog {
- my ($orig_author) = @_;
- $orig_author = command_oneline('rev-parse', '--sq-quote', $orig_author);
- my $author = `$::_authors_prog $orig_author`;
- if ($? != 0) {
- die "$::_authors_prog failed with exit code $?\n"
- }
- if ($author =~ /^\s*(.+?)\s*<(.*)>\s*$/) {
- my ($name, $email) = ($1, $2);
- $email = undef if length $2 == 0;
- return [$name, $email];
- } else {
- die "Author: $orig_author: $::_authors_prog returned "
- . "invalid author format: $author\n";
- }
-}
-
-sub check_author {
- my ($author) = @_;
- if (!defined $author || length $author == 0) {
- $author = '(no author)';
- }
- if (!defined $::users{$author}) {
- if (defined $::_authors_prog) {
- $::users{$author} = call_authors_prog($author);
- } elsif (defined $::_authors) {
- die "Author: $author not defined in $::_authors file\n";
- }
- }
- $author;
-}
-
-sub find_extra_svk_parents {
- my ($self, $ed, $tickets, $parents) = @_;
- # aha! svk:merge property changed...
- my @tickets = split "\n", $tickets;
- my @known_parents;
- for my $ticket ( @tickets ) {
- my ($uuid, $path, $rev) = split /:/, $ticket;
- if ( $uuid eq $self->ra_uuid ) {
- my $url = $self->{url};
- my $repos_root = $url;
- my $branch_from = $path;
- $branch_from =~ s{^/}{};
- my $gs = $self->other_gs($repos_root."/".$branch_from,
- $url,
- $branch_from,
- $rev,
- $self->{ref_id});
- if ( my $commit = $gs->rev_map_get($rev, $uuid) ) {
- # wahey! we found it, but it might be
- # an old one (!)
- push @known_parents, [ $rev, $commit ];
- }
- }
- }
- # Ordering matters; highest-numbered commit merge tickets
- # first, as they may account for later merge ticket additions
- # or changes.
- @known_parents = map {$_->[1]} sort {$b->[0] <=> $a->[0]} @known_parents;
- for my $parent ( @known_parents ) {
- my @cmd = ('rev-list', $parent, map { "^$_" } @$parents );
- my ($msg_fh, $ctx) = command_output_pipe(@cmd);
- my $new;
- while ( <$msg_fh> ) {
- $new=1;last;
- }
- command_close_pipe($msg_fh, $ctx);
- if ( $new ) {
- print STDERR
- "Found merge parent (svk:merge ticket): $parent\n";
- push @$parents, $parent;
- }
- }
-}
-
-sub lookup_svn_merge {
- my $uuid = shift;
- my $url = shift;
- my $merge = shift;
-
- my ($source, $revs) = split ":", $merge;
- my $path = $source;
- $path =~ s{^/}{};
- my $gs = Git::SVN->find_by_url($url.$source, $url, $path);
- if ( !$gs ) {
- warn "Couldn't find revmap for $url$source\n";
- return;
- }
- my @ranges = split ",", $revs;
- my ($tip, $tip_commit);
- my @merged_commit_ranges;
- # find the tip
- for my $range ( @ranges ) {
- my ($bottom, $top) = split "-", $range;
- $top ||= $bottom;
- my $bottom_commit = $gs->find_rev_after( $bottom, 1, $top );
- my $top_commit = $gs->find_rev_before( $top, 1, $bottom );
-
- unless ($top_commit and $bottom_commit) {
- warn "W:unknown path/rev in svn:mergeinfo "
- ."dirprop: $source:$range\n";
- next;
- }
-
- if (scalar(command('rev-parse', "$bottom_commit^@"))) {
- push @merged_commit_ranges,
- "$bottom_commit^..$top_commit";
- } else {
- push @merged_commit_ranges, "$top_commit";
- }
-
- if ( !defined $tip or $top > $tip ) {
- $tip = $top;
- $tip_commit = $top_commit;
- }
- }
- return ($tip_commit, @merged_commit_ranges);
-}
-
-sub _rev_list {
- my ($msg_fh, $ctx) = command_output_pipe(
- "rev-list", @_,
- );
- my @rv;
- while ( <$msg_fh> ) {
- chomp;
- push @rv, $_;
- }
- command_close_pipe($msg_fh, $ctx);
- @rv;
-}
-
-sub check_cherry_pick {
- my $base = shift;
- my $tip = shift;
- my $parents = shift;
- my @ranges = @_;
- my %commits = map { $_ => 1 }
- _rev_list("--no-merges", $tip, "--not", $base, @$parents, "--");
- for my $range ( @ranges ) {
- delete @commits{_rev_list($range, "--")};
- }
- for my $commit (keys %commits) {
- if (has_no_changes($commit)) {
- delete $commits{$commit};
- }
- }
- return (keys %commits);
-}
-
-sub has_no_changes {
- my $commit = shift;
-
- my @revs = split / /, command_oneline(
- qw(rev-list --parents -1 -m), $commit);
-
- # Commits with no parents, e.g. the start of a partial branch,
- # have changes by definition.
- return 1 if (@revs < 2);
-
- # Commits with multiple parents, e.g a merge, have no changes
- # by definition.
- return 0 if (@revs > 2);
-
- return (command_oneline("rev-parse", "$commit^{tree}") eq
- command_oneline("rev-parse", "$commit~1^{tree}"));
-}
-
-sub tie_for_persistent_memoization {
- my $hash = shift;
- my $path = shift;
-
- if ($can_use_yaml) {
- tie %$hash => 'Git::SVN::Memoize::YAML', "$path.yaml";
- } else {
- tie %$hash => 'Memoize::Storable', "$path.db", 'nstore';
- }
-}
-
-# The GIT_DIR environment variable is not always set until after the command
-# line arguments are processed, so we can't memoize in a BEGIN block.
-{
- my $memoized = 0;
-
- sub memoize_svn_mergeinfo_functions {
- return if $memoized;
- $memoized = 1;
-
- my $cache_path = "$ENV{GIT_DIR}/svn/.caches/";
- mkpath([$cache_path]) unless -d $cache_path;
-
- my %lookup_svn_merge_cache;
- my %check_cherry_pick_cache;
- my %has_no_changes_cache;
-
- tie_for_persistent_memoization(\%lookup_svn_merge_cache,
- "$cache_path/lookup_svn_merge");
- memoize 'lookup_svn_merge',
- SCALAR_CACHE => 'FAULT',
- LIST_CACHE => ['HASH' => \%lookup_svn_merge_cache],
- ;
-
- tie_for_persistent_memoization(\%check_cherry_pick_cache,
- "$cache_path/check_cherry_pick");
- memoize 'check_cherry_pick',
- SCALAR_CACHE => 'FAULT',
- LIST_CACHE => ['HASH' => \%check_cherry_pick_cache],
- ;
-
- tie_for_persistent_memoization(\%has_no_changes_cache,
- "$cache_path/has_no_changes");
- memoize 'has_no_changes',
- SCALAR_CACHE => ['HASH' => \%has_no_changes_cache],
- LIST_CACHE => 'FAULT',
- ;
- }
-
- sub unmemoize_svn_mergeinfo_functions {
- return if not $memoized;
- $memoized = 0;
-
- Memoize::unmemoize 'lookup_svn_merge';
- Memoize::unmemoize 'check_cherry_pick';
- Memoize::unmemoize 'has_no_changes';
- }
-
- Memoize::memoize 'Git::SVN::repos_root';
-}
-
-END {
- # Force cache writeout explicitly instead of waiting for
- # global destruction to avoid segfault in Storable:
- # http://rt.cpan.org/Public/Bug/Display.html?id=36087
- unmemoize_svn_mergeinfo_functions();
-}
-
-sub parents_exclude {
- my $parents = shift;
- my @commits = @_;
- return unless @commits;
-
- my @excluded;
- my $excluded;
- do {
- my @cmd = ('rev-list', "-1", @commits, "--not", @$parents );
- $excluded = command_oneline(@cmd);
- if ( $excluded ) {
- my @new;
- my $found;
- for my $commit ( @commits ) {
- if ( $commit eq $excluded ) {
- push @excluded, $commit;
- $found++;
- last;
- }
- else {
- push @new, $commit;
- }
- }
- die "saw commit '$excluded' in rev-list output, "
- ."but we didn't ask for that commit (wanted: @commits --not @$parents)"
- unless $found;
- @commits = @new;
- }
- }
- while ($excluded and @commits);
-
- return @excluded;
-}
-
-
-# note: this function should only be called if the various dirprops
-# have actually changed
-sub find_extra_svn_parents {
- my ($self, $ed, $mergeinfo, $parents) = @_;
- # aha! svk:merge property changed...
-
- memoize_svn_mergeinfo_functions();
-
- # We first search for merged tips which are not in our
- # history. Then, we figure out which git revisions are in
- # that tip, but not this revision. If all of those revisions
- # are now marked as merge, we can add the tip as a parent.
- my @merges = split "\n", $mergeinfo;
- my @merge_tips;
- my $url = $self->{url};
- my $uuid = $self->ra_uuid;
- my %ranges;
- for my $merge ( @merges ) {
- my ($tip_commit, @ranges) =
- lookup_svn_merge( $uuid, $url, $merge );
- unless (!$tip_commit or
- grep { $_ eq $tip_commit } @$parents ) {
- push @merge_tips, $tip_commit;
- $ranges{$tip_commit} = \@ranges;
- } else {
- push @merge_tips, undef;
- }
- }
-
- my %excluded = map { $_ => 1 }
- parents_exclude($parents, grep { defined } @merge_tips);
-
- # check merge tips for new parents
- my @new_parents;
- for my $merge_tip ( @merge_tips ) {
- my $spec = shift @merges;
- next unless $merge_tip and $excluded{$merge_tip};
-
- my $ranges = $ranges{$merge_tip};
-
- # check out 'new' tips
- my $merge_base;
- eval {
- $merge_base = command_oneline(
- "merge-base",
- @$parents, $merge_tip,
- );
- };
- if ($@) {
- die "An error occurred during merge-base"
- unless $@->isa("Git::Error::Command");
-
- warn "W: Cannot find common ancestor between ".
- "@$parents and $merge_tip. Ignoring merge info.\n";
- next;
- }
-
- # double check that there are no missing non-merge commits
- my (@incomplete) = check_cherry_pick(
- $merge_base, $merge_tip,
- $parents,
- @$ranges,
- );
-
- if ( @incomplete ) {
- warn "W:svn cherry-pick ignored ($spec) - missing "
- .@incomplete." commit(s) (eg $incomplete[0])\n";
- } else {
- warn
- "Found merge parent (svn:mergeinfo prop): ",
- $merge_tip, "\n";
- push @new_parents, $merge_tip;
- }
- }
-
- # cater for merges which merge commits from multiple branches
- if ( @new_parents > 1 ) {
- for ( my $i = 0; $i <= $#new_parents; $i++ ) {
- for ( my $j = 0; $j <= $#new_parents; $j++ ) {
- next if $i == $j;
- next unless $new_parents[$i];
- next unless $new_parents[$j];
- my $revs = command_oneline(
- "rev-list", "-1",
- "$new_parents[$i]..$new_parents[$j]",
- );
- if ( !$revs ) {
- undef($new_parents[$j]);
- }
- }
- }
- }
- push @$parents, grep { defined } @new_parents;
-}
-
-sub make_log_entry {
- my ($self, $rev, $parents, $ed) = @_;
- my $untracked = $self->get_untracked($ed);
-
- my @parents = @$parents;
- my $ps = $ed->{path_strip} || "";
- for my $path ( grep { m/$ps/ } %{$ed->{dir_prop}} ) {
- my $props = $ed->{dir_prop}{$path};
- if ( $props->{"svk:merge"} ) {
- $self->find_extra_svk_parents
- ($ed, $props->{"svk:merge"}, \@parents);
- }
- if ( $props->{"svn:mergeinfo"} ) {
- $self->find_extra_svn_parents
- ($ed,
- $props->{"svn:mergeinfo"},
- \@parents);
- }
- }
-
- open my $un, '>>', "$self->{dir}/unhandled.log" or croak $!;
- print $un "r$rev\n" or croak $!;
- print $un $_, "\n" foreach @$untracked;
- my %log_entry = ( parents => \@parents, revision => $rev,
- log => '');
-
- my $headrev;
- my $logged = delete $self->{logged_rev_props};
- if (!$logged || $self->{-want_revprops}) {
- my $rp = $self->ra->rev_proplist($rev);
- foreach (sort keys %$rp) {
- my $v = $rp->{$_};
- if (/^svn:(author|date|log)$/) {
- $log_entry{$1} = $v;
- } elsif ($_ eq 'svm:headrev') {
- $headrev = $v;
- } else {
- print $un " rev_prop: ", uri_encode($_), ' ',
- uri_encode($v), "\n";
- }
- }
- } else {
- map { $log_entry{$_} = $logged->{$_} } keys %$logged;
- }
- close $un or croak $!;
-
- $log_entry{date} = parse_svn_date($log_entry{date});
- $log_entry{log} .= "\n";
- my $author = $log_entry{author} = check_author($log_entry{author});
- my ($name, $email) = defined $::users{$author} ? @{$::users{$author}}
- : ($author, undef);
-
- my ($commit_name, $commit_email) = ($name, $email);
- if ($_use_log_author) {
- my $name_field;
- if ($log_entry{log} =~ /From:\s+(.*\S)\s*\n/i) {
- $name_field = $1;
- } elsif ($log_entry{log} =~ /Signed-off-by:\s+(.*\S)\s*\n/i) {
- $name_field = $1;
- }
- if (!defined $name_field) {
- if (!defined $email) {
- $email = $name;
- }
- } elsif ($name_field =~ /(.*?)\s+<(.*)>/) {
- ($name, $email) = ($1, $2);
- } elsif ($name_field =~ /(.*)@/) {
- ($name, $email) = ($1, $name_field);
- } else {
- ($name, $email) = ($name_field, $name_field);
- }
- }
- if (defined $headrev && $self->use_svm_props) {
- if ($self->rewrite_root) {
- die "Can't have both 'useSvmProps' and 'rewriteRoot' ",
- "options set!\n";
- }
- if ($self->rewrite_uuid) {
- die "Can't have both 'useSvmProps' and 'rewriteUUID' ",
- "options set!\n";
- }
- my ($uuid, $r) = $headrev =~ m{^([a-f\d\-]{30,}):(\d+)$}i;
- # we don't want "SVM: initializing mirror for junk" ...
- return undef if $r == 0;
- my $svm = $self->svm;
- if ($uuid ne $svm->{uuid}) {
- die "UUID mismatch on SVM path:\n",
- "expected: $svm->{uuid}\n",
- " got: $uuid\n";
- }
- my $full_url = $self->full_url;
- $full_url =~ s#^\Q$svm->{replace}\E(/|$)#$svm->{source}$1# or
- die "Failed to replace '$svm->{replace}' with ",
- "'$svm->{source}' in $full_url\n";
- # throw away username for storing in records
- remove_username($full_url);
- $log_entry{metadata} = "$full_url\@$r $uuid";
- $log_entry{svm_revision} = $r;
- $email ||= "$author\@$uuid";
- $commit_email ||= "$author\@$uuid";
- } elsif ($self->use_svnsync_props) {
- my $full_url = $self->svnsync->{url};
- $full_url .= "/$self->{path}" if length $self->{path};
- remove_username($full_url);
- my $uuid = $self->svnsync->{uuid};
- $log_entry{metadata} = "$full_url\@$rev $uuid";
- $email ||= "$author\@$uuid";
- $commit_email ||= "$author\@$uuid";
- } else {
- my $url = $self->metadata_url;
- remove_username($url);
- my $uuid = $self->rewrite_uuid || $self->ra->get_uuid;
- $log_entry{metadata} = "$url\@$rev " . $uuid;
- $email ||= "$author\@" . $uuid;
- $commit_email ||= "$author\@" . $uuid;
- }
- $log_entry{name} = $name;
- $log_entry{email} = $email;
- $log_entry{commit_name} = $commit_name;
- $log_entry{commit_email} = $commit_email;
- \%log_entry;
-}
-
-sub fetch {
- my ($self, $min_rev, $max_rev, @parents) = @_;
- my ($last_rev, $last_commit) = $self->last_rev_commit;
- my ($base, $head) = $self->get_fetch_range($min_rev, $max_rev);
- $self->ra->gs_fetch_loop_common($base, $head, [$self]);
-}
-
-sub set_tree_cb {
- my ($self, $log_entry, $tree, $rev, $date, $author) = @_;
- $self->{inject_parents} = { $rev => $tree };
- $self->fetch(undef, undef);
-}
-
-sub set_tree {
- my ($self, $tree) = (shift, shift);
- my $log_entry = ::get_commit_entry($tree);
- unless ($self->{last_rev}) {
- ::fatal("Must have an existing revision to commit");
- }
- my %ed_opts = ( r => $self->{last_rev},
- log => $log_entry->{log},
- ra => $self->ra,
- tree_a => $self->{last_commit},
- tree_b => $tree,
- editor_cb => sub {
- $self->set_tree_cb($log_entry, $tree, @_) },
- svn_path => $self->{path} );
- if (!Git::SVN::Editor->new(\%ed_opts)->apply_diff) {
- print "No changes\nr$self->{last_rev} = $tree\n";
- }
-}
-
-sub rebuild_from_rev_db {
- my ($self, $path) = @_;
- my $r = -1;
- open my $fh, '<', $path or croak "open: $!";
- binmode $fh or croak "binmode: $!";
- while (<$fh>) {
- length($_) == 41 or croak "inconsistent size in ($_) != 41";
- chomp($_);
- ++$r;
- next if $_ eq ('0' x 40);
- $self->rev_map_set($r, $_);
- print "r$r = $_\n";
- }
- close $fh or croak "close: $!";
- unlink $path or croak "unlink: $!";
-}
-
-sub rebuild {
- my ($self) = @_;
- my $map_path = $self->map_path;
- my $partial = (-e $map_path && ! -z $map_path);
- return unless ::verify_ref($self->refname.'^0');
- if (!$partial && ($self->use_svm_props || $self->no_metadata)) {
- my $rev_db = $self->rev_db_path;
- $self->rebuild_from_rev_db($rev_db);
- if ($self->use_svm_props) {
- my $svm_rev_db = $self->rev_db_path($self->svm_uuid);
- $self->rebuild_from_rev_db($svm_rev_db);
- }
- $self->unlink_rev_db_symlink;
- return;
- }
- print "Rebuilding $map_path ...\n" if (!$partial);
- my ($base_rev, $head) = ($partial ? $self->rev_map_max_norebuild(1) :
- (undef, undef));
- my ($log, $ctx) =
- command_output_pipe(qw/rev-list --pretty=raw --reverse/,
- ($head ? "$head.." : "") . $self->refname,
- '--');
- my $metadata_url = $self->metadata_url;
- remove_username($metadata_url);
- my $svn_uuid = $self->rewrite_uuid || $self->ra_uuid;
- my $c;
- while (<$log>) {
- if ( m{^commit ($::sha1)$} ) {
- $c = $1;
- next;
- }
- next unless s{^\s*(git-svn-id:)}{$1};
- my ($url, $rev, $uuid) = ::extract_metadata($_);
- remove_username($url);
-
- # ignore merges (from set-tree)
- next if (!defined $rev || !$uuid);
-
- # if we merged or otherwise started elsewhere, this is
- # how we break out of it
- if (($uuid ne $svn_uuid) ||
- ($metadata_url && $url && ($url ne $metadata_url))) {
- next;
- }
- if ($partial && $head) {
- print "Partial-rebuilding $map_path ...\n";
- print "Currently at $base_rev = $head\n";
- $head = undef;
- }
-
- $self->rev_map_set($rev, $c);
- print "r$rev = $c\n";
- }
- command_close_pipe($log, $ctx);
- print "Done rebuilding $map_path\n" if (!$partial || !$head);
- my $rev_db_path = $self->rev_db_path;
- if (-f $self->rev_db_path) {
- unlink $self->rev_db_path or croak "unlink: $!";
- }
- $self->unlink_rev_db_symlink;
-}
-
-# rev_map:
-# Tie::File seems to be prone to offset errors if revisions get sparse,
-# it's not that fast, either. Tie::File is also not in Perl 5.6. So
-# one of my favorite modules is out :< Next up would be one of the DBM
-# modules, but I'm not sure which is most portable...
-#
-# This is the replacement for the rev_db format, which was too big
-# and inefficient for large repositories with a lot of sparse history
-# (mainly tags)
-#
-# The format is this:
-# - 24 bytes for every record,
-# * 4 bytes for the integer representing an SVN revision number
-# * 20 bytes representing the sha1 of a git commit
-# - No empty padding records like the old format
-# (except the last record, which can be overwritten)
-# - new records are written append-only since SVN revision numbers
-# increase monotonically
-# - lookups on SVN revision number are done via a binary search
-# - Piping the file to xxd -c24 is a good way of dumping it for
-# viewing or editing (piped back through xxd -r), should the need
-# ever arise.
-# - The last record can be padding revision with an all-zero sha1
-# This is used to optimize fetch performance when using multiple
-# "fetch" directives in .git/config
-#
-# These files are disposable unless noMetadata or useSvmProps is set
-
-sub _rev_map_set {
- my ($fh, $rev, $commit) = @_;
-
- binmode $fh or croak "binmode: $!";
- my $size = (stat($fh))[7];
- ($size % 24) == 0 or croak "inconsistent size: $size";
-
- my $wr_offset = 0;
- if ($size > 0) {
- sysseek($fh, -24, SEEK_END) or croak "seek: $!";
- my $read = sysread($fh, my $buf, 24) or croak "read: $!";
- $read == 24 or croak "read only $read bytes (!= 24)";
- my ($last_rev, $last_commit) = unpack(rev_map_fmt, $buf);
- if ($last_commit eq ('0' x40)) {
- if ($size >= 48) {
- sysseek($fh, -48, SEEK_END) or croak "seek: $!";
- $read = sysread($fh, $buf, 24) or
- croak "read: $!";
- $read == 24 or
- croak "read only $read bytes (!= 24)";
- ($last_rev, $last_commit) =
- unpack(rev_map_fmt, $buf);
- if ($last_commit eq ('0' x40)) {
- croak "inconsistent .rev_map\n";
- }
- }
- if ($last_rev >= $rev) {
- croak "last_rev is higher!: $last_rev >= $rev";
- }
- $wr_offset = -24;
- }
- }
- sysseek($fh, $wr_offset, SEEK_END) or croak "seek: $!";
- syswrite($fh, pack(rev_map_fmt, $rev, $commit), 24) == 24 or
- croak "write: $!";
-}
-
-sub _rev_map_reset {
- my ($fh, $rev, $commit) = @_;
- my $c = _rev_map_get($fh, $rev);
- $c eq $commit or die "_rev_map_reset(@_) commit $c does not match!\n";
- my $offset = sysseek($fh, 0, SEEK_CUR) or croak "seek: $!";
- truncate $fh, $offset or croak "truncate: $!";
-}
-
-sub mkfile {
- my ($path) = @_;
- unless (-e $path) {
- my ($dir, $base) = ($path =~ m#^(.*?)/?([^/]+)$#);
- mkpath([$dir]) unless -d $dir;
- open my $fh, '>>', $path or die "Couldn't create $path: $!\n";
- close $fh or die "Couldn't close (create) $path: $!\n";
- }
-}
-
-sub rev_map_set {
- my ($self, $rev, $commit, $update_ref, $uuid) = @_;
- defined $commit or die "missing arg3\n";
- length $commit == 40 or die "arg3 must be a full SHA1 hexsum\n";
- my $db = $self->map_path($uuid);
- my $db_lock = "$db.lock";
- my $sigmask;
- $update_ref ||= 0;
- if ($update_ref) {
- $sigmask = POSIX::SigSet->new();
- my $signew = POSIX::SigSet->new(SIGINT, SIGHUP, SIGTERM,
- SIGALRM, SIGUSR1, SIGUSR2);
- sigprocmask(SIG_BLOCK, $signew, $sigmask) or
- croak "Can't block signals: $!";
- }
- mkfile($db);
-
- $LOCKFILES{$db_lock} = 1;
- my $sync;
- # both of these options make our .rev_db file very, very important
- # and we can't afford to lose it because rebuild() won't work
- if ($self->use_svm_props || $self->no_metadata) {
- $sync = 1;
- copy($db, $db_lock) or die "rev_map_set(@_): ",
- "Failed to copy: ",
- "$db => $db_lock ($!)\n";
- } else {
- rename $db, $db_lock or die "rev_map_set(@_): ",
- "Failed to rename: ",
- "$db => $db_lock ($!)\n";
- }
-
- sysopen(my $fh, $db_lock, O_RDWR | O_CREAT)
- or croak "Couldn't open $db_lock: $!\n";
- $update_ref eq 'reset' ? _rev_map_reset($fh, $rev, $commit) :
- _rev_map_set($fh, $rev, $commit);
- if ($sync) {
- $fh->flush or die "Couldn't flush $db_lock: $!\n";
- $fh->sync or die "Couldn't sync $db_lock: $!\n";
- }
- close $fh or croak $!;
- if ($update_ref) {
- $_head = $self;
- my $note = "";
- $note = " ($update_ref)" if ($update_ref !~ /^\d*$/);
- command_noisy('update-ref', '-m', "r$rev$note",
- $self->refname, $commit);
- }
- rename $db_lock, $db or die "rev_map_set(@_): ", "Failed to rename: ",
- "$db_lock => $db ($!)\n";
- delete $LOCKFILES{$db_lock};
- if ($update_ref) {
- sigprocmask(SIG_SETMASK, $sigmask) or
- croak "Can't restore signal mask: $!";
- }
-}
-
-# If want_commit, this will return an array of (rev, commit) where
-# commit _must_ be a valid commit in the archive.
-# Otherwise, it'll return the max revision (whether or not the
-# commit is valid or just a 0x40 placeholder).
-sub rev_map_max {
- my ($self, $want_commit) = @_;
- $self->rebuild;
- my ($r, $c) = $self->rev_map_max_norebuild($want_commit);
- $want_commit ? ($r, $c) : $r;
-}
-
-sub rev_map_max_norebuild {
- my ($self, $want_commit) = @_;
- my $map_path = $self->map_path;
- stat $map_path or return $want_commit ? (0, undef) : 0;
- sysopen(my $fh, $map_path, O_RDONLY) or croak "open: $!";
- binmode $fh or croak "binmode: $!";
- my $size = (stat($fh))[7];
- ($size % 24) == 0 or croak "inconsistent size: $size";
-
- if ($size == 0) {
- close $fh or croak "close: $!";
- return $want_commit ? (0, undef) : 0;
- }
-
- sysseek($fh, -24, SEEK_END) or croak "seek: $!";
- sysread($fh, my $buf, 24) == 24 or croak "read: $!";
- my ($r, $c) = unpack(rev_map_fmt, $buf);
- if ($want_commit && $c eq ('0' x40)) {
- if ($size < 48) {
- return $want_commit ? (0, undef) : 0;
- }
- sysseek($fh, -48, SEEK_END) or croak "seek: $!";
- sysread($fh, $buf, 24) == 24 or croak "read: $!";
- ($r, $c) = unpack(rev_map_fmt, $buf);
- if ($c eq ('0'x40)) {
- croak "Penultimate record is all-zeroes in $map_path";
- }
- }
- close $fh or croak "close: $!";
- $want_commit ? ($r, $c) : $r;
-}
-
-sub rev_map_get {
- my ($self, $rev, $uuid) = @_;
- my $map_path = $self->map_path($uuid);
- return undef unless -e $map_path;
-
- sysopen(my $fh, $map_path, O_RDONLY) or croak "open: $!";
- my $c = _rev_map_get($fh, $rev);
- close($fh) or croak "close: $!";
- $c
-}
-
-sub _rev_map_get {
- my ($fh, $rev) = @_;
-
- binmode $fh or croak "binmode: $!";
- my $size = (stat($fh))[7];
- ($size % 24) == 0 or croak "inconsistent size: $size";
-
- if ($size == 0) {
- return undef;
- }
-
- my ($l, $u) = (0, $size - 24);
- my ($r, $c, $buf);
-
- while ($l <= $u) {
- my $i = int(($l/24 + $u/24) / 2) * 24;
- sysseek($fh, $i, SEEK_SET) or croak "seek: $!";
- sysread($fh, my $buf, 24) == 24 or croak "read: $!";
- my ($r, $c) = unpack(rev_map_fmt, $buf);
-
- if ($r < $rev) {
- $l = $i + 24;
- } elsif ($r > $rev) {
- $u = $i - 24;
- } else { # $r == $rev
- return $c eq ('0' x 40) ? undef : $c;
- }
- }
- undef;
-}
-
-# Finds the first svn revision that exists on (if $eq_ok is true) or
-# before $rev for the current branch. It will not search any lower
-# than $min_rev. Returns the git commit hash and svn revision number
-# if found, else (undef, undef).
-sub find_rev_before {
- my ($self, $rev, $eq_ok, $min_rev) = @_;
- --$rev unless $eq_ok;
- $min_rev ||= 1;
- my $max_rev = $self->rev_map_max;
- $rev = $max_rev if ($rev > $max_rev);
- while ($rev >= $min_rev) {
- if (my $c = $self->rev_map_get($rev)) {
- return ($rev, $c);
- }
- --$rev;
- }
- return (undef, undef);
-}
-
-# Finds the first svn revision that exists on (if $eq_ok is true) or
-# after $rev for the current branch. It will not search any higher
-# than $max_rev. Returns the git commit hash and svn revision number
-# if found, else (undef, undef).
-sub find_rev_after {
- my ($self, $rev, $eq_ok, $max_rev) = @_;
- ++$rev unless $eq_ok;
- $max_rev ||= $self->rev_map_max;
- while ($rev <= $max_rev) {
- if (my $c = $self->rev_map_get($rev)) {
- return ($rev, $c);
- }
- ++$rev;
- }
- return (undef, undef);
-}
-
-sub _new {
- my ($class, $repo_id, $ref_id, $path) = @_;
- unless (defined $repo_id && length $repo_id) {
- $repo_id = $Git::SVN::default_repo_id;
- }
- unless (defined $ref_id && length $ref_id) {
- $_prefix = '' unless defined($_prefix);
- $_[2] = $ref_id =
- "refs/remotes/$_prefix$Git::SVN::default_ref_id";
- }
- $_[1] = $repo_id;
- my $dir = "$ENV{GIT_DIR}/svn/$ref_id";
-
- # Older repos imported by us used $GIT_DIR/svn/foo instead of
- # $GIT_DIR/svn/refs/remotes/foo when tracking refs/remotes/foo
- if ($ref_id =~ m{^refs/remotes/(.*)}) {
- my $old_dir = "$ENV{GIT_DIR}/svn/$1";
- if (-d $old_dir && ! -d $dir) {
- $dir = $old_dir;
- }
- }
-
- $_[3] = $path = '' unless (defined $path);
- mkpath([$dir]);
- bless {
- ref_id => $ref_id, dir => $dir, index => "$dir/index",
- path => $path, config => "$ENV{GIT_DIR}/svn/config",
- map_root => "$dir/.rev_map", repo_id => $repo_id }, $class;
-}
-
-# for read-only access of old .rev_db formats
-sub unlink_rev_db_symlink {
- my ($self) = @_;
- my $link = $self->rev_db_path;
- $link =~ s/\.[\w-]+$// or croak "missing UUID at the end of $link";
- if (-l $link) {
- unlink $link or croak "unlink: $link failed!";
- }
-}
-
-sub rev_db_path {
- my ($self, $uuid) = @_;
- my $db_path = $self->map_path($uuid);
- $db_path =~ s{/\.rev_map\.}{/\.rev_db\.}
- or croak "map_path: $db_path does not contain '/.rev_map.' !";
- $db_path;
-}
-
-# the new replacement for .rev_db
-sub map_path {
- my ($self, $uuid) = @_;
- $uuid ||= $self->ra_uuid;
- "$self->{map_root}.$uuid";
-}
-
-sub uri_encode {
- my ($f) = @_;
- $f =~ s#([^a-zA-Z0-9\*!\:_\./\-])#uc sprintf("%%%02x",ord($1))#eg;
- $f
-}
-
-sub uri_decode {
- my ($f) = @_;
- $f =~ s#%([0-9a-fA-F]{2})#chr(hex($1))#eg;
- $f
-}
-
-sub remove_username {
- $_[0] =~ s{^([^:]*://)[^@]+@}{$1};
-}
-
-package Git::SVN::Log;
-use strict;
-use warnings;
-use POSIX qw/strftime/;
-use constant commit_log_separator => ('-' x 72) . "\n";
-use vars qw/$TZ $limit $color $pager $non_recursive $verbose $oneline
- %rusers $show_commit $incremental/;
-my $l_fmt;
-
-sub cmt_showable {
- my ($c) = @_;
- return 1 if defined $c->{r};
-
- # big commit message got truncated by the 16k pretty buffer in rev-list
- if ($c->{l} && $c->{l}->[-1] eq "...\n" &&
- $c->{a_raw} =~ /\@([a-f\d\-]+)>$/) {
- @{$c->{l}} = ();
- my @log = command(qw/cat-file commit/, $c->{c});
-
- # shift off the headers
- shift @log while ($log[0] ne '');
- shift @log;
-
- # TODO: make $c->{l} not have a trailing newline in the future
- @{$c->{l}} = map { "$_\n" } grep !/^git-svn-id: /, @log;
-
- (undef, $c->{r}, undef) = ::extract_metadata(
- (grep(/^git-svn-id: /, @log))[-1]);
- }
- return defined $c->{r};
-}
-
-sub log_use_color {
- return $color || Git->repository->get_colorbool('color.diff');
-}
-
-sub git_svn_log_cmd {
- my ($r_min, $r_max, @args) = @_;
- my $head = 'HEAD';
- my (@files, @log_opts);
- foreach my $x (@args) {
- if ($x eq '--' || @files) {
- push @files, $x;
- } else {
- if (::verify_ref("$x^0")) {
- $head = $x;
- } else {
- push @log_opts, $x;
- }
- }
- }
-
- my ($url, $rev, $uuid, $gs) = ::working_head_info($head);
- $gs ||= Git::SVN->_new;
- my @cmd = (qw/log --abbrev-commit --pretty=raw --default/,
- $gs->refname);
- push @cmd, '-r' unless $non_recursive;
- push @cmd, qw/--raw --name-status/ if $verbose;
- push @cmd, '--color' if log_use_color();
- push @cmd, @log_opts;
- if (defined $r_max && $r_max == $r_min) {
- push @cmd, '--max-count=1';
- if (my $c = $gs->rev_map_get($r_max)) {
- push @cmd, $c;
- }
- } elsif (defined $r_max) {
- if ($r_max < $r_min) {
- ($r_min, $r_max) = ($r_max, $r_min);
- }
- my (undef, $c_max) = $gs->find_rev_before($r_max, 1, $r_min);
- my (undef, $c_min) = $gs->find_rev_after($r_min, 1, $r_max);
- # If there are no commits in the range, both $c_max and $c_min
- # will be undefined. If there is at least 1 commit in the
- # range, both will be defined.
- return () if !defined $c_min || !defined $c_max;
- if ($c_min eq $c_max) {
- push @cmd, '--max-count=1', $c_min;
- } else {
- push @cmd, '--boundary', "$c_min..$c_max";
- }
- }
- return (@cmd, @files);
-}
-
-# adapted from pager.c
-sub config_pager {
- if (! -t *STDOUT) {
- $ENV{GIT_PAGER_IN_USE} = 'false';
- $pager = undef;
- return;
- }
- chomp($pager = command_oneline(qw(var GIT_PAGER)));
- if ($pager eq 'cat') {
- $pager = undef;
- }
- $ENV{GIT_PAGER_IN_USE} = defined($pager);
-}
-
-sub run_pager {
- return unless defined $pager;
- pipe my ($rfd, $wfd) or return;
- defined(my $pid = fork) or ::fatal "Can't fork: $!";
- if (!$pid) {
- open STDOUT, '>&', $wfd or
- ::fatal "Can't redirect to stdout: $!";
- return;
- }
- open STDIN, '<&', $rfd or ::fatal "Can't redirect stdin: $!";
- $ENV{LESS} ||= 'FRSX';
- exec $pager or ::fatal "Can't run pager: $! ($pager)";
-}
-
-sub format_svn_date {
- my $t = shift || time;
- my $gmoff = Git::SVN::get_tz($t);
- return strftime("%Y-%m-%d %H:%M:%S $gmoff (%a, %d %b %Y)", localtime($t));
-}
-
-sub parse_git_date {
- my ($t, $tz) = @_;
- # Date::Parse isn't in the standard Perl distro :(
- if ($tz =~ s/^\+//) {
- $t += tz_to_s_offset($tz);
- } elsif ($tz =~ s/^\-//) {
- $t -= tz_to_s_offset($tz);
- }
- return $t;
-}
-
-sub set_local_timezone {
- if (defined $TZ) {
- $ENV{TZ} = $TZ;
- } else {
- delete $ENV{TZ};
- }
-}
-
-sub tz_to_s_offset {
- my ($tz) = @_;
- $tz =~ s/(\d\d)$//;
- return ($1 * 60) + ($tz * 3600);
-}
-
-sub get_author_info {
- my ($dest, $author, $t, $tz) = @_;
- $author =~ s/(?:^\s*|\s*$)//g;
- $dest->{a_raw} = $author;
- my $au;
- if ($::_authors) {
- $au = $rusers{$author} || undef;
- }
- if (!$au) {
- ($au) = ($author =~ /<([^>]+)\@[^>]+>$/);
- }
- $dest->{t} = $t;
- $dest->{tz} = $tz;
- $dest->{a} = $au;
- $dest->{t_utc} = parse_git_date($t, $tz);
-}
-
-sub process_commit {
- my ($c, $r_min, $r_max, $defer) = @_;
- if (defined $r_min && defined $r_max) {
- if ($r_min == $c->{r} && $r_min == $r_max) {
- show_commit($c);
- return 0;
- }
- return 1 if $r_min == $r_max;
- if ($r_min < $r_max) {
- # we need to reverse the print order
- return 0 if (defined $limit && --$limit < 0);
- push @$defer, $c;
- return 1;
- }
- if ($r_min != $r_max) {
- return 1 if ($r_min < $c->{r});
- return 1 if ($r_max > $c->{r});
- }
- }
- return 0 if (defined $limit && --$limit < 0);
- show_commit($c);
- return 1;
-}
-
-sub show_commit {
- my $c = shift;
- if ($oneline) {
- my $x = "\n";
- if (my $l = $c->{l}) {
- while ($l->[0] =~ /^\s*$/) { shift @$l }
- $x = $l->[0];
- }
- $l_fmt ||= 'A' . length($c->{r});
- print 'r',pack($l_fmt, $c->{r}),' | ';
- print "$c->{c} | " if $show_commit;
- print $x;
- } else {
- show_commit_normal($c);
- }
-}
-
-sub show_commit_changed_paths {
- my ($c) = @_;
- return unless $c->{changed};
- print "Changed paths:\n", @{$c->{changed}};
-}
-
-sub show_commit_normal {
- my ($c) = @_;
- print commit_log_separator, "r$c->{r} | ";
- print "$c->{c} | " if $show_commit;
- print "$c->{a} | ", format_svn_date($c->{t_utc}), ' | ';
- my $nr_line = 0;
-
- if (my $l = $c->{l}) {
- while ($l->[$#$l] eq "\n" && $#$l > 0
- && $l->[($#$l - 1)] eq "\n") {
- pop @$l;
- }
- $nr_line = scalar @$l;
- if (!$nr_line) {
- print "1 line\n\n\n";
- } else {
- if ($nr_line == 1) {
- $nr_line = '1 line';
- } else {
- $nr_line .= ' lines';
- }
- print $nr_line, "\n";
- show_commit_changed_paths($c);
- print "\n";
- print $_ foreach @$l;
- }
- } else {
- print "1 line\n";
- show_commit_changed_paths($c);
- print "\n";
-
- }
- foreach my $x (qw/raw stat diff/) {
- if ($c->{$x}) {
- print "\n";
- print $_ foreach @{$c->{$x}}
- }
- }
-}
-
-sub cmd_show_log {
- my (@args) = @_;
- my ($r_min, $r_max);
- my $r_last = -1; # prevent dupes
- set_local_timezone();
- if (defined $::_revision) {
- if ($::_revision =~ /^(\d+):(\d+)$/) {
- ($r_min, $r_max) = ($1, $2);
- } elsif ($::_revision =~ /^\d+$/) {
- $r_min = $r_max = $::_revision;
- } else {
- ::fatal "-r$::_revision is not supported, use ",
- "standard 'git log' arguments instead";
- }
- }
-
- config_pager();
- @args = git_svn_log_cmd($r_min, $r_max, @args);
- if (!@args) {
- print commit_log_separator unless $incremental || $oneline;
- return;
- }
- my $log = command_output_pipe(@args);
- run_pager();
- my (@k, $c, $d, $stat);
- my $esc_color = qr/(?:\033\[(?:(?:\d+;)*\d*)?m)*/;
- while (<$log>) {
- if (/^${esc_color}commit (?:- )?($::sha1_short)/o) {
- my $cmt = $1;
- if ($c && cmt_showable($c) && $c->{r} != $r_last) {
- $r_last = $c->{r};
- process_commit($c, $r_min, $r_max, \@k) or
- goto out;
- }
- $d = undef;
- $c = { c => $cmt };
- } elsif (/^${esc_color}author (.+) (\d+) ([\-\+]?\d+)$/o) {
- get_author_info($c, $1, $2, $3);
- } elsif (/^${esc_color}(?:tree|parent|committer) /o) {
- # ignore
- } elsif (/^${esc_color}:\d{6} \d{6} $::sha1_short/o) {
- push @{$c->{raw}}, $_;
- } elsif (/^${esc_color}[ACRMDT]\t/) {
- # we could add $SVN->{svn_path} here, but that requires
- # remote access at the moment (repo_path_split)...
- s#^(${esc_color})([ACRMDT])\t#$1 $2 #o;
- push @{$c->{changed}}, $_;
- } elsif (/^${esc_color}diff /o) {
- $d = 1;
- push @{$c->{diff}}, $_;
- } elsif ($d) {
- push @{$c->{diff}}, $_;
- } elsif (/^\ .+\ \|\s*\d+\ $esc_color[\+\-]*
- $esc_color*[\+\-]*$esc_color$/x) {
- $stat = 1;
- push @{$c->{stat}}, $_;
- } elsif ($stat && /^ \d+ files changed, \d+ insertions/) {
- push @{$c->{stat}}, $_;
- $stat = undef;
- } elsif (/^${esc_color} (git-svn-id:.+)$/o) {
- ($c->{url}, $c->{r}, undef) = ::extract_metadata($1);
- } elsif (s/^${esc_color} //o) {
- push @{$c->{l}}, $_;
- }
- }
- if ($c && defined $c->{r} && $c->{r} != $r_last) {
- $r_last = $c->{r};
- process_commit($c, $r_min, $r_max, \@k);
- }
- if (@k) {
- ($r_min, $r_max) = ($r_max, $r_min);
- process_commit($_, $r_min, $r_max) foreach reverse @k;
- }
-out:
- close $log;
- print commit_log_separator unless $incremental || $oneline;
-}
-
-sub cmd_blame {
- my $path = pop;
-
- config_pager();
- run_pager();
-
- my ($fh, $ctx, $rev);
-
- if ($_git_format) {
- ($fh, $ctx) = command_output_pipe('blame', @_, $path);
- while (my $line = <$fh>) {
- if ($line =~ /^\^?([[:xdigit:]]+)\s/) {
- # Uncommitted edits show up as a rev ID of
- # all zeros, which we can't look up with
- # cmt_metadata
- if ($1 !~ /^0+$/) {
- (undef, $rev, undef) =
- ::cmt_metadata($1);
- $rev = '0' if (!$rev);
- } else {
- $rev = '0';
- }
- $rev = sprintf('%-10s', $rev);
- $line =~ s/^\^?[[:xdigit:]]+(\s)/$rev$1/;
- }
- print $line;
- }
- } else {
- ($fh, $ctx) = command_output_pipe('blame', '-p', @_, 'HEAD',
- '--', $path);
- my ($sha1);
- my %authors;
- my @buffer;
- my %dsha; #distinct sha keys
-
- while (my $line = <$fh>) {
- push @buffer, $line;
- if ($line =~ /^([[:xdigit:]]{40})\s\d+\s\d+/) {
- $dsha{$1} = 1;
- }
- }
-
- my $s2r = ::cmt_sha2rev_batch([keys %dsha]);
-
- foreach my $line (@buffer) {
- if ($line =~ /^([[:xdigit:]]{40})\s\d+\s\d+/) {
- $rev = $s2r->{$1};
- $rev = '0' if (!$rev)
- }
- elsif ($line =~ /^author (.*)/) {
- $authors{$rev} = $1;
- $authors{$rev} =~ s/\s/_/g;
- }
- elsif ($line =~ /^\t(.*)$/) {
- printf("%6s %10s %s\n", $rev, $authors{$rev}, $1);
- }
- }
- }
- command_close_pipe($fh, $ctx);
-}
-
-package Git::SVN::Migration;
-# these version numbers do NOT correspond to actual version numbers
-# of git nor git-svn. They are just relative.
-#
-# v0 layout: .git/$id/info/url, refs/heads/$id-HEAD
-#
-# v1 layout: .git/$id/info/url, refs/remotes/$id
-#
-# v2 layout: .git/svn/$id/info/url, refs/remotes/$id
-#
-# v3 layout: .git/svn/$id, refs/remotes/$id
-# - info/url may remain for backwards compatibility
-# - this is what we migrate up to this layout automatically,
-# - this will be used by git svn init on single branches
-# v3.1 layout (auto migrated):
-# - .rev_db => .rev_db.$UUID, .rev_db will remain as a symlink
-# for backwards compatibility
-#
-# v4 layout: .git/svn/$repo_id/$id, refs/remotes/$repo_id/$id
-# - this is only created for newly multi-init-ed
-# repositories. Similar in spirit to the
-# --use-separate-remotes option in git-clone (now default)
-# - we do not automatically migrate to this (following
-# the example set by core git)
-#
-# v5 layout: .rev_db.$UUID => .rev_map.$UUID
-# - newer, more-efficient format that uses 24-bytes per record
-# with no filler space.
-# - use xxd -c24 < .rev_map.$UUID to view and debug
-# - This is a one-way migration, repositories updated to the
-# new format will not be able to use old git-svn without
-# rebuilding the .rev_db. Rebuilding the rev_db is not
-# possible if noMetadata or useSvmProps are set; but should
-# be no problem for users that use the (sensible) defaults.
-use strict;
-use warnings;
-use Carp qw/croak/;
-use File::Path qw/mkpath/;
-use File::Basename qw/dirname basename/;
-use vars qw/$_minimize/;
-
-sub migrate_from_v0 {
- my $git_dir = $ENV{GIT_DIR};
- return undef unless -d $git_dir;
- my ($fh, $ctx) = command_output_pipe(qw/rev-parse --symbolic --all/);
- my $migrated = 0;
- while (<$fh>) {
- chomp;
- my ($id, $orig_ref) = ($_, $_);
- next unless $id =~ s#^refs/heads/(.+)-HEAD$#$1#;
- next unless -f "$git_dir/$id/info/url";
- my $new_ref = "refs/remotes/$id";
- if (::verify_ref("$new_ref^0")) {
- print STDERR "W: $orig_ref is probably an old ",
- "branch used by an ancient version of ",
- "git-svn.\n",
- "However, $new_ref also exists.\n",
- "We will not be able ",
- "to use this branch until this ",
- "ambiguity is resolved.\n";
- next;
- }
- print STDERR "Migrating from v0 layout...\n" if !$migrated;
- print STDERR "Renaming ref: $orig_ref => $new_ref\n";
- command_noisy('update-ref', $new_ref, $orig_ref);
- command_noisy('update-ref', '-d', $orig_ref, $orig_ref);
- $migrated++;
- }
- command_close_pipe($fh, $ctx);
- print STDERR "Done migrating from v0 layout...\n" if $migrated;
- $migrated;
-}
-
-sub migrate_from_v1 {
- my $git_dir = $ENV{GIT_DIR};
- my $migrated = 0;
- return $migrated unless -d $git_dir;
- my $svn_dir = "$git_dir/svn";
-
- # just in case somebody used 'svn' as their $id at some point...
- return $migrated if -d $svn_dir && ! -f "$svn_dir/info/url";
-
- print STDERR "Migrating from a git-svn v1 layout...\n";
- mkpath([$svn_dir]);
- print STDERR "Data from a previous version of git-svn exists, but\n\t",
- "$svn_dir\n\t(required for this version ",
- "($::VERSION) of git-svn) does not exist.\n";
- my ($fh, $ctx) = command_output_pipe(qw/rev-parse --symbolic --all/);
- while (<$fh>) {
- my $x = $_;
- next unless $x =~ s#^refs/remotes/##;
- chomp $x;
- next unless -f "$git_dir/$x/info/url";
- my $u = eval { ::file_to_s("$git_dir/$x/info/url") };
- next unless $u;
- my $dn = dirname("$git_dir/svn/$x");
- mkpath([$dn]) unless -d $dn;
- if ($x eq 'svn') { # they used 'svn' as GIT_SVN_ID:
- mkpath(["$git_dir/svn/svn"]);
- print STDERR " - $git_dir/$x/info => ",
- "$git_dir/svn/$x/info\n";
- rename "$git_dir/$x/info", "$git_dir/svn/$x/info" or
- croak "$!: $x";
- # don't worry too much about these, they probably
- # don't exist with repos this old (save for index,
- # and we can easily regenerate that)
- foreach my $f (qw/unhandled.log index .rev_db/) {
- rename "$git_dir/$x/$f", "$git_dir/svn/$x/$f";
- }
- } else {
- print STDERR " - $git_dir/$x => $git_dir/svn/$x\n";
- rename "$git_dir/$x", "$git_dir/svn/$x" or
- croak "$!: $x";
- }
- $migrated++;
- }
- command_close_pipe($fh, $ctx);
- print STDERR "Done migrating from a git-svn v1 layout\n";
- $migrated;
-}
-
-sub read_old_urls {
- my ($l_map, $pfx, $path) = @_;
- my @dir;
- foreach (<$path/*>) {
- if (-r "$_/info/url") {
- $pfx .= '/' if $pfx && $pfx !~ m!/$!;
- my $ref_id = $pfx . basename $_;
- my $url = ::file_to_s("$_/info/url");
- $l_map->{$ref_id} = $url;
- } elsif (-d $_) {
- push @dir, $_;
- }
- }
- foreach (@dir) {
- my $x = $_;
- $x =~ s!^\Q$ENV{GIT_DIR}\E/svn/!!o;
- read_old_urls($l_map, $x, $_);
- }
-}
-
-sub migrate_from_v2 {
- my @cfg = command(qw/config -l/);
- return if grep /^svn-remote\..+\.url=/, @cfg;
- my %l_map;
- read_old_urls(\%l_map, '', "$ENV{GIT_DIR}/svn");
- my $migrated = 0;
-
- foreach my $ref_id (sort keys %l_map) {
- eval { Git::SVN->init($l_map{$ref_id}, '', undef, $ref_id) };
- if ($@) {
- Git::SVN->init($l_map{$ref_id}, '', $ref_id, $ref_id);
- }
- $migrated++;
- }
- $migrated;
-}
-
-sub minimize_connections {
- my $r = Git::SVN::read_all_remotes();
- my $new_urls = {};
- my $root_repos = {};
- foreach my $repo_id (keys %$r) {
- my $url = $r->{$repo_id}->{url} or next;
- my $fetch = $r->{$repo_id}->{fetch} or next;
- my $ra = Git::SVN::Ra->new($url);
-
- # skip existing cases where we already connect to the root
- if (($ra->{url} eq $ra->{repos_root}) ||
- ($ra->{repos_root} eq $repo_id)) {
- $root_repos->{$ra->{url}} = $repo_id;
- next;
- }
-
- my $root_ra = Git::SVN::Ra->new($ra->{repos_root});
- my $root_path = $ra->{url};
- $root_path =~ s#^\Q$ra->{repos_root}\E(/|$)##;
- foreach my $path (keys %$fetch) {
- my $ref_id = $fetch->{$path};
- my $gs = Git::SVN->new($ref_id, $repo_id, $path);
-
- # make sure we can read when connecting to
- # a higher level of a repository
- my ($last_rev, undef) = $gs->last_rev_commit;
- if (!defined $last_rev) {
- $last_rev = eval {
- $root_ra->get_latest_revnum;
- };
- next if $@;
- }
- my $new = $root_path;
- $new .= length $path ? "/$path" : '';
- eval {
- $root_ra->get_log([$new], $last_rev, $last_rev,
- 0, 0, 1, sub { });
- };
- next if $@;
- $new_urls->{$ra->{repos_root}}->{$new} =
- { ref_id => $ref_id,
- old_repo_id => $repo_id,
- old_path => $path };
- }
- }
-
- my @emptied;
- foreach my $url (keys %$new_urls) {
- # see if we can re-use an existing [svn-remote "repo_id"]
- # instead of creating a(n ugly) new section:
- my $repo_id = $root_repos->{$url} || $url;
-
- my $fetch = $new_urls->{$url};
- foreach my $path (keys %$fetch) {
- my $x = $fetch->{$path};
- Git::SVN->init($url, $path, $repo_id, $x->{ref_id});
- my $pfx = "svn-remote.$x->{old_repo_id}";
-
- my $old_fetch = quotemeta("$x->{old_path}:".
- "$x->{ref_id}");
- command_noisy(qw/config --unset/,
- "$pfx.fetch", '^'. $old_fetch . '$');
- delete $r->{$x->{old_repo_id}}->
- {fetch}->{$x->{old_path}};
- if (!keys %{$r->{$x->{old_repo_id}}->{fetch}}) {
- command_noisy(qw/config --unset/,
- "$pfx.url");
- push @emptied, $x->{old_repo_id}
- }
- }
- }
- if (@emptied) {
- my $file = $ENV{GIT_CONFIG} || "$ENV{GIT_DIR}/config";
- print STDERR <<EOF;
-The following [svn-remote] sections in your config file ($file) are empty
-and can be safely removed:
-EOF
- print STDERR "[svn-remote \"$_\"]\n" foreach @emptied;
- }
-}
-
-sub migration_check {
- migrate_from_v0();
- migrate_from_v1();
- migrate_from_v2();
- minimize_connections() if $_minimize;
-}
-
-package Git::IndexInfo;
-use strict;
-use warnings;
-use Git qw/command_input_pipe command_close_pipe/;
-
-sub new {
- my ($class) = @_;
- my ($gui, $ctx) = command_input_pipe(qw/update-index -z --index-info/);
- bless { gui => $gui, ctx => $ctx, nr => 0}, $class;
-}
-
-sub remove {
- my ($self, $path) = @_;
- if (print { $self->{gui} } '0 ', 0 x 40, "\t", $path, "\0") {
- return ++$self->{nr};
- }
- undef;
-}
-
-sub update {
- my ($self, $mode, $hash, $path) = @_;
- if (print { $self->{gui} } $mode, ' ', $hash, "\t", $path, "\0") {
- return ++$self->{nr};
- }
- undef;
-}
-
-sub DESTROY {
- my ($self) = @_;
- command_close_pipe($self->{gui}, $self->{ctx});
-}
-
-package Git::SVN::GlobSpec;
-use strict;
-use warnings;
-
-sub new {
- my ($class, $glob, $pattern_ok) = @_;
- my $re = $glob;
- $re =~ s!/+$!!g; # no need for trailing slashes
- my (@left, @right, @patterns);
- my $state = "left";
- my $die_msg = "Only one set of wildcard directories " .
- "(e.g. '*' or '*/*/*') is supported: '$glob'\n";
- for my $part (split(m|/|, $glob)) {
- if ($part =~ /\*/ && $part ne "*") {
- die "Invalid pattern in '$glob': $part\n";
- } elsif ($pattern_ok && $part =~ /[{}]/ &&
- $part !~ /^\{[^{}]+\}/) {
- die "Invalid pattern in '$glob': $part\n";
- }
- if ($part eq "*") {
- die $die_msg if $state eq "right";
- $state = "pattern";
- push(@patterns, "[^/]*");
- } elsif ($pattern_ok && $part =~ /^\{(.*)\}$/) {
- die $die_msg if $state eq "right";
- $state = "pattern";
- my $p = quotemeta($1);
- $p =~ s/\\,/|/g;
- push(@patterns, "(?:$p)");
- } else {
- if ($state eq "left") {
- push(@left, $part);
- } else {
- push(@right, $part);
- $state = "right";
- }
- }
- }
- my $depth = @patterns;
- if ($depth == 0) {
- die "One '*' is needed in glob: '$glob'\n";
- }
- my $left = join('/', @left);
- my $right = join('/', @right);
- $re = join('/', @patterns);
- $re = join('\/',
- grep(length, quotemeta($left), "($re)", quotemeta($right)));
- my $left_re = qr/^\/\Q$left\E(\/|$)/;
- bless { left => $left, right => $right, left_regex => $left_re,
- regex => qr/$re/, glob => $glob, depth => $depth }, $class;
-}
-
-sub full_path {
- my ($self, $path) = @_;
- return (length $self->{left} ? "$self->{left}/" : '') .
- $path . (length $self->{right} ? "/$self->{right}" : '');
-}
-
__END__
Data structures:
diff --git a/git.c b/git.c
index d232de9..8788b32 100644
--- a/git.c
+++ b/git.c
@@ -256,8 +256,6 @@ static int handle_alias(int *argcp, const char ***argv)
return ret;
}
-const char git_version_string[] = GIT_VERSION;
-
#define RUN_SETUP (1<<0)
#define RUN_SETUP_GENTLY (1<<1)
#define USE_PAGER (1<<2)
@@ -353,6 +351,7 @@ static void handle_internal_command(int argc, const char **argv)
{ "commit-tree", cmd_commit_tree, RUN_SETUP },
{ "config", cmd_config, RUN_SETUP_GENTLY },
{ "count-objects", cmd_count_objects, RUN_SETUP },
+ { "credential", cmd_credential, RUN_SETUP_GENTLY },
{ "describe", cmd_describe, RUN_SETUP },
{ "diff", cmd_diff },
{ "diff-files", cmd_diff_files, RUN_SETUP | NEED_WORK_TREE },
diff --git a/gitk-git/gitk b/gitk-git/gitk
index 6f24f53..d93bd99 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -11533,6 +11533,11 @@ if {[catch {package require Tk 8.4} err]} {
exit 1
}
+# Unset GIT_TRACE var if set
+if { [info exists ::env(GIT_TRACE)] } {
+ unset ::env(GIT_TRACE)
+}
+
# defaults...
set wrcomcmd "git diff-tree --stdin -p --pretty"
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index a40ed0c..7f8c187 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4489,30 +4489,33 @@ sub git_print_log {
}
# print log
- my $signoff = 0;
- my $empty = 0;
+ my $skip_blank_line = 0;
foreach my $line (@$log) {
- if ($line =~ m/^ *(signed[ \-]off[ \-]by[ :]|acked[ \-]by[ :]|cc[ :])/i) {
- $signoff = 1;
- $empty = 0;
+ if ($line =~ m/^\s*([A-Z][-A-Za-z]*-[Bb]y|C[Cc]): /) {
if (! $opts{'-remove_signoff'}) {
print "<span class=\"signoff\">" . esc_html($line) . "</span><br/>\n";
- next;
- } else {
- # remove signoff lines
- next;
+ $skip_blank_line = 1;
}
- } else {
- $signoff = 0;
+ next;
+ }
+
+ if ($line =~ m,\s*([a-z]*link): (https?://\S+),i) {
+ if (! $opts{'-remove_signoff'}) {
+ print "<span class=\"signoff\">" . esc_html($1) . ": " .
+ "<a href=\"" . esc_html($2) . "\">" . esc_html($2) . "</a>" .
+ "</span><br/>\n";
+ $skip_blank_line = 1;
+ }
+ next;
}
# print only one empty line
# do not print empty line after signoff
if ($line eq "") {
- next if ($empty || $signoff);
- $empty = 1;
+ next if ($skip_blank_line);
+ $skip_blank_line = 1;
} else {
- $empty = 0;
+ $skip_blank_line = 0;
}
print format_log_line_html($line) . "<br/>\n";
@@ -4520,7 +4523,7 @@ sub git_print_log {
if ($opts{'-final_empty_line'}) {
# end with single empty line
- print "<br/>\n" unless $empty;
+ print "<br/>\n" unless $skip_blank_line;
}
}
diff --git a/graph.c b/graph.c
index 7e0a099..e864fe2 100644
--- a/graph.c
+++ b/graph.c
@@ -8,6 +8,34 @@
/* Internal API */
/*
+ * Output the next line for a graph.
+ * This formats the next graph line into the specified strbuf. It is not
+ * terminated with a newline.
+ *
+ * Returns 1 if the line includes the current commit, and 0 otherwise.
+ * graph_next_line() will return 1 exactly once for each time
+ * graph_update() is called.
+ */
+static int graph_next_line(struct git_graph *graph, struct strbuf *sb);
+
+/*
+ * Set up a custom scheme for column colors.
+ *
+ * The default column color scheme inserts ANSI color escapes to colorize
+ * the graph. The various color escapes are stored in an array of strings
+ * where each entry corresponds to a color, except for the last entry,
+ * which denotes the escape for resetting the color back to the default.
+ * When generating the graph, strings from this array are inserted before
+ * and after the various column characters.
+ *
+ * This function allows you to enable a custom array of color escapes.
+ * The 'colors_max' argument is the index of the last "reset" entry.
+ *
+ * This functions must be called BEFORE graph_init() is called.
+ */
+static void graph_set_column_colors(const char **colors, unsigned short colors_max);
+
+/*
* Output a padding line in the graph.
* This is similar to graph_next_line(). However, it is guaranteed to
* never print the current commit line. Instead, if the commit line is
@@ -62,7 +90,7 @@ enum graph_state {
static const char **column_colors;
static unsigned short column_colors_max;
-void graph_set_column_colors(const char **colors, unsigned short colors_max)
+static void graph_set_column_colors(const char **colors, unsigned short colors_max)
{
column_colors = colors;
column_colors_max = colors_max;
@@ -1116,7 +1144,7 @@ static void graph_output_collapsing_line(struct git_graph *graph, struct strbuf
graph_update_state(graph, GRAPH_PADDING);
}
-int graph_next_line(struct git_graph *graph, struct strbuf *sb)
+static int graph_next_line(struct git_graph *graph, struct strbuf *sb)
{
switch (graph->state) {
case GRAPH_PADDING:
diff --git a/graph.h b/graph.h
index aff960c..19b0f66 100644
--- a/graph.h
+++ b/graph.h
@@ -4,22 +4,6 @@
/* A graph is a pointer to this opaque structure */
struct git_graph;
-/*
- * Set up a custom scheme for column colors.
- *
- * The default column color scheme inserts ANSI color escapes to colorize
- * the graph. The various color escapes are stored in an array of strings
- * where each entry corresponds to a color, except for the last entry,
- * which denotes the escape for resetting the color back to the default.
- * When generating the graph, strings from this array are inserted before
- * and after the various column characters.
- *
- * This function allows you to enable a custom array of color escapes.
- * The 'colors_max' argument is the index of the last "reset" entry.
- *
- * This functions must be called BEFORE graph_init() is called.
- */
-void graph_set_column_colors(const char **colors, unsigned short colors_max);
/*
* Create a new struct git_graph.
@@ -49,17 +33,6 @@ void graph_update(struct git_graph *graph, struct commit *commit);
*/
int graph_is_commit_finished(struct git_graph const *graph);
-/*
- * Output the next line for a graph.
- * This formats the next graph line into the specified strbuf. It is not
- * terminated with a newline.
- *
- * Returns 1 if the line includes the current commit, and 0 otherwise.
- * graph_next_line() will return 1 exactly once for each time
- * graph_update() is called.
- */
-int graph_next_line(struct git_graph *graph, struct strbuf *sb);
-
/*
* graph_show_*: helper functions for printing to stdout
diff --git a/grep.c b/grep.c
index 04e3ec6..edc7776 100644
--- a/grep.c
+++ b/grep.c
@@ -3,6 +3,10 @@
#include "userdiff.h"
#include "xdiff-interface.h"
+static int grep_source_load(struct grep_source *gs);
+static int grep_source_is_binary(struct grep_source *gs);
+
+
static struct grep_pat *create_grep_pat(const char *pat, size_t patlen,
const char *origin, int no,
enum grep_pat_token t,
@@ -60,6 +64,8 @@ void append_header_grep_pattern(struct grep_opt *opt,
{
struct grep_pat *p = create_grep_pat(pat, strlen(pat), "header", 0,
GREP_PATTERN_HEAD, field);
+ if (field == GREP_HEADER_REFLOG)
+ opt->use_reflog_filter = 1;
do_append_grep_pat(&opt->header_tail, p);
}
@@ -332,6 +338,87 @@ static struct grep_expr *compile_pattern_expr(struct grep_pat **list)
return compile_pattern_or(list);
}
+static void indent(int in)
+{
+ while (in-- > 0)
+ fputc(' ', stderr);
+}
+
+static void dump_grep_pat(struct grep_pat *p)
+{
+ switch (p->token) {
+ case GREP_AND: fprintf(stderr, "*and*"); break;
+ case GREP_OPEN_PAREN: fprintf(stderr, "*(*"); break;
+ case GREP_CLOSE_PAREN: fprintf(stderr, "*)*"); break;
+ case GREP_NOT: fprintf(stderr, "*not*"); break;
+ case GREP_OR: fprintf(stderr, "*or*"); break;
+
+ case GREP_PATTERN: fprintf(stderr, "pattern"); break;
+ case GREP_PATTERN_HEAD: fprintf(stderr, "pattern_head"); break;
+ case GREP_PATTERN_BODY: fprintf(stderr, "pattern_body"); break;
+ }
+
+ switch (p->token) {
+ default: break;
+ case GREP_PATTERN_HEAD:
+ fprintf(stderr, "<head %d>", p->field); break;
+ case GREP_PATTERN_BODY:
+ fprintf(stderr, "<body>"); break;
+ }
+ switch (p->token) {
+ default: break;
+ case GREP_PATTERN_HEAD:
+ case GREP_PATTERN_BODY:
+ case GREP_PATTERN:
+ fprintf(stderr, "%.*s", (int)p->patternlen, p->pattern);
+ break;
+ }
+ fputc('\n', stderr);
+}
+
+static void dump_grep_expression_1(struct grep_expr *x, int in)
+{
+ indent(in);
+ switch (x->node) {
+ case GREP_NODE_TRUE:
+ fprintf(stderr, "true\n");
+ break;
+ case GREP_NODE_ATOM:
+ dump_grep_pat(x->u.atom);
+ break;
+ case GREP_NODE_NOT:
+ fprintf(stderr, "(not\n");
+ dump_grep_expression_1(x->u.unary, in+1);
+ indent(in);
+ fprintf(stderr, ")\n");
+ break;
+ case GREP_NODE_AND:
+ fprintf(stderr, "(and\n");
+ dump_grep_expression_1(x->u.binary.left, in+1);
+ dump_grep_expression_1(x->u.binary.right, in+1);
+ indent(in);
+ fprintf(stderr, ")\n");
+ break;
+ case GREP_NODE_OR:
+ fprintf(stderr, "(or\n");
+ dump_grep_expression_1(x->u.binary.left, in+1);
+ dump_grep_expression_1(x->u.binary.right, in+1);
+ indent(in);
+ fprintf(stderr, ")\n");
+ break;
+ }
+}
+
+static void dump_grep_expression(struct grep_opt *opt)
+{
+ struct grep_expr *x = opt->pattern_expression;
+
+ if (opt->all_match)
+ fprintf(stderr, "[all-match]\n");
+ dump_grep_expression_1(x, 0);
+ fflush(NULL);
+}
+
static struct grep_expr *grep_true_expr(void)
{
struct grep_expr *z = xcalloc(1, sizeof(*z));
@@ -395,7 +482,23 @@ static struct grep_expr *prep_header_patterns(struct grep_opt *opt)
return header_expr;
}
-void compile_grep_patterns(struct grep_opt *opt)
+static struct grep_expr *grep_splice_or(struct grep_expr *x, struct grep_expr *y)
+{
+ struct grep_expr *z = x;
+
+ while (x) {
+ assert(x->node == GREP_NODE_OR);
+ if (x->u.binary.right &&
+ x->u.binary.right->node == GREP_NODE_TRUE) {
+ x->u.binary.right = y;
+ break;
+ }
+ x = x->u.binary.right;
+ }
+ return z;
+}
+
+static void compile_grep_patterns_real(struct grep_opt *opt)
{
struct grep_pat *p;
struct grep_expr *header_expr = prep_header_patterns(opt);
@@ -415,7 +518,7 @@ void compile_grep_patterns(struct grep_opt *opt)
if (opt->all_match || header_expr)
opt->extended = 1;
- else if (!opt->extended)
+ else if (!opt->extended && !opt->debug)
return;
p = opt->pattern_list;
@@ -429,12 +532,22 @@ void compile_grep_patterns(struct grep_opt *opt)
if (!opt->pattern_expression)
opt->pattern_expression = header_expr;
+ else if (opt->all_match)
+ opt->pattern_expression = grep_splice_or(header_expr,
+ opt->pattern_expression);
else
opt->pattern_expression = grep_or_expr(opt->pattern_expression,
header_expr);
opt->all_match = 1;
}
+void compile_grep_patterns(struct grep_opt *opt)
+{
+ compile_grep_patterns_real(opt);
+ if (opt->debug)
+ dump_grep_expression(opt);
+}
+
static void free_pattern_expr(struct grep_expr *x)
{
switch (x->node) {
@@ -586,6 +699,7 @@ static struct {
} header_field[] = {
{ "author ", 7 },
{ "committer ", 10 },
+ { "reflog ", 7 },
};
static int match_one_pattern(struct grep_pat *p, char *bol, char *eol,
@@ -609,7 +723,14 @@ static int match_one_pattern(struct grep_pat *p, char *bol, char *eol,
if (strncmp(bol, field, len))
return 0;
bol += len;
- saved_ch = strip_timestamp(bol, &eol);
+ switch (p->field) {
+ case GREP_HEADER_AUTHOR:
+ case GREP_HEADER_COMMITTER:
+ saved_ch = strip_timestamp(bol, &eol);
+ break;
+ default:
+ break;
+ }
}
again:
@@ -1358,7 +1479,7 @@ static int grep_source_load_file(struct grep_source *gs)
return 0;
}
-int grep_source_load(struct grep_source *gs)
+static int grep_source_load(struct grep_source *gs)
{
if (gs->buf)
return 0;
@@ -1386,7 +1507,7 @@ void grep_source_load_driver(struct grep_source *gs)
grep_attr_unlock();
}
-int grep_source_is_binary(struct grep_source *gs)
+static int grep_source_is_binary(struct grep_source *gs)
{
grep_source_load_driver(gs);
if (gs->driver->binary != -1)
diff --git a/grep.h b/grep.h
index ed7de6b..c256ac6 100644
--- a/grep.h
+++ b/grep.h
@@ -29,9 +29,12 @@ enum grep_context {
enum grep_header_field {
GREP_HEADER_AUTHOR = 0,
- GREP_HEADER_COMMITTER
+ GREP_HEADER_COMMITTER,
+ GREP_HEADER_REFLOG,
+
+ /* Must be at the end of the enum */
+ GREP_HEADER_FIELD_MAX
};
-#define GREP_HEADER_FIELD_MAX (GREP_HEADER_COMMITTER + 1)
struct grep_pat {
struct grep_pat *next;
@@ -58,6 +61,14 @@ enum grep_expr_node {
GREP_NODE_OR
};
+enum grep_pattern_type {
+ GREP_PATTERN_TYPE_UNSPECIFIED = 0,
+ GREP_PATTERN_TYPE_BRE,
+ GREP_PATTERN_TYPE_ERE,
+ GREP_PATTERN_TYPE_FIXED,
+ GREP_PATTERN_TYPE_PCRE
+};
+
struct grep_expr {
enum grep_expr_node node;
unsigned hit;
@@ -90,11 +101,13 @@ struct grep_opt {
int word_regexp;
int fixed;
int all_match;
+ int debug;
#define GREP_BINARY_DEFAULT 0
#define GREP_BINARY_NOMATCH 1
#define GREP_BINARY_TEXT 2
int binary;
int extended;
+ int use_reflog_filter;
int pcre;
int relative;
int pathname;
@@ -103,6 +116,8 @@ struct grep_opt {
int max_depth;
int funcname;
int funcbody;
+ int extended_regexp_option;
+ int pattern_type_option;
char color_context[COLOR_MAXLEN];
char color_filename[COLOR_MAXLEN];
char color_function[COLOR_MAXLEN];
@@ -148,11 +163,10 @@ struct grep_source {
void grep_source_init(struct grep_source *gs, enum grep_source_type type,
const char *name, const void *identifier);
-int grep_source_load(struct grep_source *gs);
void grep_source_clear_data(struct grep_source *gs);
void grep_source_clear(struct grep_source *gs);
void grep_source_load_driver(struct grep_source *gs);
-int grep_source_is_binary(struct grep_source *gs);
+
int grep_source(struct grep_opt *opt, struct grep_source *gs);
diff --git a/help.c b/help.c
index 6012c07..2a42ec6 100644
--- a/help.c
+++ b/help.c
@@ -6,6 +6,7 @@
#include "common-cmds.h"
#include "string-list.h"
#include "column.h"
+#include "version.h"
void add_cmdname(struct cmdnames *cmds, const char *name, int len)
{
@@ -43,9 +44,12 @@ static void uniq(struct cmdnames *cmds)
if (!cmds->cnt)
return;
- for (i = j = 1; i < cmds->cnt; i++)
- if (strcmp(cmds->names[i]->name, cmds->names[i-1]->name))
+ for (i = j = 1; i < cmds->cnt; i++) {
+ if (!strcmp(cmds->names[i]->name, cmds->names[j-1]->name))
+ free(cmds->names[i]);
+ else
cmds->names[j++] = cmds->names[i];
+ }
cmds->cnt = j;
}
@@ -60,9 +64,10 @@ void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes)
cmp = strcmp(cmds->names[ci]->name, excludes->names[ei]->name);
if (cmp < 0)
cmds->names[cj++] = cmds->names[ci++];
- else if (cmp == 0)
- ci++, ei++;
- else if (cmp > 0)
+ else if (cmp == 0) {
+ ei++;
+ free(cmds->names[ci++]);
+ } else if (cmp > 0)
ei++;
}
diff --git a/http-push.c b/http-push.c
index a832ca7..8701c12 100644
--- a/http-push.c
+++ b/http-push.c
@@ -1610,9 +1610,8 @@ static int verify_merge_base(unsigned char *head_sha1, struct ref *remote)
{
struct commit *head = lookup_commit_or_die(head_sha1, "HEAD");
struct commit *branch = lookup_commit_or_die(remote->old_sha1, remote->name);
- struct commit_list *merge_bases = get_merge_bases(head, branch, 1);
- return (merge_bases && !merge_bases->next && merge_bases->item == branch);
+ return in_merge_bases(branch, head);
}
static int delete_remote_branch(const char *pattern, int force)
diff --git a/http-walker.c b/http-walker.c
index 51a906e..1516c5e 100644
--- a/http-walker.c
+++ b/http-walker.c
@@ -396,7 +396,7 @@ static int fetch_indices(struct walker *walker, struct alt_base *repo)
return ret;
}
-static int fetch_pack(struct walker *walker, struct alt_base *repo, unsigned char *sha1)
+static int http_fetch_pack(struct walker *walker, struct alt_base *repo, unsigned char *sha1)
{
struct packed_git *target;
int ret;
@@ -524,7 +524,7 @@ static int fetch(struct walker *walker, unsigned char *sha1)
if (!fetch_object(walker, altbase, sha1))
return 0;
while (altbase) {
- if (!fetch_pack(walker, altbase, sha1))
+ if (!http_fetch_pack(walker, altbase, sha1))
return 0;
fetch_alternates(walker, data->alt->base);
altbase = altbase->next;
diff --git a/http.c b/http.c
index 0a27b14..345c171 100644
--- a/http.c
+++ b/http.c
@@ -4,6 +4,7 @@
#include "run-command.h"
#include "url.h"
#include "credential.h"
+#include "version.h"
int active_requests;
int http_is_verbose;
@@ -299,7 +300,7 @@ static CURL *get_curl_handle(void)
curl_easy_setopt(result, CURLOPT_VERBOSE, 1);
curl_easy_setopt(result, CURLOPT_USERAGENT,
- user_agent ? user_agent : GIT_HTTP_USER_AGENT);
+ user_agent ? user_agent : git_user_agent());
if (curl_ftp_no_epsv)
curl_easy_setopt(result, CURLOPT_FTP_USE_EPSV, 0);
@@ -763,10 +764,12 @@ int handle_curl_result(struct active_request_slot *slot)
return HTTP_REAUTH;
}
} else {
+#if LIBCURL_VERSION_NUM >= 0x070c00
if (!curl_errorstr[0])
strlcpy(curl_errorstr,
curl_easy_strerror(results->curl_result),
sizeof(curl_errorstr));
+#endif
return HTTP_ERROR;
}
}
@@ -815,6 +818,7 @@ static int http_request(const char *url, void *result, int target, int options)
curl_easy_setopt(slot->curl, CURLOPT_URL, url);
curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, headers);
+ curl_easy_setopt(slot->curl, CURLOPT_ENCODING, "gzip");
if (start_active_slot(slot)) {
run_active_slot(slot);
diff --git a/ident.c b/ident.c
index 484e0a9..a4bf206 100644
--- a/ident.c
+++ b/ident.c
@@ -93,7 +93,7 @@ static void copy_email(const struct passwd *pw, struct strbuf *email)
add_domainname(email);
}
-const char *ident_default_name(void)
+static const char *ident_default_name(void)
{
if (!git_default_name.len) {
copy_gecos(xgetpwuid_self(), &git_default_name);
@@ -117,7 +117,7 @@ const char *ident_default_email(void)
return git_default_email.buf;
}
-const char *ident_default_date(void)
+static const char *ident_default_date(void)
{
if (!git_default_date[0])
datestamp(git_default_date, sizeof(git_default_date));
diff --git a/ll-merge.c b/ll-merge.c
index f3f7692..acea33b 100644
--- a/ll-merge.c
+++ b/ll-merge.c
@@ -35,7 +35,7 @@ struct ll_merge_driver {
*/
static int ll_binary_merge(const struct ll_merge_driver *drv_unused,
mmbuffer_t *result,
- const char *path_unused,
+ const char *path,
mmfile_t *orig, const char *orig_name,
mmfile_t *src1, const char *name1,
mmfile_t *src2, const char *name2,
@@ -46,16 +46,34 @@ static int ll_binary_merge(const struct ll_merge_driver *drv_unused,
assert(opts);
/*
- * The tentative merge result is "ours" for the final round,
- * or common ancestor for an internal merge. Still return
- * "conflicted merge" status.
+ * The tentative merge result is the or common ancestor for an internal merge.
*/
- stolen = opts->virtual_ancestor ? orig : src1;
+ if (opts->virtual_ancestor) {
+ stolen = orig;
+ } else {
+ switch (opts->variant) {
+ default:
+ warning("Cannot merge binary files: %s (%s vs. %s)",
+ path, name1, name2);
+ /* fallthru */
+ case XDL_MERGE_FAVOR_OURS:
+ stolen = src1;
+ break;
+ case XDL_MERGE_FAVOR_THEIRS:
+ stolen = src2;
+ break;
+ }
+ }
result->ptr = stolen->ptr;
result->size = stolen->size;
stolen->ptr = NULL;
- return 1;
+
+ /*
+ * With -Xtheirs or -Xours, we have cleanly merged;
+ * otherwise we got a conflict.
+ */
+ return (opts->variant ? 0 : 1);
}
static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,
@@ -73,8 +91,6 @@ static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,
if (buffer_is_binary(orig->ptr, orig->size) ||
buffer_is_binary(src1->ptr, src1->size) ||
buffer_is_binary(src2->ptr, src2->size)) {
- warning("Cannot merge binary files: %s (%s vs. %s)",
- path, name1, name2);
return ll_binary_merge(drv_unused, result,
path,
orig, orig_name,
diff --git a/merge-recursive.c b/merge-recursive.c
index e02da35..d882060 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -187,7 +187,7 @@ static void output_commit_title(struct merge_options *o, struct commit *commit)
else {
printf("%s ", find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV));
if (parse_commit(commit) != 0)
- printf("(bad commit)\n");
+ printf(_("(bad commit)\n"));
else {
const char *title;
int len = find_commit_subject(commit->buffer, &title);
@@ -203,7 +203,7 @@ static int add_cacheinfo(unsigned int mode, const unsigned char *sha1,
struct cache_entry *ce;
ce = make_cache_entry(mode, sha1 ? sha1 : null_sha1, path, stage, refresh);
if (!ce)
- return error("addinfo_cache failed for path '%s'", path);
+ return error(_("addinfo_cache failed for path '%s'"), path);
return add_cache_entry(ce, options);
}
@@ -265,7 +265,7 @@ struct tree *write_tree_from_memory(struct merge_options *o)
if (!cache_tree_fully_valid(active_cache_tree) &&
cache_tree_update(active_cache_tree,
active_cache, active_nr, 0) < 0)
- die("error building trees");
+ die(_("error building trees"));
result = lookup_tree(active_cache_tree->sha1);
@@ -669,7 +669,7 @@ static int would_lose_untracked(const char *path)
static int make_room_for_path(struct merge_options *o, const char *path)
{
int status, i;
- const char *msg = "failed to create path '%s'%s";
+ const char *msg = _("failed to create path '%s'%s");
/* Unlink any D/F conflict files that are in the way */
for (i = 0; i < o->df_conflict_file_set.nr; i++) {
@@ -680,7 +680,7 @@ static int make_room_for_path(struct merge_options *o, const char *path)
path[df_pathlen] == '/' &&
strncmp(path, df_path, df_pathlen) == 0) {
output(o, 3,
- "Removing %s to make room for subdirectory\n",
+ _("Removing %s to make room for subdirectory\n"),
df_path);
unlink(df_path);
unsorted_string_list_delete_item(&o->df_conflict_file_set,
@@ -694,7 +694,7 @@ static int make_room_for_path(struct merge_options *o, const char *path)
if (status) {
if (status == -3) {
/* something else exists */
- error(msg, path, ": perhaps a D/F conflict?");
+ error(msg, path, _(": perhaps a D/F conflict?"));
return -1;
}
die(msg, path, "");
@@ -705,7 +705,7 @@ static int make_room_for_path(struct merge_options *o, const char *path)
* tracking it.
*/
if (would_lose_untracked(path))
- return error("refusing to lose untracked file at '%s'",
+ return error(_("refusing to lose untracked file at '%s'"),
path);
/* Successful unlink is good.. */
@@ -715,7 +715,7 @@ static int make_room_for_path(struct merge_options *o, const char *path)
if (errno == ENOENT)
return 0;
/* .. but not some other error (who really cares what?) */
- return error(msg, path, ": perhaps a D/F conflict?");
+ return error(msg, path, _(": perhaps a D/F conflict?"));
}
static void update_file_flags(struct merge_options *o,
@@ -745,9 +745,9 @@ static void update_file_flags(struct merge_options *o,
buf = read_sha1_file(sha, &type, &size);
if (!buf)
- die("cannot read object %s '%s'", sha1_to_hex(sha), path);
+ die(_("cannot read object %s '%s'"), sha1_to_hex(sha), path);
if (type != OBJ_BLOB)
- die("blob expected for %s '%s'", sha1_to_hex(sha), path);
+ die(_("blob expected for %s '%s'"), sha1_to_hex(sha), path);
if (S_ISREG(mode)) {
struct strbuf strbuf = STRBUF_INIT;
if (convert_to_working_tree(path, buf, size, &strbuf)) {
@@ -770,7 +770,7 @@ static void update_file_flags(struct merge_options *o,
mode = 0666;
fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, mode);
if (fd < 0)
- die_errno("failed to open '%s'", path);
+ die_errno(_("failed to open '%s'"), path);
write_in_full(fd, buf, size);
close(fd);
} else if (S_ISLNK(mode)) {
@@ -778,10 +778,10 @@ static void update_file_flags(struct merge_options *o,
safe_create_leading_directories_const(path);
unlink(path);
if (symlink(lnk, path))
- die_errno("failed to symlink '%s'", path);
+ die_errno(_("failed to symlink '%s'"), path);
free(lnk);
} else
- die("do not know what to do with %06o %s '%s'",
+ die(_("do not know what to do with %06o %s '%s'"),
mode, sha1_to_hex(sha), path);
free(buf);
}
@@ -844,14 +844,14 @@ static int merge_3way(struct merge_options *o,
if (strcmp(a->path, b->path) ||
(o->ancestor != NULL && strcmp(a->path, one->path) != 0)) {
base_name = o->ancestor == NULL ? NULL :
- xstrdup(mkpath("%s:%s", o->ancestor, one->path));
- name1 = xstrdup(mkpath("%s:%s", branch1, a->path));
- name2 = xstrdup(mkpath("%s:%s", branch2, b->path));
+ mkpathdup("%s:%s", o->ancestor, one->path);
+ name1 = mkpathdup("%s:%s", branch1, a->path);
+ name2 = mkpathdup("%s:%s", branch2, b->path);
} else {
base_name = o->ancestor == NULL ? NULL :
- xstrdup(mkpath("%s", o->ancestor));
- name1 = xstrdup(mkpath("%s", branch1));
- name2 = xstrdup(mkpath("%s", branch2));
+ mkpathdup("%s", o->ancestor);
+ name1 = mkpathdup("%s", branch1);
+ name2 = mkpathdup("%s", branch2);
}
read_mmblob(&orig, one->sha1);
@@ -861,6 +861,7 @@ static int merge_3way(struct merge_options *o,
merge_status = ll_merge(result_buf, a->path, &orig, base_name,
&src1, name1, &src2, name2, &ll_opts);
+ free(base_name);
free(name1);
free(name2);
free(orig.ptr);
@@ -918,11 +919,11 @@ static struct merge_file_info merge_file_1(struct merge_options *o,
branch1, branch2);
if ((merge_status < 0) || !result_buf.ptr)
- die("Failed to execute internal merge");
+ die(_("Failed to execute internal merge"));
if (write_sha1_file(result_buf.ptr, result_buf.size,
blob_type, result.sha))
- die("Unable to add %s to database",
+ die(_("Unable to add %s to database"),
a->path);
free(result_buf.ptr);
@@ -938,7 +939,7 @@ static struct merge_file_info merge_file_1(struct merge_options *o,
if (!sha_eq(a->sha1, b->sha1))
result.clean = 0;
} else {
- die("unsupported object type in the tree");
+ die(_("unsupported object type in the tree"));
}
}
@@ -1016,22 +1017,32 @@ static void handle_change_delete(struct merge_options *o,
remove_file_from_cache(path);
update_file(o, 0, o_sha, o_mode, renamed ? renamed : path);
} else if (!a_sha) {
- output(o, 1, "CONFLICT (%s/delete): %s deleted in %s "
- "and %s in %s. Version %s of %s left in tree%s%s.",
- change, path, o->branch1,
- change_past, o->branch2, o->branch2, path,
- NULL == renamed ? "" : " at ",
- NULL == renamed ? "" : renamed);
- update_file(o, 0, b_sha, b_mode, renamed ? renamed : path);
+ if (!renamed) {
+ output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s "
+ "and %s in %s. Version %s of %s left in tree."),
+ change, path, o->branch1, change_past,
+ o->branch2, o->branch2, path);
+ update_file(o, 0, b_sha, b_mode, path);
+ } else {
+ output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s "
+ "and %s in %s. Version %s of %s left in tree at %s."),
+ change, path, o->branch1, change_past,
+ o->branch2, o->branch2, path, renamed);
+ update_file(o, 0, b_sha, b_mode, renamed);
+ }
} else {
- output(o, 1, "CONFLICT (%s/delete): %s deleted in %s "
- "and %s in %s. Version %s of %s left in tree%s%s.",
- change, path, o->branch2,
- change_past, o->branch1, o->branch1, path,
- NULL == renamed ? "" : " at ",
- NULL == renamed ? "" : renamed);
- if (renamed)
+ if (!renamed) {
+ output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s "
+ "and %s in %s. Version %s of %s left in tree."),
+ change, path, o->branch2, change_past,
+ o->branch1, o->branch1, path);
+ } else {
+ output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s "
+ "and %s in %s. Version %s of %s left in tree at %s."),
+ change, path, o->branch2, change_past,
+ o->branch1, o->branch1, path, renamed);
update_file(o, 0, a_sha, a_mode, renamed);
+ }
/*
* No need to call update_file() on path when !renamed, since
* that would needlessly touch path. We could call
@@ -1067,7 +1078,7 @@ static void conflict_rename_delete(struct merge_options *o,
orig->sha1, orig->mode,
a_sha, a_mode,
b_sha, b_mode,
- "rename", "renamed");
+ _("rename"), _("renamed"));
if (o->call_depth) {
remove_file_from_cache(dest->path);
@@ -1123,7 +1134,7 @@ static void handle_file(struct merge_options *o,
} else {
if (dir_in_way(rename->path, !o->call_depth)) {
dst_name = unique_path(o, rename->path, cur_branch);
- output(o, 1, "%s is a directory in %s adding as %s instead",
+ output(o, 1, _("%s is a directory in %s adding as %s instead"),
rename->path, other_branch, dst_name);
}
}
@@ -1145,12 +1156,12 @@ static void conflict_rename_rename_1to2(struct merge_options *o,
struct diff_filespec *a = ci->pair1->two;
struct diff_filespec *b = ci->pair2->two;
- output(o, 1, "CONFLICT (rename/rename): "
+ output(o, 1, _("CONFLICT (rename/rename): "
"Rename \"%s\"->\"%s\" in branch \"%s\" "
- "rename \"%s\"->\"%s\" in \"%s\"%s",
+ "rename \"%s\"->\"%s\" in \"%s\"%s"),
one->path, a->path, ci->branch1,
one->path, b->path, ci->branch2,
- o->call_depth ? " (left unresolved)" : "");
+ o->call_depth ? _(" (left unresolved)") : "");
if (o->call_depth) {
struct merge_file_info mfi;
struct diff_filespec other;
@@ -1204,9 +1215,9 @@ static void conflict_rename_rename_2to1(struct merge_options *o,
struct merge_file_info mfi_c1;
struct merge_file_info mfi_c2;
- output(o, 1, "CONFLICT (rename/rename): "
+ output(o, 1, _("CONFLICT (rename/rename): "
"Rename %s->%s in %s. "
- "Rename %s->%s in %s",
+ "Rename %s->%s in %s"),
a->path, c1->path, ci->branch1,
b->path, c2->path, ci->branch2);
@@ -1234,7 +1245,7 @@ static void conflict_rename_rename_2to1(struct merge_options *o,
} else {
char *new_path1 = unique_path(o, path, ci->branch1);
char *new_path2 = unique_path(o, path, ci->branch2);
- output(o, 1, "Renaming %s to %s and %s to %s instead",
+ output(o, 1, _("Renaming %s to %s and %s to %s instead"),
a->path, new_path1, b->path, new_path2);
remove_file(o, 0, path, 0);
update_file(o, 0, mfi_c1.sha, mfi_c1.mode, new_path1);
@@ -1433,8 +1444,8 @@ static int process_renames(struct merge_options *o,
} else if (!sha_eq(dst_other.sha1, null_sha1)) {
clean_merge = 0;
try_merge = 1;
- output(o, 1, "CONFLICT (rename/add): Rename %s->%s in %s. "
- "%s added in %s",
+ output(o, 1, _("CONFLICT (rename/add): Rename %s->%s in %s. "
+ "%s added in %s"),
ren1_src, ren1_dst, branch1,
ren1_dst, branch2);
if (o->call_depth) {
@@ -1443,12 +1454,12 @@ static int process_renames(struct merge_options *o,
ren1->pair->two->sha1, ren1->pair->two->mode,
dst_other.sha1, dst_other.mode,
branch1, branch2);
- output(o, 1, "Adding merged %s", ren1_dst);
+ output(o, 1, _("Adding merged %s"), ren1_dst);
update_file(o, 0, mfi.sha, mfi.mode, ren1_dst);
try_merge = 0;
} else {
char *new_path = unique_path(o, ren1_dst, branch2);
- output(o, 1, "Adding as %s instead", new_path);
+ output(o, 1, _("Adding as %s instead"), new_path);
update_file(o, 0, dst_other.sha1, dst_other.mode, new_path);
free(new_path);
}
@@ -1499,10 +1510,10 @@ static int read_sha1_strbuf(const unsigned char *sha1, struct strbuf *dst)
unsigned long size;
buf = read_sha1_file(sha1, &type, &size);
if (!buf)
- return error("cannot read object %s", sha1_to_hex(sha1));
+ return error(_("cannot read object %s"), sha1_to_hex(sha1));
if (type != OBJ_BLOB) {
free(buf);
- return error("object %s is not a blob", sha1_to_hex(sha1));
+ return error(_("object %s is not a blob"), sha1_to_hex(sha1));
}
strbuf_attach(dst, buf, size, size + 1);
return 0;
@@ -1550,7 +1561,7 @@ static void handle_modify_delete(struct merge_options *o,
o_sha, o_mode,
a_sha, a_mode,
b_sha, b_mode,
- "modify", "modified");
+ _("modify"), _("modified"));
}
static int merge_content(struct merge_options *o,
@@ -1560,14 +1571,14 @@ static int merge_content(struct merge_options *o,
unsigned char *b_sha, int b_mode,
struct rename_conflict_info *rename_conflict_info)
{
- const char *reason = "content";
+ const char *reason = _("content");
const char *path1 = NULL, *path2 = NULL;
struct merge_file_info mfi;
struct diff_filespec one, a, b;
unsigned df_conflict_remains = 0;
if (!o_sha) {
- reason = "add/add";
+ reason = _("add/add");
o_sha = (unsigned char *)null_sha1;
}
one.path = a.path = b.path = (char *)path;
@@ -1601,7 +1612,7 @@ static int merge_content(struct merge_options *o,
if (mfi.clean && !df_conflict_remains &&
sha_eq(mfi.sha, a_sha) && mfi.mode == a_mode) {
int path_renamed_outside_HEAD;
- output(o, 3, "Skipped %s (merged same as existing)", path);
+ output(o, 3, _("Skipped %s (merged same as existing)"), path);
/*
* The content merge resulted in the same file contents we
* already had. We can return early if those file contents
@@ -1615,12 +1626,12 @@ static int merge_content(struct merge_options *o,
return mfi.clean;
}
} else
- output(o, 2, "Auto-merging %s", path);
+ output(o, 2, _("Auto-merging %s"), path);
if (!mfi.clean) {
if (S_ISGITLINK(mfi.mode))
- reason = "submodule";
- output(o, 1, "CONFLICT (%s): Merge conflict in %s",
+ reason = _("submodule");
+ output(o, 1, _("CONFLICT (%s): Merge conflict in %s"),
reason, path);
if (rename_conflict_info && !df_conflict_remains)
update_stages(path, &one, &a, &b);
@@ -1646,7 +1657,7 @@ static int merge_content(struct merge_options *o,
}
new_path = unique_path(o, path, rename_conflict_info->branch1);
- output(o, 1, "Adding as %s instead", new_path);
+ output(o, 1, _("Adding as %s instead"), new_path);
update_file(o, 0, mfi.sha, mfi.mode, new_path);
free(new_path);
mfi.clean = 0;
@@ -1710,7 +1721,7 @@ static int process_entry(struct merge_options *o,
/* Deleted in both or deleted in one and
* unchanged in the other */
if (a_sha)
- output(o, 2, "Removing %s", path);
+ output(o, 2, _("Removing %s"), path);
/* do not touch working file if it did not exist */
remove_file(o, 1, path, !a_sha);
} else {
@@ -1735,19 +1746,19 @@ static int process_entry(struct merge_options *o,
other_branch = o->branch2;
mode = a_mode;
sha = a_sha;
- conf = "file/directory";
+ conf = _("file/directory");
} else {
add_branch = o->branch2;
other_branch = o->branch1;
mode = b_mode;
sha = b_sha;
- conf = "directory/file";
+ conf = _("directory/file");
}
if (dir_in_way(path, !o->call_depth)) {
char *new_path = unique_path(o, path, add_branch);
clean_merge = 0;
- output(o, 1, "CONFLICT (%s): There is a directory with name %s in %s. "
- "Adding %s as %s",
+ output(o, 1, _("CONFLICT (%s): There is a directory with name %s in %s. "
+ "Adding %s as %s"),
conf, path, other_branch, path, new_path);
if (o->call_depth)
remove_file_from_cache(path);
@@ -1756,7 +1767,7 @@ static int process_entry(struct merge_options *o,
remove_file_from_cache(path);
free(new_path);
} else {
- output(o, 2, "Adding %s", path);
+ output(o, 2, _("Adding %s"), path);
/* do not overwrite file if already present */
update_file_flags(o, sha, mode, path, 1, !a_sha);
}
@@ -1773,7 +1784,7 @@ static int process_entry(struct merge_options *o,
*/
remove_file(o, 1, path, !a_mode);
} else
- die("Fatal merge failure, shouldn't happen.");
+ die(_("Fatal merge failure, shouldn't happen."));
return clean_merge;
}
@@ -1792,7 +1803,7 @@ int merge_trees(struct merge_options *o,
}
if (sha_eq(common->object.sha1, merge->object.sha1)) {
- output(o, 0, "Already up-to-date!");
+ output(o, 0, _("Already up-to-date!"));
*result = head;
return 1;
}
@@ -1801,7 +1812,7 @@ int merge_trees(struct merge_options *o,
if (code != 0) {
if (show(o, 4) || o->call_depth)
- die("merging of trees %s and %s failed",
+ die(_("merging of trees %s and %s failed"),
sha1_to_hex(head->object.sha1),
sha1_to_hex(merge->object.sha1));
else
@@ -1831,7 +1842,7 @@ int merge_trees(struct merge_options *o,
for (i = 0; i < entries->nr; i++) {
struct stage_data *e = entries->items[i].util;
if (!e->processed)
- die("Unprocessed path??? %s",
+ die(_("Unprocessed path??? %s"),
entries->items[i].string);
}
@@ -1876,7 +1887,7 @@ int merge_recursive(struct merge_options *o,
int clean;
if (show(o, 4)) {
- output(o, 4, "Merging:");
+ output(o, 4, _("Merging:"));
output_commit_title(o, h1);
output_commit_title(o, h2);
}
@@ -1887,7 +1898,10 @@ int merge_recursive(struct merge_options *o,
}
if (show(o, 5)) {
- output(o, 5, "found %u common ancestor(s):", commit_list_count(ca));
+ unsigned cnt = commit_list_count(ca);
+
+ output(o, 5, Q_("found %u common ancestor:",
+ "found %u common ancestors:", cnt), cnt);
for (iter = ca; iter; iter = iter->next)
output_commit_title(o, iter->item);
}
@@ -1923,7 +1937,7 @@ int merge_recursive(struct merge_options *o,
o->call_depth--;
if (!merged_common_ancestors)
- die("merge returned no commit");
+ die(_("merge returned no commit"));
}
discard_cache();
@@ -1980,7 +1994,7 @@ int merge_recursive_generic(struct merge_options *o,
for (i = 0; i < num_base_list; ++i) {
struct commit *base;
if (!(base = get_ref(base_list[i], sha1_to_hex(base_list[i]))))
- return error("Could not parse object '%s'",
+ return error(_("Could not parse object '%s'"),
sha1_to_hex(base_list[i]));
commit_list_insert(base, &ca);
}
@@ -1992,7 +2006,7 @@ int merge_recursive_generic(struct merge_options *o,
if (active_cache_changed &&
(write_cache(index_fd, active_cache, active_nr) ||
commit_locked_index(lock)))
- return error("Unable to write index.");
+ return error(_("Unable to write index."));
return clean ? 0 : 1;
}
diff --git a/mergetools/codecompare b/mergetools/codecompare
new file mode 100644
index 0000000..3f0486b
--- /dev/null
+++ b/mergetools/codecompare
@@ -0,0 +1,25 @@
+diff_cmd () {
+ "$merge_tool_path" "$LOCAL" "$REMOTE"
+}
+
+merge_cmd () {
+ touch "$BACKUP"
+ if $base_present
+ then
+ "$merge_tool_path" -MF="$LOCAL" -TF="$REMOTE" -BF="$BASE" \
+ -RF="$MERGED"
+ else
+ "$merge_tool_path" -MF="$LOCAL" -TF="$REMOTE" \
+ -RF="$MERGED"
+ fi
+ check_unchanged
+}
+
+translate_merge_tool_path() {
+ if merge_mode
+ then
+ echo CodeMerge
+ else
+ echo CodeCompare
+ fi
+}
diff --git a/mergetools/defaults b/mergetools/defaults
index 1d8f2a3..21e63ec 100644
--- a/mergetools/defaults
+++ b/mergetools/defaults
@@ -8,36 +8,12 @@ can_diff () {
}
diff_cmd () {
- merge_tool_cmd="$(get_merge_tool_cmd "$1")"
- if test -z "$merge_tool_cmd"
- then
- status=1
- break
- fi
- ( eval $merge_tool_cmd )
- status=$?
+ status=1
return $status
}
merge_cmd () {
- merge_tool_cmd="$(get_merge_tool_cmd "$1")"
- if test -z "$merge_tool_cmd"
- then
- status=1
- break
- fi
- trust_exit_code="$(git config --bool \
- mergetool."$1".trustExitCode || echo false)"
- if test "$trust_exit_code" = "false"
- then
- touch "$BACKUP"
- ( eval $merge_tool_cmd )
- status=$?
- check_unchanged
- else
- ( eval $merge_tool_cmd )
- status=$?
- fi
+ status=1
return $status
}
diff --git a/notes-merge.c b/notes-merge.c
index 7d62904..0f67bd3 100644
--- a/notes-merge.c
+++ b/notes-merge.c
@@ -522,8 +522,10 @@ static int merge_from_diffs(struct notes_merge_options *o,
free(changes);
if (o->verbosity >= 4)
- printf("Merge result: %i unmerged notes and a %s notes tree\n",
- conflicts, t->dirty ? "dirty" : "clean");
+ printf(t->dirty ?
+ "Merge result: %i unmerged notes and a dirty notes tree\n" :
+ "Merge result: %i unmerged notes and a clean notes tree\n",
+ conflicts);
return conflicts ? -1 : 1;
}
diff --git a/notes.c b/notes.c
index 93e9868..bc454e1 100644
--- a/notes.c
+++ b/notes.c
@@ -1196,8 +1196,18 @@ void free_notes(struct notes_tree *t)
memset(t, 0, sizeof(struct notes_tree));
}
-void format_note(struct notes_tree *t, const unsigned char *object_sha1,
- struct strbuf *sb, const char *output_encoding, int flags)
+/*
+ * Fill the given strbuf with the notes associated with the given object.
+ *
+ * If the given notes_tree structure is not initialized, it will be auto-
+ * initialized to the default value (see documentation for init_notes() above).
+ * If the given notes_tree is NULL, the internal/default notes_tree will be
+ * used instead.
+ *
+ * 'flags' is a bitwise combination of the flags for format_display_notes.
+ */
+static void format_note(struct notes_tree *t, const unsigned char *object_sha1,
+ struct strbuf *sb, const char *output_encoding, int flags)
{
static const char utf8[] = "utf-8";
const unsigned char *sha1;
diff --git a/notes.h b/notes.h
index c716694..3592b19 100644
--- a/notes.h
+++ b/notes.h
@@ -241,20 +241,6 @@ void free_notes(struct notes_tree *t);
#define NOTES_SHOW_HEADER 1
#define NOTES_INDENT 2
-/*
- * Fill the given strbuf with the notes associated with the given object.
- *
- * If the given notes_tree structure is not initialized, it will be auto-
- * initialized to the default value (see documentation for init_notes() above).
- * If the given notes_tree is NULL, the internal/default notes_tree will be
- * used instead.
- *
- * 'flags' is a bitwise combination of the above formatting flags.
- */
-void format_note(struct notes_tree *t, const unsigned char *object_sha1,
- struct strbuf *sb, const char *output_encoding, int flags);
-
-
struct string_list;
struct display_notes_opt {
diff --git a/parse-options.c b/parse-options.c
index ab70c29..c1c66bd 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -476,6 +476,7 @@ int parse_options(int argc, const char **argv, const char *prefix,
usage_with_options(usagestr, options);
}
+ precompose_argv(argc, argv);
return parse_options_end(&ctx);
}
diff --git a/parse-options.h b/parse-options.h
index 77a4a8b..71a39c6 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -238,6 +238,6 @@ extern int parse_opt_noop_cb(const struct option *, const char *, int);
#define OPT__COLOR(var, h) \
OPT_COLOR_FLAG(0, "color", (var), (h))
#define OPT_COLUMN(s, l, v, h) \
- { OPTION_CALLBACK, (s), (l), (v), "style", (h), PARSE_OPT_OPTARG, parseopt_column_callback }
+ { OPTION_CALLBACK, (s), (l), (v), N_("style"), (h), PARSE_OPT_OPTARG, parseopt_column_callback }
#endif
diff --git a/path.c b/path.c
index 6f2aa69..cbbdf7d 100644
--- a/path.c
+++ b/path.c
@@ -48,7 +48,7 @@ char *mksnpath(char *buf, size_t n, const char *fmt, ...)
return cleanup_path(buf);
}
-static char *git_vsnpath(char *buf, size_t n, const char *fmt, va_list args)
+static char *vsnpath(char *buf, size_t n, const char *fmt, va_list args)
{
const char *git_dir = get_git_dir();
size_t len;
@@ -70,21 +70,37 @@ bad:
char *git_snpath(char *buf, size_t n, const char *fmt, ...)
{
+ char *ret;
va_list args;
va_start(args, fmt);
- (void)git_vsnpath(buf, n, fmt, args);
+ ret = vsnpath(buf, n, fmt, args);
va_end(args);
- return buf;
+ return ret;
}
char *git_pathdup(const char *fmt, ...)
{
- char path[PATH_MAX];
+ char path[PATH_MAX], *ret;
+ va_list args;
+ va_start(args, fmt);
+ ret = vsnpath(path, sizeof(path), fmt, args);
+ va_end(args);
+ return xstrdup(ret);
+}
+
+char *mkpathdup(const char *fmt, ...)
+{
+ char *path;
+ struct strbuf sb = STRBUF_INIT;
va_list args;
+
va_start(args, fmt);
- (void)git_vsnpath(path, sizeof(path), fmt, args);
+ strbuf_vaddf(&sb, fmt, args);
va_end(args);
- return xstrdup(path);
+ path = xstrdup(cleanup_path(sb.buf));
+
+ strbuf_release(&sb);
+ return path;
}
char *mkpath(const char *fmt, ...)
@@ -103,23 +119,40 @@ char *mkpath(const char *fmt, ...)
char *git_path(const char *fmt, ...)
{
- const char *git_dir = get_git_dir();
char *pathname = get_pathname();
va_list args;
- unsigned len;
+ char *ret;
- len = strlen(git_dir);
- if (len > PATH_MAX-100)
- return bad_path;
- memcpy(pathname, git_dir, len);
- if (len && git_dir[len-1] != '/')
- pathname[len++] = '/';
va_start(args, fmt);
- len += vsnprintf(pathname + len, PATH_MAX - len, fmt, args);
+ ret = vsnpath(pathname, PATH_MAX, fmt, args);
va_end(args);
- if (len >= PATH_MAX)
- return bad_path;
- return cleanup_path(pathname);
+ return ret;
+}
+
+void home_config_paths(char **global, char **xdg, char *file)
+{
+ char *xdg_home = getenv("XDG_CONFIG_HOME");
+ char *home = getenv("HOME");
+ char *to_free = NULL;
+
+ if (!home) {
+ if (global)
+ *global = NULL;
+ } else {
+ if (!xdg_home) {
+ to_free = mkpathdup("%s/.config", home);
+ xdg_home = to_free;
+ }
+ if (global)
+ *global = mkpathdup("%s/.gitconfig", home);
+ }
+
+ if (!xdg_home)
+ *xdg = NULL;
+ else
+ *xdg = mkpathdup("%s/git/%s", xdg_home, file);
+
+ free(to_free);
}
char *git_path_submodule(const char *path, const char *fmt, ...)
diff --git a/perl/.gitignore b/perl/.gitignore
index d5c6e22..0f1fc27 100644
--- a/perl/.gitignore
+++ b/perl/.gitignore
@@ -5,3 +5,4 @@ MYMETA.yml
blib
blibdirs
pm_to_blib
+PM.stamp
diff --git a/perl/Git/IndexInfo.pm b/perl/Git/IndexInfo.pm
new file mode 100644
index 0000000..a43108c
--- /dev/null
+++ b/perl/Git/IndexInfo.pm
@@ -0,0 +1,33 @@
+package Git::IndexInfo;
+use strict;
+use warnings;
+use Git qw/command_input_pipe command_close_pipe/;
+
+sub new {
+ my ($class) = @_;
+ my ($gui, $ctx) = command_input_pipe(qw/update-index -z --index-info/);
+ bless { gui => $gui, ctx => $ctx, nr => 0}, $class;
+}
+
+sub remove {
+ my ($self, $path) = @_;
+ if (print { $self->{gui} } '0 ', 0 x 40, "\t", $path, "\0") {
+ return ++$self->{nr};
+ }
+ undef;
+}
+
+sub update {
+ my ($self, $mode, $hash, $path) = @_;
+ if (print { $self->{gui} } $mode, ' ', $hash, "\t", $path, "\0") {
+ return ++$self->{nr};
+ }
+ undef;
+}
+
+sub DESTROY {
+ my ($self) = @_;
+ command_close_pipe($self->{gui}, $self->{ctx});
+}
+
+1;
diff --git a/perl/Git/SVN.pm b/perl/Git/SVN.pm
new file mode 100644
index 0000000..59215fa
--- /dev/null
+++ b/perl/Git/SVN.pm
@@ -0,0 +1,2394 @@
+package Git::SVN;
+use strict;
+use warnings;
+use Fcntl qw/:DEFAULT :seek/;
+use constant rev_map_fmt => 'NH40';
+use vars qw/$_no_metadata
+ $_repack $_repack_flags $_use_svm_props $_head
+ $_use_svnsync_props $no_reuse_existing
+ $_use_log_author $_add_author_from $_localtime/;
+use Carp qw/croak/;
+use File::Path qw/mkpath/;
+use File::Copy qw/copy/;
+use IPC::Open3;
+use Time::Local;
+use Memoize; # core since 5.8.0, Jul 2002
+use Memoize::Storable;
+use POSIX qw(:signal_h);
+
+use Git qw(
+ command
+ command_oneline
+ command_noisy
+ command_output_pipe
+ command_close_pipe
+);
+use Git::SVN::Utils qw(
+ fatal
+ can_compress
+ join_paths
+ canonicalize_path
+ canonicalize_url
+ add_path_to_url
+);
+
+my $can_use_yaml;
+BEGIN {
+ $can_use_yaml = eval { require Git::SVN::Memoize::YAML; 1};
+}
+
+our $_follow_parent = 1;
+our $_minimize_url = 'unset';
+our $default_repo_id = 'svn';
+our $default_ref_id = $ENV{GIT_SVN_ID} || 'git-svn';
+
+my ($_gc_nr, $_gc_period);
+
+# properties that we do not log:
+my %SKIP_PROP;
+BEGIN {
+ %SKIP_PROP = map { $_ => 1 } qw/svn:wc:ra_dav:version-url
+ svn:special svn:executable
+ svn:entry:committed-rev
+ svn:entry:last-author
+ svn:entry:uuid
+ svn:entry:committed-date/;
+
+ # some options are read globally, but can be overridden locally
+ # per [svn-remote "..."] section. Command-line options will *NOT*
+ # override options set in an [svn-remote "..."] section
+ no strict 'refs';
+ for my $option (qw/follow_parent no_metadata use_svm_props
+ use_svnsync_props/) {
+ my $key = $option;
+ $key =~ tr/_//d;
+ my $prop = "-$option";
+ *$option = sub {
+ my ($self) = @_;
+ return $self->{$prop} if exists $self->{$prop};
+ my $k = "svn-remote.$self->{repo_id}.$key";
+ eval { command_oneline(qw/config --get/, $k) };
+ if ($@) {
+ $self->{$prop} = ${"Git::SVN::_$option"};
+ } else {
+ my $v = command_oneline(qw/config --bool/,$k);
+ $self->{$prop} = $v eq 'false' ? 0 : 1;
+ }
+ return $self->{$prop};
+ }
+ }
+}
+
+
+my (%LOCKFILES, %INDEX_FILES);
+END {
+ unlink keys %LOCKFILES if %LOCKFILES;
+ unlink keys %INDEX_FILES if %INDEX_FILES;
+}
+
+sub resolve_local_globs {
+ my ($url, $fetch, $glob_spec) = @_;
+ return unless defined $glob_spec;
+ my $ref = $glob_spec->{ref};
+ my $path = $glob_spec->{path};
+ foreach (command(qw#for-each-ref --format=%(refname) refs/#)) {
+ next unless m#^$ref->{regex}$#;
+ my $p = $1;
+ my $pathname = desanitize_refname($path->full_path($p));
+ my $refname = desanitize_refname($ref->full_path($p));
+ if (my $existing = $fetch->{$pathname}) {
+ if ($existing ne $refname) {
+ die "Refspec conflict:\n",
+ "existing: $existing\n",
+ " globbed: $refname\n";
+ }
+ my $u = (::cmt_metadata("$refname"))[0];
+ $u =~ s!^\Q$url\E(/|$)!! or die
+ "$refname: '$url' not found in '$u'\n";
+ if ($pathname ne $u) {
+ warn "W: Refspec glob conflict ",
+ "(ref: $refname):\n",
+ "expected path: $pathname\n",
+ " real path: $u\n",
+ "Continuing ahead with $u\n";
+ next;
+ }
+ } else {
+ $fetch->{$pathname} = $refname;
+ }
+ }
+}
+
+sub parse_revision_argument {
+ my ($base, $head) = @_;
+ if (!defined $::_revision || $::_revision eq 'BASE:HEAD') {
+ return ($base, $head);
+ }
+ return ($1, $2) if ($::_revision =~ /^(\d+):(\d+)$/);
+ return ($::_revision, $::_revision) if ($::_revision =~ /^\d+$/);
+ return ($head, $head) if ($::_revision eq 'HEAD');
+ return ($base, $1) if ($::_revision =~ /^BASE:(\d+)$/);
+ return ($1, $head) if ($::_revision =~ /^(\d+):HEAD$/);
+ die "revision argument: $::_revision not understood by git-svn\n";
+}
+
+sub fetch_all {
+ my ($repo_id, $remotes) = @_;
+ if (ref $repo_id) {
+ my $gs = $repo_id;
+ $repo_id = undef;
+ $repo_id = $gs->{repo_id};
+ }
+ $remotes ||= read_all_remotes();
+ my $remote = $remotes->{$repo_id} or
+ die "[svn-remote \"$repo_id\"] unknown\n";
+ my $fetch = $remote->{fetch};
+ my $url = $remote->{url} or die "svn-remote.$repo_id.url not defined\n";
+ my (@gs, @globs);
+ my $ra = Git::SVN::Ra->new($url);
+ my $uuid = $ra->get_uuid;
+ my $head = $ra->get_latest_revnum;
+
+ # ignore errors, $head revision may not even exist anymore
+ eval { $ra->get_log("", $head, 0, 1, 0, 1, sub { $head = $_[1] }) };
+ warn "W: $@\n" if $@;
+
+ my $base = defined $fetch ? $head : 0;
+
+ # read the max revs for wildcard expansion (branches/*, tags/*)
+ foreach my $t (qw/branches tags/) {
+ defined $remote->{$t} or next;
+ push @globs, @{$remote->{$t}};
+
+ my $max_rev = eval { tmp_config(qw/--int --get/,
+ "svn-remote.$repo_id.${t}-maxRev") };
+ if (defined $max_rev && ($max_rev < $base)) {
+ $base = $max_rev;
+ } elsif (!defined $max_rev) {
+ $base = 0;
+ }
+ }
+
+ if ($fetch) {
+ foreach my $p (sort keys %$fetch) {
+ my $gs = Git::SVN->new($fetch->{$p}, $repo_id, $p);
+ my $lr = $gs->rev_map_max;
+ if (defined $lr) {
+ $base = $lr if ($lr < $base);
+ }
+ push @gs, $gs;
+ }
+ }
+
+ ($base, $head) = parse_revision_argument($base, $head);
+ $ra->gs_fetch_loop_common($base, $head, \@gs, \@globs);
+}
+
+sub read_all_remotes {
+ my $r = {};
+ my $use_svm_props = eval { command_oneline(qw/config --bool
+ svn.useSvmProps/) };
+ $use_svm_props = $use_svm_props eq 'true' if $use_svm_props;
+ my $svn_refspec = qr{\s*(.*?)\s*:\s*(.+?)\s*};
+ foreach (grep { s/^svn-remote\.// } command(qw/config -l/)) {
+ if (m!^(.+)\.fetch=$svn_refspec$!) {
+ my ($remote, $local_ref, $remote_ref) = ($1, $2, $3);
+ die("svn-remote.$remote: remote ref '$remote_ref' "
+ . "must start with 'refs/'\n")
+ unless $remote_ref =~ m{^refs/};
+ $local_ref = uri_decode($local_ref);
+ $r->{$remote}->{fetch}->{$local_ref} = $remote_ref;
+ $r->{$remote}->{svm} = {} if $use_svm_props;
+ } elsif (m!^(.+)\.usesvmprops=\s*(.*)\s*$!) {
+ $r->{$1}->{svm} = {};
+ } elsif (m!^(.+)\.url=\s*(.*)\s*$!) {
+ $r->{$1}->{url} = canonicalize_url($2);
+ } elsif (m!^(.+)\.pushurl=\s*(.*)\s*$!) {
+ $r->{$1}->{pushurl} = canonicalize_url($2);
+ } elsif (m!^(.+)\.ignore-refs=\s*(.*)\s*$!) {
+ $r->{$1}->{ignore_refs_regex} = $2;
+ } elsif (m!^(.+)\.(branches|tags)=$svn_refspec$!) {
+ my ($remote, $t, $local_ref, $remote_ref) =
+ ($1, $2, $3, $4);
+ die("svn-remote.$remote: remote ref '$remote_ref' ($t) "
+ . "must start with 'refs/'\n")
+ unless $remote_ref =~ m{^refs/};
+ $local_ref = uri_decode($local_ref);
+
+ require Git::SVN::GlobSpec;
+ my $rs = {
+ t => $t,
+ remote => $remote,
+ path => Git::SVN::GlobSpec->new($local_ref, 1),
+ ref => Git::SVN::GlobSpec->new($remote_ref, 0) };
+ if (length($rs->{ref}->{right}) != 0) {
+ die "The '*' glob character must be the last ",
+ "character of '$remote_ref'\n";
+ }
+ push @{ $r->{$remote}->{$t} }, $rs;
+ }
+ }
+
+ map {
+ if (defined $r->{$_}->{svm}) {
+ my $svm;
+ eval {
+ my $section = "svn-remote.$_";
+ $svm = {
+ source => tmp_config('--get',
+ "$section.svm-source"),
+ replace => tmp_config('--get',
+ "$section.svm-replace"),
+ }
+ };
+ $r->{$_}->{svm} = $svm;
+ }
+ } keys %$r;
+
+ foreach my $remote (keys %$r) {
+ foreach ( grep { defined $_ }
+ map { $r->{$remote}->{$_} } qw(branches tags) ) {
+ foreach my $rs ( @$_ ) {
+ $rs->{ignore_refs_regex} =
+ $r->{$remote}->{ignore_refs_regex};
+ }
+ }
+ }
+
+ $r;
+}
+
+sub init_vars {
+ $_gc_nr = $_gc_period = 1000;
+ if (defined $_repack || defined $_repack_flags) {
+ warn "Repack options are obsolete; they have no effect.\n";
+ }
+}
+
+sub verify_remotes_sanity {
+ return unless -d $ENV{GIT_DIR};
+ my %seen;
+ foreach (command(qw/config -l/)) {
+ if (m!^svn-remote\.(?:.+)\.fetch=.*:refs/remotes/(\S+)\s*$!) {
+ if ($seen{$1}) {
+ die "Remote ref refs/remote/$1 is tracked by",
+ "\n \"$_\"\nand\n \"$seen{$1}\"\n",
+ "Please resolve this ambiguity in ",
+ "your git configuration file before ",
+ "continuing\n";
+ }
+ $seen{$1} = $_;
+ }
+ }
+}
+
+sub find_existing_remote {
+ my ($url, $remotes) = @_;
+ return undef if $no_reuse_existing;
+ my $existing;
+ foreach my $repo_id (keys %$remotes) {
+ my $u = $remotes->{$repo_id}->{url} or next;
+ next if $u ne $url;
+ $existing = $repo_id;
+ last;
+ }
+ $existing;
+}
+
+sub init_remote_config {
+ my ($self, $url, $no_write) = @_;
+ $url = canonicalize_url($url);
+ my $r = read_all_remotes();
+ my $existing = find_existing_remote($url, $r);
+ if ($existing) {
+ unless ($no_write) {
+ print STDERR "Using existing ",
+ "[svn-remote \"$existing\"]\n";
+ }
+ $self->{repo_id} = $existing;
+ } elsif ($_minimize_url) {
+ my $min_url = Git::SVN::Ra->new($url)->minimize_url;
+ $existing = find_existing_remote($min_url, $r);
+ if ($existing) {
+ unless ($no_write) {
+ print STDERR "Using existing ",
+ "[svn-remote \"$existing\"]\n";
+ }
+ $self->{repo_id} = $existing;
+ }
+ if ($min_url ne $url) {
+ unless ($no_write) {
+ print STDERR "Using higher level of URL: ",
+ "$url => $min_url\n";
+ }
+ my $old_path = $self->path;
+ $url =~ s!^\Q$min_url\E(/|$)!!;
+ $url = join_paths($url, $old_path);
+ $self->path($url);
+ $url = $min_url;
+ }
+ }
+ my $orig_url;
+ if (!$existing) {
+ # verify that we aren't overwriting anything:
+ $orig_url = eval {
+ command_oneline('config', '--get',
+ "svn-remote.$self->{repo_id}.url")
+ };
+ if ($orig_url && ($orig_url ne $url)) {
+ die "svn-remote.$self->{repo_id}.url already set: ",
+ "$orig_url\nwanted to set to: $url\n";
+ }
+ }
+ my ($xrepo_id, $xpath) = find_ref($self->refname);
+ if (!$no_write && defined $xpath) {
+ die "svn-remote.$xrepo_id.fetch already set to track ",
+ "$xpath:", $self->refname, "\n";
+ }
+ unless ($no_write) {
+ command_noisy('config',
+ "svn-remote.$self->{repo_id}.url", $url);
+ my $path = $self->path;
+ $path =~ s{^/}{};
+ $path =~ s{%([0-9A-F]{2})}{chr hex($1)}ieg;
+ $self->path($path);
+ command_noisy('config', '--add',
+ "svn-remote.$self->{repo_id}.fetch",
+ $self->path.":".$self->refname);
+ }
+ $self->url($url);
+}
+
+sub find_by_url { # repos_root and, path are optional
+ my ($class, $full_url, $repos_root, $path) = @_;
+
+ $full_url = canonicalize_url($full_url);
+
+ return undef unless defined $full_url;
+ remove_username($full_url);
+ remove_username($repos_root) if defined $repos_root;
+ my $remotes = read_all_remotes();
+ if (defined $full_url && defined $repos_root && !defined $path) {
+ $path = $full_url;
+ $path =~ s#^\Q$repos_root\E(?:/|$)##;
+ }
+ foreach my $repo_id (keys %$remotes) {
+ my $u = $remotes->{$repo_id}->{url} or next;
+ remove_username($u);
+ next if defined $repos_root && $repos_root ne $u;
+
+ my $fetch = $remotes->{$repo_id}->{fetch} || {};
+ foreach my $t (qw/branches tags/) {
+ foreach my $globspec (@{$remotes->{$repo_id}->{$t}}) {
+ resolve_local_globs($u, $fetch, $globspec);
+ }
+ }
+ my $p = $path;
+ my $rwr = rewrite_root({repo_id => $repo_id});
+ my $svm = $remotes->{$repo_id}->{svm}
+ if defined $remotes->{$repo_id}->{svm};
+ unless (defined $p) {
+ $p = $full_url;
+ my $z = $u;
+ my $prefix = '';
+ if ($rwr) {
+ $z = $rwr;
+ remove_username($z);
+ } elsif (defined $svm) {
+ $z = $svm->{source};
+ $prefix = $svm->{replace};
+ $prefix =~ s#^\Q$u\E(?:/|$)##;
+ $prefix =~ s#/$##;
+ }
+ $p =~ s#^\Q$z\E(?:/|$)#$prefix# or next;
+ }
+
+ # remote fetch paths are not URI escaped. Decode ours
+ # so they match
+ $p = uri_decode($p);
+
+ foreach my $f (keys %$fetch) {
+ next if $f ne $p;
+ return Git::SVN->new($fetch->{$f}, $repo_id, $f);
+ }
+ }
+ undef;
+}
+
+sub init {
+ my ($class, $url, $path, $repo_id, $ref_id, $no_write) = @_;
+ my $self = _new($class, $repo_id, $ref_id, $path);
+ if (defined $url) {
+ $self->init_remote_config($url, $no_write);
+ }
+ $self;
+}
+
+sub find_ref {
+ my ($ref_id) = @_;
+ foreach (command(qw/config -l/)) {
+ next unless m!^svn-remote\.(.+)\.fetch=
+ \s*(.*?)\s*:\s*(.+?)\s*$!x;
+ my ($repo_id, $path, $ref) = ($1, $2, $3);
+ if ($ref eq $ref_id) {
+ $path = '' if ($path =~ m#^\./?#);
+ return ($repo_id, $path);
+ }
+ }
+ (undef, undef, undef);
+}
+
+sub new {
+ my ($class, $ref_id, $repo_id, $path) = @_;
+ if (defined $ref_id && !defined $repo_id && !defined $path) {
+ ($repo_id, $path) = find_ref($ref_id);
+ if (!defined $repo_id) {
+ die "Could not find a \"svn-remote.*.fetch\" key ",
+ "in the repository configuration matching: ",
+ "$ref_id\n";
+ }
+ }
+ my $self = _new($class, $repo_id, $ref_id, $path);
+ if (!defined $self->path || !length $self->path) {
+ my $fetch = command_oneline('config', '--get',
+ "svn-remote.$repo_id.fetch",
+ ":$ref_id\$") or
+ die "Failed to read \"svn-remote.$repo_id.fetch\" ",
+ "\":$ref_id\$\" in config\n";
+ my($path) = split(/\s*:\s*/, $fetch);
+ $self->path($path);
+ }
+ {
+ my $path = $self->path;
+ $path =~ s{\A/}{};
+ $path =~ s{/\z}{};
+ $self->path($path);
+ }
+ my $url = command_oneline('config', '--get',
+ "svn-remote.$repo_id.url") or
+ die "Failed to read \"svn-remote.$repo_id.url\" in config\n";
+ $self->url($url);
+ $self->{pushurl} = eval { command_oneline('config', '--get',
+ "svn-remote.$repo_id.pushurl") };
+ $self->rebuild;
+ $self;
+}
+
+sub refname {
+ my ($refname) = $_[0]->{ref_id} ;
+
+ # It cannot end with a slash /, we'll throw up on this because
+ # SVN can't have directories with a slash in their name, either:
+ if ($refname =~ m{/$}) {
+ die "ref: '$refname' ends with a trailing slash, this is ",
+ "not permitted by git nor Subversion\n";
+ }
+
+ # It cannot have ASCII control character space, tilde ~, caret ^,
+ # colon :, question-mark ?, asterisk *, space, or open bracket [
+ # anywhere.
+ #
+ # Additionally, % must be escaped because it is used for escaping
+ # and we want our escaped refname to be reversible
+ $refname =~ s{([ \%~\^:\?\*\[\t])}{uc sprintf('%%%02x',ord($1))}eg;
+
+ # no slash-separated component can begin with a dot .
+ # /.* becomes /%2E*
+ $refname =~ s{/\.}{/%2E}g;
+
+ # It cannot have two consecutive dots .. anywhere
+ # .. becomes %2E%2E
+ $refname =~ s{\.\.}{%2E%2E}g;
+
+ # trailing dots and .lock are not allowed
+ # .$ becomes %2E and .lock becomes %2Elock
+ $refname =~ s{\.(?=$|lock$)}{%2E};
+
+ # the sequence @{ is used to access the reflog
+ # @{ becomes %40{
+ $refname =~ s{\@\{}{%40\{}g;
+
+ return $refname;
+}
+
+sub desanitize_refname {
+ my ($refname) = @_;
+ $refname =~ s{%(?:([0-9A-F]{2}))}{chr hex($1)}eg;
+ return $refname;
+}
+
+sub svm_uuid {
+ my ($self) = @_;
+ return $self->{svm}->{uuid} if $self->svm;
+ $self->ra;
+ unless ($self->{svm}) {
+ die "SVM UUID not cached, and reading remotely failed\n";
+ }
+ $self->{svm}->{uuid};
+}
+
+sub svm {
+ my ($self) = @_;
+ return $self->{svm} if $self->{svm};
+ my $svm;
+ # see if we have it in our config, first:
+ eval {
+ my $section = "svn-remote.$self->{repo_id}";
+ $svm = {
+ source => tmp_config('--get', "$section.svm-source"),
+ uuid => tmp_config('--get', "$section.svm-uuid"),
+ replace => tmp_config('--get', "$section.svm-replace"),
+ }
+ };
+ if ($svm && $svm->{source} && $svm->{uuid} && $svm->{replace}) {
+ $self->{svm} = $svm;
+ }
+ $self->{svm};
+}
+
+sub _set_svm_vars {
+ my ($self, $ra) = @_;
+ return $ra if $self->svm;
+
+ my @err = ( "useSvmProps set, but failed to read SVM properties\n",
+ "(svm:source, svm:uuid) ",
+ "from the following URLs:\n" );
+ sub read_svm_props {
+ my ($self, $ra, $path, $r) = @_;
+ my $props = ($ra->get_dir($path, $r))[2];
+ my $src = $props->{'svm:source'};
+ my $uuid = $props->{'svm:uuid'};
+ return undef if (!$src || !$uuid);
+
+ chomp($src, $uuid);
+
+ $uuid =~ m{^[0-9a-f\-]{30,}$}i
+ or die "doesn't look right - svm:uuid is '$uuid'\n";
+
+ # the '!' is used to mark the repos_root!/relative/path
+ $src =~ s{/?!/?}{/};
+ $src =~ s{/+$}{}; # no trailing slashes please
+ # username is of no interest
+ $src =~ s{(^[a-z\+]*://)[^/@]*@}{$1};
+
+ my $replace = add_path_to_url($ra->url, $path);
+
+ my $section = "svn-remote.$self->{repo_id}";
+ tmp_config("$section.svm-source", $src);
+ tmp_config("$section.svm-replace", $replace);
+ tmp_config("$section.svm-uuid", $uuid);
+ $self->{svm} = {
+ source => $src,
+ uuid => $uuid,
+ replace => $replace
+ };
+ }
+
+ my $r = $ra->get_latest_revnum;
+ my $path = $self->path;
+ my %tried;
+ while (length $path) {
+ my $try = add_path_to_url($self->url, $path);
+ unless ($tried{$try}) {
+ return $ra if $self->read_svm_props($ra, $path, $r);
+ $tried{$try} = 1;
+ }
+ $path =~ s#/?[^/]+$##;
+ }
+ die "Path: '$path' should be ''\n" if $path ne '';
+ return $ra if $self->read_svm_props($ra, $path, $r);
+ $tried{ add_path_to_url($self->url, $path) } = 1;
+
+ if ($ra->{repos_root} eq $self->url) {
+ die @err, (map { " $_\n" } keys %tried), "\n";
+ }
+
+ # nope, make sure we're connected to the repository root:
+ my $ok;
+ my @tried_b;
+ $path = $ra->{svn_path};
+ $ra = Git::SVN::Ra->new($ra->{repos_root});
+ while (length $path) {
+ my $try = add_path_to_url($ra->url, $path);
+ unless ($tried{$try}) {
+ $ok = $self->read_svm_props($ra, $path, $r);
+ last if $ok;
+ $tried{$try} = 1;
+ }
+ $path =~ s#/?[^/]+$##;
+ }
+ die "Path: '$path' should be ''\n" if $path ne '';
+ $ok ||= $self->read_svm_props($ra, $path, $r);
+ $tried{ add_path_to_url($ra->url, $path) } = 1;
+ if (!$ok) {
+ die @err, (map { " $_\n" } keys %tried), "\n";
+ }
+ Git::SVN::Ra->new($self->url);
+}
+
+sub svnsync {
+ my ($self) = @_;
+ return $self->{svnsync} if $self->{svnsync};
+
+ if ($self->no_metadata) {
+ die "Can't have both 'noMetadata' and ",
+ "'useSvnsyncProps' options set!\n";
+ }
+ if ($self->rewrite_root) {
+ die "Can't have both 'useSvnsyncProps' and 'rewriteRoot' ",
+ "options set!\n";
+ }
+ if ($self->rewrite_uuid) {
+ die "Can't have both 'useSvnsyncProps' and 'rewriteUUID' ",
+ "options set!\n";
+ }
+
+ my $svnsync;
+ # see if we have it in our config, first:
+ eval {
+ my $section = "svn-remote.$self->{repo_id}";
+
+ my $url = tmp_config('--get', "$section.svnsync-url");
+ ($url) = ($url =~ m{^([a-z\+]+://\S+)$}) or
+ die "doesn't look right - svn:sync-from-url is '$url'\n";
+
+ my $uuid = tmp_config('--get', "$section.svnsync-uuid");
+ ($uuid) = ($uuid =~ m{^([0-9a-f\-]{30,})$}i) or
+ die "doesn't look right - svn:sync-from-uuid is '$uuid'\n";
+
+ $svnsync = { url => $url, uuid => $uuid }
+ };
+ if ($svnsync && $svnsync->{url} && $svnsync->{uuid}) {
+ return $self->{svnsync} = $svnsync;
+ }
+
+ my $err = "useSvnsyncProps set, but failed to read " .
+ "svnsync property: svn:sync-from-";
+ my $rp = $self->ra->rev_proplist(0);
+
+ my $url = $rp->{'svn:sync-from-url'} or die $err . "url\n";
+ ($url) = ($url =~ m{^([a-z\+]+://\S+)$}) or
+ die "doesn't look right - svn:sync-from-url is '$url'\n";
+
+ my $uuid = $rp->{'svn:sync-from-uuid'} or die $err . "uuid\n";
+ ($uuid) = ($uuid =~ m{^([0-9a-f\-]{30,})$}i) or
+ die "doesn't look right - svn:sync-from-uuid is '$uuid'\n";
+
+ my $section = "svn-remote.$self->{repo_id}";
+ tmp_config('--add', "$section.svnsync-uuid", $uuid);
+ tmp_config('--add', "$section.svnsync-url", $url);
+ return $self->{svnsync} = { url => $url, uuid => $uuid };
+}
+
+# this allows us to memoize our SVN::Ra UUID locally and avoid a
+# remote lookup (useful for 'git svn log').
+sub ra_uuid {
+ my ($self) = @_;
+ unless ($self->{ra_uuid}) {
+ my $key = "svn-remote.$self->{repo_id}.uuid";
+ my $uuid = eval { tmp_config('--get', $key) };
+ if (!$@ && $uuid && $uuid =~ /^([a-f\d\-]{30,})$/i) {
+ $self->{ra_uuid} = $uuid;
+ } else {
+ die "ra_uuid called without URL\n" unless $self->url;
+ $self->{ra_uuid} = $self->ra->get_uuid;
+ tmp_config('--add', $key, $self->{ra_uuid});
+ }
+ }
+ $self->{ra_uuid};
+}
+
+sub _set_repos_root {
+ my ($self, $repos_root) = @_;
+ my $k = "svn-remote.$self->{repo_id}.reposRoot";
+ $repos_root ||= $self->ra->{repos_root};
+ tmp_config($k, $repos_root);
+ $repos_root;
+}
+
+sub repos_root {
+ my ($self) = @_;
+ my $k = "svn-remote.$self->{repo_id}.reposRoot";
+ eval { tmp_config('--get', $k) } || $self->_set_repos_root;
+}
+
+sub ra {
+ my ($self) = shift;
+ my $ra = Git::SVN::Ra->new($self->url);
+ $self->_set_repos_root($ra->{repos_root});
+ if ($self->use_svm_props && !$self->{svm}) {
+ if ($self->no_metadata) {
+ die "Can't have both 'noMetadata' and ",
+ "'useSvmProps' options set!\n";
+ } elsif ($self->use_svnsync_props) {
+ die "Can't have both 'useSvnsyncProps' and ",
+ "'useSvmProps' options set!\n";
+ }
+ $ra = $self->_set_svm_vars($ra);
+ $self->{-want_revprops} = 1;
+ }
+ $ra;
+}
+
+# prop_walk(PATH, REV, SUB)
+# -------------------------
+# Recursively traverse PATH at revision REV and invoke SUB for each
+# directory that contains a SVN property. SUB will be invoked as
+# follows: &SUB(gs, path, props); where `gs' is this instance of
+# Git::SVN, `path' the path to the directory where the properties
+# `props' were found. The `path' will be relative to point of checkout,
+# that is, if url://repo/trunk is the current Git branch, and that
+# directory contains a sub-directory `d', SUB will be invoked with `/d/'
+# as `path' (note the trailing `/').
+sub prop_walk {
+ my ($self, $path, $rev, $sub) = @_;
+
+ $path =~ s#^/##;
+ my ($dirent, undef, $props) = $self->ra->get_dir($path, $rev);
+ $path =~ s#^/*#/#g;
+ my $p = $path;
+ # Strip the irrelevant part of the path.
+ $p =~ s#^/+\Q@{[$self->path]}\E(/|$)#/#;
+ # Ensure the path is terminated by a `/'.
+ $p =~ s#/*$#/#;
+
+ # The properties contain all the internal SVN stuff nobody
+ # (usually) cares about.
+ my $interesting_props = 0;
+ foreach (keys %{$props}) {
+ # If it doesn't start with `svn:', it must be a
+ # user-defined property.
+ ++$interesting_props and next if $_ !~ /^svn:/;
+ # FIXME: Fragile, if SVN adds new public properties,
+ # this needs to be updated.
+ ++$interesting_props if /^svn:(?:ignore|keywords|executable
+ |eol-style|mime-type
+ |externals|needs-lock)$/x;
+ }
+ &$sub($self, $p, $props) if $interesting_props;
+
+ foreach (sort keys %$dirent) {
+ next if $dirent->{$_}->{kind} != $SVN::Node::dir;
+ $self->prop_walk($self->path . $p . $_, $rev, $sub);
+ }
+}
+
+sub last_rev { ($_[0]->last_rev_commit)[0] }
+sub last_commit { ($_[0]->last_rev_commit)[1] }
+
+# returns the newest SVN revision number and newest commit SHA1
+sub last_rev_commit {
+ my ($self) = @_;
+ if (defined $self->{last_rev} && defined $self->{last_commit}) {
+ return ($self->{last_rev}, $self->{last_commit});
+ }
+ my $c = ::verify_ref($self->refname.'^0');
+ if ($c && !$self->use_svm_props && !$self->no_metadata) {
+ my $rev = (::cmt_metadata($c))[1];
+ if (defined $rev) {
+ ($self->{last_rev}, $self->{last_commit}) = ($rev, $c);
+ return ($rev, $c);
+ }
+ }
+ my $map_path = $self->map_path;
+ unless (-e $map_path) {
+ ($self->{last_rev}, $self->{last_commit}) = (undef, undef);
+ return (undef, undef);
+ }
+ my ($rev, $commit) = $self->rev_map_max(1);
+ ($self->{last_rev}, $self->{last_commit}) = ($rev, $commit);
+ return ($rev, $commit);
+}
+
+sub get_fetch_range {
+ my ($self, $min, $max) = @_;
+ $max ||= $self->ra->get_latest_revnum;
+ $min ||= $self->rev_map_max;
+ (++$min, $max);
+}
+
+sub tmp_config {
+ my (@args) = @_;
+ my $old_def_config = "$ENV{GIT_DIR}/svn/config";
+ my $config = "$ENV{GIT_DIR}/svn/.metadata";
+ if (! -f $config && -f $old_def_config) {
+ rename $old_def_config, $config or
+ die "Failed rename $old_def_config => $config: $!\n";
+ }
+ my $old_config = $ENV{GIT_CONFIG};
+ $ENV{GIT_CONFIG} = $config;
+ $@ = undef;
+ my @ret = eval {
+ unless (-f $config) {
+ mkfile($config);
+ open my $fh, '>', $config or
+ die "Can't open $config: $!\n";
+ print $fh "; This file is used internally by ",
+ "git-svn\n" or die
+ "Couldn't write to $config: $!\n";
+ print $fh "; You should not have to edit it\n" or
+ die "Couldn't write to $config: $!\n";
+ close $fh or die "Couldn't close $config: $!\n";
+ }
+ command('config', @args);
+ };
+ my $err = $@;
+ if (defined $old_config) {
+ $ENV{GIT_CONFIG} = $old_config;
+ } else {
+ delete $ENV{GIT_CONFIG};
+ }
+ die $err if $err;
+ wantarray ? @ret : $ret[0];
+}
+
+sub tmp_index_do {
+ my ($self, $sub) = @_;
+ my $old_index = $ENV{GIT_INDEX_FILE};
+ $ENV{GIT_INDEX_FILE} = $self->{index};
+ $@ = undef;
+ my @ret = eval {
+ my ($dir, $base) = ($self->{index} =~ m#^(.*?)/?([^/]+)$#);
+ mkpath([$dir]) unless -d $dir;
+ &$sub;
+ };
+ my $err = $@;
+ if (defined $old_index) {
+ $ENV{GIT_INDEX_FILE} = $old_index;
+ } else {
+ delete $ENV{GIT_INDEX_FILE};
+ }
+ die $err if $err;
+ wantarray ? @ret : $ret[0];
+}
+
+sub assert_index_clean {
+ my ($self, $treeish) = @_;
+
+ $self->tmp_index_do(sub {
+ command_noisy('read-tree', $treeish) unless -e $self->{index};
+ my $x = command_oneline('write-tree');
+ my ($y) = (command(qw/cat-file commit/, $treeish) =~
+ /^tree ($::sha1)/mo);
+ return if $y eq $x;
+
+ warn "Index mismatch: $y != $x\nrereading $treeish\n";
+ unlink $self->{index} or die "unlink $self->{index}: $!\n";
+ command_noisy('read-tree', $treeish);
+ $x = command_oneline('write-tree');
+ if ($y ne $x) {
+ fatal "trees ($treeish) $y != $x\n",
+ "Something is seriously wrong...";
+ }
+ });
+}
+
+sub get_commit_parents {
+ my ($self, $log_entry) = @_;
+ my (%seen, @ret, @tmp);
+ # legacy support for 'set-tree'; this is only used by set_tree_cb:
+ if (my $ip = $self->{inject_parents}) {
+ if (my $commit = delete $ip->{$log_entry->{revision}}) {
+ push @tmp, $commit;
+ }
+ }
+ if (my $cur = ::verify_ref($self->refname.'^0')) {
+ push @tmp, $cur;
+ }
+ if (my $ipd = $self->{inject_parents_dcommit}) {
+ if (my $commit = delete $ipd->{$log_entry->{revision}}) {
+ push @tmp, @$commit;
+ }
+ }
+ push @tmp, $_ foreach (@{$log_entry->{parents}}, @tmp);
+ while (my $p = shift @tmp) {
+ next if $seen{$p};
+ $seen{$p} = 1;
+ push @ret, $p;
+ }
+ @ret;
+}
+
+sub rewrite_root {
+ my ($self) = @_;
+ return $self->{-rewrite_root} if exists $self->{-rewrite_root};
+ my $k = "svn-remote.$self->{repo_id}.rewriteRoot";
+ my $rwr = eval { command_oneline(qw/config --get/, $k) };
+ if ($rwr) {
+ $rwr =~ s#/+$##;
+ if ($rwr !~ m#^[a-z\+]+://#) {
+ die "$rwr is not a valid URL (key: $k)\n";
+ }
+ }
+ $self->{-rewrite_root} = $rwr;
+}
+
+sub rewrite_uuid {
+ my ($self) = @_;
+ return $self->{-rewrite_uuid} if exists $self->{-rewrite_uuid};
+ my $k = "svn-remote.$self->{repo_id}.rewriteUUID";
+ my $rwid = eval { command_oneline(qw/config --get/, $k) };
+ if ($rwid) {
+ $rwid =~ s#/+$##;
+ if ($rwid !~ m#^[a-f0-9]{8}-(?:[a-f0-9]{4}-){3}[a-f0-9]{12}$#) {
+ die "$rwid is not a valid UUID (key: $k)\n";
+ }
+ }
+ $self->{-rewrite_uuid} = $rwid;
+}
+
+sub metadata_url {
+ my ($self) = @_;
+ my $url = $self->rewrite_root || $self->url;
+ return canonicalize_url( add_path_to_url( $url, $self->path ) );
+}
+
+sub full_url {
+ my ($self) = @_;
+ return canonicalize_url( add_path_to_url( $self->url, $self->path ) );
+}
+
+sub full_pushurl {
+ my ($self) = @_;
+ if ($self->{pushurl}) {
+ return canonicalize_url( add_path_to_url( $self->{pushurl}, $self->path ) );
+ } else {
+ return $self->full_url;
+ }
+}
+
+sub set_commit_header_env {
+ my ($log_entry) = @_;
+ my %env;
+ foreach my $ned (qw/NAME EMAIL DATE/) {
+ foreach my $ac (qw/AUTHOR COMMITTER/) {
+ $env{"GIT_${ac}_${ned}"} = $ENV{"GIT_${ac}_${ned}"};
+ }
+ }
+
+ $ENV{GIT_AUTHOR_NAME} = $log_entry->{name};
+ $ENV{GIT_AUTHOR_EMAIL} = $log_entry->{email};
+ $ENV{GIT_AUTHOR_DATE} = $ENV{GIT_COMMITTER_DATE} = $log_entry->{date};
+
+ $ENV{GIT_COMMITTER_NAME} = (defined $log_entry->{commit_name})
+ ? $log_entry->{commit_name}
+ : $log_entry->{name};
+ $ENV{GIT_COMMITTER_EMAIL} = (defined $log_entry->{commit_email})
+ ? $log_entry->{commit_email}
+ : $log_entry->{email};
+ \%env;
+}
+
+sub restore_commit_header_env {
+ my ($env) = @_;
+ foreach my $ned (qw/NAME EMAIL DATE/) {
+ foreach my $ac (qw/AUTHOR COMMITTER/) {
+ my $k = "GIT_${ac}_${ned}";
+ if (defined $env->{$k}) {
+ $ENV{$k} = $env->{$k};
+ } else {
+ delete $ENV{$k};
+ }
+ }
+ }
+}
+
+sub gc {
+ command_noisy('gc', '--auto');
+};
+
+sub do_git_commit {
+ my ($self, $log_entry) = @_;
+ my $lr = $self->last_rev;
+ if (defined $lr && $lr >= $log_entry->{revision}) {
+ die "Last fetched revision of ", $self->refname,
+ " was r$lr, but we are about to fetch: ",
+ "r$log_entry->{revision}!\n";
+ }
+ if (my $c = $self->rev_map_get($log_entry->{revision})) {
+ croak "$log_entry->{revision} = $c already exists! ",
+ "Why are we refetching it?\n";
+ }
+ my $old_env = set_commit_header_env($log_entry);
+ my $tree = $log_entry->{tree};
+ if (!defined $tree) {
+ $tree = $self->tmp_index_do(sub {
+ command_oneline('write-tree') });
+ }
+ die "Tree is not a valid sha1: $tree\n" if $tree !~ /^$::sha1$/o;
+
+ my @exec = ('git', 'commit-tree', $tree);
+ foreach ($self->get_commit_parents($log_entry)) {
+ push @exec, '-p', $_;
+ }
+ defined(my $pid = open3(my $msg_fh, my $out_fh, '>&STDERR', @exec))
+ or croak $!;
+ binmode $msg_fh;
+
+ # we always get UTF-8 from SVN, but we may want our commits in
+ # a different encoding.
+ if (my $enc = Git::config('i18n.commitencoding')) {
+ require Encode;
+ Encode::from_to($log_entry->{log}, 'UTF-8', $enc);
+ }
+ print $msg_fh $log_entry->{log} or croak $!;
+ restore_commit_header_env($old_env);
+ unless ($self->no_metadata) {
+ print $msg_fh "\ngit-svn-id: $log_entry->{metadata}\n"
+ or croak $!;
+ }
+ $msg_fh->flush == 0 or croak $!;
+ close $msg_fh or croak $!;
+ chomp(my $commit = do { local $/; <$out_fh> });
+ close $out_fh or croak $!;
+ waitpid $pid, 0;
+ croak $? if $?;
+ if ($commit !~ /^$::sha1$/o) {
+ die "Failed to commit, invalid sha1: $commit\n";
+ }
+
+ $self->rev_map_set($log_entry->{revision}, $commit, 1);
+
+ $self->{last_rev} = $log_entry->{revision};
+ $self->{last_commit} = $commit;
+ print "r$log_entry->{revision}" unless $::_q > 1;
+ if (defined $log_entry->{svm_revision}) {
+ print " (\@$log_entry->{svm_revision})" unless $::_q > 1;
+ $self->rev_map_set($log_entry->{svm_revision}, $commit,
+ 0, $self->svm_uuid);
+ }
+ print " = $commit ($self->{ref_id})\n" unless $::_q > 1;
+ if (--$_gc_nr == 0) {
+ $_gc_nr = $_gc_period;
+ gc();
+ }
+ return $commit;
+}
+
+sub match_paths {
+ my ($self, $paths, $r) = @_;
+ return 1 if $self->path eq '';
+ if (my $path = $paths->{"/".$self->path}) {
+ return ($path->{action} eq 'D') ? 0 : 1;
+ }
+ $self->{path_regex} ||= qr{^/\Q@{[$self->path]}\E/};
+ if (grep /$self->{path_regex}/, keys %$paths) {
+ return 1;
+ }
+ my $c = '';
+ foreach (split m#/#, $self->path) {
+ $c .= "/$_";
+ next unless ($paths->{$c} &&
+ ($paths->{$c}->{action} =~ /^[AR]$/));
+ if ($self->ra->check_path($self->path, $r) ==
+ $SVN::Node::dir) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+sub find_parent_branch {
+ my ($self, $paths, $rev) = @_;
+ return undef unless $self->follow_parent;
+ unless (defined $paths) {
+ my $err_handler = $SVN::Error::handler;
+ $SVN::Error::handler = \&Git::SVN::Ra::skip_unknown_revs;
+ $self->ra->get_log([$self->path], $rev, $rev, 0, 1, 1,
+ sub { $paths = $_[0] });
+ $SVN::Error::handler = $err_handler;
+ }
+ return undef unless defined $paths;
+
+ # look for a parent from another branch:
+ my @b_path_components = split m#/#, $self->path;
+ my @a_path_components;
+ my $i;
+ while (@b_path_components) {
+ $i = $paths->{'/'.join('/', @b_path_components)};
+ last if $i && defined $i->{copyfrom_path};
+ unshift(@a_path_components, pop(@b_path_components));
+ }
+ return undef unless defined $i && defined $i->{copyfrom_path};
+ my $branch_from = $i->{copyfrom_path};
+ if (@a_path_components) {
+ print STDERR "branch_from: $branch_from => ";
+ $branch_from .= '/'.join('/', @a_path_components);
+ print STDERR $branch_from, "\n";
+ }
+ my $r = $i->{copyfrom_rev};
+ my $repos_root = $self->ra->{repos_root};
+ my $url = $self->ra->url;
+ my $new_url = canonicalize_url( add_path_to_url( $url, $branch_from ) );
+ print STDERR "Found possible branch point: ",
+ "$new_url => ", $self->full_url, ", $r\n"
+ unless $::_q > 1;
+ $branch_from =~ s#^/##;
+ my $gs = $self->other_gs($new_url, $url,
+ $branch_from, $r, $self->{ref_id});
+ my ($r0, $parent) = $gs->find_rev_before($r, 1);
+ {
+ my ($base, $head);
+ if (!defined $r0 || !defined $parent) {
+ ($base, $head) = parse_revision_argument(0, $r);
+ } else {
+ if ($r0 < $r) {
+ $gs->ra->get_log([$gs->path], $r0 + 1, $r, 1,
+ 0, 1, sub { $base = $_[1] - 1 });
+ }
+ }
+ if (defined $base && $base <= $r) {
+ $gs->fetch($base, $r);
+ }
+ ($r0, $parent) = $gs->find_rev_before($r, 1);
+ }
+ if (defined $r0 && defined $parent) {
+ print STDERR "Found branch parent: ($self->{ref_id}) $parent\n"
+ unless $::_q > 1;
+ my $ed;
+ if ($self->ra->can_do_switch) {
+ $self->assert_index_clean($parent);
+ print STDERR "Following parent with do_switch\n"
+ unless $::_q > 1;
+ # do_switch works with svn/trunk >= r22312, but that
+ # is not included with SVN 1.4.3 (the latest version
+ # at the moment), so we can't rely on it
+ $self->{last_rev} = $r0;
+ $self->{last_commit} = $parent;
+ $ed = Git::SVN::Fetcher->new($self, $gs->path);
+ $gs->ra->gs_do_switch($r0, $rev, $gs,
+ $self->full_url, $ed)
+ or die "SVN connection failed somewhere...\n";
+ } elsif ($self->ra->trees_match($new_url, $r0,
+ $self->full_url, $rev)) {
+ print STDERR "Trees match:\n",
+ " $new_url\@$r0\n",
+ " ${\$self->full_url}\@$rev\n",
+ "Following parent with no changes\n"
+ unless $::_q > 1;
+ $self->tmp_index_do(sub {
+ command_noisy('read-tree', $parent);
+ });
+ $self->{last_commit} = $parent;
+ } else {
+ print STDERR "Following parent with do_update\n"
+ unless $::_q > 1;
+ $ed = Git::SVN::Fetcher->new($self);
+ $self->ra->gs_do_update($rev, $rev, $self, $ed)
+ or die "SVN connection failed somewhere...\n";
+ }
+ print STDERR "Successfully followed parent\n" unless $::_q > 1;
+ return $self->make_log_entry($rev, [$parent], $ed);
+ }
+ return undef;
+}
+
+sub do_fetch {
+ my ($self, $paths, $rev) = @_;
+ my $ed;
+ my ($last_rev, @parents);
+ if (my $lc = $self->last_commit) {
+ # we can have a branch that was deleted, then re-added
+ # under the same name but copied from another path, in
+ # which case we'll have multiple parents (we don't
+ # want to break the original ref, nor lose copypath info):
+ if (my $log_entry = $self->find_parent_branch($paths, $rev)) {
+ push @{$log_entry->{parents}}, $lc;
+ return $log_entry;
+ }
+ $ed = Git::SVN::Fetcher->new($self);
+ $last_rev = $self->{last_rev};
+ $ed->{c} = $lc;
+ @parents = ($lc);
+ } else {
+ $last_rev = $rev;
+ if (my $log_entry = $self->find_parent_branch($paths, $rev)) {
+ return $log_entry;
+ }
+ $ed = Git::SVN::Fetcher->new($self);
+ }
+ unless ($self->ra->gs_do_update($last_rev, $rev, $self, $ed)) {
+ die "SVN connection failed somewhere...\n";
+ }
+ $self->make_log_entry($rev, \@parents, $ed);
+}
+
+sub mkemptydirs {
+ my ($self, $r) = @_;
+
+ sub scan {
+ my ($r, $empty_dirs, $line) = @_;
+ if (defined $r && $line =~ /^r(\d+)$/) {
+ return 0 if $1 > $r;
+ } elsif ($line =~ /^ \+empty_dir: (.+)$/) {
+ $empty_dirs->{$1} = 1;
+ } elsif ($line =~ /^ \-empty_dir: (.+)$/) {
+ my @d = grep {m[^\Q$1\E(/|$)]} (keys %$empty_dirs);
+ delete @$empty_dirs{@d};
+ }
+ 1; # continue
+ };
+
+ my %empty_dirs = ();
+ my $gz_file = "$self->{dir}/unhandled.log.gz";
+ if (-f $gz_file) {
+ if (!can_compress()) {
+ warn "Compress::Zlib could not be found; ",
+ "empty directories in $gz_file will not be read\n";
+ } else {
+ my $gz = Compress::Zlib::gzopen($gz_file, "rb") or
+ die "Unable to open $gz_file: $!\n";
+ my $line;
+ while ($gz->gzreadline($line) > 0) {
+ scan($r, \%empty_dirs, $line) or last;
+ }
+ $gz->gzclose;
+ }
+ }
+
+ if (open my $fh, '<', "$self->{dir}/unhandled.log") {
+ binmode $fh or croak "binmode: $!";
+ while (<$fh>) {
+ scan($r, \%empty_dirs, $_) or last;
+ }
+ close $fh;
+ }
+
+ my $strip = qr/\A\Q@{[$self->path]}\E(?:\/|$)/;
+ foreach my $d (sort keys %empty_dirs) {
+ $d = uri_decode($d);
+ $d =~ s/$strip//;
+ next unless length($d);
+ next if -d $d;
+ if (-e $d) {
+ warn "$d exists but is not a directory\n";
+ } else {
+ print "creating empty directory: $d\n";
+ mkpath([$d]);
+ }
+ }
+}
+
+sub get_untracked {
+ my ($self, $ed) = @_;
+ my @out;
+ my $h = $ed->{empty};
+ foreach (sort keys %$h) {
+ my $act = $h->{$_} ? '+empty_dir' : '-empty_dir';
+ push @out, " $act: " . uri_encode($_);
+ warn "W: $act: $_\n";
+ }
+ foreach my $t (qw/dir_prop file_prop/) {
+ $h = $ed->{$t} or next;
+ foreach my $path (sort keys %$h) {
+ my $ppath = $path eq '' ? '.' : $path;
+ foreach my $prop (sort keys %{$h->{$path}}) {
+ next if $SKIP_PROP{$prop};
+ my $v = $h->{$path}->{$prop};
+ my $t_ppath_prop = "$t: " .
+ uri_encode($ppath) . ' ' .
+ uri_encode($prop);
+ if (defined $v) {
+ push @out, " +$t_ppath_prop " .
+ uri_encode($v);
+ } else {
+ push @out, " -$t_ppath_prop";
+ }
+ }
+ }
+ }
+ foreach my $t (qw/absent_file absent_directory/) {
+ $h = $ed->{$t} or next;
+ foreach my $parent (sort keys %$h) {
+ foreach my $path (sort @{$h->{$parent}}) {
+ push @out, " $t: " .
+ uri_encode("$parent/$path");
+ warn "W: $t: $parent/$path ",
+ "Insufficient permissions?\n";
+ }
+ }
+ }
+ \@out;
+}
+
+sub get_tz {
+ # some systmes don't handle or mishandle %z, so be creative.
+ my $t = shift || time;
+ my $gm = timelocal(gmtime($t));
+ my $sign = qw( + + - )[ $t <=> $gm ];
+ return sprintf("%s%02d%02d", $sign, (gmtime(abs($t - $gm)))[2,1]);
+}
+
+# parse_svn_date(DATE)
+# --------------------
+# Given a date (in UTC) from Subversion, return a string in the format
+# "<TZ Offset> <local date/time>" that Git will use.
+#
+# By default the parsed date will be in UTC; if $Git::SVN::_localtime
+# is true we'll convert it to the local timezone instead.
+sub parse_svn_date {
+ my $date = shift || return '+0000 1970-01-01 00:00:00';
+ my ($Y,$m,$d,$H,$M,$S) = ($date =~ /^(\d{4})\-(\d\d)\-(\d\d)T
+ (\d\d)\:(\d\d)\:(\d\d)\.\d*Z$/x) or
+ croak "Unable to parse date: $date\n";
+ my $parsed_date; # Set next.
+
+ if ($Git::SVN::_localtime) {
+ # Translate the Subversion datetime to an epoch time.
+ # Begin by switching ourselves to $date's timezone, UTC.
+ my $old_env_TZ = $ENV{TZ};
+ $ENV{TZ} = 'UTC';
+
+ my $epoch_in_UTC =
+ POSIX::strftime('%s', $S, $M, $H, $d, $m - 1, $Y - 1900);
+
+ # Determine our local timezone (including DST) at the
+ # time of $epoch_in_UTC. $Git::SVN::Log::TZ stored the
+ # value of TZ, if any, at the time we were run.
+ if (defined $Git::SVN::Log::TZ) {
+ $ENV{TZ} = $Git::SVN::Log::TZ;
+ } else {
+ delete $ENV{TZ};
+ }
+
+ my $our_TZ = get_tz();
+
+ # This converts $epoch_in_UTC into our local timezone.
+ my ($sec, $min, $hour, $mday, $mon, $year,
+ $wday, $yday, $isdst) = localtime($epoch_in_UTC);
+
+ $parsed_date = sprintf('%s %04d-%02d-%02d %02d:%02d:%02d',
+ $our_TZ, $year + 1900, $mon + 1,
+ $mday, $hour, $min, $sec);
+
+ # Reset us to the timezone in effect when we entered
+ # this routine.
+ if (defined $old_env_TZ) {
+ $ENV{TZ} = $old_env_TZ;
+ } else {
+ delete $ENV{TZ};
+ }
+ } else {
+ $parsed_date = "+0000 $Y-$m-$d $H:$M:$S";
+ }
+
+ return $parsed_date;
+}
+
+sub other_gs {
+ my ($self, $new_url, $url,
+ $branch_from, $r, $old_ref_id) = @_;
+ my $gs = Git::SVN->find_by_url($new_url, $url, $branch_from);
+ unless ($gs) {
+ my $ref_id = $old_ref_id;
+ $ref_id =~ s/\@\d+-*$//;
+ $ref_id .= "\@$r";
+ # just grow a tail if we're not unique enough :x
+ $ref_id .= '-' while find_ref($ref_id);
+ my ($u, $p, $repo_id) = ($new_url, '', $ref_id);
+ if ($u =~ s#^\Q$url\E(/|$)##) {
+ $p = $u;
+ $u = $url;
+ $repo_id = $self->{repo_id};
+ }
+ while (1) {
+ # It is possible to tag two different subdirectories at
+ # the same revision. If the url for an existing ref
+ # does not match, we must either find a ref with a
+ # matching url or create a new ref by growing a tail.
+ $gs = Git::SVN->init($u, $p, $repo_id, $ref_id, 1);
+ my (undef, $max_commit) = $gs->rev_map_max(1);
+ last if (!$max_commit);
+ my ($url) = ::cmt_metadata($max_commit);
+ last if ($url eq $gs->metadata_url);
+ $ref_id .= '-';
+ }
+ print STDERR "Initializing parent: $ref_id\n" unless $::_q > 1;
+ }
+ $gs
+}
+
+sub call_authors_prog {
+ my ($orig_author) = @_;
+ $orig_author = command_oneline('rev-parse', '--sq-quote', $orig_author);
+ my $author = `$::_authors_prog $orig_author`;
+ if ($? != 0) {
+ die "$::_authors_prog failed with exit code $?\n"
+ }
+ if ($author =~ /^\s*(.+?)\s*<(.*)>\s*$/) {
+ my ($name, $email) = ($1, $2);
+ $email = undef if length $2 == 0;
+ return [$name, $email];
+ } else {
+ die "Author: $orig_author: $::_authors_prog returned "
+ . "invalid author format: $author\n";
+ }
+}
+
+sub check_author {
+ my ($author) = @_;
+ if (!defined $author || length $author == 0) {
+ $author = '(no author)';
+ }
+ if (!defined $::users{$author}) {
+ if (defined $::_authors_prog) {
+ $::users{$author} = call_authors_prog($author);
+ } elsif (defined $::_authors) {
+ die "Author: $author not defined in $::_authors file\n";
+ }
+ }
+ $author;
+}
+
+sub find_extra_svk_parents {
+ my ($self, $ed, $tickets, $parents) = @_;
+ # aha! svk:merge property changed...
+ my @tickets = split "\n", $tickets;
+ my @known_parents;
+ for my $ticket ( @tickets ) {
+ my ($uuid, $path, $rev) = split /:/, $ticket;
+ if ( $uuid eq $self->ra_uuid ) {
+ my $repos_root = $self->url;
+ my $branch_from = $path;
+ $branch_from =~ s{^/}{};
+ my $gs = $self->other_gs(add_path_to_url( $repos_root, $branch_from ),
+ $repos_root,
+ $branch_from,
+ $rev,
+ $self->{ref_id});
+ if ( my $commit = $gs->rev_map_get($rev, $uuid) ) {
+ # wahey! we found it, but it might be
+ # an old one (!)
+ push @known_parents, [ $rev, $commit ];
+ }
+ }
+ }
+ # Ordering matters; highest-numbered commit merge tickets
+ # first, as they may account for later merge ticket additions
+ # or changes.
+ @known_parents = map {$_->[1]} sort {$b->[0] <=> $a->[0]} @known_parents;
+ for my $parent ( @known_parents ) {
+ my @cmd = ('rev-list', $parent, map { "^$_" } @$parents );
+ my ($msg_fh, $ctx) = command_output_pipe(@cmd);
+ my $new;
+ while ( <$msg_fh> ) {
+ $new=1;last;
+ }
+ command_close_pipe($msg_fh, $ctx);
+ if ( $new ) {
+ print STDERR
+ "Found merge parent (svk:merge ticket): $parent\n";
+ push @$parents, $parent;
+ }
+ }
+}
+
+sub lookup_svn_merge {
+ my $uuid = shift;
+ my $url = shift;
+ my $merge = shift;
+
+ my ($source, $revs) = split ":", $merge;
+ my $path = $source;
+ $path =~ s{^/}{};
+ my $gs = Git::SVN->find_by_url($url.$source, $url, $path);
+ if ( !$gs ) {
+ warn "Couldn't find revmap for $url$source\n";
+ return;
+ }
+ my @ranges = split ",", $revs;
+ my ($tip, $tip_commit);
+ my @merged_commit_ranges;
+ # find the tip
+ for my $range ( @ranges ) {
+ my ($bottom, $top) = split "-", $range;
+ $top ||= $bottom;
+ my $bottom_commit = $gs->find_rev_after( $bottom, 1, $top );
+ my $top_commit = $gs->find_rev_before( $top, 1, $bottom );
+
+ unless ($top_commit and $bottom_commit) {
+ warn "W:unknown path/rev in svn:mergeinfo "
+ ."dirprop: $source:$range\n";
+ next;
+ }
+
+ if (scalar(command('rev-parse', "$bottom_commit^@"))) {
+ push @merged_commit_ranges,
+ "$bottom_commit^..$top_commit";
+ } else {
+ push @merged_commit_ranges, "$top_commit";
+ }
+
+ if ( !defined $tip or $top > $tip ) {
+ $tip = $top;
+ $tip_commit = $top_commit;
+ }
+ }
+ return ($tip_commit, @merged_commit_ranges);
+}
+
+sub _rev_list {
+ my ($msg_fh, $ctx) = command_output_pipe(
+ "rev-list", @_,
+ );
+ my @rv;
+ while ( <$msg_fh> ) {
+ chomp;
+ push @rv, $_;
+ }
+ command_close_pipe($msg_fh, $ctx);
+ @rv;
+}
+
+sub check_cherry_pick {
+ my $base = shift;
+ my $tip = shift;
+ my $parents = shift;
+ my @ranges = @_;
+ my %commits = map { $_ => 1 }
+ _rev_list("--no-merges", $tip, "--not", $base, @$parents, "--");
+ for my $range ( @ranges ) {
+ delete @commits{_rev_list($range, "--")};
+ }
+ for my $commit (keys %commits) {
+ if (has_no_changes($commit)) {
+ delete $commits{$commit};
+ }
+ }
+ return (keys %commits);
+}
+
+sub has_no_changes {
+ my $commit = shift;
+
+ my @revs = split / /, command_oneline(
+ qw(rev-list --parents -1 -m), $commit);
+
+ # Commits with no parents, e.g. the start of a partial branch,
+ # have changes by definition.
+ return 1 if (@revs < 2);
+
+ # Commits with multiple parents, e.g a merge, have no changes
+ # by definition.
+ return 0 if (@revs > 2);
+
+ return (command_oneline("rev-parse", "$commit^{tree}") eq
+ command_oneline("rev-parse", "$commit~1^{tree}"));
+}
+
+sub tie_for_persistent_memoization {
+ my $hash = shift;
+ my $path = shift;
+
+ if ($can_use_yaml) {
+ tie %$hash => 'Git::SVN::Memoize::YAML', "$path.yaml";
+ } else {
+ tie %$hash => 'Memoize::Storable', "$path.db", 'nstore';
+ }
+}
+
+# The GIT_DIR environment variable is not always set until after the command
+# line arguments are processed, so we can't memoize in a BEGIN block.
+{
+ my $memoized = 0;
+
+ sub memoize_svn_mergeinfo_functions {
+ return if $memoized;
+ $memoized = 1;
+
+ my $cache_path = "$ENV{GIT_DIR}/svn/.caches/";
+ mkpath([$cache_path]) unless -d $cache_path;
+
+ my %lookup_svn_merge_cache;
+ my %check_cherry_pick_cache;
+ my %has_no_changes_cache;
+
+ tie_for_persistent_memoization(\%lookup_svn_merge_cache,
+ "$cache_path/lookup_svn_merge");
+ memoize 'lookup_svn_merge',
+ SCALAR_CACHE => 'FAULT',
+ LIST_CACHE => ['HASH' => \%lookup_svn_merge_cache],
+ ;
+
+ tie_for_persistent_memoization(\%check_cherry_pick_cache,
+ "$cache_path/check_cherry_pick");
+ memoize 'check_cherry_pick',
+ SCALAR_CACHE => 'FAULT',
+ LIST_CACHE => ['HASH' => \%check_cherry_pick_cache],
+ ;
+
+ tie_for_persistent_memoization(\%has_no_changes_cache,
+ "$cache_path/has_no_changes");
+ memoize 'has_no_changes',
+ SCALAR_CACHE => ['HASH' => \%has_no_changes_cache],
+ LIST_CACHE => 'FAULT',
+ ;
+ }
+
+ sub unmemoize_svn_mergeinfo_functions {
+ return if not $memoized;
+ $memoized = 0;
+
+ Memoize::unmemoize 'lookup_svn_merge';
+ Memoize::unmemoize 'check_cherry_pick';
+ Memoize::unmemoize 'has_no_changes';
+ }
+
+ sub clear_memoized_mergeinfo_caches {
+ die "Only call this method in non-memoized context" if ($memoized);
+
+ my $cache_path = "$ENV{GIT_DIR}/svn/.caches/";
+ return unless -d $cache_path;
+
+ for my $cache_file (("$cache_path/lookup_svn_merge",
+ "$cache_path/check_cherry_pick",
+ "$cache_path/has_no_changes")) {
+ for my $suffix (qw(yaml db)) {
+ my $file = "$cache_file.$suffix";
+ next unless -e $file;
+ unlink($file) or die "unlink($file) failed: $!\n";
+ }
+ }
+ }
+
+
+ Memoize::memoize 'Git::SVN::repos_root';
+}
+
+END {
+ # Force cache writeout explicitly instead of waiting for
+ # global destruction to avoid segfault in Storable:
+ # http://rt.cpan.org/Public/Bug/Display.html?id=36087
+ unmemoize_svn_mergeinfo_functions();
+}
+
+sub parents_exclude {
+ my $parents = shift;
+ my @commits = @_;
+ return unless @commits;
+
+ my @excluded;
+ my $excluded;
+ do {
+ my @cmd = ('rev-list', "-1", @commits, "--not", @$parents );
+ $excluded = command_oneline(@cmd);
+ if ( $excluded ) {
+ my @new;
+ my $found;
+ for my $commit ( @commits ) {
+ if ( $commit eq $excluded ) {
+ push @excluded, $commit;
+ $found++;
+ }
+ else {
+ push @new, $commit;
+ }
+ }
+ die "saw commit '$excluded' in rev-list output, "
+ ."but we didn't ask for that commit (wanted: @commits --not @$parents)"
+ unless $found;
+ @commits = @new;
+ }
+ }
+ while ($excluded and @commits);
+
+ return @excluded;
+}
+
+
+# note: this function should only be called if the various dirprops
+# have actually changed
+sub find_extra_svn_parents {
+ my ($self, $ed, $mergeinfo, $parents) = @_;
+ # aha! svk:merge property changed...
+
+ memoize_svn_mergeinfo_functions();
+
+ # We first search for merged tips which are not in our
+ # history. Then, we figure out which git revisions are in
+ # that tip, but not this revision. If all of those revisions
+ # are now marked as merge, we can add the tip as a parent.
+ my @merges = split "\n", $mergeinfo;
+ my @merge_tips;
+ my $url = $self->url;
+ my $uuid = $self->ra_uuid;
+ my @all_ranges;
+ for my $merge ( @merges ) {
+ my ($tip_commit, @ranges) =
+ lookup_svn_merge( $uuid, $url, $merge );
+ unless (!$tip_commit or
+ grep { $_ eq $tip_commit } @$parents ) {
+ push @merge_tips, $tip_commit;
+ push @all_ranges, @ranges;
+ } else {
+ push @merge_tips, undef;
+ }
+ }
+
+ my %excluded = map { $_ => 1 }
+ parents_exclude($parents, grep { defined } @merge_tips);
+
+ # check merge tips for new parents
+ my @new_parents;
+ for my $merge_tip ( @merge_tips ) {
+ my $spec = shift @merges;
+ next unless $merge_tip and $excluded{$merge_tip};
+
+ # check out 'new' tips
+ my $merge_base;
+ eval {
+ $merge_base = command_oneline(
+ "merge-base",
+ @$parents, $merge_tip,
+ );
+ };
+ if ($@) {
+ die "An error occurred during merge-base"
+ unless $@->isa("Git::Error::Command");
+
+ warn "W: Cannot find common ancestor between ".
+ "@$parents and $merge_tip. Ignoring merge info.\n";
+ next;
+ }
+
+ # double check that there are no missing non-merge commits
+ my (@incomplete) = check_cherry_pick(
+ $merge_base, $merge_tip,
+ $parents,
+ @all_ranges,
+ );
+
+ if ( @incomplete ) {
+ warn "W:svn cherry-pick ignored ($spec) - missing "
+ .@incomplete." commit(s) (eg $incomplete[0])\n";
+ } else {
+ warn
+ "Found merge parent (svn:mergeinfo prop): ",
+ $merge_tip, "\n";
+ push @new_parents, $merge_tip;
+ }
+ }
+
+ # cater for merges which merge commits from multiple branches
+ if ( @new_parents > 1 ) {
+ for ( my $i = 0; $i <= $#new_parents; $i++ ) {
+ for ( my $j = 0; $j <= $#new_parents; $j++ ) {
+ next if $i == $j;
+ next unless $new_parents[$i];
+ next unless $new_parents[$j];
+ my $revs = command_oneline(
+ "rev-list", "-1",
+ "$new_parents[$i]..$new_parents[$j]",
+ );
+ if ( !$revs ) {
+ undef($new_parents[$j]);
+ }
+ }
+ }
+ }
+ push @$parents, grep { defined } @new_parents;
+}
+
+sub make_log_entry {
+ my ($self, $rev, $parents, $ed) = @_;
+ my $untracked = $self->get_untracked($ed);
+
+ my @parents = @$parents;
+ my $ps = $ed->{path_strip} || "";
+ for my $path ( grep { m/$ps/ } %{$ed->{dir_prop}} ) {
+ my $props = $ed->{dir_prop}{$path};
+ if ( $props->{"svk:merge"} ) {
+ $self->find_extra_svk_parents
+ ($ed, $props->{"svk:merge"}, \@parents);
+ }
+ if ( $props->{"svn:mergeinfo"} ) {
+ $self->find_extra_svn_parents
+ ($ed,
+ $props->{"svn:mergeinfo"},
+ \@parents);
+ }
+ }
+
+ open my $un, '>>', "$self->{dir}/unhandled.log" or croak $!;
+ print $un "r$rev\n" or croak $!;
+ print $un $_, "\n" foreach @$untracked;
+ my %log_entry = ( parents => \@parents, revision => $rev,
+ log => '');
+
+ my $headrev;
+ my $logged = delete $self->{logged_rev_props};
+ if (!$logged || $self->{-want_revprops}) {
+ my $rp = $self->ra->rev_proplist($rev);
+ foreach (sort keys %$rp) {
+ my $v = $rp->{$_};
+ if (/^svn:(author|date|log)$/) {
+ $log_entry{$1} = $v;
+ } elsif ($_ eq 'svm:headrev') {
+ $headrev = $v;
+ } else {
+ print $un " rev_prop: ", uri_encode($_), ' ',
+ uri_encode($v), "\n";
+ }
+ }
+ } else {
+ map { $log_entry{$_} = $logged->{$_} } keys %$logged;
+ }
+ close $un or croak $!;
+
+ $log_entry{date} = parse_svn_date($log_entry{date});
+ $log_entry{log} .= "\n";
+ my $author = $log_entry{author} = check_author($log_entry{author});
+ my ($name, $email) = defined $::users{$author} ? @{$::users{$author}}
+ : ($author, undef);
+
+ my ($commit_name, $commit_email) = ($name, $email);
+ if ($_use_log_author) {
+ my $name_field;
+ if ($log_entry{log} =~ /From:\s+(.*\S)\s*\n/i) {
+ $name_field = $1;
+ } elsif ($log_entry{log} =~ /Signed-off-by:\s+(.*\S)\s*\n/i) {
+ $name_field = $1;
+ }
+ if (!defined $name_field) {
+ if (!defined $email) {
+ $email = $name;
+ }
+ } elsif ($name_field =~ /(.*?)\s+<(.*)>/) {
+ ($name, $email) = ($1, $2);
+ } elsif ($name_field =~ /(.*)@/) {
+ ($name, $email) = ($1, $name_field);
+ } else {
+ ($name, $email) = ($name_field, $name_field);
+ }
+ }
+ if (defined $headrev && $self->use_svm_props) {
+ if ($self->rewrite_root) {
+ die "Can't have both 'useSvmProps' and 'rewriteRoot' ",
+ "options set!\n";
+ }
+ if ($self->rewrite_uuid) {
+ die "Can't have both 'useSvmProps' and 'rewriteUUID' ",
+ "options set!\n";
+ }
+ my ($uuid, $r) = $headrev =~ m{^([a-f\d\-]{30,}):(\d+)$}i;
+ # we don't want "SVM: initializing mirror for junk" ...
+ return undef if $r == 0;
+ my $svm = $self->svm;
+ if ($uuid ne $svm->{uuid}) {
+ die "UUID mismatch on SVM path:\n",
+ "expected: $svm->{uuid}\n",
+ " got: $uuid\n";
+ }
+ my $full_url = $self->full_url;
+ $full_url =~ s#^\Q$svm->{replace}\E(/|$)#$svm->{source}$1# or
+ die "Failed to replace '$svm->{replace}' with ",
+ "'$svm->{source}' in $full_url\n";
+ # throw away username for storing in records
+ remove_username($full_url);
+ $log_entry{metadata} = "$full_url\@$r $uuid";
+ $log_entry{svm_revision} = $r;
+ $email ||= "$author\@$uuid";
+ $commit_email ||= "$author\@$uuid";
+ } elsif ($self->use_svnsync_props) {
+ my $full_url = canonicalize_url(
+ add_path_to_url( $self->svnsync->{url}, $self->path )
+ );
+ remove_username($full_url);
+ my $uuid = $self->svnsync->{uuid};
+ $log_entry{metadata} = "$full_url\@$rev $uuid";
+ $email ||= "$author\@$uuid";
+ $commit_email ||= "$author\@$uuid";
+ } else {
+ my $url = $self->metadata_url;
+ remove_username($url);
+ my $uuid = $self->rewrite_uuid || $self->ra->get_uuid;
+ $log_entry{metadata} = "$url\@$rev " . $uuid;
+ $email ||= "$author\@" . $uuid;
+ $commit_email ||= "$author\@" . $uuid;
+ }
+ $log_entry{name} = $name;
+ $log_entry{email} = $email;
+ $log_entry{commit_name} = $commit_name;
+ $log_entry{commit_email} = $commit_email;
+ \%log_entry;
+}
+
+sub fetch {
+ my ($self, $min_rev, $max_rev, @parents) = @_;
+ my ($last_rev, $last_commit) = $self->last_rev_commit;
+ my ($base, $head) = $self->get_fetch_range($min_rev, $max_rev);
+ $self->ra->gs_fetch_loop_common($base, $head, [$self]);
+}
+
+sub set_tree_cb {
+ my ($self, $log_entry, $tree, $rev, $date, $author) = @_;
+ $self->{inject_parents} = { $rev => $tree };
+ $self->fetch(undef, undef);
+}
+
+sub set_tree {
+ my ($self, $tree) = (shift, shift);
+ my $log_entry = ::get_commit_entry($tree);
+ unless ($self->{last_rev}) {
+ fatal("Must have an existing revision to commit");
+ }
+ my %ed_opts = ( r => $self->{last_rev},
+ log => $log_entry->{log},
+ ra => $self->ra,
+ tree_a => $self->{last_commit},
+ tree_b => $tree,
+ editor_cb => sub {
+ $self->set_tree_cb($log_entry, $tree, @_) },
+ svn_path => $self->path );
+ if (!Git::SVN::Editor->new(\%ed_opts)->apply_diff) {
+ print "No changes\nr$self->{last_rev} = $tree\n";
+ }
+}
+
+sub rebuild_from_rev_db {
+ my ($self, $path) = @_;
+ my $r = -1;
+ open my $fh, '<', $path or croak "open: $!";
+ binmode $fh or croak "binmode: $!";
+ while (<$fh>) {
+ length($_) == 41 or croak "inconsistent size in ($_) != 41";
+ chomp($_);
+ ++$r;
+ next if $_ eq ('0' x 40);
+ $self->rev_map_set($r, $_);
+ print "r$r = $_\n";
+ }
+ close $fh or croak "close: $!";
+ unlink $path or croak "unlink: $!";
+}
+
+sub rebuild {
+ my ($self) = @_;
+ my $map_path = $self->map_path;
+ my $partial = (-e $map_path && ! -z $map_path);
+ return unless ::verify_ref($self->refname.'^0');
+ if (!$partial && ($self->use_svm_props || $self->no_metadata)) {
+ my $rev_db = $self->rev_db_path;
+ $self->rebuild_from_rev_db($rev_db);
+ if ($self->use_svm_props) {
+ my $svm_rev_db = $self->rev_db_path($self->svm_uuid);
+ $self->rebuild_from_rev_db($svm_rev_db);
+ }
+ $self->unlink_rev_db_symlink;
+ return;
+ }
+ print "Rebuilding $map_path ...\n" if (!$partial);
+ my ($base_rev, $head) = ($partial ? $self->rev_map_max_norebuild(1) :
+ (undef, undef));
+ my ($log, $ctx) =
+ command_output_pipe(qw/rev-list --pretty=raw --reverse/,
+ ($head ? "$head.." : "") . $self->refname,
+ '--');
+ my $metadata_url = $self->metadata_url;
+ remove_username($metadata_url);
+ my $svn_uuid = $self->rewrite_uuid || $self->ra_uuid;
+ my $c;
+ while (<$log>) {
+ if ( m{^commit ($::sha1)$} ) {
+ $c = $1;
+ next;
+ }
+ next unless s{^\s*(git-svn-id:)}{$1};
+ my ($url, $rev, $uuid) = ::extract_metadata($_);
+ remove_username($url);
+
+ # ignore merges (from set-tree)
+ next if (!defined $rev || !$uuid);
+
+ # if we merged or otherwise started elsewhere, this is
+ # how we break out of it
+ if (($uuid ne $svn_uuid) ||
+ ($metadata_url && $url && ($url ne $metadata_url))) {
+ next;
+ }
+ if ($partial && $head) {
+ print "Partial-rebuilding $map_path ...\n";
+ print "Currently at $base_rev = $head\n";
+ $head = undef;
+ }
+
+ $self->rev_map_set($rev, $c);
+ print "r$rev = $c\n";
+ }
+ command_close_pipe($log, $ctx);
+ print "Done rebuilding $map_path\n" if (!$partial || !$head);
+ my $rev_db_path = $self->rev_db_path;
+ if (-f $self->rev_db_path) {
+ unlink $self->rev_db_path or croak "unlink: $!";
+ }
+ $self->unlink_rev_db_symlink;
+}
+
+# rev_map:
+# Tie::File seems to be prone to offset errors if revisions get sparse,
+# it's not that fast, either. Tie::File is also not in Perl 5.6. So
+# one of my favorite modules is out :< Next up would be one of the DBM
+# modules, but I'm not sure which is most portable...
+#
+# This is the replacement for the rev_db format, which was too big
+# and inefficient for large repositories with a lot of sparse history
+# (mainly tags)
+#
+# The format is this:
+# - 24 bytes for every record,
+# * 4 bytes for the integer representing an SVN revision number
+# * 20 bytes representing the sha1 of a git commit
+# - No empty padding records like the old format
+# (except the last record, which can be overwritten)
+# - new records are written append-only since SVN revision numbers
+# increase monotonically
+# - lookups on SVN revision number are done via a binary search
+# - Piping the file to xxd -c24 is a good way of dumping it for
+# viewing or editing (piped back through xxd -r), should the need
+# ever arise.
+# - The last record can be padding revision with an all-zero sha1
+# This is used to optimize fetch performance when using multiple
+# "fetch" directives in .git/config
+#
+# These files are disposable unless noMetadata or useSvmProps is set
+
+sub _rev_map_set {
+ my ($fh, $rev, $commit) = @_;
+
+ binmode $fh or croak "binmode: $!";
+ my $size = (stat($fh))[7];
+ ($size % 24) == 0 or croak "inconsistent size: $size";
+
+ my $wr_offset = 0;
+ if ($size > 0) {
+ sysseek($fh, -24, SEEK_END) or croak "seek: $!";
+ my $read = sysread($fh, my $buf, 24) or croak "read: $!";
+ $read == 24 or croak "read only $read bytes (!= 24)";
+ my ($last_rev, $last_commit) = unpack(rev_map_fmt, $buf);
+ if ($last_commit eq ('0' x40)) {
+ if ($size >= 48) {
+ sysseek($fh, -48, SEEK_END) or croak "seek: $!";
+ $read = sysread($fh, $buf, 24) or
+ croak "read: $!";
+ $read == 24 or
+ croak "read only $read bytes (!= 24)";
+ ($last_rev, $last_commit) =
+ unpack(rev_map_fmt, $buf);
+ if ($last_commit eq ('0' x40)) {
+ croak "inconsistent .rev_map\n";
+ }
+ }
+ if ($last_rev >= $rev) {
+ croak "last_rev is higher!: $last_rev >= $rev";
+ }
+ $wr_offset = -24;
+ }
+ }
+ sysseek($fh, $wr_offset, SEEK_END) or croak "seek: $!";
+ syswrite($fh, pack(rev_map_fmt, $rev, $commit), 24) == 24 or
+ croak "write: $!";
+}
+
+sub _rev_map_reset {
+ my ($fh, $rev, $commit) = @_;
+ my $c = _rev_map_get($fh, $rev);
+ $c eq $commit or die "_rev_map_reset(@_) commit $c does not match!\n";
+ my $offset = sysseek($fh, 0, SEEK_CUR) or croak "seek: $!";
+ truncate $fh, $offset or croak "truncate: $!";
+}
+
+sub mkfile {
+ my ($path) = @_;
+ unless (-e $path) {
+ my ($dir, $base) = ($path =~ m#^(.*?)/?([^/]+)$#);
+ mkpath([$dir]) unless -d $dir;
+ open my $fh, '>>', $path or die "Couldn't create $path: $!\n";
+ close $fh or die "Couldn't close (create) $path: $!\n";
+ }
+}
+
+sub rev_map_set {
+ my ($self, $rev, $commit, $update_ref, $uuid) = @_;
+ defined $commit or die "missing arg3\n";
+ length $commit == 40 or die "arg3 must be a full SHA1 hexsum\n";
+ my $db = $self->map_path($uuid);
+ my $db_lock = "$db.lock";
+ my $sigmask;
+ $update_ref ||= 0;
+ if ($update_ref) {
+ $sigmask = POSIX::SigSet->new();
+ my $signew = POSIX::SigSet->new(SIGINT, SIGHUP, SIGTERM,
+ SIGALRM, SIGUSR1, SIGUSR2);
+ sigprocmask(SIG_BLOCK, $signew, $sigmask) or
+ croak "Can't block signals: $!";
+ }
+ mkfile($db);
+
+ $LOCKFILES{$db_lock} = 1;
+ my $sync;
+ # both of these options make our .rev_db file very, very important
+ # and we can't afford to lose it because rebuild() won't work
+ if ($self->use_svm_props || $self->no_metadata) {
+ $sync = 1;
+ copy($db, $db_lock) or die "rev_map_set(@_): ",
+ "Failed to copy: ",
+ "$db => $db_lock ($!)\n";
+ } else {
+ rename $db, $db_lock or die "rev_map_set(@_): ",
+ "Failed to rename: ",
+ "$db => $db_lock ($!)\n";
+ }
+
+ sysopen(my $fh, $db_lock, O_RDWR | O_CREAT)
+ or croak "Couldn't open $db_lock: $!\n";
+ if ($update_ref eq 'reset') {
+ clear_memoized_mergeinfo_caches();
+ _rev_map_reset($fh, $rev, $commit);
+ } else {
+ _rev_map_set($fh, $rev, $commit);
+ }
+
+ if ($sync) {
+ $fh->flush or die "Couldn't flush $db_lock: $!\n";
+ $fh->sync or die "Couldn't sync $db_lock: $!\n";
+ }
+ close $fh or croak $!;
+ if ($update_ref) {
+ $_head = $self;
+ my $note = "";
+ $note = " ($update_ref)" if ($update_ref !~ /^\d*$/);
+ command_noisy('update-ref', '-m', "r$rev$note",
+ $self->refname, $commit);
+ }
+ rename $db_lock, $db or die "rev_map_set(@_): ", "Failed to rename: ",
+ "$db_lock => $db ($!)\n";
+ delete $LOCKFILES{$db_lock};
+ if ($update_ref) {
+ sigprocmask(SIG_SETMASK, $sigmask) or
+ croak "Can't restore signal mask: $!";
+ }
+}
+
+# If want_commit, this will return an array of (rev, commit) where
+# commit _must_ be a valid commit in the archive.
+# Otherwise, it'll return the max revision (whether or not the
+# commit is valid or just a 0x40 placeholder).
+sub rev_map_max {
+ my ($self, $want_commit) = @_;
+ $self->rebuild;
+ my ($r, $c) = $self->rev_map_max_norebuild($want_commit);
+ $want_commit ? ($r, $c) : $r;
+}
+
+sub rev_map_max_norebuild {
+ my ($self, $want_commit) = @_;
+ my $map_path = $self->map_path;
+ stat $map_path or return $want_commit ? (0, undef) : 0;
+ sysopen(my $fh, $map_path, O_RDONLY) or croak "open: $!";
+ binmode $fh or croak "binmode: $!";
+ my $size = (stat($fh))[7];
+ ($size % 24) == 0 or croak "inconsistent size: $size";
+
+ if ($size == 0) {
+ close $fh or croak "close: $!";
+ return $want_commit ? (0, undef) : 0;
+ }
+
+ sysseek($fh, -24, SEEK_END) or croak "seek: $!";
+ sysread($fh, my $buf, 24) == 24 or croak "read: $!";
+ my ($r, $c) = unpack(rev_map_fmt, $buf);
+ if ($want_commit && $c eq ('0' x40)) {
+ if ($size < 48) {
+ return $want_commit ? (0, undef) : 0;
+ }
+ sysseek($fh, -48, SEEK_END) or croak "seek: $!";
+ sysread($fh, $buf, 24) == 24 or croak "read: $!";
+ ($r, $c) = unpack(rev_map_fmt, $buf);
+ if ($c eq ('0'x40)) {
+ croak "Penultimate record is all-zeroes in $map_path";
+ }
+ }
+ close $fh or croak "close: $!";
+ $want_commit ? ($r, $c) : $r;
+}
+
+sub rev_map_get {
+ my ($self, $rev, $uuid) = @_;
+ my $map_path = $self->map_path($uuid);
+ return undef unless -e $map_path;
+
+ sysopen(my $fh, $map_path, O_RDONLY) or croak "open: $!";
+ my $c = _rev_map_get($fh, $rev);
+ close($fh) or croak "close: $!";
+ $c
+}
+
+sub _rev_map_get {
+ my ($fh, $rev) = @_;
+
+ binmode $fh or croak "binmode: $!";
+ my $size = (stat($fh))[7];
+ ($size % 24) == 0 or croak "inconsistent size: $size";
+
+ if ($size == 0) {
+ return undef;
+ }
+
+ my ($l, $u) = (0, $size - 24);
+ my ($r, $c, $buf);
+
+ while ($l <= $u) {
+ my $i = int(($l/24 + $u/24) / 2) * 24;
+ sysseek($fh, $i, SEEK_SET) or croak "seek: $!";
+ sysread($fh, my $buf, 24) == 24 or croak "read: $!";
+ my ($r, $c) = unpack(rev_map_fmt, $buf);
+
+ if ($r < $rev) {
+ $l = $i + 24;
+ } elsif ($r > $rev) {
+ $u = $i - 24;
+ } else { # $r == $rev
+ return $c eq ('0' x 40) ? undef : $c;
+ }
+ }
+ undef;
+}
+
+# Finds the first svn revision that exists on (if $eq_ok is true) or
+# before $rev for the current branch. It will not search any lower
+# than $min_rev. Returns the git commit hash and svn revision number
+# if found, else (undef, undef).
+sub find_rev_before {
+ my ($self, $rev, $eq_ok, $min_rev) = @_;
+ --$rev unless $eq_ok;
+ $min_rev ||= 1;
+ my $max_rev = $self->rev_map_max;
+ $rev = $max_rev if ($rev > $max_rev);
+ while ($rev >= $min_rev) {
+ if (my $c = $self->rev_map_get($rev)) {
+ return ($rev, $c);
+ }
+ --$rev;
+ }
+ return (undef, undef);
+}
+
+# Finds the first svn revision that exists on (if $eq_ok is true) or
+# after $rev for the current branch. It will not search any higher
+# than $max_rev. Returns the git commit hash and svn revision number
+# if found, else (undef, undef).
+sub find_rev_after {
+ my ($self, $rev, $eq_ok, $max_rev) = @_;
+ ++$rev unless $eq_ok;
+ $max_rev ||= $self->rev_map_max;
+ while ($rev <= $max_rev) {
+ if (my $c = $self->rev_map_get($rev)) {
+ return ($rev, $c);
+ }
+ ++$rev;
+ }
+ return (undef, undef);
+}
+
+sub _new {
+ my ($class, $repo_id, $ref_id, $path) = @_;
+ unless (defined $repo_id && length $repo_id) {
+ $repo_id = $default_repo_id;
+ }
+ unless (defined $ref_id && length $ref_id) {
+ # Access the prefix option from the git-svn main program if it's loaded.
+ my $prefix = defined &::opt_prefix ? ::opt_prefix() : "";
+ $_[2] = $ref_id =
+ "refs/remotes/$prefix$default_ref_id";
+ }
+ $_[1] = $repo_id;
+ my $dir = "$ENV{GIT_DIR}/svn/$ref_id";
+
+ # Older repos imported by us used $GIT_DIR/svn/foo instead of
+ # $GIT_DIR/svn/refs/remotes/foo when tracking refs/remotes/foo
+ if ($ref_id =~ m{^refs/remotes/(.*)}) {
+ my $old_dir = "$ENV{GIT_DIR}/svn/$1";
+ if (-d $old_dir && ! -d $dir) {
+ $dir = $old_dir;
+ }
+ }
+
+ $_[3] = $path = '' unless (defined $path);
+ mkpath([$dir]);
+ my $obj = bless {
+ ref_id => $ref_id, dir => $dir, index => "$dir/index",
+ config => "$ENV{GIT_DIR}/svn/config",
+ map_root => "$dir/.rev_map", repo_id => $repo_id }, $class;
+
+ # Ensure it gets canonicalized
+ $obj->path($path);
+
+ return $obj;
+}
+
+sub path {
+ my $self = shift;
+
+ if (@_) {
+ my $path = shift;
+ $self->{_path} = canonicalize_path($path);
+ return;
+ }
+
+ return $self->{_path};
+}
+
+sub url {
+ my $self = shift;
+
+ if (@_) {
+ my $url = shift;
+ $self->{url} = canonicalize_url($url);
+ return;
+ }
+
+ return $self->{url};
+}
+
+# for read-only access of old .rev_db formats
+sub unlink_rev_db_symlink {
+ my ($self) = @_;
+ my $link = $self->rev_db_path;
+ $link =~ s/\.[\w-]+$// or croak "missing UUID at the end of $link";
+ if (-l $link) {
+ unlink $link or croak "unlink: $link failed!";
+ }
+}
+
+sub rev_db_path {
+ my ($self, $uuid) = @_;
+ my $db_path = $self->map_path($uuid);
+ $db_path =~ s{/\.rev_map\.}{/\.rev_db\.}
+ or croak "map_path: $db_path does not contain '/.rev_map.' !";
+ $db_path;
+}
+
+# the new replacement for .rev_db
+sub map_path {
+ my ($self, $uuid) = @_;
+ $uuid ||= $self->ra_uuid;
+ "$self->{map_root}.$uuid";
+}
+
+sub uri_encode {
+ my ($f) = @_;
+ $f =~ s#([^a-zA-Z0-9\*!\:_\./\-])#uc sprintf("%%%02x",ord($1))#eg;
+ $f
+}
+
+sub uri_decode {
+ my ($f) = @_;
+ $f =~ s#%([0-9a-fA-F]{2})#chr(hex($1))#eg;
+ $f
+}
+
+sub remove_username {
+ $_[0] =~ s{^([^:]*://)[^@]+@}{$1};
+}
+
+1;
diff --git a/perl/Git/SVN/Editor.pm b/perl/Git/SVN/Editor.pm
index 755092f..3bbc20a 100644
--- a/perl/Git/SVN/Editor.pm
+++ b/perl/Git/SVN/Editor.pm
@@ -345,7 +345,30 @@ sub M {
$self->close_file($fbat,undef,$self->{pool});
}
-sub T { shift->M(@_) }
+sub T {
+ my ($self, $m, $deletions) = @_;
+
+ # Work around subversion issue 4091: toggling the "is a
+ # symlink" property requires removing and re-adding a
+ # file or else "svn up" on affected clients trips an
+ # assertion and aborts.
+ if (($m->{mode_b} =~ /^120/ && $m->{mode_a} !~ /^120/) ||
+ ($m->{mode_b} !~ /^120/ && $m->{mode_a} =~ /^120/)) {
+ $self->D({
+ mode_a => $m->{mode_a}, mode_b => '000000',
+ sha1_a => $m->{sha1_a}, sha1_b => '0' x 40,
+ chg => 'D', file_b => $m->{file_b}
+ });
+ $self->A({
+ mode_a => '000000', mode_b => $m->{mode_b},
+ sha1_a => '0' x 40, sha1_b => $m->{sha1_b},
+ chg => 'A', file_b => $m->{file_b}
+ });
+ return;
+ }
+
+ $self->M($m, $deletions);
+}
sub change_file_prop {
my ($self, $fbat, $pname, $pval) = @_;
diff --git a/perl/Git/SVN/Fetcher.pm b/perl/Git/SVN/Fetcher.pm
index ef8e9ed..046a7a2 100644
--- a/perl/Git/SVN/Fetcher.pm
+++ b/perl/Git/SVN/Fetcher.pm
@@ -57,6 +57,7 @@ sub new {
$self->{file_prop} = {};
$self->{absent_dir} = {};
$self->{absent_file} = {};
+ require Git::IndexInfo;
$self->{gii} = $git_svn->tmp_index_do(sub { Git::IndexInfo->new });
$self->{pathnameencoding} = Git::config('svn.pathnameencoding');
$self;
@@ -82,7 +83,7 @@ sub _mark_empty_symlinks {
chomp(my $empty_blob = `git hash-object -t blob --stdin < /dev/null`);
my ($ls, $ctx) = command_output_pipe(qw/ls-tree -r -z/, $cmt);
local $/ = "\0";
- my $pfx = defined($switch_path) ? $switch_path : $git_svn->{path};
+ my $pfx = defined($switch_path) ? $switch_path : $git_svn->path;
$pfx .= '/' if length($pfx);
while (<$ls>) {
chomp;
diff --git a/perl/Git/SVN/GlobSpec.pm b/perl/Git/SVN/GlobSpec.pm
new file mode 100644
index 0000000..c95f5d7
--- /dev/null
+++ b/perl/Git/SVN/GlobSpec.pm
@@ -0,0 +1,61 @@
+package Git::SVN::GlobSpec;
+use strict;
+use warnings;
+
+sub new {
+ my ($class, $glob, $pattern_ok) = @_;
+ my $re = $glob;
+ $re =~ s!/+$!!g; # no need for trailing slashes
+ my (@left, @right, @patterns);
+ my $state = "left";
+ my $die_msg = "Only one set of wildcard directories " .
+ "(e.g. '*' or '*/*/*') is supported: '$glob'\n";
+ for my $part (split(m|/|, $glob)) {
+ if ($part =~ /\*/ && $part ne "*") {
+ die "Invalid pattern in '$glob': $part\n";
+ } elsif ($pattern_ok && $part =~ /[{}]/ &&
+ $part !~ /^\{[^{}]+\}/) {
+ die "Invalid pattern in '$glob': $part\n";
+ }
+ if ($part eq "*") {
+ die $die_msg if $state eq "right";
+ $state = "pattern";
+ push(@patterns, "[^/]*");
+ } elsif ($pattern_ok && $part =~ /^\{(.*)\}$/) {
+ die $die_msg if $state eq "right";
+ $state = "pattern";
+ my $p = quotemeta($1);
+ $p =~ s/\\,/|/g;
+ push(@patterns, "(?:$p)");
+ } else {
+ if ($state eq "left") {
+ push(@left, $part);
+ } else {
+ push(@right, $part);
+ $state = "right";
+ }
+ }
+ }
+ my $depth = @patterns;
+ if ($depth == 0) {
+ die "One '*' is needed in glob: '$glob'\n";
+ }
+ my $left = join('/', @left);
+ my $right = join('/', @right);
+ $re = join('/', @patterns);
+ $re = join('\/',
+ grep(length, quotemeta($left),
+ "($re)(?=/|\$)",
+ quotemeta($right)));
+ my $left_re = qr/^\/\Q$left\E(\/|$)/;
+ bless { left => $left, right => $right, left_regex => $left_re,
+ regex => qr/$re/, glob => $glob, depth => $depth }, $class;
+}
+
+sub full_path {
+ my ($self, $path) = @_;
+ return (length $self->{left} ? "$self->{left}/" : '') .
+ $path . (length $self->{right} ? "/$self->{right}" : '');
+}
+
+1;
diff --git a/perl/Git/SVN/Log.pm b/perl/Git/SVN/Log.pm
new file mode 100644
index 0000000..3cc1c6f
--- /dev/null
+++ b/perl/Git/SVN/Log.pm
@@ -0,0 +1,395 @@
+package Git::SVN::Log;
+use strict;
+use warnings;
+use Git::SVN::Utils qw(fatal);
+use Git qw(command command_oneline command_output_pipe command_close_pipe);
+use POSIX qw/strftime/;
+use constant commit_log_separator => ('-' x 72) . "\n";
+use vars qw/$TZ $limit $color $pager $non_recursive $verbose $oneline
+ %rusers $show_commit $incremental/;
+
+# Option set in git-svn
+our $_git_format;
+
+sub cmt_showable {
+ my ($c) = @_;
+ return 1 if defined $c->{r};
+
+ # big commit message got truncated by the 16k pretty buffer in rev-list
+ if ($c->{l} && $c->{l}->[-1] eq "...\n" &&
+ $c->{a_raw} =~ /\@([a-f\d\-]+)>$/) {
+ @{$c->{l}} = ();
+ my @log = command(qw/cat-file commit/, $c->{c});
+
+ # shift off the headers
+ shift @log while ($log[0] ne '');
+ shift @log;
+
+ # TODO: make $c->{l} not have a trailing newline in the future
+ @{$c->{l}} = map { "$_\n" } grep !/^git-svn-id: /, @log;
+
+ (undef, $c->{r}, undef) = ::extract_metadata(
+ (grep(/^git-svn-id: /, @log))[-1]);
+ }
+ return defined $c->{r};
+}
+
+sub log_use_color {
+ return $color || Git->repository->get_colorbool('color.diff');
+}
+
+sub git_svn_log_cmd {
+ my ($r_min, $r_max, @args) = @_;
+ my $head = 'HEAD';
+ my (@files, @log_opts);
+ foreach my $x (@args) {
+ if ($x eq '--' || @files) {
+ push @files, $x;
+ } else {
+ if (::verify_ref("$x^0")) {
+ $head = $x;
+ } else {
+ push @log_opts, $x;
+ }
+ }
+ }
+
+ my ($url, $rev, $uuid, $gs) = ::working_head_info($head);
+
+ require Git::SVN;
+ $gs ||= Git::SVN->_new;
+ my @cmd = (qw/log --abbrev-commit --pretty=raw --default/,
+ $gs->refname);
+ push @cmd, '-r' unless $non_recursive;
+ push @cmd, qw/--raw --name-status/ if $verbose;
+ push @cmd, '--color' if log_use_color();
+ push @cmd, @log_opts;
+ if (defined $r_max && $r_max == $r_min) {
+ push @cmd, '--max-count=1';
+ if (my $c = $gs->rev_map_get($r_max)) {
+ push @cmd, $c;
+ }
+ } elsif (defined $r_max) {
+ if ($r_max < $r_min) {
+ ($r_min, $r_max) = ($r_max, $r_min);
+ }
+ my (undef, $c_max) = $gs->find_rev_before($r_max, 1, $r_min);
+ my (undef, $c_min) = $gs->find_rev_after($r_min, 1, $r_max);
+ # If there are no commits in the range, both $c_max and $c_min
+ # will be undefined. If there is at least 1 commit in the
+ # range, both will be defined.
+ return () if !defined $c_min || !defined $c_max;
+ if ($c_min eq $c_max) {
+ push @cmd, '--max-count=1', $c_min;
+ } else {
+ push @cmd, '--boundary', "$c_min..$c_max";
+ }
+ }
+ return (@cmd, @files);
+}
+
+# adapted from pager.c
+sub config_pager {
+ if (! -t *STDOUT) {
+ $ENV{GIT_PAGER_IN_USE} = 'false';
+ $pager = undef;
+ return;
+ }
+ chomp($pager = command_oneline(qw(var GIT_PAGER)));
+ if ($pager eq 'cat') {
+ $pager = undef;
+ }
+ $ENV{GIT_PAGER_IN_USE} = defined($pager);
+}
+
+sub run_pager {
+ return unless defined $pager;
+ pipe my ($rfd, $wfd) or return;
+ defined(my $pid = fork) or fatal "Can't fork: $!";
+ if (!$pid) {
+ open STDOUT, '>&', $wfd or
+ fatal "Can't redirect to stdout: $!";
+ return;
+ }
+ open STDIN, '<&', $rfd or fatal "Can't redirect stdin: $!";
+ $ENV{LESS} ||= 'FRSX';
+ exec $pager or fatal "Can't run pager: $! ($pager)";
+}
+
+sub format_svn_date {
+ my $t = shift || time;
+ require Git::SVN;
+ my $gmoff = Git::SVN::get_tz($t);
+ return strftime("%Y-%m-%d %H:%M:%S $gmoff (%a, %d %b %Y)", localtime($t));
+}
+
+sub parse_git_date {
+ my ($t, $tz) = @_;
+ # Date::Parse isn't in the standard Perl distro :(
+ if ($tz =~ s/^\+//) {
+ $t += tz_to_s_offset($tz);
+ } elsif ($tz =~ s/^\-//) {
+ $t -= tz_to_s_offset($tz);
+ }
+ return $t;
+}
+
+sub set_local_timezone {
+ if (defined $TZ) {
+ $ENV{TZ} = $TZ;
+ } else {
+ delete $ENV{TZ};
+ }
+}
+
+sub tz_to_s_offset {
+ my ($tz) = @_;
+ $tz =~ s/(\d\d)$//;
+ return ($1 * 60) + ($tz * 3600);
+}
+
+sub get_author_info {
+ my ($dest, $author, $t, $tz) = @_;
+ $author =~ s/(?:^\s*|\s*$)//g;
+ $dest->{a_raw} = $author;
+ my $au;
+ if ($::_authors) {
+ $au = $rusers{$author} || undef;
+ }
+ if (!$au) {
+ ($au) = ($author =~ /<([^>]+)\@[^>]+>$/);
+ }
+ $dest->{t} = $t;
+ $dest->{tz} = $tz;
+ $dest->{a} = $au;
+ $dest->{t_utc} = parse_git_date($t, $tz);
+}
+
+sub process_commit {
+ my ($c, $r_min, $r_max, $defer) = @_;
+ if (defined $r_min && defined $r_max) {
+ if ($r_min == $c->{r} && $r_min == $r_max) {
+ show_commit($c);
+ return 0;
+ }
+ return 1 if $r_min == $r_max;
+ if ($r_min < $r_max) {
+ # we need to reverse the print order
+ return 0 if (defined $limit && --$limit < 0);
+ push @$defer, $c;
+ return 1;
+ }
+ if ($r_min != $r_max) {
+ return 1 if ($r_min < $c->{r});
+ return 1 if ($r_max > $c->{r});
+ }
+ }
+ return 0 if (defined $limit && --$limit < 0);
+ show_commit($c);
+ return 1;
+}
+
+my $l_fmt;
+sub show_commit {
+ my $c = shift;
+ if ($oneline) {
+ my $x = "\n";
+ if (my $l = $c->{l}) {
+ while ($l->[0] =~ /^\s*$/) { shift @$l }
+ $x = $l->[0];
+ }
+ $l_fmt ||= 'A' . length($c->{r});
+ print 'r',pack($l_fmt, $c->{r}),' | ';
+ print "$c->{c} | " if $show_commit;
+ print $x;
+ } else {
+ show_commit_normal($c);
+ }
+}
+
+sub show_commit_changed_paths {
+ my ($c) = @_;
+ return unless $c->{changed};
+ print "Changed paths:\n", @{$c->{changed}};
+}
+
+sub show_commit_normal {
+ my ($c) = @_;
+ print commit_log_separator, "r$c->{r} | ";
+ print "$c->{c} | " if $show_commit;
+ print "$c->{a} | ", format_svn_date($c->{t_utc}), ' | ';
+ my $nr_line = 0;
+
+ if (my $l = $c->{l}) {
+ while ($l->[$#$l] eq "\n" && $#$l > 0
+ && $l->[($#$l - 1)] eq "\n") {
+ pop @$l;
+ }
+ $nr_line = scalar @$l;
+ if (!$nr_line) {
+ print "1 line\n\n\n";
+ } else {
+ if ($nr_line == 1) {
+ $nr_line = '1 line';
+ } else {
+ $nr_line .= ' lines';
+ }
+ print $nr_line, "\n";
+ show_commit_changed_paths($c);
+ print "\n";
+ print $_ foreach @$l;
+ }
+ } else {
+ print "1 line\n";
+ show_commit_changed_paths($c);
+ print "\n";
+
+ }
+ foreach my $x (qw/raw stat diff/) {
+ if ($c->{$x}) {
+ print "\n";
+ print $_ foreach @{$c->{$x}}
+ }
+ }
+}
+
+sub cmd_show_log {
+ my (@args) = @_;
+ my ($r_min, $r_max);
+ my $r_last = -1; # prevent dupes
+ set_local_timezone();
+ if (defined $::_revision) {
+ if ($::_revision =~ /^(\d+):(\d+)$/) {
+ ($r_min, $r_max) = ($1, $2);
+ } elsif ($::_revision =~ /^\d+$/) {
+ $r_min = $r_max = $::_revision;
+ } else {
+ fatal "-r$::_revision is not supported, use ",
+ "standard 'git log' arguments instead";
+ }
+ }
+
+ config_pager();
+ @args = git_svn_log_cmd($r_min, $r_max, @args);
+ if (!@args) {
+ print commit_log_separator unless $incremental || $oneline;
+ return;
+ }
+ my $log = command_output_pipe(@args);
+ run_pager();
+ my (@k, $c, $d, $stat);
+ my $esc_color = qr/(?:\033\[(?:(?:\d+;)*\d*)?m)*/;
+ while (<$log>) {
+ if (/^${esc_color}commit (?:- )?($::sha1_short)/o) {
+ my $cmt = $1;
+ if ($c && cmt_showable($c) && $c->{r} != $r_last) {
+ $r_last = $c->{r};
+ process_commit($c, $r_min, $r_max, \@k) or
+ goto out;
+ }
+ $d = undef;
+ $c = { c => $cmt };
+ } elsif (/^${esc_color}author (.+) (\d+) ([\-\+]?\d+)$/o) {
+ get_author_info($c, $1, $2, $3);
+ } elsif (/^${esc_color}(?:tree|parent|committer) /o) {
+ # ignore
+ } elsif (/^${esc_color}:\d{6} \d{6} $::sha1_short/o) {
+ push @{$c->{raw}}, $_;
+ } elsif (/^${esc_color}[ACRMDT]\t/) {
+ # we could add $SVN->{svn_path} here, but that requires
+ # remote access at the moment (repo_path_split)...
+ s#^(${esc_color})([ACRMDT])\t#$1 $2 #o;
+ push @{$c->{changed}}, $_;
+ } elsif (/^${esc_color}diff /o) {
+ $d = 1;
+ push @{$c->{diff}}, $_;
+ } elsif ($d) {
+ push @{$c->{diff}}, $_;
+ } elsif (/^\ .+\ \|\s*\d+\ $esc_color[\+\-]*
+ $esc_color*[\+\-]*$esc_color$/x) {
+ $stat = 1;
+ push @{$c->{stat}}, $_;
+ } elsif ($stat && /^ \d+ files changed, \d+ insertions/) {
+ push @{$c->{stat}}, $_;
+ $stat = undef;
+ } elsif (/^${esc_color} (git-svn-id:.+)$/o) {
+ ($c->{url}, $c->{r}, undef) = ::extract_metadata($1);
+ } elsif (s/^${esc_color} //o) {
+ push @{$c->{l}}, $_;
+ }
+ }
+ if ($c && defined $c->{r} && $c->{r} != $r_last) {
+ $r_last = $c->{r};
+ process_commit($c, $r_min, $r_max, \@k);
+ }
+ if (@k) {
+ ($r_min, $r_max) = ($r_max, $r_min);
+ process_commit($_, $r_min, $r_max) foreach reverse @k;
+ }
+out:
+ close $log;
+ print commit_log_separator unless $incremental || $oneline;
+}
+
+sub cmd_blame {
+ my $path = pop;
+
+ config_pager();
+ run_pager();
+
+ my ($fh, $ctx, $rev);
+
+ if ($_git_format) {
+ ($fh, $ctx) = command_output_pipe('blame', @_, $path);
+ while (my $line = <$fh>) {
+ if ($line =~ /^\^?([[:xdigit:]]+)\s/) {
+ # Uncommitted edits show up as a rev ID of
+ # all zeros, which we can't look up with
+ # cmt_metadata
+ if ($1 !~ /^0+$/) {
+ (undef, $rev, undef) =
+ ::cmt_metadata($1);
+ $rev = '0' if (!$rev);
+ } else {
+ $rev = '0';
+ }
+ $rev = sprintf('%-10s', $rev);
+ $line =~ s/^\^?[[:xdigit:]]+(\s)/$rev$1/;
+ }
+ print $line;
+ }
+ } else {
+ ($fh, $ctx) = command_output_pipe('blame', '-p', @_, 'HEAD',
+ '--', $path);
+ my ($sha1);
+ my %authors;
+ my @buffer;
+ my %dsha; #distinct sha keys
+
+ while (my $line = <$fh>) {
+ push @buffer, $line;
+ if ($line =~ /^([[:xdigit:]]{40})\s\d+\s\d+/) {
+ $dsha{$1} = 1;
+ }
+ }
+
+ my $s2r = ::cmt_sha2rev_batch([keys %dsha]);
+
+ foreach my $line (@buffer) {
+ if ($line =~ /^([[:xdigit:]]{40})\s\d+\s\d+/) {
+ $rev = $s2r->{$1};
+ $rev = '0' if (!$rev)
+ }
+ elsif ($line =~ /^author (.*)/) {
+ $authors{$rev} = $1;
+ $authors{$rev} =~ s/\s/_/g;
+ }
+ elsif ($line =~ /^\t(.*)$/) {
+ printf("%6s %10s %s\n", $rev, $authors{$rev}, $1);
+ }
+ }
+ }
+ command_close_pipe($fh, $ctx);
+}
+
+1;
diff --git a/perl/Git/SVN/Migration.pm b/perl/Git/SVN/Migration.pm
new file mode 100644
index 0000000..30daf35
--- /dev/null
+++ b/perl/Git/SVN/Migration.pm
@@ -0,0 +1,258 @@
+package Git::SVN::Migration;
+# these version numbers do NOT correspond to actual version numbers
+# of git nor git-svn. They are just relative.
+#
+# v0 layout: .git/$id/info/url, refs/heads/$id-HEAD
+#
+# v1 layout: .git/$id/info/url, refs/remotes/$id
+#
+# v2 layout: .git/svn/$id/info/url, refs/remotes/$id
+#
+# v3 layout: .git/svn/$id, refs/remotes/$id
+# - info/url may remain for backwards compatibility
+# - this is what we migrate up to this layout automatically,
+# - this will be used by git svn init on single branches
+# v3.1 layout (auto migrated):
+# - .rev_db => .rev_db.$UUID, .rev_db will remain as a symlink
+# for backwards compatibility
+#
+# v4 layout: .git/svn/$repo_id/$id, refs/remotes/$repo_id/$id
+# - this is only created for newly multi-init-ed
+# repositories. Similar in spirit to the
+# --use-separate-remotes option in git-clone (now default)
+# - we do not automatically migrate to this (following
+# the example set by core git)
+#
+# v5 layout: .rev_db.$UUID => .rev_map.$UUID
+# - newer, more-efficient format that uses 24-bytes per record
+# with no filler space.
+# - use xxd -c24 < .rev_map.$UUID to view and debug
+# - This is a one-way migration, repositories updated to the
+# new format will not be able to use old git-svn without
+# rebuilding the .rev_db. Rebuilding the rev_db is not
+# possible if noMetadata or useSvmProps are set; but should
+# be no problem for users that use the (sensible) defaults.
+use strict;
+use warnings;
+use Carp qw/croak/;
+use File::Path qw/mkpath/;
+use File::Basename qw/dirname basename/;
+
+our $_minimize;
+use Git qw(
+ command
+ command_noisy
+ command_output_pipe
+ command_close_pipe
+);
+
+sub migrate_from_v0 {
+ my $git_dir = $ENV{GIT_DIR};
+ return undef unless -d $git_dir;
+ my ($fh, $ctx) = command_output_pipe(qw/rev-parse --symbolic --all/);
+ my $migrated = 0;
+ while (<$fh>) {
+ chomp;
+ my ($id, $orig_ref) = ($_, $_);
+ next unless $id =~ s#^refs/heads/(.+)-HEAD$#$1#;
+ next unless -f "$git_dir/$id/info/url";
+ my $new_ref = "refs/remotes/$id";
+ if (::verify_ref("$new_ref^0")) {
+ print STDERR "W: $orig_ref is probably an old ",
+ "branch used by an ancient version of ",
+ "git-svn.\n",
+ "However, $new_ref also exists.\n",
+ "We will not be able ",
+ "to use this branch until this ",
+ "ambiguity is resolved.\n";
+ next;
+ }
+ print STDERR "Migrating from v0 layout...\n" if !$migrated;
+ print STDERR "Renaming ref: $orig_ref => $new_ref\n";
+ command_noisy('update-ref', $new_ref, $orig_ref);
+ command_noisy('update-ref', '-d', $orig_ref, $orig_ref);
+ $migrated++;
+ }
+ command_close_pipe($fh, $ctx);
+ print STDERR "Done migrating from v0 layout...\n" if $migrated;
+ $migrated;
+}
+
+sub migrate_from_v1 {
+ my $git_dir = $ENV{GIT_DIR};
+ my $migrated = 0;
+ return $migrated unless -d $git_dir;
+ my $svn_dir = "$git_dir/svn";
+
+ # just in case somebody used 'svn' as their $id at some point...
+ return $migrated if -d $svn_dir && ! -f "$svn_dir/info/url";
+
+ print STDERR "Migrating from a git-svn v1 layout...\n";
+ mkpath([$svn_dir]);
+ print STDERR "Data from a previous version of git-svn exists, but\n\t",
+ "$svn_dir\n\t(required for this version ",
+ "($::VERSION) of git-svn) does not exist.\n";
+ my ($fh, $ctx) = command_output_pipe(qw/rev-parse --symbolic --all/);
+ while (<$fh>) {
+ my $x = $_;
+ next unless $x =~ s#^refs/remotes/##;
+ chomp $x;
+ next unless -f "$git_dir/$x/info/url";
+ my $u = eval { ::file_to_s("$git_dir/$x/info/url") };
+ next unless $u;
+ my $dn = dirname("$git_dir/svn/$x");
+ mkpath([$dn]) unless -d $dn;
+ if ($x eq 'svn') { # they used 'svn' as GIT_SVN_ID:
+ mkpath(["$git_dir/svn/svn"]);
+ print STDERR " - $git_dir/$x/info => ",
+ "$git_dir/svn/$x/info\n";
+ rename "$git_dir/$x/info", "$git_dir/svn/$x/info" or
+ croak "$!: $x";
+ # don't worry too much about these, they probably
+ # don't exist with repos this old (save for index,
+ # and we can easily regenerate that)
+ foreach my $f (qw/unhandled.log index .rev_db/) {
+ rename "$git_dir/$x/$f", "$git_dir/svn/$x/$f";
+ }
+ } else {
+ print STDERR " - $git_dir/$x => $git_dir/svn/$x\n";
+ rename "$git_dir/$x", "$git_dir/svn/$x" or
+ croak "$!: $x";
+ }
+ $migrated++;
+ }
+ command_close_pipe($fh, $ctx);
+ print STDERR "Done migrating from a git-svn v1 layout\n";
+ $migrated;
+}
+
+sub read_old_urls {
+ my ($l_map, $pfx, $path) = @_;
+ my @dir;
+ foreach (<$path/*>) {
+ if (-r "$_/info/url") {
+ $pfx .= '/' if $pfx && $pfx !~ m!/$!;
+ my $ref_id = $pfx . basename $_;
+ my $url = ::file_to_s("$_/info/url");
+ $l_map->{$ref_id} = $url;
+ } elsif (-d $_) {
+ push @dir, $_;
+ }
+ }
+ foreach (@dir) {
+ my $x = $_;
+ $x =~ s!^\Q$ENV{GIT_DIR}\E/svn/!!o;
+ read_old_urls($l_map, $x, $_);
+ }
+}
+
+sub migrate_from_v2 {
+ my @cfg = command(qw/config -l/);
+ return if grep /^svn-remote\..+\.url=/, @cfg;
+ my %l_map;
+ read_old_urls(\%l_map, '', "$ENV{GIT_DIR}/svn");
+ my $migrated = 0;
+
+ require Git::SVN;
+ foreach my $ref_id (sort keys %l_map) {
+ eval { Git::SVN->init($l_map{$ref_id}, '', undef, $ref_id) };
+ if ($@) {
+ Git::SVN->init($l_map{$ref_id}, '', $ref_id, $ref_id);
+ }
+ $migrated++;
+ }
+ $migrated;
+}
+
+sub minimize_connections {
+ require Git::SVN;
+ require Git::SVN::Ra;
+
+ my $r = Git::SVN::read_all_remotes();
+ my $new_urls = {};
+ my $root_repos = {};
+ foreach my $repo_id (keys %$r) {
+ my $url = $r->{$repo_id}->{url} or next;
+ my $fetch = $r->{$repo_id}->{fetch} or next;
+ my $ra = Git::SVN::Ra->new($url);
+
+ # skip existing cases where we already connect to the root
+ if (($ra->url eq $ra->{repos_root}) ||
+ ($ra->{repos_root} eq $repo_id)) {
+ $root_repos->{$ra->url} = $repo_id;
+ next;
+ }
+
+ my $root_ra = Git::SVN::Ra->new($ra->{repos_root});
+ my $root_path = $ra->url;
+ $root_path =~ s#^\Q$ra->{repos_root}\E(/|$)##;
+ foreach my $path (keys %$fetch) {
+ my $ref_id = $fetch->{$path};
+ my $gs = Git::SVN->new($ref_id, $repo_id, $path);
+
+ # make sure we can read when connecting to
+ # a higher level of a repository
+ my ($last_rev, undef) = $gs->last_rev_commit;
+ if (!defined $last_rev) {
+ $last_rev = eval {
+ $root_ra->get_latest_revnum;
+ };
+ next if $@;
+ }
+ my $new = $root_path;
+ $new .= length $path ? "/$path" : '';
+ eval {
+ $root_ra->get_log([$new], $last_rev, $last_rev,
+ 0, 0, 1, sub { });
+ };
+ next if $@;
+ $new_urls->{$ra->{repos_root}}->{$new} =
+ { ref_id => $ref_id,
+ old_repo_id => $repo_id,
+ old_path => $path };
+ }
+ }
+
+ my @emptied;
+ foreach my $url (keys %$new_urls) {
+ # see if we can re-use an existing [svn-remote "repo_id"]
+ # instead of creating a(n ugly) new section:
+ my $repo_id = $root_repos->{$url} || $url;
+
+ my $fetch = $new_urls->{$url};
+ foreach my $path (keys %$fetch) {
+ my $x = $fetch->{$path};
+ Git::SVN->init($url, $path, $repo_id, $x->{ref_id});
+ my $pfx = "svn-remote.$x->{old_repo_id}";
+
+ my $old_fetch = quotemeta("$x->{old_path}:".
+ "$x->{ref_id}");
+ command_noisy(qw/config --unset/,
+ "$pfx.fetch", '^'. $old_fetch . '$');
+ delete $r->{$x->{old_repo_id}}->
+ {fetch}->{$x->{old_path}};
+ if (!keys %{$r->{$x->{old_repo_id}}->{fetch}}) {
+ command_noisy(qw/config --unset/,
+ "$pfx.url");
+ push @emptied, $x->{old_repo_id}
+ }
+ }
+ }
+ if (@emptied) {
+ my $file = $ENV{GIT_CONFIG} || "$ENV{GIT_DIR}/config";
+ print STDERR <<EOF;
+The following [svn-remote] sections in your config file ($file) are empty
+and can be safely removed:
+EOF
+ print STDERR "[svn-remote \"$_\"]\n" foreach @emptied;
+ }
+}
+
+sub migration_check {
+ migrate_from_v0();
+ migrate_from_v1();
+ migrate_from_v2();
+ minimize_connections() if $_minimize;
+}
+
+1;
diff --git a/perl/Git/SVN/Ra.pm b/perl/Git/SVN/Ra.pm
index 23ff43e..049c97b 100644
--- a/perl/Git/SVN/Ra.pm
+++ b/perl/Git/SVN/Ra.pm
@@ -3,6 +3,12 @@ use vars qw/@ISA $config_dir $_ignore_refs_regex $_log_window_size/;
use strict;
use warnings;
use SVN::Client;
+use Git::SVN::Utils qw(
+ canonicalize_url
+ canonicalize_path
+ add_path_to_url
+);
+
use SVN::Ra;
BEGIN {
@ISA = qw(SVN::Ra);
@@ -62,29 +68,11 @@ sub _auth_providers () {
\@rv;
}
-sub escape_uri_only {
- my ($uri) = @_;
- my @tmp;
- foreach (split m{/}, $uri) {
- s/([^~\w.%+-]|%(?![a-fA-F0-9]{2}))/sprintf("%%%02X",ord($1))/eg;
- push @tmp, $_;
- }
- join('/', @tmp);
-}
-
-sub escape_url {
- my ($url) = @_;
- if ($url =~ m#^(https?)://([^/]+)(.*)$#) {
- my ($scheme, $domain, $uri) = ($1, $2, escape_uri_only($3));
- $url = "$scheme://$domain$uri";
- }
- $url;
-}
sub new {
my ($class, $url) = @_;
- $url =~ s!/+$!!;
- return $RA if ($RA && $RA->{url} eq $url);
+ $url = canonicalize_url($url);
+ return $RA if ($RA && $RA->url eq $url);
::_req_svn();
@@ -115,17 +103,34 @@ sub new {
$Git::SVN::Prompt::_no_auth_cache = 1;
}
} # no warnings 'once'
- my $self = SVN::Ra->new(url => escape_url($url), auth => $baton,
+
+ my $self = SVN::Ra->new(url => $url, auth => $baton,
config => $config,
pool => SVN::Pool->new,
auth_provider_callbacks => $callbacks);
- $self->{url} = $url;
+ $RA = bless $self, $class;
+
+ # Make sure its canonicalized
+ $self->url($url);
$self->{svn_path} = $url;
$self->{repos_root} = $self->get_repos_root;
$self->{svn_path} =~ s#^\Q$self->{repos_root}\E(/|$)##;
$self->{cache} = { check_path => { r => 0, data => {} },
get_dir => { r => 0, data => {} } };
- $RA = bless $self, $class;
+
+ return $RA;
+}
+
+sub url {
+ my $self = shift;
+
+ if (@_) {
+ my $url = shift;
+ $self->{url} = canonicalize_url($url);
+ return;
+ }
+
+ return $self->{url};
}
sub check_path {
@@ -195,6 +200,7 @@ sub get_log {
qw/copyfrom_path copyfrom_rev action/;
if ($s{'copyfrom_path'}) {
$s{'copyfrom_path'} =~ s/$prefix_regex//;
+ $s{'copyfrom_path'} = canonicalize_path($s{'copyfrom_path'});
}
$_[0]{$p} = \%s;
}
@@ -246,7 +252,7 @@ sub get_commit_editor {
sub gs_do_update {
my ($self, $rev_a, $rev_b, $gs, $editor) = @_;
my $new = ($rev_a == $rev_b);
- my $path = $gs->{path};
+ my $path = $gs->path;
if ($new && -e $gs->{index}) {
unlink $gs->{index} or die
@@ -282,30 +288,33 @@ sub gs_do_update {
# svn_ra_reparent didn't work before 1.4)
sub gs_do_switch {
my ($self, $rev_a, $rev_b, $gs, $url_b, $editor) = @_;
- my $path = $gs->{path};
+ my $path = $gs->path;
my $pool = SVN::Pool->new;
- my $full_url = $self->{url};
- my $old_url = $full_url;
- $full_url .= '/' . $path if length $path;
+ my $old_url = $self->url;
+ my $full_url = add_path_to_url( $self->url, $path );
my ($ra, $reparented);
if ($old_url =~ m#^svn(\+ssh)?://# ||
($full_url =~ m#^https?://# &&
- escape_url($full_url) ne $full_url)) {
+ canonicalize_url($full_url) ne $full_url)) {
$_[0] = undef;
$self = undef;
$RA = undef;
$ra = Git::SVN::Ra->new($full_url);
$ra_invalid = 1;
} elsif ($old_url ne $full_url) {
- SVN::_Ra::svn_ra_reparent($self->{session}, $full_url, $pool);
- $self->{url} = $full_url;
+ SVN::_Ra::svn_ra_reparent(
+ $self->{session},
+ canonicalize_url($full_url),
+ $pool
+ );
+ $self->url($full_url);
$reparented = 1;
}
$ra ||= $self;
- $url_b = escape_url($url_b);
+ $url_b = canonicalize_url($url_b);
my $reporter = $ra->do_switch($rev_b, '', 1, $url_b, $editor, $pool);
my @lock = (::compare_svn_version('1.2.0') >= 0) ? (undef) : ();
$reporter->set_path('', $rev_a, 0, @lock, $pool);
@@ -313,7 +322,7 @@ sub gs_do_switch {
if ($reparented) {
SVN::_Ra::svn_ra_reparent($self->{session}, $old_url, $pool);
- $self->{url} = $old_url;
+ $self->url($old_url);
}
$pool->clear;
@@ -326,7 +335,7 @@ sub longest_common_path {
my $common_max = scalar @$gsv;
foreach my $gs (@$gsv) {
- my @tmp = split m#/#, $gs->{path};
+ my @tmp = split m#/#, $gs->path;
my $p = '';
foreach (@tmp) {
$p .= length($p) ? "/$_" : $_;
@@ -362,7 +371,7 @@ sub gs_fetch_loop_common {
my $inc = $_log_window_size;
my ($min, $max) = ($base, $head < $base + $inc ? $head : $base + $inc);
my $longest_path = longest_common_path($gsv, $globs);
- my $ra_url = $self->{url};
+ my $ra_url = $self->url;
my $find_trailing_edge;
while (1) {
my %revs;
@@ -407,7 +416,7 @@ sub gs_fetch_loop_common {
}
$SVN::Error::handler = $err_handler;
- my %exists = map { $_->{path} => $_ } @$gsv;
+ my %exists = map { $_->path => $_ } @$gsv;
foreach my $r (sort {$a <=> $b} keys %revs) {
my ($paths, $logged) = @{$revs{$r}};
@@ -508,7 +517,7 @@ sub match_globs {
($self->check_path($p, $r) !=
$SVN::Node::dir));
next unless $p =~ /$g->{path}->{regex}/;
- $exists->{$p} = Git::SVN->init($self->{url}, $p, undef,
+ $exists->{$p} = Git::SVN->init($self->url, $p, undef,
$g->{ref}->full_path($de), 1);
}
}
@@ -532,7 +541,7 @@ sub match_globs {
next if ($self->check_path($pathname, $r) !=
$SVN::Node::dir);
$exists->{$pathname} = Git::SVN->init(
- $self->{url}, $pathname, undef,
+ $self->url, $pathname, undef,
$g->{ref}->full_path($p), 1);
}
my $c = '';
@@ -548,19 +557,20 @@ sub match_globs {
sub minimize_url {
my ($self) = @_;
- return $self->{url} if ($self->{url} eq $self->{repos_root});
+ return $self->url if ($self->url eq $self->{repos_root});
my $url = $self->{repos_root};
my @components = split(m!/!, $self->{svn_path});
my $c = '';
do {
- $url .= "/$c" if length $c;
+ $url = add_path_to_url($url, $c);
eval {
my $ra = (ref $self)->new($url);
my $latest = $ra->get_latest_revnum;
$ra->get_log("", $latest, 0, 1, 0, 1, sub {});
};
} while ($@ && ($c = shift @components));
- $url;
+
+ return canonicalize_url($url);
}
sub can_do_switch {
@@ -568,7 +578,7 @@ sub can_do_switch {
unless (defined $can_do_switch) {
my $pool = SVN::Pool->new;
my $rep = eval {
- $self->do_switch(1, '', 0, $self->{url},
+ $self->do_switch(1, '', 0, $self->url,
SVN::Delta::Editor->new, $pool);
};
if ($@) {
diff --git a/perl/Git/SVN/Utils.pm b/perl/Git/SVN/Utils.pm
new file mode 100644
index 0000000..8b8cf37
--- /dev/null
+++ b/perl/Git/SVN/Utils.pm
@@ -0,0 +1,232 @@
+package Git::SVN::Utils;
+
+use strict;
+use warnings;
+
+use SVN::Core;
+
+use base qw(Exporter);
+
+our @EXPORT_OK = qw(
+ fatal
+ can_compress
+ canonicalize_path
+ canonicalize_url
+ join_paths
+ add_path_to_url
+);
+
+
+=head1 NAME
+
+Git::SVN::Utils - utility functions used across Git::SVN
+
+=head1 SYNOPSIS
+
+ use Git::SVN::Utils qw(functions to import);
+
+=head1 DESCRIPTION
+
+This module contains functions which are useful across many different
+parts of Git::SVN. Mostly it's a place to put utility functions
+rather than duplicate the code or have classes grabbing at other
+classes.
+
+=head1 FUNCTIONS
+
+All functions can be imported only on request.
+
+=head3 fatal
+
+ fatal(@message);
+
+Display a message and exit with a fatal error code.
+
+=cut
+
+# Note: not certain why this is in use instead of die. Probably because
+# the exit code of die is 255? Doesn't appear to be used consistently.
+sub fatal (@) { print STDERR "@_\n"; exit 1 }
+
+
+=head3 can_compress
+
+ my $can_compress = can_compress;
+
+Returns true if Compress::Zlib is available, false otherwise.
+
+=cut
+
+my $can_compress;
+sub can_compress {
+ return $can_compress if defined $can_compress;
+
+ return $can_compress = eval { require Compress::Zlib; };
+}
+
+
+=head3 canonicalize_path
+
+ my $canoncalized_path = canonicalize_path($path);
+
+Converts $path into a canonical form which is safe to pass to the SVN
+API as a file path.
+
+=cut
+
+# Turn foo/../bar into bar
+sub _collapse_dotdot {
+ my $path = shift;
+
+ 1 while $path =~ s{/[^/]+/+\.\.}{};
+ 1 while $path =~ s{[^/]+/+\.\./}{};
+ 1 while $path =~ s{[^/]+/+\.\.}{};
+
+ return $path;
+}
+
+
+sub canonicalize_path {
+ my $path = shift;
+ my $rv;
+
+ # The 1.7 way to do it
+ if ( defined &SVN::_Core::svn_dirent_canonicalize ) {
+ $path = _collapse_dotdot($path);
+ $rv = SVN::_Core::svn_dirent_canonicalize($path);
+ }
+ # The 1.6 way to do it
+ # This can return undef on subversion-perl-1.4.2-2.el5 (CentOS 5.2)
+ elsif ( defined &SVN::_Core::svn_path_canonicalize ) {
+ $path = _collapse_dotdot($path);
+ $rv = SVN::_Core::svn_path_canonicalize($path);
+ }
+
+ return $rv if defined $rv;
+
+ # No SVN API canonicalization is available, or the SVN API
+ # didn't return a successful result, do it ourselves
+ return _canonicalize_path_ourselves($path);
+}
+
+
+sub _canonicalize_path_ourselves {
+ my ($path) = @_;
+ my $dot_slash_added = 0;
+ if (substr($path, 0, 1) ne "/") {
+ $path = "./" . $path;
+ $dot_slash_added = 1;
+ }
+ $path =~ s#/+#/#g;
+ $path =~ s#/\.(?:/|$)#/#g;
+ $path = _collapse_dotdot($path);
+ $path =~ s#/$##g;
+ $path =~ s#^\./## if $dot_slash_added;
+ $path =~ s#^\.$##;
+ return $path;
+}
+
+
+=head3 canonicalize_url
+
+ my $canonicalized_url = canonicalize_url($url);
+
+Converts $url into a canonical form which is safe to pass to the SVN
+API as a URL.
+
+=cut
+
+sub canonicalize_url {
+ my $url = shift;
+
+ # The 1.7 way to do it
+ if ( defined &SVN::_Core::svn_uri_canonicalize ) {
+ return SVN::_Core::svn_uri_canonicalize($url);
+ }
+ # There wasn't a 1.6 way to do it, so we do it ourself.
+ else {
+ return _canonicalize_url_ourselves($url);
+ }
+}
+
+
+sub _canonicalize_url_path {
+ my ($uri_path) = @_;
+
+ my @parts;
+ foreach my $part (split m{/+}, $uri_path) {
+ $part =~ s/([^~\w.%+-]|%(?![a-fA-F0-9]{2}))/sprintf("%%%02X",ord($1))/eg;
+ push @parts, $part;
+ }
+
+ return join('/', @parts);
+}
+
+sub _canonicalize_url_ourselves {
+ my ($url) = @_;
+ if ($url =~ m#^([^:]+)://([^/]*)(.*)$#) {
+ my ($scheme, $domain, $uri) = ($1, $2, _canonicalize_url_path(canonicalize_path($3)));
+ $url = "$scheme://$domain$uri";
+ }
+ $url;
+}
+
+
+=head3 join_paths
+
+ my $new_path = join_paths(@paths);
+
+Appends @paths together into a single path. Any empty paths are ignored.
+
+=cut
+
+sub join_paths {
+ my @paths = @_;
+
+ @paths = grep { defined $_ && length $_ } @paths;
+
+ return '' unless @paths;
+ return $paths[0] if @paths == 1;
+
+ my $new_path = shift @paths;
+ $new_path =~ s{/+$}{};
+
+ my $last_path = pop @paths;
+ $last_path =~ s{^/+}{};
+
+ for my $path (@paths) {
+ $path =~ s{^/+}{};
+ $path =~ s{/+$}{};
+ $new_path .= "/$path";
+ }
+
+ return $new_path .= "/$last_path";
+}
+
+
+=head3 add_path_to_url
+
+ my $new_url = add_path_to_url($url, $path);
+
+Appends $path onto the $url. If $path is empty, $url is returned unchanged.
+
+=cut
+
+sub add_path_to_url {
+ my($url, $path) = @_;
+
+ return $url if !defined $path or !length $path;
+
+ # Strip trailing and leading slashes so we don't
+ # wind up with http://x.com///path
+ $url =~ s{/+$}{};
+ $path =~ s{^/+}{};
+
+ # If a path has a % in it, URI escape it so it's not
+ # mistaken for a URI escape later.
+ $path =~ s{%}{%25}g;
+
+ return join '/', $url, $path;
+}
+
+1;
diff --git a/perl/Makefile b/perl/Makefile
index fe7a486..15d96fc 100644
--- a/perl/Makefile
+++ b/perl/Makefile
@@ -20,36 +20,57 @@ clean:
$(RM) ppport.h
$(RM) $(makfile)
$(RM) $(makfile).old
+ $(RM) PM.stamp
+
+$(makfile): PM.stamp
ifdef NO_PERL_MAKEMAKER
instdir_SQ = $(subst ','\'',$(prefix)/lib)
modules += Git
modules += Git/I18N
+modules += Git/IndexInfo
+modules += Git/SVN
modules += Git/SVN/Memoize/YAML
modules += Git/SVN/Fetcher
modules += Git/SVN/Editor
+modules += Git/SVN/GlobSpec
+modules += Git/SVN/Log
+modules += Git/SVN/Migration
modules += Git/SVN/Prompt
modules += Git/SVN/Ra
+modules += Git/SVN/Utils
$(makfile): ../GIT-CFLAGS Makefile
echo all: private-Error.pm Git.pm Git/I18N.pm > $@
- echo ' mkdir -p blib/lib/Git/SVN/Memoize' >> $@
set -e; \
for i in $(modules); \
do \
+ if test $$i = $${i%/*}; \
+ then \
+ subdir=; \
+ else \
+ subdir=/$${i%/*}; \
+ fi; \
echo ' $(RM) blib/lib/'$$i'.pm' >> $@; \
+ echo ' mkdir -p blib/lib'$$subdir >> $@; \
echo ' cp '$$i'.pm blib/lib/'$$i'.pm' >> $@; \
done
echo ' $(RM) blib/lib/Error.pm' >> $@
'$(PERL_PATH_SQ)' -MError -e 'exit($$Error::VERSION < 0.15009)' || \
echo ' cp private-Error.pm blib/lib/Error.pm' >> $@
echo install: >> $@
- echo ' mkdir -p "$$(DESTDIR)$(instdir_SQ)/Git/SVN/Memoize"' >> $@
set -e; \
for i in $(modules); \
do \
+ if test $$i = $${i%/*}; \
+ then \
+ subdir=; \
+ else \
+ subdir=/$${i%/*}; \
+ fi; \
echo ' $(RM) "$$(DESTDIR)$(instdir_SQ)/'$$i'.pm"' >> $@; \
+ echo ' mkdir -p "$$(DESTDIR)$(instdir_SQ)'$$subdir'"' >> $@; \
echo ' cp '$$i'.pm "$$(DESTDIR)$(instdir_SQ)/'$$i'.pm"' >> $@; \
done
echo ' $(RM) "$$(DESTDIR)$(instdir_SQ)/Error.pm"' >> $@
diff --git a/perl/Makefile.PL b/perl/Makefile.PL
index b54b04a..3f29ba9 100644
--- a/perl/Makefile.PL
+++ b/perl/Makefile.PL
@@ -2,11 +2,16 @@ use strict;
use warnings;
use ExtUtils::MakeMaker;
use Getopt::Long;
+use File::Find;
+
+# Don't forget to update the perl/Makefile, too.
+# Don't forget to test with NO_PERL_MAKEMAKER=YesPlease
# Sanity: die at first unknown option
Getopt::Long::Configure qw/ pass_through /;
-GetOptions("localedir=s" => \my $localedir);
+my $localedir = '';
+GetOptions("localedir=s" => \$localedir);
sub MY::postamble {
return <<'MAKE_FRAG';
@@ -24,24 +29,22 @@ endif
MAKE_FRAG
}
-# XXX. When editing this list:
-#
-# * Please update perl/Makefile, too.
-# * Don't forget to test with NO_PERL_MAKEMAKER=YesPlease
-my %pm = (
- 'Git.pm' => '$(INST_LIBDIR)/Git.pm',
- 'Git/I18N.pm' => '$(INST_LIBDIR)/Git/I18N.pm',
- 'Git/SVN/Memoize/YAML.pm' => '$(INST_LIBDIR)/Git/SVN/Memoize/YAML.pm',
- 'Git/SVN/Fetcher.pm' => '$(INST_LIBDIR)/Git/SVN/Fetcher.pm',
- 'Git/SVN/Editor.pm' => '$(INST_LIBDIR)/Git/SVN/Editor.pm',
- 'Git/SVN/Prompt.pm' => '$(INST_LIBDIR)/Git/SVN/Prompt.pm',
- 'Git/SVN/Ra.pm' => '$(INST_LIBDIR)/Git/SVN/Ra.pm',
-);
+# Find all the .pm files in "Git/" and Git.pm
+my %pm;
+find sub {
+ return unless /\.pm$/;
+
+ # sometimes File::Find prepends a ./ Strip it.
+ my $pm_path = $File::Find::name;
+ $pm_path =~ s{^\./}{};
+
+ $pm{$pm_path} = '$(INST_LIBDIR)/'.$pm_path;
+}, "Git", "Git.pm";
+
# We come with our own bundled Error.pm. It's not in the set of default
# Perl modules so install it if it's not available on the system yet.
-eval { require Error };
-if ($@ || $Error::VERSION < 0.15009) {
+if ( !eval { require Error } || $Error::VERSION < 0.15009) {
$pm{'private-Error.pm'} = '$(INST_LIBDIR)/Error.pm';
}
diff --git a/pkt-line.c b/pkt-line.c
index 5a04984..eaba15f 100644
--- a/pkt-line.c
+++ b/pkt-line.c
@@ -135,13 +135,19 @@ void packet_buf_write(struct strbuf *buf, const char *fmt, ...)
strbuf_add(buf, buffer, n);
}
-static void safe_read(int fd, void *buffer, unsigned size)
+static int safe_read(int fd, void *buffer, unsigned size, int return_line_fail)
{
ssize_t ret = read_in_full(fd, buffer, size);
if (ret < 0)
die_errno("read error");
- else if (ret < size)
+ else if (ret < size) {
+ if (return_line_fail)
+ return -1;
+
die("The remote end hung up unexpectedly");
+ }
+
+ return ret;
}
static int packet_length(const char *linelen)
@@ -169,12 +175,14 @@ static int packet_length(const char *linelen)
return len;
}
-int packet_read_line(int fd, char *buffer, unsigned size)
+static int packet_read_internal(int fd, char *buffer, unsigned size, int return_line_fail)
{
- int len;
+ int len, ret;
char linelen[4];
- safe_read(fd, linelen, 4);
+ ret = safe_read(fd, linelen, 4, return_line_fail);
+ if (return_line_fail && ret < 0)
+ return ret;
len = packet_length(linelen);
if (len < 0)
die("protocol error: bad line length character: %.4s", linelen);
@@ -185,12 +193,24 @@ int packet_read_line(int fd, char *buffer, unsigned size)
len -= 4;
if (len >= size)
die("protocol error: bad line length %d", len);
- safe_read(fd, buffer, len);
+ ret = safe_read(fd, buffer, len, return_line_fail);
+ if (return_line_fail && ret < 0)
+ return ret;
buffer[len] = 0;
packet_trace(buffer, len, 0);
return len;
}
+int packet_read(int fd, char *buffer, unsigned size)
+{
+ return packet_read_internal(fd, buffer, size, 1);
+}
+
+int packet_read_line(int fd, char *buffer, unsigned size)
+{
+ return packet_read_internal(fd, buffer, size, 0);
+}
+
int packet_get_line(struct strbuf *out,
char **src_buf, size_t *src_len)
{
diff --git a/pkt-line.h b/pkt-line.h
index 1e5dcfe..8cfeb0c 100644
--- a/pkt-line.h
+++ b/pkt-line.h
@@ -13,6 +13,7 @@ void packet_buf_flush(struct strbuf *buf);
void packet_buf_write(struct strbuf *buf, const char *fmt, ...) __attribute__((format (printf, 2, 3)));
int packet_read_line(int fd, char *buffer, unsigned size);
+int packet_read(int fd, char *buffer, unsigned size);
int packet_get_line(struct strbuf *out, char **src_buf, size_t *src_len);
ssize_t safe_write(int, const void *, ssize_t);
diff --git a/po/TEAMS b/po/TEAMS
index e9ebc8c..1b9e994 100644
--- a/po/TEAMS
+++ b/po/TEAMS
@@ -33,8 +33,9 @@ Repository: https://github.com/nafmo/git-l10n-sv/
Leader: Peter Krefting <peter@softwolves.pp.se>
Language: vi (Vietnamese)
-Repository: https://github.com/vnwildman/git.git
+Repository: https://github.com/vnwildman/git/
Leader: Trần Ngá»c Quân <vnwildman AT gmail.com>
+Members: Nguyá»…n Thái Ngá»c Duy <pclouds AT gmail.com>
Language: zh_CN (Simplified Chinese)
Repository: https://github.com/gotgit/git-po-zh_CN/
diff --git a/po/de.po b/po/de.po
index 70d8418..0db9a9b 100644
--- a/po/de.po
+++ b/po/de.po
@@ -5,9 +5,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: git 1.7.11\n"
+"Project-Id-Version: git 1.7.12\n"
"Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2012-06-08 10:20+0800\n"
+"POT-Creation-Date: 2012-09-05 06:20+0800\n"
"PO-Revision-Date: 2012-03-28 18:46+0200\n"
"Last-Translator: Ralf Thielow <ralf.thielow@googlemail.com>\n"
"Language-Team: German\n"
@@ -48,17 +48,17 @@ msgstr "'%s' sieht nicht wie eine v2 Paketdatei aus"
msgid "unrecognized header: %s%s (%d)"
msgstr "nicht erkannter Kopfbereich: %s%s (%d)"
-#: bundle.c:89 builtin/commit.c:696
+#: bundle.c:89 builtin/commit.c:699
#, c-format
msgid "could not open '%s'"
msgstr "Konnte '%s' nicht öffnen"
#: bundle.c:140
msgid "Repository lacks these prerequisite commits:"
-msgstr "Dem Projektarchiv fehlen folgende vorrausgesetzte Versionen:"
+msgstr "Dem Projektarchiv fehlen folgende vorausgesetzte Versionen:"
-#: bundle.c:164 sequencer.c:550 sequencer.c:982 builtin/log.c:289
-#: builtin/log.c:720 builtin/log.c:1309 builtin/log.c:1528 builtin/merge.c:347
+#: bundle.c:164 sequencer.c:550 sequencer.c:982 builtin/log.c:290
+#: builtin/log.c:727 builtin/log.c:1313 builtin/log.c:1529 builtin/merge.c:347
#: builtin/shortlog.c:181
msgid "revision walk setup failed"
msgstr "Einrichtung des Revisionsgangs fehlgeschlagen"
@@ -71,44 +71,48 @@ msgstr[0] "Das Paket enthält %d Referenz"
msgstr[1] "Das Paket enthält %d Referenzen"
#: bundle.c:192
+msgid "The bundle records a complete history."
+msgstr "Das Paket speichert eine komplette Historie."
+
+#: bundle.c:195
#, c-format
msgid "The bundle requires this ref"
msgid_plural "The bundle requires these %d refs"
msgstr[0] "Das Paket benötigt diese Referenz"
msgstr[1] "Das Paket benötigt diese %d Referenzen"
-#: bundle.c:290
+#: bundle.c:294
msgid "rev-list died"
msgstr "\"rev-list\" abgebrochen"
-#: bundle.c:296 builtin/log.c:1205 builtin/shortlog.c:284
+#: bundle.c:300 builtin/log.c:1209 builtin/shortlog.c:284
#, c-format
msgid "unrecognized argument: %s"
msgstr "nicht erkanntes Argument: %s"
-#: bundle.c:331
+#: bundle.c:335
#, c-format
msgid "ref '%s' is excluded by the rev-list options"
msgstr "Referenz '%s' wird durch \"rev-list\" Optionen ausgeschlossen"
-#: bundle.c:376
+#: bundle.c:380
msgid "Refusing to create empty bundle."
msgstr "Erstellung eines leeren Pakets zurückgewiesen."
-#: bundle.c:394
+#: bundle.c:398
msgid "Could not spawn pack-objects"
msgstr "Konnte Paketobjekte nicht erstellen"
-#: bundle.c:412
+#: bundle.c:416
msgid "pack-objects died"
msgstr "Erstellung der Paketobjekte abgebrochen"
-#: bundle.c:415
+#: bundle.c:419
#, c-format
msgid "cannot create '%s'"
msgstr "kann '%s' nicht erstellen"
-#: bundle.c:437
+#: bundle.c:441
msgid "index-pack died"
msgstr "Erstellung der Paketindexdatei abgebrochen"
@@ -227,32 +231,32 @@ msgstr ""
"Fehler in 'diff.dirstat' Konfigurationsvariable gefunden:\n"
"%s"
-#: diff.c:1400
-msgid " 0 files changed\n"
-msgstr " 0 Dateien geändert\n"
+#: diff.c:1401
+msgid " 0 files changed"
+msgstr " 0 Dateien geändert"
-#: diff.c:1404
+#: diff.c:1405
#, c-format
msgid " %d file changed"
msgid_plural " %d files changed"
msgstr[0] " %d Datei geändert"
msgstr[1] " %d Dateien geändert"
-#: diff.c:1421
+#: diff.c:1422
#, c-format
msgid ", %d insertion(+)"
msgid_plural ", %d insertions(+)"
msgstr[0] ", %d Zeile hinzugefügt(+)"
msgstr[1] ", %d Zeilen hinzugefügt(+)"
-#: diff.c:1432
+#: diff.c:1433
#, c-format
msgid ", %d deletion(-)"
msgid_plural ", %d deletions(-)"
msgstr[0] ", %d Zeile entfernt(-)"
msgstr[1] ", %d Zeilen entfernt(-)"
-#: diff.c:3478
+#: diff.c:3460
#, c-format
msgid ""
"Failed to parse --dirstat/-X option parameter:\n"
@@ -288,16 +292,16 @@ msgstr "'%s': %s"
msgid "'%s': short read %s"
msgstr "'%s': read() zu kurz %s"
-#: help.c:207
+#: help.c:212
#, c-format
msgid "available git commands in '%s'"
msgstr "Vorhandene Git-Kommandos in '%s'"
-#: help.c:214
+#: help.c:219
msgid "git commands available from elsewhere on your $PATH"
msgstr "Vorhandene Git-Kommandos irgendwo in deinem $PATH"
-#: help.c:270
+#: help.c:275
#, c-format
msgid ""
"'%s' appears to be a git command, but we were not\n"
@@ -306,11 +310,11 @@ msgstr ""
"'%s' scheint ein git-Kommando zu sein, konnte aber\n"
"nicht ausgeführt werden. Vielleicht ist git-%s fehlerhaft?"
-#: help.c:327
+#: help.c:332
msgid "Uh oh. Your system reports no Git commands at all."
msgstr "Uh oh. Keine Git-Kommandos auf deinem System vorhanden."
-#: help.c:349
+#: help.c:354
#, c-format
msgid ""
"WARNING: You called a Git command named '%s', which does not exist.\n"
@@ -319,17 +323,17 @@ msgstr ""
"Warnung: Du hast das nicht existierende Git-Kommando '%s' ausgeführt.\n"
"Setze fort unter der Annahme das du '%s' gemeint hast"
-#: help.c:354
+#: help.c:359
#, c-format
msgid "in %0.1f seconds automatically..."
msgstr "automatisch in %0.1f Sekunden..."
-#: help.c:361
+#: help.c:366
#, c-format
msgid "git: '%s' is not a git command. See 'git --help'."
msgstr "git: '%s' ist kein Git-Kommando. Siehe 'git --help'."
-#: help.c:365
+#: help.c:370
msgid ""
"\n"
"Did you mean this?"
@@ -343,35 +347,293 @@ msgstr[1] ""
"\n"
"Hast du eines von diesen gemeint?"
-#: parse-options.c:493
+#: merge-recursive.c:190
+#, c-format
+msgid "(bad commit)\n"
+msgstr "(ungültige Version)\n"
+
+#: merge-recursive.c:206
+#, c-format
+msgid "addinfo_cache failed for path '%s'"
+msgstr "addinfo_cache für Pfad '%s' fehlgeschlagen"
+
+#: merge-recursive.c:268
+msgid "error building trees"
+msgstr "Fehler beim Erstellen der Bäume"
+
+#: merge-recursive.c:672
+#, c-format
+msgid "failed to create path '%s'%s"
+msgstr "Fehler beim Erstellen des Pfades '%s'%s"
+
+#: merge-recursive.c:683
+#, c-format
+msgid "Removing %s to make room for subdirectory\n"
+msgstr "Entferne %s um Platz für Unterverzeichnis zu schaffen\n"
+
+#. something else exists
+#. .. but not some other error (who really cares what?)
+#: merge-recursive.c:697 merge-recursive.c:718
+msgid ": perhaps a D/F conflict?"
+msgstr ": vielleicht ein Verzeichnis/Datei-Konflikt?"
+
+#: merge-recursive.c:708
+#, c-format
+msgid "refusing to lose untracked file at '%s'"
+msgstr "verweigere, da unbeobachtete Dateien in '%s' verloren gehen würden"
+
+#: merge-recursive.c:748
+#, c-format
+msgid "cannot read object %s '%s'"
+msgstr "kann Objekt %s '%s' nicht lesen"
+
+#: merge-recursive.c:750
+#, c-format
+msgid "blob expected for %s '%s'"
+msgstr "Blob erwartet für %s '%s'"
+
+#: merge-recursive.c:773 builtin/clone.c:302
+#, c-format
+msgid "failed to open '%s'"
+msgstr "Fehler beim Öffnen von '%s'"
+
+#: merge-recursive.c:781
+#, c-format
+msgid "failed to symlink '%s'"
+msgstr "Fehler beim Erstellen einer symbolischen Verknüpfung für '%s'"
+
+#: merge-recursive.c:784
+#, c-format
+msgid "do not know what to do with %06o %s '%s'"
+msgstr "weiß nicht was mit %06o %s '%s' zu machen ist"
+
+#: merge-recursive.c:921
+msgid "Failed to execute internal merge"
+msgstr "Fehler bei Ausführung der internen Zusammenführung"
+
+#: merge-recursive.c:925
+#, c-format
+msgid "Unable to add %s to database"
+msgstr "Konnte %s nicht zur Datenbank hinzufügen"
+
+#: merge-recursive.c:941
+msgid "unsupported object type in the tree"
+msgstr "nicht unterstützter Objekttyp im Baum"
+
+#: merge-recursive.c:1020 merge-recursive.c:1034
+#, c-format
+msgid ""
+"CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left "
+"in tree."
+msgstr ""
+"KONFLIKT (%s/löschen): %s gelöscht in %s und %s in %s. Stand %s von %s wurde "
+"im Arbeitsbereich gelassen."
+
+#: merge-recursive.c:1026 merge-recursive.c:1039
+#, c-format
+msgid ""
+"CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left "
+"in tree at %s."
+msgstr ""
+"KONFLIKT (%s/löschen): %s gelöscht in %s und %s in %s. Stand %s von %s wurde "
+"im Arbeitsbereich bei %s gelassen."
+
+#: merge-recursive.c:1080
+msgid "rename"
+msgstr "umbenennen"
+
+#: merge-recursive.c:1080
+msgid "renamed"
+msgstr "umbenannt"
+
+#: merge-recursive.c:1136
+#, c-format
+msgid "%s is a directory in %s adding as %s instead"
+msgstr "%s ist ein Verzeichnis in %s, füge es stattdessen als %s hinzu"
+
+#: merge-recursive.c:1158
+#, c-format
+msgid ""
+"CONFLICT (rename/rename): Rename \"%s\"->\"%s\" in branch \"%s\" rename \"%s"
+"\"->\"%s\" in \"%s\"%s"
+msgstr ""
+"KONFLIKT (umbenennen/umbenennen): Benenne um \"%s\"->\"%s\" in Zweig \"%s\" "
+"und \"%s\"->\"%s\" in Zweig \"%s\"%s"
+
+#: merge-recursive.c:1163
+msgid " (left unresolved)"
+msgstr " (bleibt unaufgelöst)"
+
+#: merge-recursive.c:1217
+#, c-format
+msgid "CONFLICT (rename/rename): Rename %s->%s in %s. Rename %s->%s in %s"
+msgstr ""
+"KONFLIKT (umbenennen/umbenennen): Benenne um %s->%s in %s. Benenne um %s->%s "
+"in %s"
+
+#: merge-recursive.c:1247
+#, c-format
+msgid "Renaming %s to %s and %s to %s instead"
+msgstr "Benenne stattdessen %s nach %s und %s nach %s um"
+
+#: merge-recursive.c:1446
+#, c-format
+msgid "CONFLICT (rename/add): Rename %s->%s in %s. %s added in %s"
+msgstr ""
+"KONFLIKT (umbenennen/hinzufügen): Benenne um %s->%s in %s. %s hinzugefügt in "
+"%s"
+
+#: merge-recursive.c:1456
+#, c-format
+msgid "Adding merged %s"
+msgstr "Füge zusammengeführte Datei %s hinzu"
+
+#: merge-recursive.c:1461 merge-recursive.c:1659
+#, c-format
+msgid "Adding as %s instead"
+msgstr "Füge stattdessen als %s hinzu"
+
+#: merge-recursive.c:1512
+#, c-format
+msgid "cannot read object %s"
+msgstr "kann Objekt %s nicht lesen"
+
+#: merge-recursive.c:1515
+#, c-format
+msgid "object %s is not a blob"
+msgstr "Objekt %s ist kein Blob"
+
+#: merge-recursive.c:1563
+msgid "modify"
+msgstr "ändern"
+
+#: merge-recursive.c:1563
+msgid "modified"
+msgstr "geändert"
+
+#: merge-recursive.c:1573
+msgid "content"
+msgstr "Inhalt"
+
+#: merge-recursive.c:1580
+msgid "add/add"
+msgstr "hinzufügen/hinzufügen"
+
+#: merge-recursive.c:1614
+#, c-format
+msgid "Skipped %s (merged same as existing)"
+msgstr "%s ausgelassen (Ergebnis der Zusammenführung existiert bereits)"
+
+#: merge-recursive.c:1628
+#, c-format
+msgid "Auto-merging %s"
+msgstr "automatische Zusammenführung von %s"
+
+#: merge-recursive.c:1632 git-submodule.sh:869
+msgid "submodule"
+msgstr "Unterprojekt"
+
+#: merge-recursive.c:1633
+#, c-format
+msgid "CONFLICT (%s): Merge conflict in %s"
+msgstr "KONFLIKT (%s): Zusammenführungskonflikt in %s"
+
+#: merge-recursive.c:1723
+#, c-format
+msgid "Removing %s"
+msgstr "Entferne %s"
+
+#: merge-recursive.c:1748
+msgid "file/directory"
+msgstr "Datei/Verzeichnis"
+
+#: merge-recursive.c:1754
+msgid "directory/file"
+msgstr "Verzeichnis/Datei"
+
+#: merge-recursive.c:1759
+#, c-format
+msgid "CONFLICT (%s): There is a directory with name %s in %s. Adding %s as %s"
+msgstr ""
+"KONFLIKT (%s): Es existiert bereits ein Verzeichnis %s in %s. Füge %s als %s "
+"hinzu."
+
+#: merge-recursive.c:1769
+#, c-format
+msgid "Adding %s"
+msgstr "Füge %s hinzu"
+
+#: merge-recursive.c:1786
+msgid "Fatal merge failure, shouldn't happen."
+msgstr "Fataler Fehler bei der Zusammenführung. Sollte nicht passieren."
+
+#: merge-recursive.c:1805
+msgid "Already up-to-date!"
+msgstr "Bereits aktuell!"
+
+#: merge-recursive.c:1814
+#, c-format
+msgid "merging of trees %s and %s failed"
+msgstr "Zusammenführen der Bäume %s und %s fehlgeschlagen"
+
+#: merge-recursive.c:1844
+#, c-format
+msgid "Unprocessed path??? %s"
+msgstr "unverarbeiteter Pfad??? %s"
+
+#: merge-recursive.c:1889
+msgid "Merging:"
+msgstr "Zusammenführung:"
+
+#: merge-recursive.c:1902
+#, c-format
+msgid "found %u common ancestor:"
+msgid_plural "found %u common ancestors:"
+msgstr[0] "%u gemeinsamen Vorfahren gefunden"
+msgstr[1] "%u gemeinsame Vorfahren gefunden"
+
+#: merge-recursive.c:1939
+msgid "merge returned no commit"
+msgstr "Zusammenführung hat keine Version zurückgegeben"
+
+#: merge-recursive.c:1996
+#, c-format
+msgid "Could not parse object '%s'"
+msgstr "Konnte Objekt '%s' nicht parsen."
+
+#: merge-recursive.c:2008 builtin/merge.c:696
+msgid "Unable to write index."
+msgstr "Konnte Bereitstellung nicht schreiben."
+
+#: parse-options.c:494
msgid "..."
msgstr "..."
-#: parse-options.c:511
+#: parse-options.c:512
#, c-format
msgid "usage: %s"
msgstr "Verwendung: %s"
#. TRANSLATORS: the colon here should align with the
#. one in "usage: %s" translation
-#: parse-options.c:515
+#: parse-options.c:516
#, c-format
msgid " or: %s"
msgstr " oder: %s"
-#: parse-options.c:518
+#: parse-options.c:519
#, c-format
msgid " %s"
msgstr " %s"
-#: remote.c:1629
+#: remote.c:1632
#, c-format
msgid "Your branch is ahead of '%s' by %d commit.\n"
msgid_plural "Your branch is ahead of '%s' by %d commits.\n"
msgstr[0] "Dein Zweig ist vor '%s' um %d Version.\n"
msgstr[1] "Dein Zweig ist vor '%s' um %d Versionen.\n"
-#: remote.c:1635
+#: remote.c:1638
#, c-format
msgid "Your branch is behind '%s' by %d commit, and can be fast-forwarded.\n"
msgid_plural ""
@@ -382,7 +644,7 @@ msgstr[1] ""
"Dein Zweig ist zu '%s' um %d Versionen hinterher, und kann vorgespult "
"werden.\n"
-#: remote.c:1643
+#: remote.c:1646
#, c-format
msgid ""
"Your branch and '%s' have diverged,\n"
@@ -397,14 +659,14 @@ msgstr[1] ""
"Dein Zweig und '%s' sind divergiert,\n"
"und haben jeweils %d und %d unterschiedliche Versionen.\n"
-#: sequencer.c:121 builtin/merge.c:865 builtin/merge.c:978
-#: builtin/merge.c:1088 builtin/merge.c:1098
+#: sequencer.c:121 builtin/merge.c:864 builtin/merge.c:977
+#: builtin/merge.c:1087 builtin/merge.c:1097
#, c-format
msgid "Could not open '%s' for writing"
msgstr "Konnte '%s' nicht zum Schreiben öffnen."
-#: sequencer.c:123 builtin/merge.c:333 builtin/merge.c:868
-#: builtin/merge.c:1090 builtin/merge.c:1103
+#: sequencer.c:123 builtin/merge.c:333 builtin/merge.c:867
+#: builtin/merge.c:1089 builtin/merge.c:1102
#, c-format
msgid "Could not write to '%s'"
msgstr "Konnte nicht nach '%s' schreiben."
@@ -610,7 +872,7 @@ msgstr "kann Zweigspitze (HEAD) nicht auflösen"
msgid "cannot abort from a branch yet to be born"
msgstr "kann nicht abbrechen: bin auf einem Zweig, der noch geboren wird"
-#: sequencer.c:805 builtin/apply.c:3697
+#: sequencer.c:805 builtin/apply.c:3987
#, c-format
msgid "cannot open %s: %s"
msgstr "Kann %s nicht öffnen: %s"
@@ -644,21 +906,21 @@ msgstr "Kann nicht zu initialer Version zurücksetzen."
msgid "Can't cherry-pick into empty head"
msgstr "Kann \"cherry-pick\" nicht in einem leerem Kopf ausführen."
-#: sha1_name.c:864
+#: sha1_name.c:1044
msgid "HEAD does not point to a branch"
msgstr "Zweigspitze (HEAD) zeigt auf keinen Zweig"
-#: sha1_name.c:867
+#: sha1_name.c:1047
#, c-format
msgid "No such branch: '%s'"
msgstr "Kein solcher Zweig '%s'"
-#: sha1_name.c:869
+#: sha1_name.c:1049
#, c-format
msgid "No upstream configured for branch '%s'"
msgstr "Kein entferntes Projektarchiv für Zweig '%s' konfiguriert."
-#: sha1_name.c:872
+#: sha1_name.c:1052
#, c-format
msgid "Upstream branch '%s' not stored as a remote-tracking branch"
msgstr ""
@@ -673,252 +935,367 @@ msgstr "konnte aktuellen Benutzer nicht in Passwort-Datei finden: %s"
msgid "no such user"
msgstr "kein solcher Benutzer"
-#: wt-status.c:135
+#: wt-status.c:140
msgid "Unmerged paths:"
msgstr "Nicht zusammengeführte Pfade:"
-#: wt-status.c:141 wt-status.c:158
+#: wt-status.c:167 wt-status.c:194
#, c-format
msgid " (use \"git reset %s <file>...\" to unstage)"
msgstr ""
" (benutze \"git reset %s <Datei>...\" zum Herausnehmen aus der "
"Bereitstellung)"
-#: wt-status.c:143 wt-status.c:160
+#: wt-status.c:169 wt-status.c:196
msgid " (use \"git rm --cached <file>...\" to unstage)"
msgstr ""
" (benutze \"git rm --cached <Datei>...\" zum Herausnehmen aus der "
"Bereitstellung)"
-#: wt-status.c:144
+#: wt-status.c:173
+msgid " (use \"git add <file>...\" to mark resolution)"
+msgstr " (benutze \"git add/rm <Datei>...\" um die Auflösung zu markieren)"
+
+#: wt-status.c:175 wt-status.c:179
msgid " (use \"git add/rm <file>...\" as appropriate to mark resolution)"
msgstr ""
" (benutze \"git add/rm <Datei>...\" um die Auflösung entsprechend zu "
"markieren)"
-#: wt-status.c:152
+#: wt-status.c:177
+msgid " (use \"git rm <file>...\" to mark resolution)"
+msgstr " (benutze \"git add/rm <Datei>...\" um die Auflösung zu markieren)"
+
+#: wt-status.c:188
msgid "Changes to be committed:"
msgstr "zum Eintragen bereitgestellte Änderungen:"
-#: wt-status.c:170
+#: wt-status.c:206
msgid "Changes not staged for commit:"
msgstr "Änderungen, die nicht zum Eintragen bereitgestellt sind:"
-#: wt-status.c:174
+#: wt-status.c:210
msgid " (use \"git add <file>...\" to update what will be committed)"
msgstr " (benutze \"git add <Datei>...\" zum Bereitstellen)"
-#: wt-status.c:176
+#: wt-status.c:212
msgid " (use \"git add/rm <file>...\" to update what will be committed)"
msgstr " (benutze \"git add/rm <Datei>...\" zum Bereitstellen)"
-#: wt-status.c:177
+#: wt-status.c:213
msgid ""
" (use \"git checkout -- <file>...\" to discard changes in working directory)"
msgstr ""
" (benutze \"git checkout -- <Datei>...\" um die Änderungen im "
"Arbeitsverzeichnis zu verwerfen)"
-#: wt-status.c:179
+#: wt-status.c:215
msgid " (commit or discard the untracked or modified content in submodules)"
msgstr ""
" (trage ein oder verwerfe den unbeobachteten oder geänderten Inhalt in den "
"Unterprojekten)"
-#: wt-status.c:188
+#: wt-status.c:224
#, c-format
msgid "%s files:"
msgstr "%s Dateien:"
-#: wt-status.c:191
+#: wt-status.c:227
#, c-format
msgid " (use \"git %s <file>...\" to include in what will be committed)"
msgstr " (benutze \"git %s <Datei>...\" zum Einfügen in die Eintragung)"
-#: wt-status.c:208
+#: wt-status.c:244
msgid "bug"
msgstr "Fehler"
-#: wt-status.c:213
+#: wt-status.c:249
msgid "both deleted:"
msgstr "beide gelöscht:"
-#: wt-status.c:214
+#: wt-status.c:250
msgid "added by us:"
msgstr "von uns hinzugefügt:"
-#: wt-status.c:215
+#: wt-status.c:251
msgid "deleted by them:"
msgstr "von denen gelöscht:"
-#: wt-status.c:216
+#: wt-status.c:252
msgid "added by them:"
msgstr "von denen hinzugefügt:"
-#: wt-status.c:217
+#: wt-status.c:253
msgid "deleted by us:"
msgstr "von uns gelöscht:"
-#: wt-status.c:218
+#: wt-status.c:254
msgid "both added:"
msgstr "von beiden hinzugefügt:"
-#: wt-status.c:219
+#: wt-status.c:255
msgid "both modified:"
msgstr "von beiden geändert:"
-#: wt-status.c:249
+#: wt-status.c:285
msgid "new commits, "
msgstr "neue Versionen, "
-#: wt-status.c:251
+#: wt-status.c:287
msgid "modified content, "
msgstr "geänderter Inhalt, "
-#: wt-status.c:253
+#: wt-status.c:289
msgid "untracked content, "
msgstr "unbeobachteter Inhalt, "
-#: wt-status.c:267
+#: wt-status.c:303
#, c-format
msgid "new file: %s"
msgstr "neue Datei: %s"
-#: wt-status.c:270
+#: wt-status.c:306
#, c-format
msgid "copied: %s -> %s"
msgstr "kopiert: %s -> %s"
-#: wt-status.c:273
+#: wt-status.c:309
#, c-format
msgid "deleted: %s"
msgstr "gelöscht: %s"
-#: wt-status.c:276
+#: wt-status.c:312
#, c-format
msgid "modified: %s"
msgstr "geändert: %s"
-#: wt-status.c:279
+#: wt-status.c:315
#, c-format
msgid "renamed: %s -> %s"
msgstr "umbenannt: %s -> %s"
-#: wt-status.c:282
+#: wt-status.c:318
#, c-format
msgid "typechange: %s"
msgstr "Typänderung: %s"
-#: wt-status.c:285
+#: wt-status.c:321
#, c-format
msgid "unknown: %s"
msgstr "unbekannt: %s"
-#: wt-status.c:288
+#: wt-status.c:324
#, c-format
msgid "unmerged: %s"
msgstr "nicht zusammengeführt: %s"
-#: wt-status.c:291
+#: wt-status.c:327
#, c-format
msgid "bug: unhandled diff status %c"
msgstr "Fehler: unbehandelter Differenz-Status %c"
-#: wt-status.c:737
+#: wt-status.c:785
+msgid "You have unmerged paths."
+msgstr "Du hast nicht zusammengeführte Pfade."
+
+#: wt-status.c:788 wt-status.c:912
+msgid " (fix conflicts and run \"git commit\")"
+msgstr " (behebe die Konflikte und führe \"git commit\" aus)"
+
+#: wt-status.c:791
+msgid "All conflicts fixed but you are still merging."
+msgstr ""
+"Alle Konflikte sind behoben, aber du bist immer noch beim Zusammenführen."
+
+#: wt-status.c:794
+msgid " (use \"git commit\" to conclude merge)"
+msgstr " (benutze \"git commit\" um die Zusammenführung abzuschließen)"
+
+#: wt-status.c:804
+msgid "You are in the middle of an am session."
+msgstr "Eine \"am\"-Sitzung ist im Gange."
+
+#: wt-status.c:807
+msgid "The current patch is empty."
+msgstr "Der aktuelle Patch ist leer."
+
+#: wt-status.c:811
+msgid " (fix conflicts and then run \"git am --resolved\")"
+msgstr " (behebe die Konflikte und führe dann \"git am --resolved\" aus)"
+
+#: wt-status.c:813
+msgid " (use \"git am --skip\" to skip this patch)"
+msgstr " (benutze \"git am --skip\" um diesen Patch auszulassen)"
+
+#: wt-status.c:815
+msgid " (use \"git am --abort\" to restore the original branch)"
+msgstr ""
+" (benutze \"git am --abort\" um den ursprünglichen Zweig wiederherzustellen)"
+
+#: wt-status.c:873 wt-status.c:883
+msgid "You are currently rebasing."
+msgstr "Du bist gerade beim Neuaufbau."
+
+#: wt-status.c:876
+msgid " (fix conflicts and then run \"git rebase --continue\")"
+msgstr " (behebe die Konflikte und führe dann \"git rebase --continue\" aus)"
+
+#: wt-status.c:878
+msgid " (use \"git rebase --skip\" to skip this patch)"
+msgstr " (benutze \"git rebase --skip\" um diesen Patch auszulassen)"
+
+#: wt-status.c:880
+msgid " (use \"git rebase --abort\" to check out the original branch)"
+msgstr ""
+" (benutze \"git rebase --abort\" um den ursprünglichen Zweig auszuchecken)"
+
+#: wt-status.c:886
+msgid " (all conflicts fixed: run \"git rebase --continue\")"
+msgstr " (alle Konflikte behoben: führe \"git rebase --continue\" aus)"
+
+#: wt-status.c:888
+msgid "You are currently splitting a commit during a rebase."
+msgstr "Du teilst gerade eine Version während eines Neuaufbaus auf."
+
+#: wt-status.c:891
+msgid " (Once your working directory is clean, run \"git rebase --continue\")"
+msgstr ""
+" (Sobald dein Arbeitsverzeichnis sauber ist, führe \"git rebase --continue"
+"\" aus)"
+
+#: wt-status.c:893
+msgid "You are currently editing a commit during a rebase."
+msgstr "Du editierst gerade eine Version während eines Neuaufbaus."
+
+#: wt-status.c:896
+msgid " (use \"git commit --amend\" to amend the current commit)"
+msgstr ""
+" (benutze \"git commit --amend\" um die aktuelle Version nachzubessern)"
+
+#: wt-status.c:898
+msgid ""
+" (use \"git rebase --continue\" once you are satisfied with your changes)"
+msgstr ""
+" (benutze \"git rebase --continue\" sobald deine Änderungen abgeschlossen "
+"sind)"
+
+#: wt-status.c:908
+msgid "You are currently cherry-picking."
+msgstr "Du führst gerade \"cherry-pick\" aus."
+
+#: wt-status.c:915
+msgid " (all conflicts fixed: run \"git commit\")"
+msgstr " (alle Konflikte behoben: führe \"git commit\" aus)"
+
+#: wt-status.c:924
+msgid "You are currently bisecting."
+msgstr "Du bist gerade beim Halbieren."
+
+#: wt-status.c:927
+msgid " (use \"git bisect reset\" to get back to the original branch)"
+msgstr ""
+" (benutze \"git bisect reset\" um zum ursprünglichen Zweig zurückzukehren)"
+
+#: wt-status.c:978
msgid "On branch "
msgstr "Auf Zweig "
-#: wt-status.c:744
+#: wt-status.c:985
msgid "Not currently on any branch."
msgstr "Im Moment auf keinem Zweig."
-#: wt-status.c:755
+#: wt-status.c:997
msgid "Initial commit"
msgstr "Initiale Version"
-#: wt-status.c:769
+#: wt-status.c:1011
msgid "Untracked"
msgstr "Unbeobachtete"
-#: wt-status.c:771
+#: wt-status.c:1013
msgid "Ignored"
msgstr "Ignorierte"
-#: wt-status.c:773
+#: wt-status.c:1015
#, c-format
msgid "Untracked files not listed%s"
msgstr "Unbeobachtete Dateien nicht aufgelistet%s"
-#: wt-status.c:775
+#: wt-status.c:1017
msgid " (use -u option to show untracked files)"
msgstr " (benutze die Option -u um unbeobachteten Dateien anzuzeigen)"
-#: wt-status.c:781
+#: wt-status.c:1023
msgid "No changes"
msgstr "Keine Änderungen"
-#: wt-status.c:785
+#: wt-status.c:1027
#, c-format
msgid "no changes added to commit%s\n"
msgstr "keine Änderungen zum Eintragen hinzugefügt%s\n"
-#: wt-status.c:787
+#: wt-status.c:1029
msgid " (use \"git add\" and/or \"git commit -a\")"
msgstr " (benutze \"git add\" und/oder \"git commit -a\")"
-#: wt-status.c:789
+#: wt-status.c:1031
#, c-format
msgid "nothing added to commit but untracked files present%s\n"
msgstr ""
"nichts zum Eintragen hinzugefügt, aber es gibt unbeobachtete Dateien%s\n"
-#: wt-status.c:791
+#: wt-status.c:1033
msgid " (use \"git add\" to track)"
msgstr " (benutze \"git add\" zum Beobachten)"
-#: wt-status.c:793 wt-status.c:796 wt-status.c:799
+#: wt-status.c:1035 wt-status.c:1038 wt-status.c:1041
#, c-format
msgid "nothing to commit%s\n"
msgstr "nichts zum Eintragen%s\n"
-#: wt-status.c:794
+#: wt-status.c:1036
msgid " (create/copy files and use \"git add\" to track)"
msgstr " (Erstelle/Kopiere Dateien und benutze \"git add\" zum Beobachten)"
-#: wt-status.c:797
+#: wt-status.c:1039
msgid " (use -u to show untracked files)"
msgstr " (benutze die Option -u um unbeobachtete Dateien anzuzeigen)"
-#: wt-status.c:800
+#: wt-status.c:1042
msgid " (working directory clean)"
msgstr " (Arbeitsverzeichnis sauber)"
-#: wt-status.c:908
+#: wt-status.c:1150
msgid "HEAD (no branch)"
msgstr "HEAD (kein Zweig)"
-#: wt-status.c:914
+#: wt-status.c:1156
msgid "Initial commit on "
msgstr "Initiale Version auf "
-#: wt-status.c:929
+#: wt-status.c:1171
msgid "behind "
msgstr "hinterher "
-#: wt-status.c:932 wt-status.c:935
+#: wt-status.c:1174 wt-status.c:1177
msgid "ahead "
msgstr "voraus "
-#: wt-status.c:937
+#: wt-status.c:1179
msgid ", behind "
msgstr ", hinterher "
+#: compat/precompose_utf8.c:58 builtin/clone.c:341
+#, c-format
+msgid "failed to unlink '%s'"
+msgstr "Konnte '%s' nicht entfernen"
+
#: builtin/add.c:62
#, c-format
msgid "unexpected diff status %c"
msgstr "unerwarteter Differenz-Status %c"
-#: builtin/add.c:67 builtin/commit.c:226
+#: builtin/add.c:67 builtin/commit.c:229
msgid "updating files failed"
msgstr "Aktualisierung der Dateien fehlgeschlagen"
@@ -937,7 +1314,7 @@ msgid "Unstaged changes after refreshing the index:"
msgstr ""
"Nicht bereitgestellte Änderungen nach Aktualisierung der Bereitstellung:"
-#: builtin/add.c:195 builtin/add.c:456 builtin/rm.c:186
+#: builtin/add.c:195 builtin/add.c:459 builtin/rm.c:186
#, c-format
msgid "pathspec '%s' did not match any files"
msgstr "Pfadspezifikation '%s' stimmt mit keinen Dateien überein"
@@ -1012,79 +1389,79 @@ msgstr "Nichts spezifiziert, nichts hinzugefügt.\n"
msgid "Maybe you wanted to say 'git add .'?\n"
msgstr "Wolltest du vielleicht 'git add .' sagen?\n"
-#: builtin/add.c:420 builtin/clean.c:95 builtin/commit.c:286 builtin/mv.c:82
+#: builtin/add.c:420 builtin/clean.c:95 builtin/commit.c:289 builtin/mv.c:82
#: builtin/rm.c:162
msgid "index file corrupt"
msgstr "Bereitstellungsdatei beschädigt"
-#: builtin/add.c:476 builtin/apply.c:4108 builtin/mv.c:229 builtin/rm.c:260
+#: builtin/add.c:480 builtin/apply.c:4432 builtin/mv.c:229 builtin/rm.c:260
msgid "Unable to write new index file"
msgstr "Konnte neue Bereitstellungsdatei nicht schreiben."
-#: builtin/apply.c:53
+#: builtin/apply.c:57
msgid "git apply [options] [<patch>...]"
msgstr "git apply [Optionen] [<Patch>...]"
-#: builtin/apply.c:106
+#: builtin/apply.c:110
#, c-format
msgid "unrecognized whitespace option '%s'"
msgstr "nicht erkannte Option für Leerzeichen: '%s'"
-#: builtin/apply.c:121
+#: builtin/apply.c:125
#, c-format
msgid "unrecognized whitespace ignore option '%s'"
msgstr "nicht erkannte Option zum Ignorieren von Leerzeichen: '%s'"
-#: builtin/apply.c:815
+#: builtin/apply.c:823
#, c-format
msgid "Cannot prepare timestamp regexp %s"
msgstr "Kann regulären Ausdruck für Zeitstempel %s nicht verarbeiten"
-#: builtin/apply.c:824
+#: builtin/apply.c:832
#, c-format
msgid "regexec returned %d for input: %s"
msgstr "Ausführung des regulären Ausdrucks gab %d zurück. Eingabe: %s"
-#: builtin/apply.c:905
+#: builtin/apply.c:913
#, c-format
msgid "unable to find filename in patch at line %d"
msgstr "Konnte keinen Dateinamen in Zeile %d des Patches finden."
-#: builtin/apply.c:937
+#: builtin/apply.c:945
#, c-format
msgid "git apply: bad git-diff - expected /dev/null, got %s on line %d"
msgstr ""
"git apply: ungültiges 'git-diff' - erwartete /dev/null, erhielt %s in Zeile "
"%d"
-#: builtin/apply.c:941
+#: builtin/apply.c:949
#, c-format
msgid "git apply: bad git-diff - inconsistent new filename on line %d"
msgstr ""
"git apply: ungültiges 'git-diff' - Inkonsistenter neuer Dateiname in Zeile %d"
-#: builtin/apply.c:942
+#: builtin/apply.c:950
#, c-format
msgid "git apply: bad git-diff - inconsistent old filename on line %d"
msgstr ""
"git apply: ungültiges 'git-diff' - Inkonsistenter alter Dateiname in Zeile %d"
-#: builtin/apply.c:949
+#: builtin/apply.c:957
#, c-format
msgid "git apply: bad git-diff - expected /dev/null on line %d"
msgstr "git apply: ungültiges 'git-diff' - erwartete /dev/null in Zeile %d"
-#: builtin/apply.c:1394
+#: builtin/apply.c:1402
#, c-format
msgid "recount: unexpected line: %.*s"
msgstr "recount: unerwartete Zeile: %.*s"
-#: builtin/apply.c:1451
+#: builtin/apply.c:1459
#, c-format
msgid "patch fragment without header at line %d: %.*s"
msgstr "Patch-Fragment ohne Kopfbereich bei Zeile %d: %.*s"
-#: builtin/apply.c:1468
+#: builtin/apply.c:1476
#, c-format
msgid ""
"git diff header lacks filename information when removing %d leading pathname "
@@ -1099,70 +1476,70 @@ msgstr[1] ""
"Dem Kopfbereich von \"git diff\" fehlen Informationen zum Dateinamen, wenn "
"%d vorangestellte Teile des Pfades entfernt werden (Zeile %d)"
-#: builtin/apply.c:1628
+#: builtin/apply.c:1636
msgid "new file depends on old contents"
msgstr "neue Datei hängt von alten Inhalten ab"
-#: builtin/apply.c:1630
+#: builtin/apply.c:1638
msgid "deleted file still has contents"
msgstr "entfernte Datei hat noch Inhalte"
-#: builtin/apply.c:1656
+#: builtin/apply.c:1664
#, c-format
msgid "corrupt patch at line %d"
msgstr "fehlerhafter Patch bei Zeile %d"
-#: builtin/apply.c:1692
+#: builtin/apply.c:1700
#, c-format
msgid "new file %s depends on old contents"
msgstr "neue Datei %s hängt von alten Inhalten ab"
-#: builtin/apply.c:1694
+#: builtin/apply.c:1702
#, c-format
msgid "deleted file %s still has contents"
msgstr "entfernte Datei %s hat noch Inhalte"
-#: builtin/apply.c:1697
+#: builtin/apply.c:1705
#, c-format
msgid "** warning: file %s becomes empty but is not deleted"
msgstr "** Warnung: Datei %s wird leer, aber nicht entfernt."
-#: builtin/apply.c:1843
+#: builtin/apply.c:1851
#, c-format
msgid "corrupt binary patch at line %d: %.*s"
msgstr "fehlerhafter Binär-Patch bei Zeile %d: %.*s"
#. there has to be one hunk (forward hunk)
-#: builtin/apply.c:1872
+#: builtin/apply.c:1880
#, c-format
msgid "unrecognized binary patch at line %d"
msgstr "nicht erkannter Binär-Patch bei Zeile %d"
-#: builtin/apply.c:1958
+#: builtin/apply.c:1966
#, c-format
msgid "patch with only garbage at line %d"
msgstr "Patch mit nutzlosen Informationen bei Zeile %d"
-#: builtin/apply.c:2048
+#: builtin/apply.c:2056
#, c-format
msgid "unable to read symlink %s"
msgstr "konnte symbolische Verknüpfung %s nicht lesen"
-#: builtin/apply.c:2052
+#: builtin/apply.c:2060
#, c-format
msgid "unable to open or read %s"
msgstr "konnte %s nicht öffnen oder lesen"
-#: builtin/apply.c:2123
+#: builtin/apply.c:2131
msgid "oops"
msgstr "Ups"
-#: builtin/apply.c:2645
+#: builtin/apply.c:2653
#, c-format
msgid "invalid start of line: '%c'"
msgstr "Ungültiger Zeilenanfang: '%c'"
-#: builtin/apply.c:2763
+#: builtin/apply.c:2771
#, c-format
msgid "Hunk #%d succeeded at %d (offset %d line)."
msgid_plural "Hunk #%d succeeded at %d (offset %d lines)."
@@ -1170,12 +1547,12 @@ msgstr[0] "Patch-Bereich #%d erfolgreich angewendet bei %d (%d Zeile versetzt)"
msgstr[1] ""
"Patch-Bereich #%d erfolgreich angewendet bei %d (%d Zeilen versetzt)"
-#: builtin/apply.c:2775
+#: builtin/apply.c:2783
#, c-format
msgid "Context reduced to (%ld/%ld) to apply fragment at %d"
msgstr "Kontext reduziert zu (%ld/%ld) um Patch-Bereich bei %d anzuwenden"
-#: builtin/apply.c:2781
+#: builtin/apply.c:2789
#, c-format
msgid ""
"while searching for:\n"
@@ -1184,329 +1561,339 @@ msgstr ""
"bei der Suche nach:\n"
"%.*s"
-#: builtin/apply.c:2800
+#: builtin/apply.c:2808
#, c-format
msgid "missing binary patch data for '%s'"
msgstr "keine Daten in Binär-Patch für '%s'"
-#: builtin/apply.c:2903
+#: builtin/apply.c:2911
#, c-format
msgid "binary patch does not apply to '%s'"
msgstr "Konnte Binär-Patch nicht auf '%s' anwenden"
-#: builtin/apply.c:2909
+#: builtin/apply.c:2917
#, c-format
msgid "binary patch to '%s' creates incorrect result (expecting %s, got %s)"
msgstr ""
"Binär-Patch für '%s' erzeugt falsches Ergebnis (erwartete %s, bekam %s)"
-#: builtin/apply.c:2930
+#: builtin/apply.c:2938
#, c-format
msgid "patch failed: %s:%ld"
msgstr "Anwendung des Patches fehlgeschlagen: %s:%ld"
-#: builtin/apply.c:3045
+#: builtin/apply.c:3060
#, c-format
-msgid "patch %s has been renamed/deleted"
-msgstr "Patch %s wurde umbenannt/gelöscht"
+msgid "cannot checkout %s"
+msgstr "kann %s nicht auschecken"
-#: builtin/apply.c:3052 builtin/apply.c:3069
+#: builtin/apply.c:3105 builtin/apply.c:3114 builtin/apply.c:3158
#, c-format
msgid "read of %s failed"
msgstr "Konnte %s nicht lesen"
-#: builtin/apply.c:3084
-msgid "removal patch leaves file contents"
-msgstr "Lösch-Patch hinterlässt Dateiinhalte"
-
-#: builtin/apply.c:3105
+#: builtin/apply.c:3138 builtin/apply.c:3360
#, c-format
-msgid "%s: already exists in working directory"
-msgstr "%s existiert bereits im Arbeitsverzeichnis"
+msgid "path %s has been renamed/deleted"
+msgstr "Pfad %s wurde umbenannt/gelöscht"
-#: builtin/apply.c:3143
+#: builtin/apply.c:3219 builtin/apply.c:3374
#, c-format
-msgid "%s: has been deleted/renamed"
-msgstr "%s wurde gelöscht/umbenannt"
+msgid "%s: does not exist in index"
+msgstr "%s ist nicht bereitgestellt"
-#: builtin/apply.c:3148 builtin/apply.c:3179
+#: builtin/apply.c:3223 builtin/apply.c:3366 builtin/apply.c:3388
#, c-format
msgid "%s: %s"
msgstr "%s: %s"
-#: builtin/apply.c:3159
-#, c-format
-msgid "%s: does not exist in index"
-msgstr "%s ist nicht bereitgestellt"
-
-#: builtin/apply.c:3173
+#: builtin/apply.c:3228 builtin/apply.c:3382
#, c-format
msgid "%s: does not match index"
msgstr "%s entspricht nicht der Bereitstellung"
-#: builtin/apply.c:3190
+#: builtin/apply.c:3330
+msgid "removal patch leaves file contents"
+msgstr "Lösch-Patch hinterlässt Dateiinhalte"
+
+#: builtin/apply.c:3399
#, c-format
msgid "%s: wrong type"
msgstr "%s: falscher Typ"
-#: builtin/apply.c:3192
+#: builtin/apply.c:3401
#, c-format
msgid "%s has type %o, expected %o"
msgstr "%s ist vom Typ %o, erwartete %o"
-#: builtin/apply.c:3247
+#: builtin/apply.c:3502
#, c-format
msgid "%s: already exists in index"
msgstr "%s ist bereits bereitgestellt"
-#: builtin/apply.c:3267
+#: builtin/apply.c:3505
+#, c-format
+msgid "%s: already exists in working directory"
+msgstr "%s existiert bereits im Arbeitsverzeichnis"
+
+#: builtin/apply.c:3525
#, c-format
msgid "new mode (%o) of %s does not match old mode (%o)"
msgstr "neuer Modus (%o) von %s entspricht nicht dem alten Modus (%o)"
-#: builtin/apply.c:3272
+#: builtin/apply.c:3530
#, c-format
msgid "new mode (%o) of %s does not match old mode (%o) of %s"
msgstr "neuer Modus (%o) von %s entspricht nicht dem alten Modus (%o) von %s"
-#: builtin/apply.c:3280
+#: builtin/apply.c:3538
#, c-format
msgid "%s: patch does not apply"
msgstr "%s: Patch konnte nicht angewendet werden"
-#: builtin/apply.c:3293
+#: builtin/apply.c:3551
#, c-format
msgid "Checking patch %s..."
msgstr "Prüfe Patch %s..."
-#: builtin/apply.c:3348 builtin/checkout.c:212 builtin/reset.c:158
+#: builtin/apply.c:3606 builtin/checkout.c:213 builtin/reset.c:158
#, c-format
msgid "make_cache_entry failed for path '%s'"
msgstr "make_cache_entry für Pfad '%s' fehlgeschlagen"
-#: builtin/apply.c:3491
+#: builtin/apply.c:3749
#, c-format
msgid "unable to remove %s from index"
msgstr "konnte %s nicht aus der Bereitstellung entfernen"
-#: builtin/apply.c:3518
+#: builtin/apply.c:3777
#, c-format
msgid "corrupt patch for subproject %s"
msgstr "fehlerhafter Patch für Unterprojekt %s"
-#: builtin/apply.c:3522
+#: builtin/apply.c:3781
#, c-format
msgid "unable to stat newly created file '%s'"
msgstr "konnte neu erstellte Datei '%s' nicht lesen"
-#: builtin/apply.c:3527
+#: builtin/apply.c:3786
#, c-format
msgid "unable to create backing store for newly created file %s"
msgstr "kann internen Speicher für eben erstellte Datei %s nicht erzeugen"
-#: builtin/apply.c:3530
+#: builtin/apply.c:3789 builtin/apply.c:3897
#, c-format
msgid "unable to add cache entry for %s"
msgstr "kann für %s keinen Eintrag in den Zwischenspeicher hinzufügen"
-#: builtin/apply.c:3563
+#: builtin/apply.c:3822
#, c-format
msgid "closing file '%s'"
msgstr "schließe Datei '%s'"
-#: builtin/apply.c:3612
+#: builtin/apply.c:3871
#, c-format
msgid "unable to write file '%s' mode %o"
msgstr "konnte Datei '%s' mit Modus %o nicht schreiben"
-#: builtin/apply.c:3668
+#: builtin/apply.c:3958
#, c-format
msgid "Applied patch %s cleanly."
msgstr "Patch %s sauber angewendet"
-#: builtin/apply.c:3676
+#: builtin/apply.c:3966
msgid "internal error"
msgstr "interner Fehler"
#. Say this even without --verbose
-#: builtin/apply.c:3679
+#: builtin/apply.c:3969
#, c-format
msgid "Applying patch %%s with %d reject..."
msgid_plural "Applying patch %%s with %d rejects..."
msgstr[0] "Wende Patch %%s mit %d Zurückweisung an..."
msgstr[1] "Wende Patch %%s mit %d Zurückweisungen an..."
-#: builtin/apply.c:3689
+#: builtin/apply.c:3979
#, c-format
msgid "truncating .rej filename to %.*s.rej"
msgstr "Verkürze Name von .rej Datei zu %.*s.rej"
-#: builtin/apply.c:3710
+#: builtin/apply.c:4000
#, c-format
msgid "Hunk #%d applied cleanly."
msgstr "Patch-Bereich #%d sauber angewendet."
-#: builtin/apply.c:3713
+#: builtin/apply.c:4003
#, c-format
msgid "Rejected hunk #%d."
msgstr "Patch-Bereich #%d zurückgewiesen."
-#: builtin/apply.c:3844
+#: builtin/apply.c:4153
msgid "unrecognized input"
msgstr "nicht erkannte Eingabe"
-#: builtin/apply.c:3855
+#: builtin/apply.c:4164
msgid "unable to read index file"
msgstr "Konnte Bereitstellungsdatei nicht lesen"
-#: builtin/apply.c:3970 builtin/apply.c:3973
+#: builtin/apply.c:4283 builtin/apply.c:4286
msgid "path"
msgstr "Pfad"
-#: builtin/apply.c:3971
+#: builtin/apply.c:4284
msgid "don't apply changes matching the given path"
msgstr "wendet keine Änderungen im angegebenen Pfad an"
-#: builtin/apply.c:3974
+#: builtin/apply.c:4287
msgid "apply changes matching the given path"
msgstr "wendet Änderungen nur im angegebenen Pfad an"
-#: builtin/apply.c:3976
+#: builtin/apply.c:4289
msgid "num"
msgstr "Anzahl"
-#: builtin/apply.c:3977
+#: builtin/apply.c:4290
msgid "remove <num> leading slashes from traditional diff paths"
msgstr ""
-"entfernt <Anzahl> vorrangestellte Schrägstriche von herkömmlichen "
+"entfernt <Anzahl> vorangestellte Schrägstriche von herkömmlichen "
"Differenzpfaden"
-#: builtin/apply.c:3980
+#: builtin/apply.c:4293
msgid "ignore additions made by the patch"
msgstr "ignoriert hinzugefügte Zeilen des Patches"
-#: builtin/apply.c:3982
+#: builtin/apply.c:4295
msgid "instead of applying the patch, output diffstat for the input"
msgstr ""
"anstatt der Anwendung des Patches, wird der \"diffstat\" für die Eingabe "
"ausgegeben"
-#: builtin/apply.c:3986
+#: builtin/apply.c:4299
msgid "shows number of added and deleted lines in decimal notation"
msgstr ""
"zeigt die Anzahl von hinzugefügten/entfernten Zeilen in Dezimalnotation"
-#: builtin/apply.c:3988
+#: builtin/apply.c:4301
msgid "instead of applying the patch, output a summary for the input"
msgstr ""
"anstatt der Anwendung des Patches, wird eine Zusammenfassung für die Eingabe "
"ausgegeben"
-#: builtin/apply.c:3990
+#: builtin/apply.c:4303
msgid "instead of applying the patch, see if the patch is applicable"
msgstr ""
"anstatt der Anwendung des Patches, zeige ob Patch angewendet werden kann"
-#: builtin/apply.c:3992
+#: builtin/apply.c:4305
msgid "make sure the patch is applicable to the current index"
msgstr ""
"stellt sicher, dass der Patch in der aktuellen Bereitstellung angewendet "
"werden kann"
-#: builtin/apply.c:3994
+#: builtin/apply.c:4307
msgid "apply a patch without touching the working tree"
msgstr "wendet einen Patch an, ohne Änderungen im Arbeitszweig vorzunehmen"
-#: builtin/apply.c:3996
+#: builtin/apply.c:4309
msgid "also apply the patch (use with --stat/--summary/--check)"
msgstr "wendet den Patch an (Benutzung mit --stat/--summary/--check)"
-#: builtin/apply.c:3998
+#: builtin/apply.c:4311
+msgid "attempt three-way merge if a patch does not apply"
+msgstr ""
+"versucht 3-Wege-Zusammenführung, wenn der Patch nicht angewendet werden "
+"konnte"
+
+#: builtin/apply.c:4313
msgid "build a temporary index based on embedded index information"
msgstr ""
"erstellt eine temporäre Bereitstellung basierend auf den integrierten "
"Bereitstellungsinformationen"
-#: builtin/apply.c:4000
+#: builtin/apply.c:4315
msgid "paths are separated with NUL character"
msgstr "Pfade sind getrennt durch NUL Zeichen"
-#: builtin/apply.c:4003
+#: builtin/apply.c:4318
msgid "ensure at least <n> lines of context match"
msgstr ""
"stellt sicher, dass mindestens <Anzahl> Zeilen des Kontextes übereinstimmen"
-#: builtin/apply.c:4004
+#: builtin/apply.c:4319
msgid "action"
msgstr "Aktion"
-#: builtin/apply.c:4005
+#: builtin/apply.c:4320
msgid "detect new or modified lines that have whitespace errors"
msgstr "ermittelt neue oder geänderte Zeilen die Fehler in Leerzeichen haben"
-#: builtin/apply.c:4008 builtin/apply.c:4011
+#: builtin/apply.c:4323 builtin/apply.c:4326
msgid "ignore changes in whitespace when finding context"
msgstr "ignoriert Änderungen in Leerzeichen bei der Suche des Kontextes"
-#: builtin/apply.c:4014
+#: builtin/apply.c:4329
msgid "apply the patch in reverse"
msgstr "wendet den Patch in umgekehrter Reihenfolge an"
-#: builtin/apply.c:4016
+#: builtin/apply.c:4331
msgid "don't expect at least one line of context"
msgstr "erwartet keinen Kontext"
-#: builtin/apply.c:4018
+#: builtin/apply.c:4333
msgid "leave the rejected hunks in corresponding *.rej files"
msgstr ""
"hinterlässt zurückgewiesene Patch-Bereiche in den entsprechenden *.rej "
"Dateien"
-#: builtin/apply.c:4020
+#: builtin/apply.c:4335
msgid "allow overlapping hunks"
msgstr "erlaubt sich überlappende Patch-Bereiche"
-#: builtin/apply.c:4021
+#: builtin/apply.c:4336
msgid "be verbose"
msgstr "erweiterte Ausgaben"
-#: builtin/apply.c:4023
+#: builtin/apply.c:4338
msgid "tolerate incorrectly detected missing new-line at the end of file"
msgstr "toleriert fehlerhaft erkannten fehlenden Zeilenumbruch am Dateiende"
-#: builtin/apply.c:4026
+#: builtin/apply.c:4341
msgid "do not trust the line counts in the hunk headers"
msgstr "vertraut nicht den Zeilennummern im Kopf des Patch-Bereiches"
-#: builtin/apply.c:4028
+#: builtin/apply.c:4343
msgid "root"
msgstr "Wurzelverzeichnis"
-#: builtin/apply.c:4029
+#: builtin/apply.c:4344
msgid "prepend <root> to all filenames"
msgstr "stellt <Wurzelverzeichnis> vor alle Dateinamen"
-#: builtin/apply.c:4050
+#: builtin/apply.c:4366
+msgid "--3way outside a repository"
+msgstr "--3way außerhalb eines Projektarchivs"
+
+#: builtin/apply.c:4374
msgid "--index outside a repository"
msgstr "--index außerhalb eines Projektarchivs"
-#: builtin/apply.c:4053
+#: builtin/apply.c:4377
msgid "--cached outside a repository"
msgstr "--cached außerhalb eines Projektarchivs"
-#: builtin/apply.c:4069
+#: builtin/apply.c:4393
#, c-format
msgid "can't open patch '%s'"
msgstr "kann Patch '%s' nicht öffnen"
-#: builtin/apply.c:4083
+#: builtin/apply.c:4407
#, c-format
msgid "squelched %d whitespace error"
msgid_plural "squelched %d whitespace errors"
msgstr[0] "unterdrückte %d Fehler in Leerzeichen"
msgstr[1] "unterdrückte %d Fehler in Leerzeichen"
-#: builtin/apply.c:4089 builtin/apply.c:4099
+#: builtin/apply.c:4413 builtin/apply.c:4423
#, c-format
msgid "%d line adds whitespace errors."
msgid_plural "%d lines add whitespace errors."
@@ -1675,7 +2062,7 @@ msgstr "Konnte einige Referenzen nicht lesen"
#: builtin/branch.c:613
msgid "cannot rename the current branch while not on any."
msgstr ""
-"Kann aktuellen Zweig nicht umbennen, solange du dich auf keinem befindest."
+"Kann aktuellen Zweig nicht umbenennen, solange du dich auf keinem befindest."
#: builtin/branch.c:623
#, c-format
@@ -1716,7 +2103,7 @@ msgstr "Konnte Beschreibungsvorlage für Zweig nicht schreiben: %s"
msgid "Failed to resolve HEAD as a valid ref."
msgstr "Konnte Zweigspitze (HEAD) nicht als gültige Referenz auflösen."
-#: builtin/branch.c:788 builtin/clone.c:558
+#: builtin/branch.c:788 builtin/clone.c:561
msgid "HEAD not found below refs/heads!"
msgstr "Zweigspitze (HEAD) wurde nicht unter \"refs/heads\" gefunden!"
@@ -1743,54 +2130,50 @@ msgstr "Um ein Paket zu erstellen wird ein Projektarchiv benötigt."
msgid "Need a repository to unbundle."
msgstr "Zum Entpacken wird ein Projektarchiv benötigt."
-#: builtin/checkout.c:113 builtin/checkout.c:146
+#: builtin/checkout.c:114 builtin/checkout.c:147
#, c-format
msgid "path '%s' does not have our version"
msgstr "Pfad '%s' hat nicht unsere Version."
-#: builtin/checkout.c:115 builtin/checkout.c:148
+#: builtin/checkout.c:116 builtin/checkout.c:149
#, c-format
msgid "path '%s' does not have their version"
msgstr "Pfad '%s' hat nicht deren Version."
-#: builtin/checkout.c:131
+#: builtin/checkout.c:132
#, c-format
msgid "path '%s' does not have all necessary versions"
msgstr "Pfad '%s' hat nicht alle notwendigen Versionen."
-#: builtin/checkout.c:175
+#: builtin/checkout.c:176
#, c-format
msgid "path '%s' does not have necessary versions"
msgstr "Pfad '%s' hat nicht die notwendigen Versionen."
-#: builtin/checkout.c:192
+#: builtin/checkout.c:193
#, c-format
msgid "path '%s': cannot merge"
msgstr "Pfad '%s': kann nicht zusammenführen"
-#: builtin/checkout.c:209
+#: builtin/checkout.c:210
#, c-format
msgid "Unable to add merge result for '%s'"
msgstr "Konnte Ergebnis der Zusammenführung von '%s' nicht hinzufügen."
-#: builtin/checkout.c:234 builtin/checkout.c:392
+#: builtin/checkout.c:235 builtin/checkout.c:392
msgid "corrupt index file"
msgstr "beschädigte Bereitstellungsdatei"
-#: builtin/checkout.c:264 builtin/checkout.c:271
+#: builtin/checkout.c:265 builtin/checkout.c:272
#, c-format
msgid "path '%s' is unmerged"
msgstr "Pfad '%s' ist nicht zusammengeführt."
-#: builtin/checkout.c:302 builtin/checkout.c:498 builtin/clone.c:583
-#: builtin/merge.c:812
+#: builtin/checkout.c:303 builtin/checkout.c:498 builtin/clone.c:586
+#: builtin/merge.c:811
msgid "unable to write new index file"
msgstr "Konnte neue Bereitstellungsdatei nicht schreiben."
-#: builtin/checkout.c:319 builtin/diff.c:302 builtin/merge.c:408
-msgid "diff_setup_done failed"
-msgstr "diff_setup_done fehlgeschlagen"
-
#: builtin/checkout.c:414
msgid "you need to resolve your current index first"
msgstr "Du musst zuerst deine aktuelle Bereitstellung auflösen."
@@ -1881,7 +2264,7 @@ msgstr "interner Fehler im Revisionsgang"
msgid "Previous HEAD position was"
msgstr "Vorherige Position der Zweigspitze (HEAD) war"
-#: builtin/checkout.c:724
+#: builtin/checkout.c:724 builtin/checkout.c:919
msgid "You are on a branch yet to be born"
msgstr "du bist auf einem Zweig, der noch geboren wird"
@@ -1897,47 +2280,47 @@ msgstr "Ungültige Referenz: %s"
msgid "reference is not a tree: %s"
msgstr "Referenz ist kein Baum: %s"
-#: builtin/checkout.c:974
+#: builtin/checkout.c:976
msgid "-B cannot be used with -b"
msgstr "-B kann nicht mit -b benutzt werden"
-#: builtin/checkout.c:983
+#: builtin/checkout.c:985
msgid "--patch is incompatible with all other options"
msgstr "--patch ist inkompatibel mit allen anderen Optionen"
-#: builtin/checkout.c:986
+#: builtin/checkout.c:988
msgid "--detach cannot be used with -b/-B/--orphan"
msgstr "--detach kann nicht mit -b/-B/--orphan benutzt werden"
-#: builtin/checkout.c:988
+#: builtin/checkout.c:990
msgid "--detach cannot be used with -t"
msgstr "--detach kann nicht mit -t benutzt werden"
-#: builtin/checkout.c:994
+#: builtin/checkout.c:996
msgid "--track needs a branch name"
msgstr "--track benötigt einen Zweignamen"
-#: builtin/checkout.c:1001
+#: builtin/checkout.c:1003
msgid "Missing branch name; try -b"
msgstr "Vermisse Zweignamen; versuche -b"
-#: builtin/checkout.c:1007
+#: builtin/checkout.c:1009
msgid "--orphan and -b|-B are mutually exclusive"
msgstr "--orphan und -b|-B sind gegenseitig exklusiv"
-#: builtin/checkout.c:1009
+#: builtin/checkout.c:1011
msgid "--orphan cannot be used with -t"
msgstr "--orphan kann nicht mit -t benutzt werden"
-#: builtin/checkout.c:1019
+#: builtin/checkout.c:1021
msgid "git checkout: -f and -m are incompatible"
msgstr "git checkout: -f und -m sind inkompatibel"
-#: builtin/checkout.c:1053
+#: builtin/checkout.c:1055
msgid "invalid path specification"
msgstr "ungültige Pfadspezifikation"
-#: builtin/checkout.c:1061
+#: builtin/checkout.c:1063
#, c-format
msgid ""
"git checkout: updating paths is incompatible with switching branches.\n"
@@ -1948,29 +2331,29 @@ msgstr ""
"Hast du beabsichtigt '%s' auszuchecken, welcher nicht als Version aufgelöst "
"werden kann?"
-#: builtin/checkout.c:1063
+#: builtin/checkout.c:1065
msgid "git checkout: updating paths is incompatible with switching branches."
msgstr ""
"git checkout: Die Aktualisierung von Pfaden ist inkompatibel mit dem Wechsel "
"von Zweigen."
-#: builtin/checkout.c:1068
+#: builtin/checkout.c:1070
msgid "git checkout: --detach does not take a path argument"
msgstr "git checkout: --detach nimmt kein Pfad-Argument"
-#: builtin/checkout.c:1071
+#: builtin/checkout.c:1073
msgid ""
"git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
"checking out of the index."
msgstr ""
-"git checkout: --ours/--theirs, --force and --merge sind inkompatibel wenn\n"
+"git checkout: --ours/--theirs, --force und --merge sind inkompatibel wenn\n"
"du aus der Bereitstellung auscheckst."
-#: builtin/checkout.c:1090
+#: builtin/checkout.c:1092
msgid "Cannot switch branch to a non-commit."
msgstr "Kann Zweig nur zu einer Version wechseln."
-#: builtin/checkout.c:1093
+#: builtin/checkout.c:1095
msgid "--ours/--theirs is incompatible with switching branches."
msgstr "--ours/--theirs ist inkompatibel mit den Wechseln von Zweigen."
@@ -2023,17 +2406,12 @@ msgstr "Entferne nicht %s\n"
msgid "reference repository '%s' is not a local directory."
msgstr "Referenziertes Projektarchiv '%s' ist kein lokales Verzeichnis."
-#: builtin/clone.c:302
-#, c-format
-msgid "failed to open '%s'"
-msgstr "Fehler beim Öffnen von '%s'"
-
#: builtin/clone.c:306
#, c-format
msgid "failed to create directory '%s'"
msgstr "Fehler beim Erstellen von Verzeichnis '%s'"
-#: builtin/clone.c:308 builtin/diff.c:75
+#: builtin/clone.c:308 builtin/diff.c:77
#, c-format
msgid "failed to stat '%s'"
msgstr "Konnte '%s' nicht lesen"
@@ -2048,11 +2426,6 @@ msgstr "%s existiert und ist kein Verzeichnis"
msgid "failed to stat %s\n"
msgstr "Konnte %s nicht lesen\n"
-#: builtin/clone.c:341
-#, c-format
-msgid "failed to unlink '%s'"
-msgstr "Konnte '%s' nicht entfernen"
-
#: builtin/clone.c:346
#, c-format
msgid "failed to create link '%s'"
@@ -2068,80 +2441,80 @@ msgstr "Konnte Datei nicht nach '%s' kopieren"
msgid "done.\n"
msgstr "Fertig.\n"
-#: builtin/clone.c:440
+#: builtin/clone.c:443
#, c-format
msgid "Could not find remote branch %s to clone."
msgstr "Konnte zu klonenden externer Zweig %s nicht finden."
-#: builtin/clone.c:549
+#: builtin/clone.c:552
msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n"
msgstr ""
"Externe Zweigspitze (HEAD) bezieht sich auf eine nicht existierende Referenz "
"und kann nicht ausgecheckt werden.\n"
-#: builtin/clone.c:639
+#: builtin/clone.c:642
msgid "Too many arguments."
msgstr "Zu viele Argumente."
-#: builtin/clone.c:643
+#: builtin/clone.c:646
msgid "You must specify a repository to clone."
msgstr "Du musst ein Projektarchiv zum Klonen angeben."
-#: builtin/clone.c:654
+#: builtin/clone.c:657
#, c-format
msgid "--bare and --origin %s options are incompatible."
msgstr "--bare und --origin %s Optionen sind inkompatibel."
-#: builtin/clone.c:668
+#: builtin/clone.c:671
#, c-format
msgid "repository '%s' does not exist"
msgstr "Projektarchiv '%s' existiert nicht."
-#: builtin/clone.c:673
+#: builtin/clone.c:676
msgid "--depth is ignored in local clones; use file:// instead."
msgstr "--depth wird in lokalen Klonen ignoriert; benutze stattdessen file://."
-#: builtin/clone.c:683
+#: builtin/clone.c:686
#, c-format
msgid "destination path '%s' already exists and is not an empty directory."
msgstr "Zielpfad '%s' existiert bereits und ist kein leeres Verzeichnis."
-#: builtin/clone.c:693
+#: builtin/clone.c:696
#, c-format
msgid "working tree '%s' already exists."
msgstr "Arbeitsbaum '%s' existiert bereits."
-#: builtin/clone.c:706 builtin/clone.c:720
+#: builtin/clone.c:709 builtin/clone.c:723
#, c-format
msgid "could not create leading directories of '%s'"
msgstr "Konnte führende Verzeichnisse von '%s' nicht erstellen."
-#: builtin/clone.c:709
+#: builtin/clone.c:712
#, c-format
msgid "could not create work tree dir '%s'."
msgstr "Konnte Arbeitsverzeichnis '%s' nicht erstellen."
-#: builtin/clone.c:728
+#: builtin/clone.c:731
#, c-format
msgid "Cloning into bare repository '%s'...\n"
msgstr "Klone in bloßes Projektarchiv '%s'...\n"
-#: builtin/clone.c:730
+#: builtin/clone.c:733
#, c-format
msgid "Cloning into '%s'...\n"
msgstr "Klone nach '%s'...\n"
-#: builtin/clone.c:786
+#: builtin/clone.c:789
#, c-format
msgid "Don't know how to clone %s"
msgstr "Weiß nicht wie %s zu klonen ist."
-#: builtin/clone.c:835
+#: builtin/clone.c:838
#, c-format
msgid "Remote branch %s not found in upstream %s"
msgstr "externer Zweig %s nicht im anderen Projektarchiv %s gefunden"
-#: builtin/clone.c:842
+#: builtin/clone.c:845
msgid "You appear to have cloned an empty repository."
msgstr "Du scheinst ein leeres Projektarchiv geklont zu haben."
@@ -2202,97 +2575,97 @@ msgstr ""
"\n"
"Andernfalls benutze bitte 'git reset'\n"
-#: builtin/commit.c:253
+#: builtin/commit.c:256
msgid "failed to unpack HEAD tree object"
msgstr "Fehler beim Entpacken des Baum-Objektes der Zweigspitze (HEAD)."
-#: builtin/commit.c:295
+#: builtin/commit.c:298
msgid "unable to create temporary index"
msgstr "Konnte temporäre Bereitstellung nicht erstellen."
-#: builtin/commit.c:301
+#: builtin/commit.c:304
msgid "interactive add failed"
msgstr "interaktives Hinzufügen fehlgeschlagen"
-#: builtin/commit.c:334 builtin/commit.c:355 builtin/commit.c:405
+#: builtin/commit.c:337 builtin/commit.c:358 builtin/commit.c:408
msgid "unable to write new_index file"
msgstr "Konnte new_index Datei nicht schreiben"
-#: builtin/commit.c:386
+#: builtin/commit.c:389
msgid "cannot do a partial commit during a merge."
msgstr ""
"Kann keine partielle Eintragung durchführen, während eine Zusammenführung im "
"Gange ist."
-#: builtin/commit.c:388
+#: builtin/commit.c:391
msgid "cannot do a partial commit during a cherry-pick."
msgstr ""
"Kann keine partielle Eintragung durchführen, während \"cherry-pick\" im "
"Gange ist."
-#: builtin/commit.c:398
+#: builtin/commit.c:401
msgid "cannot read the index"
msgstr "Kann Bereitstellung nicht lesen"
-#: builtin/commit.c:418
+#: builtin/commit.c:421
msgid "unable to write temporary index file"
msgstr "Konnte temporäre Bereitstellungsdatei nicht schreiben."
-#: builtin/commit.c:493 builtin/commit.c:499
+#: builtin/commit.c:496 builtin/commit.c:502
#, c-format
msgid "invalid commit: %s"
msgstr "Ungültige Version: %s"
-#: builtin/commit.c:522
+#: builtin/commit.c:525
msgid "malformed --author parameter"
msgstr "Fehlerhafter --author Parameter"
-#: builtin/commit.c:582
+#: builtin/commit.c:585
#, c-format
msgid "Malformed ident string: '%s'"
msgstr "Fehlerhafte Identifikations-String: '%s'"
-#: builtin/commit.c:620 builtin/commit.c:653 builtin/commit.c:967
+#: builtin/commit.c:623 builtin/commit.c:656 builtin/commit.c:970
#, c-format
msgid "could not lookup commit %s"
msgstr "Konnte Version %s nicht nachschlagen"
-#: builtin/commit.c:632 builtin/shortlog.c:296
+#: builtin/commit.c:635 builtin/shortlog.c:296
#, c-format
msgid "(reading log message from standard input)\n"
msgstr "(lese Log-Nachricht von Standard-Eingabe)\n"
-#: builtin/commit.c:634
+#: builtin/commit.c:637
msgid "could not read log from standard input"
msgstr "Konnte Log nicht von Standard-Eingabe lesen."
-#: builtin/commit.c:638
+#: builtin/commit.c:641
#, c-format
msgid "could not read log file '%s'"
msgstr "Konnte Log-Datei '%s' nicht lesen"
-#: builtin/commit.c:644
+#: builtin/commit.c:647
msgid "commit has empty message"
msgstr "Version hat eine leere Beschreibung"
-#: builtin/commit.c:660
+#: builtin/commit.c:663
msgid "could not read MERGE_MSG"
msgstr "Konnte MERGE_MSG nicht lesen"
-#: builtin/commit.c:664
+#: builtin/commit.c:667
msgid "could not read SQUASH_MSG"
msgstr "Konnte SQUASH_MSG nicht lesen"
-#: builtin/commit.c:668
+#: builtin/commit.c:671
#, c-format
msgid "could not read '%s'"
msgstr "Konnte '%s' nicht lesen"
-#: builtin/commit.c:720
+#: builtin/commit.c:723
msgid "could not write commit template"
msgstr "Konnte Versionsvorlage nicht schreiben"
-#: builtin/commit.c:731
+#: builtin/commit.c:734
#, c-format
msgid ""
"\n"
@@ -2307,7 +2680,7 @@ msgstr ""
"\t%s\n"
"und versuche es erneut.\n"
-#: builtin/commit.c:736
+#: builtin/commit.c:739
#, c-format
msgid ""
"\n"
@@ -2322,7 +2695,7 @@ msgstr ""
"\t%s\n"
"und versuche es erneut.\n"
-#: builtin/commit.c:748
+#: builtin/commit.c:751
msgid ""
"Please enter the commit message for your changes. Lines starting\n"
"with '#' will be ignored, and an empty message aborts the commit.\n"
@@ -2331,7 +2704,7 @@ msgstr ""
"die mit '#' beginnen, werden ignoriert, und eine leere Versionsbeschreibung\n"
"bricht die Eintragung ab.\n"
-#: builtin/commit.c:753
+#: builtin/commit.c:756
msgid ""
"Please enter the commit message for your changes. Lines starting\n"
"with '#' will be kept; you may remove them yourself if you want to.\n"
@@ -2342,171 +2715,171 @@ msgstr ""
"entfernen.\n"
"Eine leere Versionsbeschreibung bricht die Eintragung ab.\n"
-#: builtin/commit.c:766
+#: builtin/commit.c:769
#, c-format
msgid "%sAuthor: %s"
msgstr "%sAutor: %s"
-#: builtin/commit.c:773
+#: builtin/commit.c:776
#, c-format
msgid "%sCommitter: %s"
msgstr "%sEintragender: %s"
-#: builtin/commit.c:793
+#: builtin/commit.c:796
msgid "Cannot read index"
msgstr "Kann Bereitstellung nicht lesen"
-#: builtin/commit.c:830
+#: builtin/commit.c:833
msgid "Error building trees"
msgstr "Fehler beim Erzeugen der Zweige"
-#: builtin/commit.c:845 builtin/tag.c:361
+#: builtin/commit.c:848 builtin/tag.c:361
#, c-format
msgid "Please supply the message using either -m or -F option.\n"
msgstr "Bitte liefere eine Beschreibung entweder mit der Option -m oder -F.\n"
-#: builtin/commit.c:942
+#: builtin/commit.c:945
#, c-format
msgid "No existing author found with '%s'"
msgstr "Kein existierender Autor mit '%s' gefunden."
-#: builtin/commit.c:957 builtin/commit.c:1157
+#: builtin/commit.c:960 builtin/commit.c:1160
#, c-format
msgid "Invalid untracked files mode '%s'"
msgstr "Ungültiger Modus '%s' für unbeobachtete Dateien"
-#: builtin/commit.c:997
+#: builtin/commit.c:1000
msgid "Using both --reset-author and --author does not make sense"
msgstr "Verwendung von --reset-author und --author macht keinen Sinn."
-#: builtin/commit.c:1008
+#: builtin/commit.c:1011
msgid "You have nothing to amend."
msgstr "Du hast nichts zum nachbessern."
-#: builtin/commit.c:1011
+#: builtin/commit.c:1014
msgid "You are in the middle of a merge -- cannot amend."
msgstr "Eine Zusammenführung ist im Gange -- kann nicht nachbessern."
-#: builtin/commit.c:1013
+#: builtin/commit.c:1016
msgid "You are in the middle of a cherry-pick -- cannot amend."
msgstr "\"cherry-pick\" ist im Gange -- kann nicht nachbessern."
-#: builtin/commit.c:1016
+#: builtin/commit.c:1019
msgid "Options --squash and --fixup cannot be used together"
msgstr ""
"Die Optionen --squash und --fixup können nicht gemeinsam benutzt werden."
-#: builtin/commit.c:1026
+#: builtin/commit.c:1029
msgid "Only one of -c/-C/-F/--fixup can be used."
msgstr "Nur eines von -c/-C/-F/--fixup kann benutzt werden."
-#: builtin/commit.c:1028
+#: builtin/commit.c:1031
msgid "Option -m cannot be combined with -c/-C/-F/--fixup."
msgstr "Option -m kann nicht mit -c/-C/-F/--fixup kombiniert werden"
-#: builtin/commit.c:1036
+#: builtin/commit.c:1039
msgid "--reset-author can be used only with -C, -c or --amend."
msgstr "--reset--author kann nur mit -C, -c oder --amend benutzt werden"
-#: builtin/commit.c:1053
+#: builtin/commit.c:1056
msgid "Only one of --include/--only/--all/--interactive/--patch can be used."
msgstr ""
"Nur eines von --include/--only/--all/--interactive/--patch kann benutzt "
"werden."
-#: builtin/commit.c:1055
+#: builtin/commit.c:1058
msgid "No paths with --include/--only does not make sense."
msgstr "--include/--only machen ohne Pfade keinen Sinn."
-#: builtin/commit.c:1057
+#: builtin/commit.c:1060
msgid "Clever... amending the last one with dirty index."
msgstr ""
"Klug... die letzte Version mit einer unsauberen Bereitstellung nachbessern."
-#: builtin/commit.c:1059
+#: builtin/commit.c:1062
msgid "Explicit paths specified without -i nor -o; assuming --only paths..."
msgstr ""
"Explizite Pfade ohne -i oder -o angegeben; unter der Annahme von --only "
"Pfaden..."
-#: builtin/commit.c:1069 builtin/tag.c:577
+#: builtin/commit.c:1072 builtin/tag.c:577
#, c-format
msgid "Invalid cleanup mode %s"
msgstr "Ungültiger \"cleanup\" Modus %s"
-#: builtin/commit.c:1074
+#: builtin/commit.c:1077
msgid "Paths with -a does not make sense."
msgstr "Pfade mit -a machen keinen Sinn."
-#: builtin/commit.c:1257
+#: builtin/commit.c:1260
msgid "couldn't look up newly created commit"
msgstr "Konnte neu erstellte Version nicht nachschlagen."
-#: builtin/commit.c:1259
+#: builtin/commit.c:1262
msgid "could not parse newly created commit"
msgstr "Konnte neulich erstellte Version nicht analysieren."
-#: builtin/commit.c:1300
+#: builtin/commit.c:1303
msgid "detached HEAD"
msgstr "losgelöste Zweigspitze (HEAD)"
-#: builtin/commit.c:1302
+#: builtin/commit.c:1305
msgid " (root-commit)"
msgstr " (Basis-Version)"
-#: builtin/commit.c:1446
+#: builtin/commit.c:1449
msgid "could not parse HEAD commit"
msgstr "Konnte Version der Zweigspitze (HEAD) nicht analysieren."
-#: builtin/commit.c:1484 builtin/merge.c:509
+#: builtin/commit.c:1487 builtin/merge.c:508
#, c-format
msgid "could not open '%s' for reading"
msgstr "Konnte '%s' nicht zum Lesen öffnen."
-#: builtin/commit.c:1491
+#: builtin/commit.c:1494
#, c-format
msgid "Corrupt MERGE_HEAD file (%s)"
msgstr "Beschädigte MERGE_HEAD-Datei (%s)"
-#: builtin/commit.c:1498
+#: builtin/commit.c:1501
msgid "could not read MERGE_MODE"
msgstr "Konnte MERGE_MODE nicht lesen"
-#: builtin/commit.c:1517
+#: builtin/commit.c:1520
#, c-format
msgid "could not read commit message: %s"
msgstr "Konnte Versionsbeschreibung nicht lesen: %s"
-#: builtin/commit.c:1531
+#: builtin/commit.c:1534
#, c-format
msgid "Aborting commit; you did not edit the message.\n"
msgstr "Eintragung abgebrochen; du hast die Beschreibung nicht editiert.\n"
-#: builtin/commit.c:1536
+#: builtin/commit.c:1539
#, c-format
msgid "Aborting commit due to empty commit message.\n"
msgstr "Eintragung aufgrund leerer Versionsbeschreibung abgebrochen.\n"
-#: builtin/commit.c:1551 builtin/merge.c:936 builtin/merge.c:961
+#: builtin/commit.c:1554 builtin/merge.c:935 builtin/merge.c:960
msgid "failed to write commit object"
msgstr "Fehler beim Schreiben des Versionsobjektes."
-#: builtin/commit.c:1572
+#: builtin/commit.c:1575
msgid "cannot lock HEAD ref"
msgstr "Kann Referenz der Zweigspitze (HEAD) nicht sperren."
-#: builtin/commit.c:1576
+#: builtin/commit.c:1579
msgid "cannot update HEAD ref"
msgstr "Kann Referenz der Zweigspitze (HEAD) nicht aktualisieren."
-#: builtin/commit.c:1587
+#: builtin/commit.c:1590
msgid ""
"Repository has been updated, but unable to write\n"
"new_index file. Check that disk is not full or quota is\n"
"not exceeded, and then \"git reset HEAD\" to recover."
msgstr ""
"Das Projektarchiv wurde aktualisiert, aber die \"new_index\"-Datei\n"
-"konnte nicht geschrieben werden. Prüfe, dass dein Speicher nicht\n"
+"konnte nicht geschrieben werden. Prüfe, dass deine Festplatte nicht\n"
"voll und Dein Kontingent nicht aufgebraucht ist und führe\n"
"anschließend \"git reset HEAD\" zu Wiederherstellung aus."
@@ -2594,36 +2967,36 @@ msgstr "Keine Namen gefunden, kann nichts beschreiben."
msgid "--dirty is incompatible with committishes"
msgstr "--dirty ist inkompatibel mit Versionen"
-#: builtin/diff.c:77
+#: builtin/diff.c:79
#, c-format
msgid "'%s': not a regular file or symlink"
msgstr "'%s': keine reguläre Datei oder symbolischer Link"
-#: builtin/diff.c:220
+#: builtin/diff.c:224
#, c-format
msgid "invalid option: %s"
msgstr "Ungültige Option: %s"
-#: builtin/diff.c:297
+#: builtin/diff.c:301
msgid "Not a git repository"
msgstr "Kein Git-Projektarchiv"
-#: builtin/diff.c:347
+#: builtin/diff.c:344
#, c-format
msgid "invalid object '%s' given."
msgstr "Objekt '%s' ist ungültig."
-#: builtin/diff.c:352
+#: builtin/diff.c:349
#, c-format
msgid "more than %d trees given: '%s'"
msgstr "Mehr als %d Zweige angegeben: '%s'"
-#: builtin/diff.c:362
+#: builtin/diff.c:359
#, c-format
msgid "more than two blobs given: '%s'"
msgstr "Mehr als zwei Blobs angegeben: '%s'"
-#: builtin/diff.c:370
+#: builtin/diff.c:367
#, c-format
msgid "unhandled object '%s' given."
msgstr "unbehandeltes Objekt '%s' angegeben"
@@ -2827,85 +3200,85 @@ msgstr ""
msgid "grep: failed to create thread: %s"
msgstr "grep: Fehler beim Erzeugen eines Thread: %s"
-#: builtin/grep.c:402
+#: builtin/grep.c:454
#, c-format
msgid "Failed to chdir: %s"
msgstr "Fehler beim Verzeichniswechsel: %s"
-#: builtin/grep.c:478 builtin/grep.c:512
+#: builtin/grep.c:530 builtin/grep.c:564
#, c-format
msgid "unable to read tree (%s)"
msgstr "konnte Zweig (%s) nicht lesen"
-#: builtin/grep.c:526
+#: builtin/grep.c:578
#, c-format
msgid "unable to grep from object of type %s"
msgstr "kann \"grep\" nicht mit Objekten des Typs %s durchführen"
-#: builtin/grep.c:584
+#: builtin/grep.c:636
#, c-format
msgid "switch `%c' expects a numerical value"
msgstr "Schalter '%c' erwartet einen numerischen Wert"
-#: builtin/grep.c:601
+#: builtin/grep.c:653
#, c-format
msgid "cannot open '%s'"
msgstr "kann '%s' nicht öffnen"
-#: builtin/grep.c:885
+#: builtin/grep.c:917
msgid "no pattern given."
msgstr "keine Muster angegeben"
-#: builtin/grep.c:899
+#: builtin/grep.c:931
#, c-format
msgid "bad object %s"
msgstr "ungültiges Objekt %s"
-#: builtin/grep.c:940
+#: builtin/grep.c:972
msgid "--open-files-in-pager only works on the worktree"
msgstr "--open-files-in-pager arbeitet nur innerhalb des Arbeitsbaums"
-#: builtin/grep.c:963
+#: builtin/grep.c:995
msgid "--cached or --untracked cannot be used with --no-index."
msgstr "--cached oder --untracked kann nicht mit --no-index benutzt werden"
-#: builtin/grep.c:968
+#: builtin/grep.c:1000
msgid "--no-index or --untracked cannot be used with revs."
msgstr "--no-index oder --untracked kann nicht mit Versionen benutzt werden"
-#: builtin/grep.c:971
+#: builtin/grep.c:1003
msgid "--[no-]exclude-standard cannot be used for tracked contents."
msgstr ""
"--[no-]exlude-standard kann nicht mit beobachteten Inhalten benutzt werden"
-#: builtin/grep.c:979
+#: builtin/grep.c:1011
msgid "both --cached and trees are given."
msgstr "sowohl --cached als auch Zweige gegeben"
-#: builtin/help.c:59
+#: builtin/help.c:65
#, c-format
msgid "unrecognized help format '%s'"
msgstr "nicht erkanntes Hilfeformat: %s"
-#: builtin/help.c:87
+#: builtin/help.c:93
msgid "Failed to start emacsclient."
msgstr "Konnte emacsclient nicht starten."
-#: builtin/help.c:100
+#: builtin/help.c:106
msgid "Failed to parse emacsclient version."
msgstr "Konnte Version des emacsclient nicht parsen."
-#: builtin/help.c:108
+#: builtin/help.c:114
#, c-format
msgid "emacsclient version '%d' too old (< 22)."
msgstr "Version des emacsclient '%d' ist zu alt (< 22)."
-#: builtin/help.c:126 builtin/help.c:154 builtin/help.c:163 builtin/help.c:171
+#: builtin/help.c:132 builtin/help.c:160 builtin/help.c:169 builtin/help.c:177
#, c-format
msgid "failed to exec '%s': %s"
msgstr "Fehler beim Ausführen von '%s': %s"
-#: builtin/help.c:211
+#: builtin/help.c:217
#, c-format
msgid ""
"'%s': path for unsupported man viewer.\n"
@@ -2914,7 +3287,7 @@ msgstr ""
"'%s': Pfad für nicht unterstützten Handbuchbetrachter.\n"
"Du könntest stattdessen 'man.<Werkzeug>.cmd' benutzen."
-#: builtin/help.c:223
+#: builtin/help.c:229
#, c-format
msgid ""
"'%s': cmd for supported man viewer.\n"
@@ -2923,267 +3296,273 @@ msgstr ""
"'%s': Kommando für unterstützten Handbuchbetrachter.\n"
"Du könntest stattdessen 'man.<Werkzeug>.path' benutzen."
-#: builtin/help.c:287
+#: builtin/help.c:299
msgid "The most commonly used git commands are:"
msgstr "Die allgemein verwendeten Git-Kommandos sind:"
-#: builtin/help.c:355
+#: builtin/help.c:367
#, c-format
msgid "'%s': unknown man viewer."
msgstr "'%s': unbekannter Handbuch-Betrachter."
-#: builtin/help.c:372
+#: builtin/help.c:384
msgid "no man viewer handled the request"
msgstr "kein Handbuch-Betrachter konnte mit dieser Anfrage umgehen"
-#: builtin/help.c:380
+#: builtin/help.c:392
msgid "no info viewer handled the request"
msgstr "kein Informations-Betrachter konnte mit dieser Anfrage umgehen"
-#: builtin/help.c:391
-#, c-format
-msgid "'%s': not a documentation directory."
-msgstr "'%s' ist kein Dokumentationsverzeichnis"
-
-#: builtin/help.c:432 builtin/help.c:439
+#: builtin/help.c:447 builtin/help.c:454
#, c-format
msgid "usage: %s%s"
msgstr "Verwendung: %s%s"
-#: builtin/help.c:453
+#: builtin/help.c:470
#, c-format
msgid "`git %s' is aliased to `%s'"
msgstr "für `git %s' wurde der Alias `%s' angelegt"
-#: builtin/index-pack.c:169
+#: builtin/index-pack.c:170
#, c-format
msgid "object type mismatch at %s"
msgstr "Objekt-Typen passen bei %s nicht zusammen"
-#: builtin/index-pack.c:189
+#: builtin/index-pack.c:190
msgid "object of unexpected type"
msgstr "Objekt hat unerwarteten Typ"
-#: builtin/index-pack.c:226
+#: builtin/index-pack.c:227
#, c-format
msgid "cannot fill %d byte"
msgid_plural "cannot fill %d bytes"
msgstr[0] "kann %d Byte nicht lesen"
msgstr[1] "kann %d Bytes nicht lesen"
-#: builtin/index-pack.c:236
+#: builtin/index-pack.c:237
msgid "early EOF"
msgstr "zu frühes Dateiende"
-#: builtin/index-pack.c:237
+#: builtin/index-pack.c:238
msgid "read error on input"
msgstr "Fehler beim Lesen der Eingabe"
-#: builtin/index-pack.c:249
+#: builtin/index-pack.c:250
msgid "used more bytes than were available"
msgstr "verwendete mehr Bytes als verfügbar waren"
-#: builtin/index-pack.c:256
+#: builtin/index-pack.c:257
msgid "pack too large for current definition of off_t"
msgstr "Paket ist zu groß für die aktuelle Definition von off_t"
-#: builtin/index-pack.c:272
+#: builtin/index-pack.c:273
#, c-format
msgid "unable to create '%s'"
msgstr "konnte '%s' nicht erstellen"
-#: builtin/index-pack.c:277
+#: builtin/index-pack.c:278
#, c-format
msgid "cannot open packfile '%s'"
msgstr "Kann Paketdatei '%s' nicht öffnen"
-#: builtin/index-pack.c:291
+#: builtin/index-pack.c:292
msgid "pack signature mismatch"
msgstr "Paketsignatur stimmt nicht überein"
-#: builtin/index-pack.c:311
+#: builtin/index-pack.c:312
#, c-format
msgid "pack has bad object at offset %lu: %s"
msgstr "Paket hat ein ungültiges Objekt bei Versatz %lu: %s"
-#: builtin/index-pack.c:405
+#: builtin/index-pack.c:434
#, c-format
msgid "inflate returned %d"
msgstr "Dekomprimierung gab %d zurück"
-#: builtin/index-pack.c:450
+#: builtin/index-pack.c:483
msgid "offset value overflow for delta base object"
msgstr "Wert für Versatz bei Differenzobjekt übergelaufen"
-#: builtin/index-pack.c:458
+#: builtin/index-pack.c:491
msgid "delta base offset is out of bound"
msgstr ""
"Wert für Versatz bei Differenzobjekt liegt außerhalb des gültigen Bereichs"
-#: builtin/index-pack.c:466
+#: builtin/index-pack.c:499
#, c-format
msgid "unknown object type %d"
msgstr "Unbekannter Objekt-Typ %d"
-#: builtin/index-pack.c:495
+#: builtin/index-pack.c:530
msgid "cannot pread pack file"
msgstr "Kann Paketdatei %s nicht lesen"
-#: builtin/index-pack.c:497
+#: builtin/index-pack.c:532
#, c-format
msgid "premature end of pack file, %lu byte missing"
msgid_plural "premature end of pack file, %lu bytes missing"
msgstr[0] "frühzeitiges Ende der Paketdatei, vermisse %lu Byte"
msgstr[1] "frühzeitiges Ende der Paketdatei, vermisse %lu Bytes"
-#: builtin/index-pack.c:510
+#: builtin/index-pack.c:558
msgid "serious inflate inconsistency"
msgstr "ernsthafte Inkonsistenz nach Dekomprimierung"
-#: builtin/index-pack.c:583
-#, c-format
-msgid "cannot read existing object %s"
-msgstr "Kann existierendes Objekt %s nicht lesen."
-
-#: builtin/index-pack.c:586
+#: builtin/index-pack.c:649 builtin/index-pack.c:655 builtin/index-pack.c:678
+#: builtin/index-pack.c:712 builtin/index-pack.c:721
#, c-format
msgid "SHA1 COLLISION FOUND WITH %s !"
msgstr "SHA1 KOLLISION MIT %s GEFUNDEN !"
-#: builtin/index-pack.c:598
+#: builtin/index-pack.c:652 builtin/pack-objects.c:170
+#: builtin/pack-objects.c:262
+#, c-format
+msgid "unable to read %s"
+msgstr "kann %s nicht lesen"
+
+#: builtin/index-pack.c:718
+#, c-format
+msgid "cannot read existing object %s"
+msgstr "Kann existierendes Objekt %s nicht lesen."
+
+#: builtin/index-pack.c:732
#, c-format
msgid "invalid blob object %s"
msgstr "ungültiges Blob-Objekt %s"
-#: builtin/index-pack.c:610
+#: builtin/index-pack.c:747
#, c-format
msgid "invalid %s"
msgstr "Ungültiger Objekt-Typ %s"
-#: builtin/index-pack.c:612
+#: builtin/index-pack.c:749
msgid "Error in object"
msgstr "Fehler in Objekt"
-#: builtin/index-pack.c:614
+#: builtin/index-pack.c:751
#, c-format
msgid "Not all child objects of %s are reachable"
msgstr "Nicht alle Kind-Objekte von %s sind erreichbar"
-#: builtin/index-pack.c:687 builtin/index-pack.c:713
+#: builtin/index-pack.c:821 builtin/index-pack.c:847
msgid "failed to apply delta"
msgstr "Konnte Dateiunterschied nicht anwenden"
-#: builtin/index-pack.c:850
+#: builtin/index-pack.c:986
msgid "Receiving objects"
msgstr "Empfange Objekte"
-#: builtin/index-pack.c:850
+#: builtin/index-pack.c:986
msgid "Indexing objects"
msgstr "Indiziere Objekte"
-#: builtin/index-pack.c:872
+#: builtin/index-pack.c:1012
msgid "pack is corrupted (SHA1 mismatch)"
msgstr "Paket ist beschädigt (SHA1 unterschiedlich)"
-#: builtin/index-pack.c:877
+#: builtin/index-pack.c:1017
msgid "cannot fstat packfile"
msgstr "kann Paketdatei nicht lesen"
-#: builtin/index-pack.c:880
+#: builtin/index-pack.c:1020
msgid "pack has junk at the end"
msgstr "Paketende enthält nicht verwendbaren Inhalt"
-#: builtin/index-pack.c:903
+#: builtin/index-pack.c:1031
+msgid "confusion beyond insanity in parse_pack_objects()"
+msgstr "Fehler beim Ausführen von \"parse_pack_objects()\""
+
+#: builtin/index-pack.c:1054
msgid "Resolving deltas"
msgstr "Löse Unterschiede auf"
-#: builtin/index-pack.c:954
+#: builtin/index-pack.c:1105
msgid "confusion beyond insanity"
msgstr "Fehler beim Auflösen der Unterschiede"
-#: builtin/index-pack.c:973
+#: builtin/index-pack.c:1124
#, c-format
msgid "pack has %d unresolved delta"
msgid_plural "pack has %d unresolved deltas"
msgstr[0] "Paket hat %d unaufgelöste Unterschied"
msgstr[1] "Paket hat %d unaufgelöste Unterschiede"
-#: builtin/index-pack.c:998
+#: builtin/index-pack.c:1149
#, c-format
msgid "unable to deflate appended object (%d)"
msgstr "Konnte angehängtes Objekt (%d) nicht komprimieren"
-#: builtin/index-pack.c:1077
+#: builtin/index-pack.c:1228
#, c-format
msgid "local object %s is corrupt"
msgstr "lokales Objekt %s ist beschädigt"
-#: builtin/index-pack.c:1101
+#: builtin/index-pack.c:1252
msgid "error while closing pack file"
msgstr "Fehler beim Schließen der Paketdatei"
-#: builtin/index-pack.c:1114
+#: builtin/index-pack.c:1265
#, c-format
msgid "cannot write keep file '%s'"
msgstr "Kann Paketbeschreibungsdatei '%s' nicht schreiben"
-#: builtin/index-pack.c:1122
+#: builtin/index-pack.c:1273
#, c-format
msgid "cannot close written keep file '%s'"
msgstr "Kann eben erstellte Paketbeschreibungsdatei '%s' nicht schließen"
-#: builtin/index-pack.c:1135
+#: builtin/index-pack.c:1286
msgid "cannot store pack file"
msgstr "Kann Paketdatei nicht speichern"
-#: builtin/index-pack.c:1146
+#: builtin/index-pack.c:1297
msgid "cannot store index file"
msgstr "Kann Indexdatei nicht speichern"
-#: builtin/index-pack.c:1247
+#: builtin/index-pack.c:1398
#, c-format
msgid "Cannot open existing pack file '%s'"
msgstr "Kann existierende Paketdatei '%s' nicht öffnen"
-#: builtin/index-pack.c:1249
+#: builtin/index-pack.c:1400
#, c-format
msgid "Cannot open existing pack idx file for '%s'"
msgstr "Kann existierende Indexdatei für Paket '%s' nicht öffnen"
-#: builtin/index-pack.c:1296
+#: builtin/index-pack.c:1447
#, c-format
msgid "non delta: %d object"
msgid_plural "non delta: %d objects"
msgstr[0] "kein Unterschied: %d Objekt"
msgstr[1] "kein Unterschied: %d Objekte"
-#: builtin/index-pack.c:1303
+#: builtin/index-pack.c:1454
#, c-format
msgid "chain length = %d: %lu object"
msgid_plural "chain length = %d: %lu objects"
msgstr[0] "Länge der Objekt-Liste = %d: %lu Objekt"
msgstr[1] "Länge der Objekt-Liste = %d: %lu Objekte"
-#: builtin/index-pack.c:1330
+#: builtin/index-pack.c:1481
msgid "Cannot come back to cwd"
msgstr "Kann nicht zurück zu Arbeitsverzeichnis wechseln"
-#: builtin/index-pack.c:1374 builtin/index-pack.c:1377
-#: builtin/index-pack.c:1389 builtin/index-pack.c:1393
+#: builtin/index-pack.c:1525 builtin/index-pack.c:1528
+#: builtin/index-pack.c:1540 builtin/index-pack.c:1544
#, c-format
msgid "bad %s"
msgstr "%s ist ungültig"
-#: builtin/index-pack.c:1407
+#: builtin/index-pack.c:1558
msgid "--fix-thin cannot be used without --stdin"
msgstr "--fix-thin kann nicht ohne --stdin benutzt werden"
-#: builtin/index-pack.c:1411 builtin/index-pack.c:1421
+#: builtin/index-pack.c:1562 builtin/index-pack.c:1572
#, c-format
msgid "packfile name '%s' does not end with '.pack'"
msgstr "Name der Paketdatei '%s' endet nicht mit '.pack'"
-#: builtin/index-pack.c:1430
+#: builtin/index-pack.c:1581
msgid "--verify with no packfile name given"
msgstr "--verify ohne Name der Paketdatei angegeben"
@@ -3257,63 +3636,63 @@ msgstr "kopiere keine Vorlagen mit einer falschen Formatversion %d von '%s'"
msgid "insane git directory %s"
msgstr "ungültiges Git-Verzeichnis %s"
-#: builtin/init-db.c:322 builtin/init-db.c:325
+#: builtin/init-db.c:323 builtin/init-db.c:326
#, c-format
msgid "%s already exists"
msgstr "%s existiert bereits"
-#: builtin/init-db.c:354
+#: builtin/init-db.c:355
#, c-format
msgid "unable to handle file type %d"
msgstr "kann nicht mit Dateityp %d umgehen"
-#: builtin/init-db.c:357
+#: builtin/init-db.c:358
#, c-format
msgid "unable to move %s to %s"
msgstr "Konnte %s nicht nach %s verschieben"
-#: builtin/init-db.c:362
+#: builtin/init-db.c:363
#, c-format
msgid "Could not create git link %s"
-msgstr "Konnte git-Verknüfung %s nicht erstellen"
+msgstr "Konnte git-Verknüpfung %s nicht erstellen"
#.
#. * TRANSLATORS: The first '%s' is either "Reinitialized
#. * existing" or "Initialized empty", the second " shared" or
#. * "", and the last '%s%s' is the verbatim directory name.
#.
-#: builtin/init-db.c:419
+#: builtin/init-db.c:420
#, c-format
msgid "%s%s Git repository in %s%s\n"
msgstr "%s%s Git-Projektarchiv in %s%s\n"
-#: builtin/init-db.c:420
+#: builtin/init-db.c:421
msgid "Reinitialized existing"
msgstr "Reinitialisierte existierendes"
-#: builtin/init-db.c:420
+#: builtin/init-db.c:421
msgid "Initialized empty"
msgstr "Initialisierte leeres"
-#: builtin/init-db.c:421
+#: builtin/init-db.c:422
msgid " shared"
msgstr " gemeinsames"
-#: builtin/init-db.c:440
+#: builtin/init-db.c:441
msgid "cannot tell cwd"
msgstr "kann aktuelles Arbeitsverzeichnis nicht ermitteln"
-#: builtin/init-db.c:521 builtin/init-db.c:528
+#: builtin/init-db.c:522 builtin/init-db.c:529
#, c-format
msgid "cannot mkdir %s"
msgstr "kann Verzeichnis %s nicht erstellen"
-#: builtin/init-db.c:532
+#: builtin/init-db.c:533
#, c-format
msgid "cannot chdir to %s"
msgstr "kann nicht in Verzeichnis %s wechseln"
-#: builtin/init-db.c:554
+#: builtin/init-db.c:555
#, c-format
msgid ""
"%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-"
@@ -3322,103 +3701,103 @@ msgstr ""
"%s (oder --work-tree=<Verzeichnis>) nicht erlaubt ohne Spezifizierung von %s "
"(oder --git-dir=<Verzeichnis>)"
-#: builtin/init-db.c:578
+#: builtin/init-db.c:579
msgid "Cannot access current working directory"
msgstr "Kann nicht auf aktuelles Arbeitsverzeichnis zugreifen."
-#: builtin/init-db.c:585
+#: builtin/init-db.c:586
#, c-format
msgid "Cannot access work tree '%s'"
msgstr "Kann nicht auf Arbeitsbaum '%s' zugreifen."
-#: builtin/log.c:188
+#: builtin/log.c:189
#, c-format
msgid "Final output: %d %s\n"
msgstr "letzte Ausgabe: %d %s\n"
-#: builtin/log.c:401 builtin/log.c:489
+#: builtin/log.c:403 builtin/log.c:494
#, c-format
msgid "Could not read object %s"
msgstr "Kann Objekt %s nicht lesen."
-#: builtin/log.c:513
+#: builtin/log.c:518
#, c-format
msgid "Unknown type: %d"
msgstr "Unbekannter Typ: %d"
-#: builtin/log.c:602
+#: builtin/log.c:608
msgid "format.headers without value"
msgstr "format.headers ohne Wert"
-#: builtin/log.c:676
+#: builtin/log.c:682
msgid "name of output directory is too long"
msgstr "Name des Ausgabeverzeichnisses ist zu lang."
-#: builtin/log.c:687
+#: builtin/log.c:693
#, c-format
msgid "Cannot open patch file %s"
msgstr "Kann Patch-Datei %s nicht öffnen"
-#: builtin/log.c:701
+#: builtin/log.c:707
msgid "Need exactly one range."
msgstr "Brauche genau einen Versionsbereich."
-#: builtin/log.c:709
+#: builtin/log.c:715
msgid "Not a range."
msgstr "Kein Versionsbereich."
-#: builtin/log.c:786
+#: builtin/log.c:789
msgid "Cover letter needs email format"
msgstr "Anschreiben benötigt E-Mail-Format"
-#: builtin/log.c:859
+#: builtin/log.c:862
#, c-format
msgid "insane in-reply-to: %s"
msgstr "ungültiges in-reply-to: %s"
-#: builtin/log.c:932
+#: builtin/log.c:935
msgid "Two output directories?"
msgstr "Zwei Ausgabeverzeichnisse?"
-#: builtin/log.c:1153
+#: builtin/log.c:1157
#, c-format
msgid "bogus committer info %s"
msgstr "unechte Einreicher-Informationen %s"
-#: builtin/log.c:1198
+#: builtin/log.c:1202
msgid "-n and -k are mutually exclusive."
-msgstr "-n und -k schliessen sich gegenseitig aus"
+msgstr "-n und -k schließen sich gegenseitig aus"
-#: builtin/log.c:1200
+#: builtin/log.c:1204
msgid "--subject-prefix and -k are mutually exclusive."
-msgstr "--subject-prefix und -k schliessen sich gegenseitig aus"
+msgstr "--subject-prefix und -k schließen sich gegenseitig aus"
-#: builtin/log.c:1208
+#: builtin/log.c:1212
msgid "--name-only does not make sense"
msgstr "--name-only macht keinen Sinn"
-#: builtin/log.c:1210
+#: builtin/log.c:1214
msgid "--name-status does not make sense"
msgstr "--name-status macht keinen Sinn"
-#: builtin/log.c:1212
+#: builtin/log.c:1216
msgid "--check does not make sense"
msgstr "--check macht keinen Sinn"
-#: builtin/log.c:1235
+#: builtin/log.c:1239
msgid "standard output, or directory, which one?"
msgstr "Standard-Ausgabe oder Verzeichnis, welches von beidem?"
-#: builtin/log.c:1237
+#: builtin/log.c:1241
#, c-format
msgid "Could not create directory '%s'"
msgstr "Konnte Verzeichnis '%s' nicht erstellen."
-#: builtin/log.c:1390
+#: builtin/log.c:1394
msgid "Failed to create output files"
msgstr "Fehler beim Erstellen der Ausgabedateien."
-#: builtin/log.c:1494
+#: builtin/log.c:1498
#, c-format
msgid ""
"Could not find a tracked remote branch, please specify <upstream> manually.\n"
@@ -3426,7 +3805,7 @@ msgstr ""
"Konnte gefolgten, externen Zweig nicht finden, bitte gebe <upstream> manuell "
"an.\n"
-#: builtin/log.c:1510 builtin/log.c:1512 builtin/log.c:1524
+#: builtin/log.c:1511 builtin/log.c:1513 builtin/log.c:1525
#, c-format
msgid "Unknown commit %s"
msgstr "Unbekannte Version %s"
@@ -3491,55 +3870,51 @@ msgstr ""
"Keine Zusammenführungsbeschreibung -- Zweigspitze (HEAD) wird nicht "
"aktualisiert\n"
-#: builtin/merge.c:437
+#: builtin/merge.c:436
#, c-format
msgid "'%s' does not point to a commit"
msgstr "'%s' zeigt auf keine Version"
-#: builtin/merge.c:536
+#: builtin/merge.c:535
#, c-format
msgid "Bad branch.%s.mergeoptions string: %s"
msgstr "Ungültiger branch.%s.mergeoptions String: %s"
-#: builtin/merge.c:629
+#: builtin/merge.c:628
msgid "git write-tree failed to write a tree"
msgstr "\"git write-tree\" schlug beim Schreiben eines Baumes fehl"
-#: builtin/merge.c:679
+#: builtin/merge.c:678
msgid "failed to read the cache"
msgstr "Lesen des Zwischenspeichers fehlgeschlagen"
-#: builtin/merge.c:697
-msgid "Unable to write index."
-msgstr "Konnte Bereitstellung nicht schreiben."
-
-#: builtin/merge.c:710
+#: builtin/merge.c:709
msgid "Not handling anything other than two heads merge."
msgstr "Es wird nur die Zusammenführung von zwei Zweigen behandelt."
-#: builtin/merge.c:724
+#: builtin/merge.c:723
#, c-format
msgid "Unknown option for merge-recursive: -X%s"
msgstr "Unbekannte Option für merge-recursive: -X%s"
-#: builtin/merge.c:738
+#: builtin/merge.c:737
#, c-format
msgid "unable to write %s"
msgstr "konnte %s nicht schreiben"
-#: builtin/merge.c:877
+#: builtin/merge.c:876
#, c-format
msgid "Could not read from '%s'"
msgstr "konnte nicht von '%s' lesen"
-#: builtin/merge.c:886
+#: builtin/merge.c:885
#, c-format
msgid "Not committing merge; use 'git commit' to complete the merge.\n"
msgstr ""
"Zusammenführung wurde nicht eingetragen; benutze 'git commit' um die "
"Zusammenführung abzuschließen.\n"
-#: builtin/merge.c:892
+#: builtin/merge.c:891
msgid ""
"Please enter a commit message to explain why this merge is necessary,\n"
"especially if it merges an updated upstream into a topic branch.\n"
@@ -3555,56 +3930,56 @@ msgstr ""
"Zeilen beginnend mit '#' werden ignoriert, und eine leere Beschreibung "
"bricht die Eintragung ab.\n"
-#: builtin/merge.c:916
+#: builtin/merge.c:915
msgid "Empty commit message."
msgstr "Leere Versionsbeschreibung"
-#: builtin/merge.c:928
+#: builtin/merge.c:927
#, c-format
msgid "Wonderful.\n"
msgstr "Wunderbar.\n"
-#: builtin/merge.c:993
+#: builtin/merge.c:992
#, c-format
msgid "Automatic merge failed; fix conflicts and then commit the result.\n"
msgstr ""
"Automatische Zusammenführung fehlgeschlagen; behebe die Konflikte und trage "
"dann das Ergebnis ein.\n"
-#: builtin/merge.c:1009
+#: builtin/merge.c:1008
#, c-format
msgid "'%s' is not a commit"
msgstr "'%s' ist keine Version"
-#: builtin/merge.c:1050
+#: builtin/merge.c:1049
msgid "No current branch."
msgstr "Du befindest dich auf keinem Zweig."
-#: builtin/merge.c:1052
+#: builtin/merge.c:1051
msgid "No remote for the current branch."
msgstr "Kein externes Archiv für den aktuellen Zweig."
-#: builtin/merge.c:1054
+#: builtin/merge.c:1053
msgid "No default upstream defined for the current branch."
msgstr ""
"Es ist kein externes Standard-Projektarchiv für den aktuellen Zweig "
"definiert."
-#: builtin/merge.c:1059
+#: builtin/merge.c:1058
#, c-format
msgid "No remote tracking branch for %s from %s"
msgstr "Kein externer Übernahmezweig für %s von %s"
-#: builtin/merge.c:1146 builtin/merge.c:1303
+#: builtin/merge.c:1145 builtin/merge.c:1302
#, c-format
msgid "%s - not something we can merge"
msgstr "%s - nichts was wir zusammenführen können"
-#: builtin/merge.c:1214
+#: builtin/merge.c:1213
msgid "There is no merge to abort (MERGE_HEAD missing)."
msgstr "Es gibt keine Zusammenführung zum Abbrechen (vermisse MERGE_HEAD)"
-#: builtin/merge.c:1230 git-pull.sh:31
+#: builtin/merge.c:1229 git-pull.sh:31
msgid ""
"You have not concluded your merge (MERGE_HEAD exists).\n"
"Please, commit your changes before you can merge."
@@ -3612,12 +3987,12 @@ msgstr ""
"Du hast deine Zusammenführung nicht abgeschlossen (MERGE_HEAD existiert).\n"
"Bitte trage deine Änderungen ein, bevor du zusammenführen kannst."
-#: builtin/merge.c:1233 git-pull.sh:34
+#: builtin/merge.c:1232 git-pull.sh:34
msgid "You have not concluded your merge (MERGE_HEAD exists)."
msgstr ""
"Du hast deine Zusammenführung nicht abgeschlossen (MERGE_HEAD existiert)."
-#: builtin/merge.c:1237
+#: builtin/merge.c:1236
msgid ""
"You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
"Please, commit your changes before you can merge."
@@ -3625,80 +4000,80 @@ msgstr ""
"Du hast \"cherry-pick\" nicht abgeschlossen (CHERRY_PICK_HEAD existiert).\n"
"Bitte trage deine Änderungen ein, bevor du zusammenführen kannst."
-#: builtin/merge.c:1240
+#: builtin/merge.c:1239
msgid "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)."
msgstr ""
"Du hast \"cherry-pick\" nicht abgeschlossen (CHERRY_PICK_HEAD existiert)."
-#: builtin/merge.c:1249
+#: builtin/merge.c:1248
msgid "You cannot combine --squash with --no-ff."
msgstr "Du kannst --squash nicht mit --no-ff kombinieren."
-#: builtin/merge.c:1254
+#: builtin/merge.c:1253
msgid "You cannot combine --no-ff with --ff-only."
msgstr "Du kannst --no-ff nicht mit --ff--only kombinieren."
-#: builtin/merge.c:1261
+#: builtin/merge.c:1260
msgid "No commit specified and merge.defaultToUpstream not set."
msgstr "Keine Version angegeben und merge.defaultToUpstream ist nicht gesetzt."
-#: builtin/merge.c:1293
+#: builtin/merge.c:1292
msgid "Can merge only exactly one commit into empty head"
msgstr "Kann nur exakt eine Version in einem leeren Zweig zusammenführen."
-#: builtin/merge.c:1296
+#: builtin/merge.c:1295
msgid "Squash commit into empty head not supported yet"
msgstr "Bin auf einem Zweig, der noch geboren wird; kann nicht quetschen."
-#: builtin/merge.c:1298
+#: builtin/merge.c:1297
msgid "Non-fast-forward commit does not make sense into an empty head"
msgstr "nicht vorzuspulende Version macht in einem leeren Zweig keinen Sinn"
-#: builtin/merge.c:1413
+#: builtin/merge.c:1412
#, c-format
msgid "Updating %s..%s\n"
msgstr "Aktualisiere %s..%s\n"
-#: builtin/merge.c:1451
+#: builtin/merge.c:1450
#, c-format
msgid "Trying really trivial in-index merge...\n"
msgstr "Probiere wirklich triviale \"in-index\"-Zusammenführung...\n"
-#: builtin/merge.c:1458
+#: builtin/merge.c:1457
#, c-format
msgid "Nope.\n"
msgstr "Nein.\n"
-#: builtin/merge.c:1490
+#: builtin/merge.c:1489
msgid "Not possible to fast-forward, aborting."
msgstr "Vorspulen nicht möglich, breche ab."
-#: builtin/merge.c:1513 builtin/merge.c:1592
+#: builtin/merge.c:1512 builtin/merge.c:1591
#, c-format
msgid "Rewinding the tree to pristine...\n"
msgstr "Rücklauf des Zweiges bis zum Ursprung...\n"
-#: builtin/merge.c:1517
+#: builtin/merge.c:1516
#, c-format
msgid "Trying merge strategy %s...\n"
msgstr "Probiere Zusammenführungsstrategie %s...\n"
-#: builtin/merge.c:1583
+#: builtin/merge.c:1582
#, c-format
msgid "No merge strategy handled the merge.\n"
msgstr "Keine Zusammenführungsstrategie behandelt diese Zusammenführung.\n"
-#: builtin/merge.c:1585
+#: builtin/merge.c:1584
#, c-format
msgid "Merge with strategy %s failed.\n"
msgstr "Zusammenführung mit Strategie %s fehlgeschlagen.\n"
-#: builtin/merge.c:1594
+#: builtin/merge.c:1593
#, c-format
msgid "Using the %s to prepare resolving by hand.\n"
msgstr "Benutze \"%s\" um die Auflösung per Hand vorzubereiten.\n"
-#: builtin/merge.c:1606
+#: builtin/merge.c:1605
#, c-format
msgid "Automatic merge went well; stopped before committing as requested\n"
msgstr ""
@@ -3926,22 +4301,27 @@ msgstr "Objekt %s hat keine Notiz\n"
msgid "Unknown subcommand: %s"
msgstr "Unbekanntes Unterkommando: %s"
-#: builtin/pack-objects.c:2337
+#: builtin/pack-objects.c:183 builtin/pack-objects.c:186
+#, c-format
+msgid "deflate error (%d)"
+msgstr "Fehler beim Komprimieren (%d)"
+
+#: builtin/pack-objects.c:2398
#, c-format
msgid "unsupported index version %s"
msgstr "Nicht unterstützte Bereitstellungsversion %s"
-#: builtin/pack-objects.c:2341
+#: builtin/pack-objects.c:2402
#, c-format
msgid "bad index version '%s'"
msgstr "Ungültige Bereitstellungsversion '%s'"
-#: builtin/pack-objects.c:2364
+#: builtin/pack-objects.c:2425
#, c-format
msgid "option %s does not accept negative form"
msgstr "Option %s akzeptiert keine negative Form"
-#: builtin/pack-objects.c:2368
+#: builtin/pack-objects.c:2429
#, c-format
msgid "unable to parse value '%s' for option %s"
msgstr "konnte Wert '%s' für Option %s nicht parsen"
@@ -4034,14 +4414,49 @@ msgstr ""
"aktuellen Zweiges '%s' ist, ohne mir mitzuteilen, was ich versenden\n"
"soll, um welchen externen Zweig zu aktualisieren."
-#: builtin/push.c:174
+#: builtin/push.c:151
+msgid ""
+"push.default is unset; its implicit value is changing in\n"
+"Git 2.0 from 'matching' to 'simple'. To squelch this message\n"
+"and maintain the current behavior after the default changes, use:\n"
+"\n"
+" git config --global push.default matching\n"
+"\n"
+"To squelch this message and adopt the new behavior now, use:\n"
+"\n"
+" git config --global push.default simple\n"
+"\n"
+"See 'git help config' and search for 'push.default' for further "
+"information.\n"
+"(the 'simple' mode was introduced in Git 1.7.11. Use the similar mode\n"
+"'current' instead of 'simple' if you sometimes use older versions of Git)"
+msgstr ""
+"'push.default' ist nicht gesetzt; der implizit gesetzte Wert\n"
+"wird in Git 2.0 von 'matching' nach 'simple' geändert. Um diese Meldung zu\n"
+"unterdrücken und das aktuelle Verhalten nach Änderung des Standardwertes\n"
+"beizubehalten, benutze:"
+"\n"
+" git config --global push.default matching\n"
+"\n"
+"Um diese Meldung zu unterdrücken und das neue Verhalten jetzt zu übernehmen,\n"
+"benutze:\n"
+"\n"
+" git config --global push.default simple\n"
+"\n"
+"Führe 'git help config' aus und suche nach 'push.default' für weitere "
+"Informationen.\n"
+"(Der Modus 'simple' wurde in Git 1.7.11 eingeführt. Benutze den ähnlichen"
+" Modus 'current' anstatt 'simple', falls du gelegentlich ältere Versionen von"
+" Git benutzt.)"
+
+#: builtin/push.c:199
msgid ""
"You didn't specify any refspecs to push, and push.default is \"nothing\"."
msgstr ""
"Du hast keine Referenzspezifikationen zum Versenden angegeben, und push."
"default ist \"nothing\"."
-#: builtin/push.c:181
+#: builtin/push.c:206
msgid ""
"Updates were rejected because the tip of your current branch is behind\n"
"its remote counterpart. Merge the remote changes (e.g. 'git pull')\n"
@@ -4054,22 +4469,22 @@ msgstr ""
"Siehe auch die Sektion 'Note about fast-forwards' in 'git push --help'\n"
"für weitere Details."
-#: builtin/push.c:187
+#: builtin/push.c:212
msgid ""
"Updates were rejected because a pushed branch tip is behind its remote\n"
"counterpart. If you did not intend to push that branch, you may want to\n"
-"specify branches to push or set the 'push.default' configuration\n"
-"variable to 'current' or 'upstream' to push only the current branch."
+"specify branches to push or set the 'push.default' configuration variable\n"
+"to 'simple', 'current' or 'upstream' to push only the current branch."
msgstr ""
"Aktualisierungen wurden zurückgewiesen, weil die Spitze eines versendeten\n"
"Zweiges hinter seinem externen Gegenstück zurückgefallen ist. Wenn du nicht\n"
"beabsichtigt hast, diesen Zweig zu versenden, kannst du auch den zu "
"versendenden\n"
"Zweig spezifizieren oder die Konfigurationsvariable 'push.default' zu "
-"'current'\n"
+"'simple', 'current'\n"
"oder 'upstream' setzen, um nur den aktuellen Zweig zu versenden."
-#: builtin/push.c:193
+#: builtin/push.c:218
msgid ""
"Updates were rejected because a pushed branch tip is behind its remote\n"
"counterpart. Check out this branch and merge the remote changes\n"
@@ -4083,22 +4498,22 @@ msgstr ""
"Siehe auch die Sektion 'Note about fast-forwards' in 'git push --help'\n"
"für weitere Details."
-#: builtin/push.c:233
+#: builtin/push.c:258
#, c-format
msgid "Pushing to %s\n"
msgstr "Versende nach %s\n"
-#: builtin/push.c:237
+#: builtin/push.c:262
#, c-format
msgid "failed to push some refs to '%s'"
msgstr "Fehler beim Versenden einiger Referenzen nach '%s'"
-#: builtin/push.c:269
+#: builtin/push.c:294
#, c-format
msgid "bad repository '%s'"
msgstr "ungültiges Projektarchiv '%s'"
-#: builtin/push.c:270
+#: builtin/push.c:295
msgid ""
"No configured push destination.\n"
"Either specify the URL from the command-line or configure a remote "
@@ -4120,31 +4535,31 @@ msgstr ""
"\n"
" git push <Name>\n"
-#: builtin/push.c:285
+#: builtin/push.c:310
msgid "--all and --tags are incompatible"
msgstr "--all und --tags sind inkompatibel"
-#: builtin/push.c:286
+#: builtin/push.c:311
msgid "--all can't be combined with refspecs"
msgstr "--all kann nicht mit Referenzspezifikationen kombiniert werden"
-#: builtin/push.c:291
+#: builtin/push.c:316
msgid "--mirror and --tags are incompatible"
msgstr "--mirror und --tags sind inkompatibel"
-#: builtin/push.c:292
+#: builtin/push.c:317
msgid "--mirror can't be combined with refspecs"
msgstr "--mirror kann nicht mit Referenzspezifikationen kombiniert werden"
-#: builtin/push.c:297
+#: builtin/push.c:322
msgid "--all and --mirror are incompatible"
msgstr "--all und --mirror sind inkompatibel"
-#: builtin/push.c:385
+#: builtin/push.c:410
msgid "--delete is incompatible with --all, --mirror and --tags"
msgstr "--delete ist inkompatibel mit --all, --mirror und --tags"
-#: builtin/push.c:387
+#: builtin/push.c:412
msgid "--delete doesn't make sense without any refs"
msgstr "--delete macht ohne irgendeine Referenz keinen Sinn"
@@ -4566,31 +4981,31 @@ msgstr ""
"Kann keine '%s' Zurücksetzung durchführen, während eine Zusammenführung im "
"Gange ist."
-#: builtin/reset.c:297
+#: builtin/reset.c:303
#, c-format
msgid "Could not parse object '%s'."
msgstr "Konnte Objekt '%s' nicht parsen."
-#: builtin/reset.c:302
+#: builtin/reset.c:308
msgid "--patch is incompatible with --{hard,mixed,soft}"
msgstr "--patch ist inkompatibel mit --{hard,mixed,soft}"
-#: builtin/reset.c:311
+#: builtin/reset.c:317
msgid "--mixed with paths is deprecated; use 'git reset -- <paths>' instead."
msgstr ""
"--mixed mit Pfaden ist veraltet; benutze stattdessen 'git reset -- <Pfade>'."
-#: builtin/reset.c:313
+#: builtin/reset.c:319
#, c-format
msgid "Cannot do %s reset with paths."
msgstr "Eine '%s' Zurücksetzung mit Pfaden ist nicht möglich."
-#: builtin/reset.c:325
+#: builtin/reset.c:331
#, c-format
msgid "%s reset is not allowed in a bare repository"
msgstr "'%s' Zurücksetzung ist in einem bloßen Projektarchiv nicht erlaubt"
-#: builtin/reset.c:341
+#: builtin/reset.c:347
#, c-format
msgid "Could not reset index file to revision '%s'."
msgstr "Konnte Bereitstellungsdatei nicht zu Version '%s' zurücksetzen."
@@ -4941,14 +5356,15 @@ msgstr ""
#: git-am.sh:105
#, sh-format
msgid ""
-"When you have resolved this problem run \"$cmdline --resolved\".\n"
-"If you would prefer to skip this patch, instead run \"$cmdline --skip\".\n"
-"To restore the original branch and stop patching run \"$cmdline --abort\"."
-msgstr ""
-"Wenn du das Problem aufgelöst hast, führe \"$cmdline --resolved\" aus.\n"
-"Falls du diesen Patch auslassen möchtest, führe stattdessen "
-"\"$cmdline --skip\" aus.\n"
-"Um den ursprünglichen Zweig wiederherzustellen und die Anwendung der Patches\n"
+"When you have resolved this problem, run \"$cmdline --resolved\".\n"
+"If you prefer to skip this patch, run \"$cmdline --skip\" instead.\n"
+"To restore the original branch and stop patching, run \"$cmdline --abort\"."
+msgstr ""
+"Wenn du das Problem gelöst hast, führe \"$cmdline --resolved\" aus.\n"
+"Falls du diesen Patch auslassen möchtest, führe stattdessen \"$cmdline --skip"
+"\" aus.\n"
+"Um den ursprünglichen Zweig wiederherzustellen und die Anwendung der "
+"Patches\n"
"abzubrechen, führe \"$cmdline --abort\" aus."
#: git-am.sh:121
@@ -4961,6 +5377,12 @@ msgstr ""
"Dem Projektarchiv fehlen notwendige Blobs um auf eine 3-Wege-Zusammenführung "
"zurückzufallen."
+#: git-am.sh:139
+msgid "Using index info to reconstruct a base tree..."
+msgstr ""
+"Verwende Informationen aus der Bereitstellung um einen Basisbaum "
+"nachzustellen"
+
#: git-am.sh:154
msgid ""
"Did you hand edit your patch?\n"
@@ -4973,45 +5395,53 @@ msgstr ""
msgid "Falling back to patching base and 3-way merge..."
msgstr "Falle zurück zum Patchen der Basis und der 3-Wege-Zusammenführung..."
-#: git-am.sh:275
+#: git-am.sh:179
+msgid "Failed to merge in the changes."
+msgstr "Zusammenführung der Änderungen fehlgeschlagen"
+
+#: git-am.sh:274
msgid "Only one StGIT patch series can be applied at once"
msgstr "Es kann nur eine StGIT Patch-Serie auf einmal angewendet werden."
-#: git-am.sh:362
+#: git-am.sh:361
#, sh-format
msgid "Patch format $patch_format is not supported."
msgstr "Patch-Format $patch_format wird nicht unterstützt."
-#: git-am.sh:364
+#: git-am.sh:363
msgid "Patch format detection failed."
msgstr "Patch-Formaterkennung fehlgeschlagen."
-#: git-am.sh:418
-msgid "-d option is no longer supported. Do not use."
-msgstr "-d Option wird nicht länger unterstützt. Nicht benutzen."
+#: git-am.sh:389
+msgid ""
+"The -b/--binary option has been a no-op for long time, and\n"
+"it will be removed. Please do not use it anymore."
+msgstr ""
+"Die -b/--binary Option hat seit Langem keinen Effekt und wird\n"
+"entfernt. Bitte nicht mehr verwenden."
-#: git-am.sh:481
+#: git-am.sh:477
#, sh-format
msgid "previous rebase directory $dotest still exists but mbox given."
msgstr ""
"Vorheriges Verzeichnis des Neuaufbaus $dotest existiert noch, aber mbox "
"gegeben."
-#: git-am.sh:486
+#: git-am.sh:482
msgid "Please make up your mind. --skip or --abort?"
msgstr "Bitte werde dir klar. --skip oder --abort?"
-#: git-am.sh:513
+#: git-am.sh:509
msgid "Resolve operation not in progress, we are not resuming."
msgstr "Es ist keine Auflösung im Gange, es wird nicht fortgesetzt."
-#: git-am.sh:579
+#: git-am.sh:575
#, sh-format
msgid "Dirty index: cannot apply patches (dirty: $files)"
msgstr ""
"Unsaubere Bereitstellung: kann Patches nicht anwenden (unsauber: $files)"
-#: git-am.sh:671
+#: git-am.sh:679
#, sh-format
msgid ""
"Patch is empty. Was it split wrong?\n"
@@ -5019,38 +5449,39 @@ msgid ""
"To restore the original branch and stop patching run \"$cmdline --abort\"."
msgstr ""
"Patch ist leer. Wurde er falsch aufgeteilt?\n"
-"Wenn du diesen Patch auslassen möchtest, führe stattdessen "
-"\"$cmdline --skip\" aus.\n"
-"Um den ursprünglichen Zweig wiederherzustellen und die Anwendung der Patches\n"
+"Wenn du diesen Patch auslassen möchtest, führe stattdessen \"$cmdline --skip"
+"\" aus.\n"
+"Um den ursprünglichen Zweig wiederherzustellen und die Anwendung der "
+"Patches\n"
"abzubrechen, führe \"$cmdline --abort\" aus."
-#: git-am.sh:708
+#: git-am.sh:706
msgid "Patch does not have a valid e-mail address."
msgstr "Patch enthält keine gültige eMail-Adresse."
-#: git-am.sh:755
+#: git-am.sh:753
msgid "cannot be interactive without stdin connected to a terminal."
msgstr ""
"Kann nicht interaktiv sein, ohne dass die Standard-Eingabe mit einem "
"Terminal verbunden ist."
-#: git-am.sh:759
+#: git-am.sh:757
msgid "Commit Body is:"
msgstr "Beschreibung der Eintragung ist:"
#. TRANSLATORS: Make sure to include [y], [n], [e], [v] and [a]
#. in your translation. The program will only accept English
#. input at this point.
-#: git-am.sh:766
+#: git-am.sh:764
msgid "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all "
msgstr "Anwenden? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all "
-#: git-am.sh:802
+#: git-am.sh:800
#, sh-format
msgid "Applying: $FIRSTLINE"
msgstr "Wende an: $FIRSTLINE"
-#: git-am.sh:823
+#: git-am.sh:821
msgid ""
"No changes - did you forget to use 'git add'?\n"
"If there is nothing left to stage, chances are that something else\n"
@@ -5061,7 +5492,7 @@ msgstr ""
"diese bereits anderweitig eingefügt worden sein; du könntest diesen Patch\n"
"auslassen."
-#: git-am.sh:831
+#: git-am.sh:829
msgid ""
"You still have unmerged paths in your index\n"
"did you forget to use 'git add'?"
@@ -5069,16 +5500,16 @@ msgstr ""
"Du hast immer noch nicht zusammengeführte Pfade in der Bereitstellung.\n"
"Hast du vergessen 'git add' zu benutzen?"
-#: git-am.sh:847
+#: git-am.sh:845
msgid "No changes -- Patch already applied."
msgstr "Keine Änderungen -- Patches bereits angewendet."
-#: git-am.sh:857
+#: git-am.sh:855
#, sh-format
msgid "Patch failed at $msgnum $FIRSTLINE"
msgstr "Anwendung des Patches fehlgeschlagen bei $msgnum $FIRSTLINE"
-#: git-am.sh:873
+#: git-am.sh:876
msgid "applying to an empty history"
msgstr "wende zu leerer Historie an"
@@ -5283,6 +5714,131 @@ msgstr "Kann nicht mehrere Zweige in einen ungeborenen Zweig zusammenführen"
msgid "Cannot rebase onto multiple branches"
msgstr "kann nicht auf mehrere Zweige neu aufbauen"
+#: git-rebase.sh:52
+msgid ""
+"When you have resolved this problem, run \"git rebase --continue\".\n"
+"If you prefer to skip this patch, run \"git rebase --skip\" instead.\n"
+"To check out the original branch and stop rebasing, run \"git rebase --abort"
+"\"."
+msgstr ""
+"Wenn du das Problem aufgelöst hast, führe \"git rebase --continue\" aus.\n"
+"Falls du diesen Patch auslassen möchtest, führe stattdessen \"git rebase --"
+"skip\" aus.\n"
+"Um den ursprünglichen Zweig wiederherzustellen und den Neuaufbau "
+"abzubrechen,\n"
+"führe \"git rebase --abort\" aus."
+
+#: git-rebase.sh:159
+msgid "The pre-rebase hook refused to rebase."
+msgstr "Der \"pre-rebase hook\" hat den Neuaufbau zurückgewiesen."
+
+#: git-rebase.sh:164
+msgid "It looks like git-am is in progress. Cannot rebase."
+msgstr "\"git-am\" scheint im Gange zu sein. Kann nicht neu aufbauen."
+
+#: git-rebase.sh:295
+msgid "The --exec option must be used with the --interactive option"
+msgstr "Die --exec Option muss mit der --interactive Option benutzt werden"
+
+#: git-rebase.sh:300
+msgid "No rebase in progress?"
+msgstr "Kein Neuaufbau im Gange?"
+
+#: git-rebase.sh:313
+msgid "Cannot read HEAD"
+msgstr "Kann Zweigspitze (HEAD) nicht lesen"
+
+#: git-rebase.sh:316
+msgid ""
+"You must edit all merge conflicts and then\n"
+"mark them as resolved using git add"
+msgstr ""
+"Du musst alle Zusammenführungskonflikte editieren und diese dann\n"
+"mittels \"git add\" als aufgelöst markieren"
+
+#: git-rebase.sh:334
+#, sh-format
+msgid "Could not move back to $head_name"
+msgstr "Konnte nicht zu $head_name zurückgehen"
+
+#: git-rebase.sh:350
+#, sh-format
+msgid ""
+"It seems that there is already a $state_dir_base directory, and\n"
+"I wonder if you are in the middle of another rebase. If that is the\n"
+"case, please try\n"
+"\t$cmd_live_rebase\n"
+"If that is not the case, please\n"
+"\t$cmd_clear_stale_rebase\n"
+"and run me again. I am stopping in case you still have something\n"
+"valuable there."
+msgstr ""
+"Es sieht so aus, als ob es das Verzeichnis $state_dir_base bereits gibt\n"
+"und es könnte ein anderer Neuaufbau im Gange sein. Wenn das der Fall ist,\n"
+"probiere bitte\n"
+"\t$cmd_live_rebase\n"
+"Wenn das nicht der Fall ist, probiere bitte\n"
+"\t$cmd_clear_stale_rebase\n"
+"und führe dieses Kommando nochmal aus. Es wird angehalten, falls noch\n"
+"etwas Schützenswertes vorhanden ist."
+
+#: git-rebase.sh:395
+#, sh-format
+msgid "invalid upstream $upstream_name"
+msgstr "ungültiger Übernahmezweig $upstream_name"
+
+#: git-rebase.sh:419
+#, sh-format
+msgid "$onto_name: there are more than one merge bases"
+msgstr "$onto_name: es gibt mehr als eine Zusammenführungsbasis"
+
+#: git-rebase.sh:422 git-rebase.sh:426
+#, sh-format
+msgid "$onto_name: there is no merge base"
+msgstr "$onto_name: es gibt keine Zusammenführungsbasis"
+
+#: git-rebase.sh:431
+#, sh-format
+msgid "Does not point to a valid commit: $onto_name"
+msgstr "$onto_name zeigt auf keine gültige Version"
+
+#: git-rebase.sh:454
+#, sh-format
+msgid "fatal: no such branch: $branch_name"
+msgstr "fatal: Zweig $branch_name nicht gefunden"
+
+#: git-rebase.sh:474
+msgid "Please commit or stash them."
+msgstr "Bitte trage die Änderungen ein oder benutze \"stash\"."
+
+#: git-rebase.sh:492
+#, sh-format
+msgid "Current branch $branch_name is up to date."
+msgstr "Aktueller Zweig $branch_name ist auf dem neusten Stand."
+
+#: git-rebase.sh:495
+#, sh-format
+msgid "Current branch $branch_name is up to date, rebase forced."
+msgstr ""
+"Aktueller Zweig $branch_name ist auf dem neusten Stand, Neuaufbau erzwungen."
+
+#: git-rebase.sh:506
+#, sh-format
+msgid "Changes from $mb to $onto:"
+msgstr "Änderungen von $mb zu $onto:"
+
+#. Detach HEAD and reset the tree
+#: git-rebase.sh:515
+msgid "First, rewinding head to replay your work on top of it..."
+msgstr ""
+"Zunächst wird die Zweigspitze zurückgespult, um deine Änderungen\n"
+"darauf neu anzuwenden..."
+
+#: git-rebase.sh:523
+#, sh-format
+msgid "Fast-forwarded $branch_name to $onto_name."
+msgstr "$branch_name zu $onto_name vorgespult."
+
#: git-stash.sh:51
msgid "git stash clear with parameters is unimplemented"
msgstr "git stash clear mit Parametern ist nicht implementiert"
@@ -5414,109 +5970,108 @@ msgstr "Kein Zweigname spezifiziert"
msgid "(To restore them type \"git stash apply\")"
msgstr "(Zur Wiederherstellung gebe \"git stash apply\" ein)"
-#: git-submodule.sh:56
+#: git-submodule.sh:88
#, sh-format
msgid "cannot strip one component off url '$remoteurl'"
msgstr "Kann eine Komponente von URL '$remoteurl' nicht extrahieren"
-#: git-submodule.sh:109
+#: git-submodule.sh:167
#, sh-format
msgid "No submodule mapping found in .gitmodules for path '$sm_path'"
msgstr ""
"Keine Unterprojekt-Zuordnung in .gitmodules für Pfad '$sm_path' gefunden"
-#: git-submodule.sh:150
+#: git-submodule.sh:211
#, sh-format
msgid "Clone of '$url' into submodule path '$sm_path' failed"
msgstr "Klonen von '$url' in Unterprojekt-Pfad '$sm_path' fehlgeschlagen"
-#: git-submodule.sh:160
+#: git-submodule.sh:223
#, sh-format
msgid "Gitdir '$a' is part of the submodule path '$b' or vice versa"
msgstr ""
"Git-Verzeichnis '$a' ist Teil des Unterprojekt-Pfades '$b', oder umgekehrt"
-#: git-submodule.sh:249
+#: git-submodule.sh:312
#, sh-format
msgid "repo URL: '$repo' must be absolute or begin with ./|../"
msgstr "repo URL: '$repo' muss absolut sein oder mit ./|../ beginnen"
-#: git-submodule.sh:266
+#: git-submodule.sh:329
#, sh-format
msgid "'$sm_path' already exists in the index"
msgstr "'$sm_path' existiert bereits in der Bereitstellung"
-#: git-submodule.sh:270
+#: git-submodule.sh:333
#, sh-format
msgid ""
"The following path is ignored by one of your .gitignore files:\n"
"$sm_path\n"
"Use -f if you really want to add it."
msgstr ""
-"Der folgende Pfad wird durch eine deiner \".gitignore\" Dateien "
-"ignoriert:\n"
+"Der folgende Pfad wird durch eine deiner \".gitignore\" Dateien ignoriert:\n"
"$sm_path\n"
"Benutze -f wenn du diesen wirklich hinzufügen möchtest."
-#: git-submodule.sh:281
+#: git-submodule.sh:344
#, sh-format
msgid "Adding existing repo at '$sm_path' to the index"
-msgstr "Füge existierendes Projektarchiv in '$sm_path' der Bereitstellung "
-"hinzu."
+msgstr ""
+"Füge existierendes Projektarchiv in '$sm_path' der Bereitstellung hinzu."
-#: git-submodule.sh:283
+#: git-submodule.sh:346
#, sh-format
msgid "'$sm_path' already exists and is not a valid git repo"
msgstr "'$sm_path' existiert bereits und ist kein gültiges Git-Projektarchiv"
-#: git-submodule.sh:297
+#: git-submodule.sh:360
#, sh-format
msgid "Unable to checkout submodule '$sm_path'"
msgstr "Unfähig Unterprojekt '$sm_path' auszuchecken"
-#: git-submodule.sh:302
+#: git-submodule.sh:365
#, sh-format
msgid "Failed to add submodule '$sm_path'"
msgstr "Hinzufügen von Unterprojekt '$sm_path' fehlgeschlagen"
-#: git-submodule.sh:307
+#: git-submodule.sh:370
#, sh-format
msgid "Failed to register submodule '$sm_path'"
msgstr "Registierung von Unterprojekt '$sm_path' fehlgeschlagen"
-#: git-submodule.sh:349
+#: git-submodule.sh:413
#, sh-format
msgid "Entering '$prefix$sm_path'"
msgstr "Betrete '$prefix$sm_path'"
-#: git-submodule.sh:363
+#: git-submodule.sh:427
#, sh-format
msgid "Stopping at '$sm_path'; script returned non-zero status."
msgstr "Stoppe bei '$sm_path'; Skript gab nicht-Null Status zurück."
-#: git-submodule.sh:406
+#: git-submodule.sh:471
#, sh-format
msgid "No url found for submodule path '$sm_path' in .gitmodules"
msgstr "Keine URL für Unterprojekt-Pfad '$sm_path' in .gitmodules gefunden"
-#: git-submodule.sh:415
+#: git-submodule.sh:480
#, sh-format
msgid "Failed to register url for submodule path '$sm_path'"
msgstr "Registrierung der URL für Unterprojekt-Pfad '$sm_path' fehlgeschlagen"
-#: git-submodule.sh:417
+#: git-submodule.sh:482
#, sh-format
msgid "Submodule '$name' ($url) registered for path '$sm_path'"
msgstr "Unterprojekt '$name' ($url) ist für Pfad '$sm_path' registriert"
-#: git-submodule.sh:425
+#: git-submodule.sh:490
#, sh-format
msgid "Failed to register update mode for submodule path '$sm_path'"
msgstr ""
"Registrierung des Aktualisierungsmodus für Unterprojekt-Pfad '$sm_path' "
"fehlgeschlagen"
-#: git-submodule.sh:524
+#: git-submodule.sh:590
#, sh-format
msgid ""
"Submodule path '$sm_path' not initialized\n"
@@ -5525,99 +6080,113 @@ msgstr ""
"Unterprojekt-Pfad '$sm_path' ist nicht initialisiert\n"
"Vielleicht möchtest du 'update --init' benutzen?"
-#: git-submodule.sh:537
+#: git-submodule.sh:603
#, sh-format
msgid "Unable to find current revision in submodule path '$sm_path'"
msgstr "Konnte aktuelle Version in Unterprojekt-Pfad '$sm_path' nicht finden"
-#: git-submodule.sh:556
+#: git-submodule.sh:622
#, sh-format
msgid "Unable to fetch in submodule path '$sm_path'"
msgstr "Konnte in Unterprojekt-Pfad '$sm_path' nicht anfordern"
-#: git-submodule.sh:570
+#: git-submodule.sh:636
#, sh-format
msgid "Unable to rebase '$sha1' in submodule path '$sm_path'"
msgstr "Neuaufbau von '$sha1' in Unterprojekt-Pfad '$sm_path' nicht möglich"
-#: git-submodule.sh:571
+#: git-submodule.sh:637
#, sh-format
msgid "Submodule path '$sm_path': rebased into '$sha1'"
msgstr "Unterprojekt-Pfad '$sm_path': neu aufgebaut in '$sha1'"
-#: git-submodule.sh:576
+#: git-submodule.sh:642
#, sh-format
msgid "Unable to merge '$sha1' in submodule path '$sm_path'"
msgstr ""
"Zusammenführung von '$sha1' in Unterprojekt-Pfad '$sm_path' fehlgeschlagen"
-#: git-submodule.sh:577
+#: git-submodule.sh:643
#, sh-format
msgid "Submodule path '$sm_path': merged in '$sha1'"
msgstr "Unterprojekt-Pfad '$sm_path': zusammengeführt in '$sha1'"
-#: git-submodule.sh:582
+#: git-submodule.sh:648
#, sh-format
msgid "Unable to checkout '$sha1' in submodule path '$sm_path'"
msgstr "Konnte '$sha1' in Unterprojekt-Pfad '$sm_path' nicht auschecken."
-#: git-submodule.sh:583
+#: git-submodule.sh:649
#, sh-format
msgid "Submodule path '$sm_path': checked out '$sha1'"
msgstr "Unterprojekt-Pfad: '$sm_path': '$sha1' ausgecheckt"
-#: git-submodule.sh:605 git-submodule.sh:928
+#: git-submodule.sh:671 git-submodule.sh:995
#, sh-format
msgid "Failed to recurse into submodule path '$sm_path'"
msgstr "Fehler bei Rekursion in Unterprojekt-Pfad '$sm_path'"
-#: git-submodule.sh:713
-msgid "--cached cannot be used with --files"
-msgstr "--cached kann nicht mit --files benutzt werden"
+#: git-submodule.sh:779
+msgid "The --cached option cannot be used with the --files option"
+msgstr "Die --cached Option kann nicht mit der --files Option benutzt werden"
#. unexpected type
-#: git-submodule.sh:753
+#: git-submodule.sh:819
#, sh-format
msgid "unexpected mode $mod_dst"
msgstr "unerwarteter Modus $mod_dst"
-#: git-submodule.sh:771
+#: git-submodule.sh:837
#, sh-format
msgid " Warn: $name doesn't contain commit $sha1_src"
msgstr " Warnung: $name beinhaltet nicht Version $sha1_src"
-#: git-submodule.sh:774
+#: git-submodule.sh:840
#, sh-format
msgid " Warn: $name doesn't contain commit $sha1_dst"
msgstr " Warnung: $name beinhaltet nicht Version $sha1_dst"
-#: git-submodule.sh:777
+#: git-submodule.sh:843
#, sh-format
msgid " Warn: $name doesn't contain commits $sha1_src and $sha1_dst"
msgstr ""
" Warnung: $name beinhaltet nicht die Versionen $sha1_src und $sha1_dst"
-#: git-submodule.sh:802
+#: git-submodule.sh:868
msgid "blob"
msgstr "Blob"
-#: git-submodule.sh:803
-msgid "submodule"
-msgstr "Unterprojekt"
-
-#: git-submodule.sh:840
+#: git-submodule.sh:906
msgid "# Submodules changed but not updated:"
msgstr "# Unterprojekte geändert, aber nicht aktualisiert:"
-#: git-submodule.sh:842
+#: git-submodule.sh:908
msgid "# Submodule changes to be committed:"
msgstr "# Änderungen in Unterprojekt zum Eintragen:"
-#: git-submodule.sh:974
+#: git-submodule.sh:1054
#, sh-format
msgid "Synchronizing submodule url for '$name'"
msgstr "Synchronisiere Unterprojekt-URL für '$name'"
+#~ msgid "diff setup failed"
+#~ msgstr "diff_setup_done fehlgeschlagen"
+
+#~ msgid "merge-recursive: disk full?"
+#~ msgstr "merge-recursive: Festplatte voll?"
+
+#~ msgid "diff_setup_done failed"
+#~ msgstr "diff_setup_done fehlgeschlagen"
+
+#~ msgid "-d option is no longer supported. Do not use."
+#~ msgstr "-d Option wird nicht länger unterstützt. Nicht benutzen."
+
+#~ msgid "%s: has been deleted/renamed"
+#~ msgstr "%s wurde gelöscht/umbenannt"
+
+#~ msgid "'%s': not a documentation directory."
+#~ msgstr "'%s' ist kein Dokumentationsverzeichnis"
+
#~ msgid "--"
#~ msgstr "--"
diff --git a/po/git.pot b/po/git.pot
index b666506..05177d6 100644
--- a/po/git.pot
+++ b/po/git.pot
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2012-06-08 10:20+0800\n"
+"POT-Creation-Date: 2012-09-15 10:21+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -35,6 +35,91 @@ msgid ""
"or use 'git commit -a'."
msgstr ""
+#: archive.c:10
+msgid "git archive [options] <tree-ish> [<path>...]"
+msgstr ""
+
+#: archive.c:11
+msgid "git archive --list"
+msgstr ""
+
+#: archive.c:12
+msgid ""
+"git archive --remote <repo> [--exec <cmd>] [options] <tree-ish> [<path>...]"
+msgstr ""
+
+#: archive.c:13
+msgid "git archive --remote <repo> [--exec <cmd>] --list"
+msgstr ""
+
+#: archive.c:322
+msgid "fmt"
+msgstr ""
+
+#: archive.c:322
+msgid "archive format"
+msgstr ""
+
+#: archive.c:323 builtin/log.c:1079
+msgid "prefix"
+msgstr ""
+
+#: archive.c:324
+msgid "prepend prefix to each pathname in the archive"
+msgstr ""
+
+#: archive.c:325 builtin/archive.c:91 builtin/blame.c:2332
+#: builtin/blame.c:2333 builtin/config.c:56 builtin/fast-export.c:642
+#: builtin/fast-export.c:644 builtin/grep.c:800 builtin/hash-object.c:77
+#: builtin/ls-files.c:494 builtin/ls-files.c:497 builtin/notes.c:537
+#: builtin/notes.c:694 builtin/read-tree.c:107 parse-options.h:149
+msgid "file"
+msgstr ""
+
+#: archive.c:326 builtin/archive.c:92
+msgid "write the archive to this file"
+msgstr ""
+
+#: archive.c:328
+msgid "read .gitattributes in working directory"
+msgstr ""
+
+#: archive.c:329
+msgid "report archived files on stderr"
+msgstr ""
+
+#: archive.c:330
+msgid "store only"
+msgstr ""
+
+#: archive.c:331
+msgid "compress faster"
+msgstr ""
+
+#: archive.c:339
+msgid "compress better"
+msgstr ""
+
+#: archive.c:342
+msgid "list supported archive formats"
+msgstr ""
+
+#: archive.c:344 builtin/archive.c:93 builtin/clone.c:85
+msgid "repo"
+msgstr ""
+
+#: archive.c:345 builtin/archive.c:94
+msgid "retrieve the archive from remote repository <repo>"
+msgstr ""
+
+#: archive.c:346 builtin/archive.c:95 builtin/notes.c:616
+msgid "command"
+msgstr ""
+
+#: archive.c:347 builtin/archive.c:96
+msgid "path to the remote git-upload-archive command"
+msgstr ""
+
#: bundle.c:36
#, c-format
msgid "'%s' does not look like a v2 bundle file"
@@ -45,7 +130,7 @@ msgstr ""
msgid "unrecognized header: %s%s (%d)"
msgstr ""
-#: bundle.c:89 builtin/commit.c:696
+#: bundle.c:89 builtin/commit.c:714
#, c-format
msgid "could not open '%s'"
msgstr ""
@@ -54,8 +139,8 @@ msgstr ""
msgid "Repository lacks these prerequisite commits:"
msgstr ""
-#: bundle.c:164 sequencer.c:550 sequencer.c:982 builtin/log.c:289
-#: builtin/log.c:720 builtin/log.c:1309 builtin/log.c:1528 builtin/merge.c:347
+#: bundle.c:164 sequencer.c:557 sequencer.c:989 builtin/log.c:290
+#: builtin/log.c:727 builtin/log.c:1313 builtin/log.c:1529 builtin/merge.c:347
#: builtin/shortlog.c:181
msgid "revision walk setup failed"
msgstr ""
@@ -68,44 +153,48 @@ msgstr[0] ""
msgstr[1] ""
#: bundle.c:192
+msgid "The bundle records a complete history."
+msgstr ""
+
+#: bundle.c:195
#, c-format
msgid "The bundle requires this ref"
msgid_plural "The bundle requires these %d refs"
msgstr[0] ""
msgstr[1] ""
-#: bundle.c:290
+#: bundle.c:294
msgid "rev-list died"
msgstr ""
-#: bundle.c:296 builtin/log.c:1205 builtin/shortlog.c:284
+#: bundle.c:300 builtin/log.c:1209 builtin/shortlog.c:284
#, c-format
msgid "unrecognized argument: %s"
msgstr ""
-#: bundle.c:331
+#: bundle.c:335
#, c-format
msgid "ref '%s' is excluded by the rev-list options"
msgstr ""
-#: bundle.c:376
+#: bundle.c:380
msgid "Refusing to create empty bundle."
msgstr ""
-#: bundle.c:394
+#: bundle.c:398
msgid "Could not spawn pack-objects"
msgstr ""
-#: bundle.c:412
+#: bundle.c:416
msgid "pack-objects died"
msgstr ""
-#: bundle.c:415
+#: bundle.c:419
#, c-format
msgid "cannot create '%s'"
msgstr ""
-#: bundle.c:437
+#: bundle.c:441
msgid "index-pack died"
msgstr ""
@@ -221,32 +310,32 @@ msgid ""
"%s"
msgstr ""
-#: diff.c:1400
-msgid " 0 files changed\n"
+#: diff.c:1401
+msgid " 0 files changed"
msgstr ""
-#: diff.c:1404
+#: diff.c:1405
#, c-format
msgid " %d file changed"
msgid_plural " %d files changed"
msgstr[0] ""
msgstr[1] ""
-#: diff.c:1421
+#: diff.c:1422
#, c-format
msgid ", %d insertion(+)"
msgid_plural ", %d insertions(+)"
msgstr[0] ""
msgstr[1] ""
-#: diff.c:1432
+#: diff.c:1433
#, c-format
msgid ", %d deletion(-)"
msgid_plural ", %d deletions(-)"
msgstr[0] ""
msgstr[1] ""
-#: diff.c:3478
+#: diff.c:3460
#, c-format
msgid ""
"Failed to parse --dirstat/-X option parameter:\n"
@@ -280,44 +369,44 @@ msgstr ""
msgid "'%s': short read %s"
msgstr ""
-#: help.c:207
+#: help.c:212
#, c-format
msgid "available git commands in '%s'"
msgstr ""
-#: help.c:214
+#: help.c:219
msgid "git commands available from elsewhere on your $PATH"
msgstr ""
-#: help.c:270
+#: help.c:275
#, c-format
msgid ""
"'%s' appears to be a git command, but we were not\n"
"able to execute it. Maybe git-%s is broken?"
msgstr ""
-#: help.c:327
+#: help.c:332
msgid "Uh oh. Your system reports no Git commands at all."
msgstr ""
-#: help.c:349
+#: help.c:354
#, c-format
msgid ""
"WARNING: You called a Git command named '%s', which does not exist.\n"
"Continuing under the assumption that you meant '%s'"
msgstr ""
-#: help.c:354
+#: help.c:359
#, c-format
msgid "in %0.1f seconds automatically..."
msgstr ""
-#: help.c:361
+#: help.c:366
#, c-format
msgid "git: '%s' is not a git command. See 'git --help'."
msgstr ""
-#: help.c:365
+#: help.c:370
msgid ""
"\n"
"Did you mean this?"
@@ -327,35 +416,281 @@ msgid_plural ""
msgstr[0] ""
msgstr[1] ""
-#: parse-options.c:493
+#: merge-recursive.c:190
+#, c-format
+msgid "(bad commit)\n"
+msgstr ""
+
+#: merge-recursive.c:206
+#, c-format
+msgid "addinfo_cache failed for path '%s'"
+msgstr ""
+
+#: merge-recursive.c:268
+msgid "error building trees"
+msgstr ""
+
+#: merge-recursive.c:672
+#, c-format
+msgid "failed to create path '%s'%s"
+msgstr ""
+
+#: merge-recursive.c:683
+#, c-format
+msgid "Removing %s to make room for subdirectory\n"
+msgstr ""
+
+#. something else exists
+#. .. but not some other error (who really cares what?)
+#: merge-recursive.c:697 merge-recursive.c:718
+msgid ": perhaps a D/F conflict?"
+msgstr ""
+
+#: merge-recursive.c:708
+#, c-format
+msgid "refusing to lose untracked file at '%s'"
+msgstr ""
+
+#: merge-recursive.c:748
+#, c-format
+msgid "cannot read object %s '%s'"
+msgstr ""
+
+#: merge-recursive.c:750
+#, c-format
+msgid "blob expected for %s '%s'"
+msgstr ""
+
+#: merge-recursive.c:773 builtin/clone.c:302
+#, c-format
+msgid "failed to open '%s'"
+msgstr ""
+
+#: merge-recursive.c:781
+#, c-format
+msgid "failed to symlink '%s'"
+msgstr ""
+
+#: merge-recursive.c:784
+#, c-format
+msgid "do not know what to do with %06o %s '%s'"
+msgstr ""
+
+#: merge-recursive.c:922
+msgid "Failed to execute internal merge"
+msgstr ""
+
+#: merge-recursive.c:926
+#, c-format
+msgid "Unable to add %s to database"
+msgstr ""
+
+#: merge-recursive.c:942
+msgid "unsupported object type in the tree"
+msgstr ""
+
+#: merge-recursive.c:1021 merge-recursive.c:1035
+#, c-format
+msgid ""
+"CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left "
+"in tree."
+msgstr ""
+
+#: merge-recursive.c:1027 merge-recursive.c:1040
+#, c-format
+msgid ""
+"CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left "
+"in tree at %s."
+msgstr ""
+
+#: merge-recursive.c:1081
+msgid "rename"
+msgstr ""
+
+#: merge-recursive.c:1081
+msgid "renamed"
+msgstr ""
+
+#: merge-recursive.c:1137
+#, c-format
+msgid "%s is a directory in %s adding as %s instead"
+msgstr ""
+
+#: merge-recursive.c:1159
+#, c-format
+msgid ""
+"CONFLICT (rename/rename): Rename \"%s\"->\"%s\" in branch \"%s\" rename \"%s"
+"\"->\"%s\" in \"%s\"%s"
+msgstr ""
+
+#: merge-recursive.c:1164
+msgid " (left unresolved)"
+msgstr ""
+
+#: merge-recursive.c:1218
+#, c-format
+msgid "CONFLICT (rename/rename): Rename %s->%s in %s. Rename %s->%s in %s"
+msgstr ""
+
+#: merge-recursive.c:1248
+#, c-format
+msgid "Renaming %s to %s and %s to %s instead"
+msgstr ""
+
+#: merge-recursive.c:1447
+#, c-format
+msgid "CONFLICT (rename/add): Rename %s->%s in %s. %s added in %s"
+msgstr ""
+
+#: merge-recursive.c:1457
+#, c-format
+msgid "Adding merged %s"
+msgstr ""
+
+#: merge-recursive.c:1462 merge-recursive.c:1660
+#, c-format
+msgid "Adding as %s instead"
+msgstr ""
+
+#: merge-recursive.c:1513
+#, c-format
+msgid "cannot read object %s"
+msgstr ""
+
+#: merge-recursive.c:1516
+#, c-format
+msgid "object %s is not a blob"
+msgstr ""
+
+#: merge-recursive.c:1564
+msgid "modify"
+msgstr ""
+
+#: merge-recursive.c:1564
+msgid "modified"
+msgstr ""
+
+#: merge-recursive.c:1574
+msgid "content"
+msgstr ""
+
+#: merge-recursive.c:1581
+msgid "add/add"
+msgstr ""
+
+#: merge-recursive.c:1615
+#, c-format
+msgid "Skipped %s (merged same as existing)"
+msgstr ""
+
+#: merge-recursive.c:1629
+#, c-format
+msgid "Auto-merging %s"
+msgstr ""
+
+#: merge-recursive.c:1633 git-submodule.sh:869
+msgid "submodule"
+msgstr ""
+
+#: merge-recursive.c:1634
+#, c-format
+msgid "CONFLICT (%s): Merge conflict in %s"
+msgstr ""
+
+#: merge-recursive.c:1724
+#, c-format
+msgid "Removing %s"
+msgstr ""
+
+#: merge-recursive.c:1749
+msgid "file/directory"
+msgstr ""
+
+#: merge-recursive.c:1755
+msgid "directory/file"
+msgstr ""
+
+#: merge-recursive.c:1760
+#, c-format
+msgid "CONFLICT (%s): There is a directory with name %s in %s. Adding %s as %s"
+msgstr ""
+
+#: merge-recursive.c:1770
+#, c-format
+msgid "Adding %s"
+msgstr ""
+
+#: merge-recursive.c:1787
+msgid "Fatal merge failure, shouldn't happen."
+msgstr ""
+
+#: merge-recursive.c:1806
+msgid "Already up-to-date!"
+msgstr ""
+
+#: merge-recursive.c:1815
+#, c-format
+msgid "merging of trees %s and %s failed"
+msgstr ""
+
+#: merge-recursive.c:1845
+#, c-format
+msgid "Unprocessed path??? %s"
+msgstr ""
+
+#: merge-recursive.c:1890
+msgid "Merging:"
+msgstr ""
+
+#: merge-recursive.c:1903
+#, c-format
+msgid "found %u common ancestor:"
+msgid_plural "found %u common ancestors:"
+msgstr[0] ""
+msgstr[1] ""
+
+#: merge-recursive.c:1940
+msgid "merge returned no commit"
+msgstr ""
+
+#: merge-recursive.c:1997
+#, c-format
+msgid "Could not parse object '%s'"
+msgstr ""
+
+#: merge-recursive.c:2009 builtin/merge.c:696
+msgid "Unable to write index."
+msgstr ""
+
+#: parse-options.c:494
msgid "..."
msgstr ""
-#: parse-options.c:511
+#: parse-options.c:512
#, c-format
msgid "usage: %s"
msgstr ""
#. TRANSLATORS: the colon here should align with the
#. one in "usage: %s" translation
-#: parse-options.c:515
+#: parse-options.c:516
#, c-format
msgid " or: %s"
msgstr ""
-#: parse-options.c:518
+#: parse-options.c:519
#, c-format
msgid " %s"
msgstr ""
-#: remote.c:1629
+#: remote.c:1632
#, c-format
msgid "Your branch is ahead of '%s' by %d commit.\n"
msgid_plural "Your branch is ahead of '%s' by %d commits.\n"
msgstr[0] ""
msgstr[1] ""
-#: remote.c:1635
+#: remote.c:1638
#, c-format
msgid "Your branch is behind '%s' by %d commit, and can be fast-forwarded.\n"
msgid_plural ""
@@ -363,7 +698,7 @@ msgid_plural ""
msgstr[0] ""
msgstr[1] ""
-#: remote.c:1643
+#: remote.c:1646
#, c-format
msgid ""
"Your branch and '%s' have diverged,\n"
@@ -374,14 +709,14 @@ msgid_plural ""
msgstr[0] ""
msgstr[1] ""
-#: sequencer.c:121 builtin/merge.c:865 builtin/merge.c:978
-#: builtin/merge.c:1088 builtin/merge.c:1098
+#: sequencer.c:121 builtin/merge.c:864 builtin/merge.c:977
+#: builtin/merge.c:1087 builtin/merge.c:1097
#, c-format
msgid "Could not open '%s' for writing"
msgstr ""
-#: sequencer.c:123 builtin/merge.c:333 builtin/merge.c:868
-#: builtin/merge.c:1090 builtin/merge.c:1103
+#: sequencer.c:123 builtin/merge.c:333 builtin/merge.c:867
+#: builtin/merge.c:1089 builtin/merge.c:1102
#, c-format
msgid "Could not write to '%s'"
msgstr ""
@@ -399,7 +734,7 @@ msgid ""
"and commit the result with 'git commit'"
msgstr ""
-#: sequencer.c:160 sequencer.c:758 sequencer.c:841
+#: sequencer.c:160 sequencer.c:765 sequencer.c:848
#, c-format
msgid "Could not write to %s"
msgstr ""
@@ -435,444 +770,561 @@ msgstr ""
msgid "Unable to update cache tree\n"
msgstr ""
-#: sequencer.c:324
+#: sequencer.c:327
#, c-format
msgid "Could not parse commit %s\n"
msgstr ""
-#: sequencer.c:329
+#: sequencer.c:332
#, c-format
msgid "Could not parse parent commit %s\n"
msgstr ""
-#: sequencer.c:395
+#: sequencer.c:398
msgid "Your index file is unmerged."
msgstr ""
-#: sequencer.c:398
+#: sequencer.c:401
msgid "You do not have a valid HEAD"
msgstr ""
-#: sequencer.c:413
+#: sequencer.c:416
#, c-format
msgid "Commit %s is a merge but no -m option was given."
msgstr ""
-#: sequencer.c:421
+#: sequencer.c:424
#, c-format
msgid "Commit %s does not have parent %d"
msgstr ""
-#: sequencer.c:425
+#: sequencer.c:428
#, c-format
msgid "Mainline was specified but commit %s is not a merge."
msgstr ""
#. TRANSLATORS: The first %s will be "revert" or
#. "cherry-pick", the second %s a SHA1
-#: sequencer.c:436
+#: sequencer.c:439
#, c-format
msgid "%s: cannot parse parent commit %s"
msgstr ""
-#: sequencer.c:440
+#: sequencer.c:443
#, c-format
msgid "Cannot get commit message for %s"
msgstr ""
-#: sequencer.c:524
+#: sequencer.c:527
#, c-format
msgid "could not revert %s... %s"
msgstr ""
-#: sequencer.c:525
+#: sequencer.c:528
#, c-format
msgid "could not apply %s... %s"
msgstr ""
-#: sequencer.c:553
+#: sequencer.c:560
msgid "empty commit set passed"
msgstr ""
-#: sequencer.c:561
+#: sequencer.c:568
#, c-format
msgid "git %s: failed to read the index"
msgstr ""
-#: sequencer.c:566
+#: sequencer.c:573
#, c-format
msgid "git %s: failed to refresh the index"
msgstr ""
-#: sequencer.c:624
+#: sequencer.c:631
#, c-format
msgid "Cannot %s during a %s"
msgstr ""
-#: sequencer.c:646
+#: sequencer.c:653
#, c-format
msgid "Could not parse line %d."
msgstr ""
-#: sequencer.c:651
+#: sequencer.c:658
msgid "No commits parsed."
msgstr ""
-#: sequencer.c:664
+#: sequencer.c:671
#, c-format
msgid "Could not open %s"
msgstr ""
-#: sequencer.c:668
+#: sequencer.c:675
#, c-format
msgid "Could not read %s."
msgstr ""
-#: sequencer.c:675
+#: sequencer.c:682
#, c-format
msgid "Unusable instruction sheet: %s"
msgstr ""
-#: sequencer.c:703
+#: sequencer.c:710
#, c-format
msgid "Invalid key: %s"
msgstr ""
-#: sequencer.c:706
+#: sequencer.c:713
#, c-format
msgid "Invalid value for %s: %s"
msgstr ""
-#: sequencer.c:718
+#: sequencer.c:725
#, c-format
msgid "Malformed options sheet: %s"
msgstr ""
-#: sequencer.c:739
+#: sequencer.c:746
msgid "a cherry-pick or revert is already in progress"
msgstr ""
-#: sequencer.c:740
+#: sequencer.c:747
msgid "try \"git cherry-pick (--continue | --quit | --abort)\""
msgstr ""
-#: sequencer.c:744
+#: sequencer.c:751
#, c-format
msgid "Could not create sequencer directory %s"
msgstr ""
-#: sequencer.c:760 sequencer.c:845
+#: sequencer.c:767 sequencer.c:852
#, c-format
msgid "Error wrapping up %s."
msgstr ""
-#: sequencer.c:779 sequencer.c:913
+#: sequencer.c:786 sequencer.c:920
msgid "no cherry-pick or revert in progress"
msgstr ""
-#: sequencer.c:781
+#: sequencer.c:788
msgid "cannot resolve HEAD"
msgstr ""
-#: sequencer.c:783
+#: sequencer.c:790
msgid "cannot abort from a branch yet to be born"
msgstr ""
-#: sequencer.c:805 builtin/apply.c:3697
+#: sequencer.c:812 builtin/apply.c:4005
#, c-format
msgid "cannot open %s: %s"
msgstr ""
-#: sequencer.c:808
+#: sequencer.c:815
#, c-format
msgid "cannot read %s: %s"
msgstr ""
-#: sequencer.c:809
+#: sequencer.c:816
msgid "unexpected end of file"
msgstr ""
-#: sequencer.c:815
+#: sequencer.c:822
#, c-format
msgid "stored pre-cherry-pick HEAD file '%s' is corrupt"
msgstr ""
-#: sequencer.c:838
+#: sequencer.c:845
#, c-format
msgid "Could not format %s."
msgstr ""
-#: sequencer.c:1000
+#: sequencer.c:1007
msgid "Can't revert as initial commit"
msgstr ""
-#: sequencer.c:1001
+#: sequencer.c:1008
msgid "Can't cherry-pick into empty head"
msgstr ""
-#: sha1_name.c:864
+#: sha1_name.c:1044
msgid "HEAD does not point to a branch"
msgstr ""
-#: sha1_name.c:867
+#: sha1_name.c:1047
#, c-format
msgid "No such branch: '%s'"
msgstr ""
-#: sha1_name.c:869
+#: sha1_name.c:1049
#, c-format
msgid "No upstream configured for branch '%s'"
msgstr ""
-#: sha1_name.c:872
+#: sha1_name.c:1052
#, c-format
msgid "Upstream branch '%s' not stored as a remote-tracking branch"
msgstr ""
-#: wrapper.c:413
+#: wrapper.c:408
+#, c-format
+msgid "unable to access '%s': %s"
+msgstr ""
+
+#: wrapper.c:426
#, c-format
msgid "unable to look up current user in the passwd file: %s"
msgstr ""
-#: wrapper.c:414
+#: wrapper.c:427
msgid "no such user"
msgstr ""
-#: wt-status.c:135
+#: wt-status.c:140
msgid "Unmerged paths:"
msgstr ""
-#: wt-status.c:141 wt-status.c:158
+#: wt-status.c:167 wt-status.c:194
#, c-format
msgid " (use \"git reset %s <file>...\" to unstage)"
msgstr ""
-#: wt-status.c:143 wt-status.c:160
+#: wt-status.c:169 wt-status.c:196
msgid " (use \"git rm --cached <file>...\" to unstage)"
msgstr ""
-#: wt-status.c:144
+#: wt-status.c:173
+msgid " (use \"git add <file>...\" to mark resolution)"
+msgstr ""
+
+#: wt-status.c:175 wt-status.c:179
msgid " (use \"git add/rm <file>...\" as appropriate to mark resolution)"
msgstr ""
-#: wt-status.c:152
+#: wt-status.c:177
+msgid " (use \"git rm <file>...\" to mark resolution)"
+msgstr ""
+
+#: wt-status.c:188
msgid "Changes to be committed:"
msgstr ""
-#: wt-status.c:170
+#: wt-status.c:206
msgid "Changes not staged for commit:"
msgstr ""
-#: wt-status.c:174
+#: wt-status.c:210
msgid " (use \"git add <file>...\" to update what will be committed)"
msgstr ""
-#: wt-status.c:176
+#: wt-status.c:212
msgid " (use \"git add/rm <file>...\" to update what will be committed)"
msgstr ""
-#: wt-status.c:177
+#: wt-status.c:213
msgid ""
" (use \"git checkout -- <file>...\" to discard changes in working directory)"
msgstr ""
-#: wt-status.c:179
+#: wt-status.c:215
msgid " (commit or discard the untracked or modified content in submodules)"
msgstr ""
-#: wt-status.c:188
-#, c-format
-msgid "%s files:"
-msgstr ""
-
-#: wt-status.c:191
+#: wt-status.c:227
#, c-format
msgid " (use \"git %s <file>...\" to include in what will be committed)"
msgstr ""
-#: wt-status.c:208
+#: wt-status.c:244
msgid "bug"
msgstr ""
-#: wt-status.c:213
+#: wt-status.c:249
msgid "both deleted:"
msgstr ""
-#: wt-status.c:214
+#: wt-status.c:250
msgid "added by us:"
msgstr ""
-#: wt-status.c:215
+#: wt-status.c:251
msgid "deleted by them:"
msgstr ""
-#: wt-status.c:216
+#: wt-status.c:252
msgid "added by them:"
msgstr ""
-#: wt-status.c:217
+#: wt-status.c:253
msgid "deleted by us:"
msgstr ""
-#: wt-status.c:218
+#: wt-status.c:254
msgid "both added:"
msgstr ""
-#: wt-status.c:219
+#: wt-status.c:255
msgid "both modified:"
msgstr ""
-#: wt-status.c:249
+#: wt-status.c:285
msgid "new commits, "
msgstr ""
-#: wt-status.c:251
+#: wt-status.c:287
msgid "modified content, "
msgstr ""
-#: wt-status.c:253
+#: wt-status.c:289
msgid "untracked content, "
msgstr ""
-#: wt-status.c:267
+#: wt-status.c:303
#, c-format
msgid "new file: %s"
msgstr ""
-#: wt-status.c:270
+#: wt-status.c:306
#, c-format
msgid "copied: %s -> %s"
msgstr ""
-#: wt-status.c:273
+#: wt-status.c:309
#, c-format
msgid "deleted: %s"
msgstr ""
-#: wt-status.c:276
+#: wt-status.c:312
#, c-format
msgid "modified: %s"
msgstr ""
-#: wt-status.c:279
+#: wt-status.c:315
#, c-format
msgid "renamed: %s -> %s"
msgstr ""
-#: wt-status.c:282
+#: wt-status.c:318
#, c-format
msgid "typechange: %s"
msgstr ""
-#: wt-status.c:285
+#: wt-status.c:321
#, c-format
msgid "unknown: %s"
msgstr ""
-#: wt-status.c:288
+#: wt-status.c:324
#, c-format
msgid "unmerged: %s"
msgstr ""
-#: wt-status.c:291
+#: wt-status.c:327
#, c-format
msgid "bug: unhandled diff status %c"
msgstr ""
-#: wt-status.c:737
+#: wt-status.c:785
+msgid "You have unmerged paths."
+msgstr ""
+
+#: wt-status.c:788 wt-status.c:912
+msgid " (fix conflicts and run \"git commit\")"
+msgstr ""
+
+#: wt-status.c:791
+msgid "All conflicts fixed but you are still merging."
+msgstr ""
+
+#: wt-status.c:794
+msgid " (use \"git commit\" to conclude merge)"
+msgstr ""
+
+#: wt-status.c:804
+msgid "You are in the middle of an am session."
+msgstr ""
+
+#: wt-status.c:807
+msgid "The current patch is empty."
+msgstr ""
+
+#: wt-status.c:811
+msgid " (fix conflicts and then run \"git am --resolved\")"
+msgstr ""
+
+#: wt-status.c:813
+msgid " (use \"git am --skip\" to skip this patch)"
+msgstr ""
+
+#: wt-status.c:815
+msgid " (use \"git am --abort\" to restore the original branch)"
+msgstr ""
+
+#: wt-status.c:873 wt-status.c:883
+msgid "You are currently rebasing."
+msgstr ""
+
+#: wt-status.c:876
+msgid " (fix conflicts and then run \"git rebase --continue\")"
+msgstr ""
+
+#: wt-status.c:878
+msgid " (use \"git rebase --skip\" to skip this patch)"
+msgstr ""
+
+#: wt-status.c:880
+msgid " (use \"git rebase --abort\" to check out the original branch)"
+msgstr ""
+
+#: wt-status.c:886
+msgid " (all conflicts fixed: run \"git rebase --continue\")"
+msgstr ""
+
+#: wt-status.c:888
+msgid "You are currently splitting a commit during a rebase."
+msgstr ""
+
+#: wt-status.c:891
+msgid " (Once your working directory is clean, run \"git rebase --continue\")"
+msgstr ""
+
+#: wt-status.c:893
+msgid "You are currently editing a commit during a rebase."
+msgstr ""
+
+#: wt-status.c:896
+msgid " (use \"git commit --amend\" to amend the current commit)"
+msgstr ""
+
+#: wt-status.c:898
+msgid ""
+" (use \"git rebase --continue\" once you are satisfied with your changes)"
+msgstr ""
+
+#: wt-status.c:908
+msgid "You are currently cherry-picking."
+msgstr ""
+
+#: wt-status.c:915
+msgid " (all conflicts fixed: run \"git commit\")"
+msgstr ""
+
+#: wt-status.c:924
+msgid "You are currently bisecting."
+msgstr ""
+
+#: wt-status.c:927
+msgid " (use \"git bisect reset\" to get back to the original branch)"
+msgstr ""
+
+#: wt-status.c:978
msgid "On branch "
msgstr ""
-#: wt-status.c:744
+#: wt-status.c:985
msgid "Not currently on any branch."
msgstr ""
-#: wt-status.c:755
+#: wt-status.c:997
msgid "Initial commit"
msgstr ""
-#: wt-status.c:769
-msgid "Untracked"
+#: wt-status.c:1011
+msgid "Untracked files"
msgstr ""
-#: wt-status.c:771
-msgid "Ignored"
+#: wt-status.c:1013
+msgid "Ignored files"
msgstr ""
-#: wt-status.c:773
+#: wt-status.c:1015
#, c-format
msgid "Untracked files not listed%s"
msgstr ""
-#: wt-status.c:775
+#: wt-status.c:1017
msgid " (use -u option to show untracked files)"
msgstr ""
-#: wt-status.c:781
+#: wt-status.c:1023
msgid "No changes"
msgstr ""
-#: wt-status.c:785
+#: wt-status.c:1028
#, c-format
-msgid "no changes added to commit%s\n"
+msgid "no changes added to commit (use \"git add\" and/or \"git commit -a\")\n"
msgstr ""
-#: wt-status.c:787
-msgid " (use \"git add\" and/or \"git commit -a\")"
+#: wt-status.c:1031
+#, c-format
+msgid "no changes added to commit\n"
msgstr ""
-#: wt-status.c:789
+#: wt-status.c:1034
#, c-format
-msgid "nothing added to commit but untracked files present%s\n"
+msgid ""
+"nothing added to commit but untracked files present (use \"git add\" to "
+"track)\n"
msgstr ""
-#: wt-status.c:791
-msgid " (use \"git add\" to track)"
+#: wt-status.c:1037
+#, c-format
+msgid "nothing added to commit but untracked files present\n"
msgstr ""
-#: wt-status.c:793 wt-status.c:796 wt-status.c:799
+#: wt-status.c:1040
#, c-format
-msgid "nothing to commit%s\n"
+msgid "nothing to commit (create/copy files and use \"git add\" to track)\n"
msgstr ""
-#: wt-status.c:794
-msgid " (create/copy files and use \"git add\" to track)"
+#: wt-status.c:1043 wt-status.c:1048
+#, c-format
+msgid "nothing to commit\n"
msgstr ""
-#: wt-status.c:797
-msgid " (use -u to show untracked files)"
+#: wt-status.c:1046
+#, c-format
+msgid "nothing to commit (use -u to show untracked files)\n"
msgstr ""
-#: wt-status.c:800
-msgid " (working directory clean)"
+#: wt-status.c:1050
+#, c-format
+msgid "nothing to commit, working directory clean\n"
msgstr ""
-#: wt-status.c:908
+#: wt-status.c:1158
msgid "HEAD (no branch)"
msgstr ""
-#: wt-status.c:914
+#: wt-status.c:1164
msgid "Initial commit on "
msgstr ""
-#: wt-status.c:929
+#: wt-status.c:1179
msgid "behind "
msgstr ""
-#: wt-status.c:932 wt-status.c:935
+#: wt-status.c:1182 wt-status.c:1185
msgid "ahead "
msgstr ""
-#: wt-status.c:937
+#: wt-status.c:1187
msgid ", behind "
msgstr ""
+#: compat/precompose_utf8.c:58 builtin/clone.c:341
+#, c-format
+msgid "failed to unlink '%s'"
+msgstr ""
+
+#: builtin/add.c:19
+msgid "git add [options] [--] <filepattern>..."
+msgstr ""
+
#: builtin/add.c:62
#, c-format
msgid "unexpected diff status %c"
msgstr ""
-#: builtin/add.c:67 builtin/commit.c:226
+#: builtin/add.c:67 builtin/commit.c:229
msgid "updating files failed"
msgstr ""
@@ -890,7 +1342,7 @@ msgstr ""
msgid "Unstaged changes after refreshing the index:"
msgstr ""
-#: builtin/add.c:195 builtin/add.c:456 builtin/rm.c:186
+#: builtin/add.c:195 builtin/add.c:460 builtin/rm.c:186
#, c-format
msgid "pathspec '%s' did not match any files"
msgstr ""
@@ -927,110 +1379,162 @@ msgstr ""
msgid "Could not apply '%s'"
msgstr ""
-#: builtin/add.c:312
+#: builtin/add.c:313
msgid "The following paths are ignored by one of your .gitignore files:\n"
msgstr ""
-#: builtin/add.c:352
+#: builtin/add.c:319 builtin/clean.c:52 builtin/fetch.c:78 builtin/mv.c:63
+#: builtin/prune-packed.c:76 builtin/push.c:388 builtin/remote.c:1253
+#: builtin/rm.c:133
+msgid "dry run"
+msgstr ""
+
+#: builtin/add.c:320 builtin/apply.c:4354 builtin/commit.c:1187
+#: builtin/count-objects.c:82 builtin/fsck.c:613 builtin/log.c:1477
+#: builtin/mv.c:62 builtin/read-tree.c:112
+msgid "be verbose"
+msgstr ""
+
+#: builtin/add.c:322
+msgid "interactive picking"
+msgstr ""
+
+#: builtin/add.c:323 builtin/checkout.c:1028 builtin/reset.c:248
+msgid "select hunks interactively"
+msgstr ""
+
+#: builtin/add.c:324
+msgid "edit current diff and apply"
+msgstr ""
+
+#: builtin/add.c:325
+msgid "allow adding otherwise ignored files"
+msgstr ""
+
+#: builtin/add.c:326
+msgid "update tracked files"
+msgstr ""
+
+#: builtin/add.c:327
+msgid "record only the fact that the path will be added later"
+msgstr ""
+
+#: builtin/add.c:328
+msgid "add changes from all tracked and untracked files"
+msgstr ""
+
+#: builtin/add.c:329
+msgid "don't add, only refresh the index"
+msgstr ""
+
+#: builtin/add.c:330
+msgid "just skip files which cannot be added because of errors"
+msgstr ""
+
+#: builtin/add.c:331
+msgid "check if - even missing - files are ignored in dry run"
+msgstr ""
+
+#: builtin/add.c:353
#, c-format
msgid "Use -f if you really want to add them.\n"
msgstr ""
-#: builtin/add.c:353
+#: builtin/add.c:354
msgid "no files added"
msgstr ""
-#: builtin/add.c:359
+#: builtin/add.c:360
msgid "adding files failed"
msgstr ""
-#: builtin/add.c:391
+#: builtin/add.c:392
msgid "-A and -u are mutually incompatible"
msgstr ""
-#: builtin/add.c:393
+#: builtin/add.c:394
msgid "Option --ignore-missing can only be used together with --dry-run"
msgstr ""
-#: builtin/add.c:413
+#: builtin/add.c:414
#, c-format
msgid "Nothing specified, nothing added.\n"
msgstr ""
-#: builtin/add.c:414
+#: builtin/add.c:415
#, c-format
msgid "Maybe you wanted to say 'git add .'?\n"
msgstr ""
-#: builtin/add.c:420 builtin/clean.c:95 builtin/commit.c:286 builtin/mv.c:82
+#: builtin/add.c:421 builtin/clean.c:95 builtin/commit.c:289 builtin/mv.c:82
#: builtin/rm.c:162
msgid "index file corrupt"
msgstr ""
-#: builtin/add.c:476 builtin/apply.c:4108 builtin/mv.c:229 builtin/rm.c:260
+#: builtin/add.c:481 builtin/apply.c:4450 builtin/mv.c:229 builtin/rm.c:260
msgid "Unable to write new index file"
msgstr ""
-#: builtin/apply.c:53
+#: builtin/apply.c:57
msgid "git apply [options] [<patch>...]"
msgstr ""
-#: builtin/apply.c:106
+#: builtin/apply.c:110
#, c-format
msgid "unrecognized whitespace option '%s'"
msgstr ""
-#: builtin/apply.c:121
+#: builtin/apply.c:125
#, c-format
msgid "unrecognized whitespace ignore option '%s'"
msgstr ""
-#: builtin/apply.c:815
+#: builtin/apply.c:823
#, c-format
msgid "Cannot prepare timestamp regexp %s"
msgstr ""
-#: builtin/apply.c:824
+#: builtin/apply.c:832
#, c-format
msgid "regexec returned %d for input: %s"
msgstr ""
-#: builtin/apply.c:905
+#: builtin/apply.c:913
#, c-format
msgid "unable to find filename in patch at line %d"
msgstr ""
-#: builtin/apply.c:937
+#: builtin/apply.c:945
#, c-format
msgid "git apply: bad git-diff - expected /dev/null, got %s on line %d"
msgstr ""
-#: builtin/apply.c:941
+#: builtin/apply.c:949
#, c-format
msgid "git apply: bad git-diff - inconsistent new filename on line %d"
msgstr ""
-#: builtin/apply.c:942
+#: builtin/apply.c:950
#, c-format
msgid "git apply: bad git-diff - inconsistent old filename on line %d"
msgstr ""
-#: builtin/apply.c:949
+#: builtin/apply.c:957
#, c-format
msgid "git apply: bad git-diff - expected /dev/null on line %d"
msgstr ""
-#: builtin/apply.c:1394
+#: builtin/apply.c:1420
#, c-format
msgid "recount: unexpected line: %.*s"
msgstr ""
-#: builtin/apply.c:1451
+#: builtin/apply.c:1477
#, c-format
msgid "patch fragment without header at line %d: %.*s"
msgstr ""
-#: builtin/apply.c:1468
+#: builtin/apply.c:1494
#, c-format
msgid ""
"git diff header lacks filename information when removing %d leading pathname "
@@ -1041,395 +1545,400 @@ msgid_plural ""
msgstr[0] ""
msgstr[1] ""
-#: builtin/apply.c:1628
+#: builtin/apply.c:1654
msgid "new file depends on old contents"
msgstr ""
-#: builtin/apply.c:1630
+#: builtin/apply.c:1656
msgid "deleted file still has contents"
msgstr ""
-#: builtin/apply.c:1656
+#: builtin/apply.c:1682
#, c-format
msgid "corrupt patch at line %d"
msgstr ""
-#: builtin/apply.c:1692
+#: builtin/apply.c:1718
#, c-format
msgid "new file %s depends on old contents"
msgstr ""
-#: builtin/apply.c:1694
+#: builtin/apply.c:1720
#, c-format
msgid "deleted file %s still has contents"
msgstr ""
-#: builtin/apply.c:1697
+#: builtin/apply.c:1723
#, c-format
msgid "** warning: file %s becomes empty but is not deleted"
msgstr ""
-#: builtin/apply.c:1843
+#: builtin/apply.c:1869
#, c-format
msgid "corrupt binary patch at line %d: %.*s"
msgstr ""
#. there has to be one hunk (forward hunk)
-#: builtin/apply.c:1872
+#: builtin/apply.c:1898
#, c-format
msgid "unrecognized binary patch at line %d"
msgstr ""
-#: builtin/apply.c:1958
+#: builtin/apply.c:1984
#, c-format
msgid "patch with only garbage at line %d"
msgstr ""
-#: builtin/apply.c:2048
+#: builtin/apply.c:2074
#, c-format
msgid "unable to read symlink %s"
msgstr ""
-#: builtin/apply.c:2052
+#: builtin/apply.c:2078
#, c-format
msgid "unable to open or read %s"
msgstr ""
-#: builtin/apply.c:2123
+#: builtin/apply.c:2149
msgid "oops"
msgstr ""
-#: builtin/apply.c:2645
+#: builtin/apply.c:2671
#, c-format
msgid "invalid start of line: '%c'"
msgstr ""
-#: builtin/apply.c:2763
+#: builtin/apply.c:2789
#, c-format
msgid "Hunk #%d succeeded at %d (offset %d line)."
msgid_plural "Hunk #%d succeeded at %d (offset %d lines)."
msgstr[0] ""
msgstr[1] ""
-#: builtin/apply.c:2775
+#: builtin/apply.c:2801
#, c-format
msgid "Context reduced to (%ld/%ld) to apply fragment at %d"
msgstr ""
-#: builtin/apply.c:2781
+#: builtin/apply.c:2807
#, c-format
msgid ""
"while searching for:\n"
"%.*s"
msgstr ""
-#: builtin/apply.c:2800
+#: builtin/apply.c:2826
#, c-format
msgid "missing binary patch data for '%s'"
msgstr ""
-#: builtin/apply.c:2903
+#: builtin/apply.c:2929
#, c-format
msgid "binary patch does not apply to '%s'"
msgstr ""
-#: builtin/apply.c:2909
+#: builtin/apply.c:2935
#, c-format
msgid "binary patch to '%s' creates incorrect result (expecting %s, got %s)"
msgstr ""
-#: builtin/apply.c:2930
+#: builtin/apply.c:2956
#, c-format
msgid "patch failed: %s:%ld"
msgstr ""
-#: builtin/apply.c:3045
+#: builtin/apply.c:3078
#, c-format
-msgid "patch %s has been renamed/deleted"
+msgid "cannot checkout %s"
msgstr ""
-#: builtin/apply.c:3052 builtin/apply.c:3069
+#: builtin/apply.c:3123 builtin/apply.c:3132 builtin/apply.c:3176
#, c-format
msgid "read of %s failed"
msgstr ""
-#: builtin/apply.c:3084
-msgid "removal patch leaves file contents"
-msgstr ""
-
-#: builtin/apply.c:3105
+#: builtin/apply.c:3156 builtin/apply.c:3378
#, c-format
-msgid "%s: already exists in working directory"
+msgid "path %s has been renamed/deleted"
msgstr ""
-#: builtin/apply.c:3143
+#: builtin/apply.c:3237 builtin/apply.c:3392
#, c-format
-msgid "%s: has been deleted/renamed"
+msgid "%s: does not exist in index"
msgstr ""
-#: builtin/apply.c:3148 builtin/apply.c:3179
+#: builtin/apply.c:3241 builtin/apply.c:3384 builtin/apply.c:3406
#, c-format
msgid "%s: %s"
msgstr ""
-#: builtin/apply.c:3159
+#: builtin/apply.c:3246 builtin/apply.c:3400
#, c-format
-msgid "%s: does not exist in index"
+msgid "%s: does not match index"
msgstr ""
-#: builtin/apply.c:3173
-#, c-format
-msgid "%s: does not match index"
+#: builtin/apply.c:3348
+msgid "removal patch leaves file contents"
msgstr ""
-#: builtin/apply.c:3190
+#: builtin/apply.c:3417
#, c-format
msgid "%s: wrong type"
msgstr ""
-#: builtin/apply.c:3192
+#: builtin/apply.c:3419
#, c-format
msgid "%s has type %o, expected %o"
msgstr ""
-#: builtin/apply.c:3247
+#: builtin/apply.c:3520
#, c-format
msgid "%s: already exists in index"
msgstr ""
-#: builtin/apply.c:3267
+#: builtin/apply.c:3523
+#, c-format
+msgid "%s: already exists in working directory"
+msgstr ""
+
+#: builtin/apply.c:3543
#, c-format
msgid "new mode (%o) of %s does not match old mode (%o)"
msgstr ""
-#: builtin/apply.c:3272
+#: builtin/apply.c:3548
#, c-format
msgid "new mode (%o) of %s does not match old mode (%o) of %s"
msgstr ""
-#: builtin/apply.c:3280
+#: builtin/apply.c:3556
#, c-format
msgid "%s: patch does not apply"
msgstr ""
-#: builtin/apply.c:3293
+#: builtin/apply.c:3569
#, c-format
msgid "Checking patch %s..."
msgstr ""
-#: builtin/apply.c:3348 builtin/checkout.c:212 builtin/reset.c:158
+#: builtin/apply.c:3624 builtin/checkout.c:215 builtin/reset.c:158
#, c-format
msgid "make_cache_entry failed for path '%s'"
msgstr ""
-#: builtin/apply.c:3491
+#: builtin/apply.c:3767
#, c-format
msgid "unable to remove %s from index"
msgstr ""
-#: builtin/apply.c:3518
+#: builtin/apply.c:3795
#, c-format
msgid "corrupt patch for subproject %s"
msgstr ""
-#: builtin/apply.c:3522
+#: builtin/apply.c:3799
#, c-format
msgid "unable to stat newly created file '%s'"
msgstr ""
-#: builtin/apply.c:3527
+#: builtin/apply.c:3804
#, c-format
msgid "unable to create backing store for newly created file %s"
msgstr ""
-#: builtin/apply.c:3530
+#: builtin/apply.c:3807 builtin/apply.c:3915
#, c-format
msgid "unable to add cache entry for %s"
msgstr ""
-#: builtin/apply.c:3563
+#: builtin/apply.c:3840
#, c-format
msgid "closing file '%s'"
msgstr ""
-#: builtin/apply.c:3612
+#: builtin/apply.c:3889
#, c-format
msgid "unable to write file '%s' mode %o"
msgstr ""
-#: builtin/apply.c:3668
+#: builtin/apply.c:3976
#, c-format
msgid "Applied patch %s cleanly."
msgstr ""
-#: builtin/apply.c:3676
+#: builtin/apply.c:3984
msgid "internal error"
msgstr ""
#. Say this even without --verbose
-#: builtin/apply.c:3679
+#: builtin/apply.c:3987
#, c-format
msgid "Applying patch %%s with %d reject..."
msgid_plural "Applying patch %%s with %d rejects..."
msgstr[0] ""
msgstr[1] ""
-#: builtin/apply.c:3689
+#: builtin/apply.c:3997
#, c-format
msgid "truncating .rej filename to %.*s.rej"
msgstr ""
-#: builtin/apply.c:3710
+#: builtin/apply.c:4018
#, c-format
msgid "Hunk #%d applied cleanly."
msgstr ""
-#: builtin/apply.c:3713
+#: builtin/apply.c:4021
#, c-format
msgid "Rejected hunk #%d."
msgstr ""
-#: builtin/apply.c:3844
+#: builtin/apply.c:4171
msgid "unrecognized input"
msgstr ""
-#: builtin/apply.c:3855
+#: builtin/apply.c:4182
msgid "unable to read index file"
msgstr ""
-#: builtin/apply.c:3970 builtin/apply.c:3973
+#: builtin/apply.c:4301 builtin/apply.c:4304 builtin/clone.c:91
+#: builtin/fetch.c:63
msgid "path"
msgstr ""
-#: builtin/apply.c:3971
+#: builtin/apply.c:4302
msgid "don't apply changes matching the given path"
msgstr ""
-#: builtin/apply.c:3974
+#: builtin/apply.c:4305
msgid "apply changes matching the given path"
msgstr ""
-#: builtin/apply.c:3976
+#: builtin/apply.c:4307
msgid "num"
msgstr ""
-#: builtin/apply.c:3977
+#: builtin/apply.c:4308
msgid "remove <num> leading slashes from traditional diff paths"
msgstr ""
-#: builtin/apply.c:3980
+#: builtin/apply.c:4311
msgid "ignore additions made by the patch"
msgstr ""
-#: builtin/apply.c:3982
+#: builtin/apply.c:4313
msgid "instead of applying the patch, output diffstat for the input"
msgstr ""
-#: builtin/apply.c:3986
-msgid "shows number of added and deleted lines in decimal notation"
+#: builtin/apply.c:4317
+msgid "show number of added and deleted lines in decimal notation"
msgstr ""
-#: builtin/apply.c:3988
+#: builtin/apply.c:4319
msgid "instead of applying the patch, output a summary for the input"
msgstr ""
-#: builtin/apply.c:3990
+#: builtin/apply.c:4321
msgid "instead of applying the patch, see if the patch is applicable"
msgstr ""
-#: builtin/apply.c:3992
+#: builtin/apply.c:4323
msgid "make sure the patch is applicable to the current index"
msgstr ""
-#: builtin/apply.c:3994
+#: builtin/apply.c:4325
msgid "apply a patch without touching the working tree"
msgstr ""
-#: builtin/apply.c:3996
+#: builtin/apply.c:4327
msgid "also apply the patch (use with --stat/--summary/--check)"
msgstr ""
-#: builtin/apply.c:3998
+#: builtin/apply.c:4329
+msgid "attempt three-way merge if a patch does not apply"
+msgstr ""
+
+#: builtin/apply.c:4331
msgid "build a temporary index based on embedded index information"
msgstr ""
-#: builtin/apply.c:4000
+#: builtin/apply.c:4333 builtin/checkout-index.c:197 builtin/ls-files.c:460
msgid "paths are separated with NUL character"
msgstr ""
-#: builtin/apply.c:4003
+#: builtin/apply.c:4336
msgid "ensure at least <n> lines of context match"
msgstr ""
-#: builtin/apply.c:4004
+#: builtin/apply.c:4337
msgid "action"
msgstr ""
-#: builtin/apply.c:4005
+#: builtin/apply.c:4338
msgid "detect new or modified lines that have whitespace errors"
msgstr ""
-#: builtin/apply.c:4008 builtin/apply.c:4011
+#: builtin/apply.c:4341 builtin/apply.c:4344
msgid "ignore changes in whitespace when finding context"
msgstr ""
-#: builtin/apply.c:4014
+#: builtin/apply.c:4347
msgid "apply the patch in reverse"
msgstr ""
-#: builtin/apply.c:4016
+#: builtin/apply.c:4349
msgid "don't expect at least one line of context"
msgstr ""
-#: builtin/apply.c:4018
+#: builtin/apply.c:4351
msgid "leave the rejected hunks in corresponding *.rej files"
msgstr ""
-#: builtin/apply.c:4020
+#: builtin/apply.c:4353
msgid "allow overlapping hunks"
msgstr ""
-#: builtin/apply.c:4021
-msgid "be verbose"
-msgstr ""
-
-#: builtin/apply.c:4023
+#: builtin/apply.c:4356
msgid "tolerate incorrectly detected missing new-line at the end of file"
msgstr ""
-#: builtin/apply.c:4026
+#: builtin/apply.c:4359
msgid "do not trust the line counts in the hunk headers"
msgstr ""
-#: builtin/apply.c:4028
+#: builtin/apply.c:4361
msgid "root"
msgstr ""
-#: builtin/apply.c:4029
+#: builtin/apply.c:4362
msgid "prepend <root> to all filenames"
msgstr ""
-#: builtin/apply.c:4050
+#: builtin/apply.c:4384
+msgid "--3way outside a repository"
+msgstr ""
+
+#: builtin/apply.c:4392
msgid "--index outside a repository"
msgstr ""
-#: builtin/apply.c:4053
+#: builtin/apply.c:4395
msgid "--cached outside a repository"
msgstr ""
-#: builtin/apply.c:4069
+#: builtin/apply.c:4411
#, c-format
msgid "can't open patch '%s'"
msgstr ""
-#: builtin/apply.c:4083
+#: builtin/apply.c:4425
#, c-format
msgid "squelched %d whitespace error"
msgid_plural "squelched %d whitespace errors"
msgstr[0] ""
msgstr[1] ""
-#: builtin/apply.c:4089 builtin/apply.c:4099
+#: builtin/apply.c:4431 builtin/apply.c:4441
#, c-format
msgid "%d line adds whitespace errors."
msgid_plural "%d lines add whitespace errors."
@@ -1471,175 +1980,428 @@ msgstr ""
msgid "git archive: expected a flush"
msgstr ""
-#: builtin/branch.c:144
+#: builtin/bisect--helper.c:7
+msgid "git bisect--helper --next-all [--no-checkout]"
+msgstr ""
+
+#: builtin/bisect--helper.c:17
+msgid "perform 'git bisect next'"
+msgstr ""
+
+#: builtin/bisect--helper.c:19
+msgid "update BISECT_HEAD instead of checking out the current commit"
+msgstr ""
+
+#: builtin/blame.c:25
+msgid "git blame [options] [rev-opts] [rev] [--] file"
+msgstr ""
+
+#: builtin/blame.c:30 builtin/shortlog.c:15
+msgid "[rev-opts] are documented in git-rev-list(1)"
+msgstr ""
+
+#: builtin/blame.c:2316
+msgid "Show blame entries as we find them, incrementally"
+msgstr ""
+
+#: builtin/blame.c:2317
+msgid "Show blank SHA-1 for boundary commits (Default: off)"
+msgstr ""
+
+#: builtin/blame.c:2318
+msgid "Do not treat root commits as boundaries (Default: off)"
+msgstr ""
+
+#: builtin/blame.c:2319
+msgid "Show work cost statistics"
+msgstr ""
+
+#: builtin/blame.c:2320
+msgid "Show output score for blame entries"
+msgstr ""
+
+#: builtin/blame.c:2321
+msgid "Show original filename (Default: auto)"
+msgstr ""
+
+#: builtin/blame.c:2322
+msgid "Show original linenumber (Default: off)"
+msgstr ""
+
+#: builtin/blame.c:2323
+msgid "Show in a format designed for machine consumption"
+msgstr ""
+
+#: builtin/blame.c:2324
+msgid "Show porcelain format with per-line commit information"
+msgstr ""
+
+#: builtin/blame.c:2325
+msgid "Use the same output mode as git-annotate (Default: off)"
+msgstr ""
+
+#: builtin/blame.c:2326
+msgid "Show raw timestamp (Default: off)"
+msgstr ""
+
+#: builtin/blame.c:2327
+msgid "Show long commit SHA1 (Default: off)"
+msgstr ""
+
+#: builtin/blame.c:2328
+msgid "Suppress author name and timestamp (Default: off)"
+msgstr ""
+
+#: builtin/blame.c:2329
+msgid "Show author email instead of name (Default: off)"
+msgstr ""
+
+#: builtin/blame.c:2330
+msgid "Ignore whitespace differences"
+msgstr ""
+
+#: builtin/blame.c:2331
+msgid "Spend extra cycles to find better match"
+msgstr ""
+
+#: builtin/blame.c:2332
+msgid "Use revisions from <file> instead of calling git-rev-list"
+msgstr ""
+
+#: builtin/blame.c:2333
+msgid "Use <file>'s contents as the final image"
+msgstr ""
+
+#: builtin/blame.c:2334 builtin/blame.c:2335
+msgid "score"
+msgstr ""
+
+#: builtin/blame.c:2334
+msgid "Find line copies within and across files"
+msgstr ""
+
+#: builtin/blame.c:2335
+msgid "Find line movements within and across files"
+msgstr ""
+
+#: builtin/blame.c:2336
+msgid "n,m"
+msgstr ""
+
+#: builtin/blame.c:2336
+msgid "Process only line range n,m, counting from 1"
+msgstr ""
+
+#: builtin/branch.c:23
+msgid "git branch [options] [-r | -a] [--merged | --no-merged]"
+msgstr ""
+
+#: builtin/branch.c:24
+msgid "git branch [options] [-l] [-f] <branchname> [<start-point>]"
+msgstr ""
+
+#: builtin/branch.c:25
+msgid "git branch [options] [-r] (-d | -D) <branchname>..."
+msgstr ""
+
+#: builtin/branch.c:26
+msgid "git branch [options] (-m | -M) [<oldbranch>] <newbranch>"
+msgstr ""
+
+#: builtin/branch.c:145
#, c-format
msgid ""
"deleting branch '%s' that has been merged to\n"
" '%s', but not yet merged to HEAD."
msgstr ""
-#: builtin/branch.c:148
+#: builtin/branch.c:149
#, c-format
msgid ""
"not deleting branch '%s' that is not yet merged to\n"
" '%s', even though it is merged to HEAD."
msgstr ""
-#: builtin/branch.c:180
+#: builtin/branch.c:181
msgid "cannot use -a with -d"
msgstr ""
-#: builtin/branch.c:186
+#: builtin/branch.c:187
msgid "Couldn't look up commit object for HEAD"
msgstr ""
-#: builtin/branch.c:191
+#: builtin/branch.c:192
#, c-format
msgid "Cannot delete the branch '%s' which you are currently on."
msgstr ""
-#: builtin/branch.c:202
+#: builtin/branch.c:203
#, c-format
msgid "remote branch '%s' not found."
msgstr ""
-#: builtin/branch.c:203
+#: builtin/branch.c:204
#, c-format
msgid "branch '%s' not found."
msgstr ""
-#: builtin/branch.c:210
+#: builtin/branch.c:211
#, c-format
msgid "Couldn't look up commit object for '%s'"
msgstr ""
-#: builtin/branch.c:216
+#: builtin/branch.c:217
#, c-format
msgid ""
"The branch '%s' is not fully merged.\n"
"If you are sure you want to delete it, run 'git branch -D %s'."
msgstr ""
-#: builtin/branch.c:225
+#: builtin/branch.c:226
#, c-format
msgid "Error deleting remote branch '%s'"
msgstr ""
-#: builtin/branch.c:226
+#: builtin/branch.c:227
#, c-format
msgid "Error deleting branch '%s'"
msgstr ""
-#: builtin/branch.c:233
+#: builtin/branch.c:234
#, c-format
msgid "Deleted remote branch %s (was %s).\n"
msgstr ""
-#: builtin/branch.c:234
+#: builtin/branch.c:235
#, c-format
msgid "Deleted branch %s (was %s).\n"
msgstr ""
-#: builtin/branch.c:239
+#: builtin/branch.c:240
msgid "Update of config-file failed"
msgstr ""
-#: builtin/branch.c:337
+#: builtin/branch.c:338
#, c-format
msgid "branch '%s' does not point at a commit"
msgstr ""
-#: builtin/branch.c:409
+#: builtin/branch.c:410
#, c-format
msgid "[%s: behind %d]"
msgstr ""
-#: builtin/branch.c:411
+#: builtin/branch.c:412
#, c-format
msgid "[behind %d]"
msgstr ""
-#: builtin/branch.c:415
+#: builtin/branch.c:416
#, c-format
msgid "[%s: ahead %d]"
msgstr ""
-#: builtin/branch.c:417
+#: builtin/branch.c:418
#, c-format
msgid "[ahead %d]"
msgstr ""
-#: builtin/branch.c:420
+#: builtin/branch.c:421
#, c-format
msgid "[%s: ahead %d, behind %d]"
msgstr ""
-#: builtin/branch.c:423
+#: builtin/branch.c:424
#, c-format
msgid "[ahead %d, behind %d]"
msgstr ""
-#: builtin/branch.c:535
+#: builtin/branch.c:537
msgid "(no branch)"
msgstr ""
-#: builtin/branch.c:600
+#: builtin/branch.c:602
msgid "some refs could not be read"
msgstr ""
-#: builtin/branch.c:613
+#: builtin/branch.c:615
msgid "cannot rename the current branch while not on any."
msgstr ""
-#: builtin/branch.c:623
+#: builtin/branch.c:625
#, c-format
msgid "Invalid branch name: '%s'"
msgstr ""
-#: builtin/branch.c:638
+#: builtin/branch.c:640
msgid "Branch rename failed"
msgstr ""
-#: builtin/branch.c:642
+#: builtin/branch.c:644
#, c-format
msgid "Renamed a misnamed branch '%s' away"
msgstr ""
-#: builtin/branch.c:646
+#: builtin/branch.c:648
#, c-format
msgid "Branch renamed to %s, but HEAD is not updated!"
msgstr ""
-#: builtin/branch.c:653
+#: builtin/branch.c:655
msgid "Branch is renamed, but update of config-file failed"
msgstr ""
-#: builtin/branch.c:668
+#: builtin/branch.c:670
#, c-format
msgid "malformed object name %s"
msgstr ""
-#: builtin/branch.c:692
+#: builtin/branch.c:694
#, c-format
msgid "could not write branch description template: %s"
msgstr ""
-#: builtin/branch.c:783
+#: builtin/branch.c:724
+msgid "Generic options"
+msgstr ""
+
+#: builtin/branch.c:726
+msgid "show hash and subject, give twice for upstream branch"
+msgstr ""
+
+#: builtin/branch.c:727
+msgid "suppress informational messages"
+msgstr ""
+
+#: builtin/branch.c:728
+msgid "set up tracking mode (see git-pull(1))"
+msgstr ""
+
+#: builtin/branch.c:730
+msgid "change upstream info"
+msgstr ""
+
+#: builtin/branch.c:734
+msgid "use colored output"
+msgstr ""
+
+#: builtin/branch.c:735
+msgid "act on remote-tracking branches"
+msgstr ""
+
+#: builtin/branch.c:738 builtin/branch.c:744 builtin/branch.c:765
+#: builtin/branch.c:771 builtin/commit.c:1395 builtin/commit.c:1396
+#: builtin/commit.c:1397 builtin/commit.c:1398 builtin/tag.c:470
+msgid "commit"
+msgstr ""
+
+#: builtin/branch.c:739 builtin/branch.c:745
+msgid "print only branches that contain the commit"
+msgstr ""
+
+#: builtin/branch.c:751
+msgid "Specific git-branch actions:"
+msgstr ""
+
+#: builtin/branch.c:752
+msgid "list both remote-tracking and local branches"
+msgstr ""
+
+#: builtin/branch.c:754
+msgid "delete fully merged branch"
+msgstr ""
+
+#: builtin/branch.c:755
+msgid "delete branch (even if not merged)"
+msgstr ""
+
+#: builtin/branch.c:756
+msgid "move/rename a branch and its reflog"
+msgstr ""
+
+#: builtin/branch.c:757
+msgid "move/rename a branch, even if target exists"
+msgstr ""
+
+#: builtin/branch.c:758
+msgid "list branch names"
+msgstr ""
+
+#: builtin/branch.c:759
+msgid "create the branch's reflog"
+msgstr ""
+
+#: builtin/branch.c:761
+msgid "edit the description for the branch"
+msgstr ""
+
+#: builtin/branch.c:762
+msgid "force creation (when already exists)"
+msgstr ""
+
+#: builtin/branch.c:765
+msgid "print only not merged branches"
+msgstr ""
+
+#: builtin/branch.c:771
+msgid "print only merged branches"
+msgstr ""
+
+#: builtin/branch.c:775
+msgid "list branches in columns"
+msgstr ""
+
+#: builtin/branch.c:788
msgid "Failed to resolve HEAD as a valid ref."
msgstr ""
-#: builtin/branch.c:788 builtin/clone.c:558
+#: builtin/branch.c:793 builtin/clone.c:561
msgid "HEAD not found below refs/heads!"
msgstr ""
-#: builtin/branch.c:808
+#: builtin/branch.c:813
msgid "--column and --verbose are incompatible"
msgstr ""
-#: builtin/branch.c:857
+#: builtin/branch.c:864
+#, c-format
+msgid "branch '%s' does not exist"
+msgstr ""
+
+#: builtin/branch.c:876
+#, c-format
+msgid "Branch '%s' has no upstream information"
+msgstr ""
+
+#: builtin/branch.c:891
msgid "-a and -r options to 'git branch' do not make sense with a branch name"
msgstr ""
+#: builtin/branch.c:894
+#, c-format
+msgid ""
+"The --set-upstream flag is deprecated and will be removed. Consider using --"
+"track or --set-upstream-to\n"
+msgstr ""
+
+#: builtin/branch.c:911
+#, c-format
+msgid ""
+"\n"
+"If you wanted to make '%s' track '%s', do this:\n"
+"\n"
+msgstr ""
+
+#: builtin/branch.c:912
+#, c-format
+msgid " git branch -d %s\n"
+msgstr ""
+
+#: builtin/branch.c:913
+#, c-format
+msgid " git branch --set-upstream-to %s\n"
+msgstr ""
+
#: builtin/bundle.c:47
#, c-format
msgid "%s is okay\n"
@@ -1653,99 +2415,227 @@ msgstr ""
msgid "Need a repository to unbundle."
msgstr ""
-#: builtin/checkout.c:113 builtin/checkout.c:146
+#: builtin/cat-file.c:247
+msgid "git cat-file (-t|-s|-e|-p|<type>|--textconv) <object>"
+msgstr ""
+
+#: builtin/cat-file.c:248
+msgid "git cat-file (--batch|--batch-check) < <list_of_objects>"
+msgstr ""
+
+#: builtin/cat-file.c:266
+msgid "<type> can be one of: blob, tree, commit, tag"
+msgstr ""
+
+#: builtin/cat-file.c:267
+msgid "show object type"
+msgstr ""
+
+#: builtin/cat-file.c:268
+msgid "show object size"
+msgstr ""
+
+#: builtin/cat-file.c:270
+msgid "exit with zero when there's no error"
+msgstr ""
+
+#: builtin/cat-file.c:271
+msgid "pretty-print object's content"
+msgstr ""
+
+#: builtin/cat-file.c:273
+msgid "for blob objects, run textconv on object's content"
+msgstr ""
+
+#: builtin/cat-file.c:275
+msgid "show info and content of objects fed from the standard input"
+msgstr ""
+
+#: builtin/cat-file.c:278
+msgid "show info about objects fed from the standard input"
+msgstr ""
+
+#: builtin/check-attr.c:11
+msgid "git check-attr [-a | --all | attr...] [--] pathname..."
+msgstr ""
+
+#: builtin/check-attr.c:12
+msgid "git check-attr --stdin [-a | --all | attr...] < <list-of-paths>"
+msgstr ""
+
+#: builtin/check-attr.c:19
+msgid "report all attributes set on file"
+msgstr ""
+
+#: builtin/check-attr.c:20
+msgid "use .gitattributes only from the index"
+msgstr ""
+
+#: builtin/check-attr.c:21 builtin/hash-object.c:75
+msgid "read file names from stdin"
+msgstr ""
+
+#: builtin/check-attr.c:23
+msgid "input paths are terminated by a null character"
+msgstr ""
+
+#: builtin/checkout-index.c:126
+msgid "git checkout-index [options] [--] [<file>...]"
+msgstr ""
+
+#: builtin/checkout-index.c:187
+msgid "check out all files in the index"
+msgstr ""
+
+#: builtin/checkout-index.c:188
+msgid "force overwrite of existing files"
+msgstr ""
+
+#: builtin/checkout-index.c:190
+msgid "no warning for existing files and files not in index"
+msgstr ""
+
+#: builtin/checkout-index.c:192
+msgid "don't checkout new files"
+msgstr ""
+
+#: builtin/checkout-index.c:194
+msgid "update stat information in the index file"
+msgstr ""
+
+#: builtin/checkout-index.c:200
+msgid "read list of paths from the standard input"
+msgstr ""
+
+#: builtin/checkout-index.c:202
+msgid "write the content to temporary files"
+msgstr ""
+
+#: builtin/checkout-index.c:203 builtin/column.c:30
+msgid "string"
+msgstr ""
+
+#: builtin/checkout-index.c:204
+msgid "when creating files, prepend <string>"
+msgstr ""
+
+#: builtin/checkout-index.c:207
+msgid "copy out the files from named stage"
+msgstr ""
+
+#: builtin/checkout.c:25
+msgid "git checkout [options] <branch>"
+msgstr ""
+
+#: builtin/checkout.c:26
+msgid "git checkout [options] [<branch>] -- <file>..."
+msgstr ""
+
+#: builtin/checkout.c:116 builtin/checkout.c:149
#, c-format
msgid "path '%s' does not have our version"
msgstr ""
-#: builtin/checkout.c:115 builtin/checkout.c:148
+#: builtin/checkout.c:118 builtin/checkout.c:151
#, c-format
msgid "path '%s' does not have their version"
msgstr ""
-#: builtin/checkout.c:131
+#: builtin/checkout.c:134
#, c-format
msgid "path '%s' does not have all necessary versions"
msgstr ""
-#: builtin/checkout.c:175
+#: builtin/checkout.c:178
#, c-format
msgid "path '%s' does not have necessary versions"
msgstr ""
-#: builtin/checkout.c:192
+#: builtin/checkout.c:195
#, c-format
msgid "path '%s': cannot merge"
msgstr ""
-#: builtin/checkout.c:209
+#: builtin/checkout.c:212
#, c-format
msgid "Unable to add merge result for '%s'"
msgstr ""
-#: builtin/checkout.c:234 builtin/checkout.c:392
+#: builtin/checkout.c:236 builtin/checkout.c:239 builtin/checkout.c:242
+#: builtin/checkout.c:245
+#, c-format
+msgid "'%s' cannot be used with updating paths"
+msgstr ""
+
+#: builtin/checkout.c:248 builtin/checkout.c:251
+#, c-format
+msgid "'%s' cannot be used with %s"
+msgstr ""
+
+#: builtin/checkout.c:254
+#, c-format
+msgid "Cannot update paths and switch to branch '%s' at the same time."
+msgstr ""
+
+#: builtin/checkout.c:265 builtin/checkout.c:426
msgid "corrupt index file"
msgstr ""
-#: builtin/checkout.c:264 builtin/checkout.c:271
+#: builtin/checkout.c:295 builtin/checkout.c:302
#, c-format
msgid "path '%s' is unmerged"
msgstr ""
-#: builtin/checkout.c:302 builtin/checkout.c:498 builtin/clone.c:583
-#: builtin/merge.c:812
+#: builtin/checkout.c:333 builtin/checkout.c:534 builtin/clone.c:586
+#: builtin/merge.c:811
msgid "unable to write new index file"
msgstr ""
-#: builtin/checkout.c:319 builtin/diff.c:302 builtin/merge.c:408
-msgid "diff_setup_done failed"
-msgstr ""
-
-#: builtin/checkout.c:414
+#: builtin/checkout.c:448
msgid "you need to resolve your current index first"
msgstr ""
-#: builtin/checkout.c:533
+#: builtin/checkout.c:569
#, c-format
msgid "Can not do reflog for '%s'\n"
msgstr ""
-#: builtin/checkout.c:566
+#: builtin/checkout.c:602
msgid "HEAD is now at"
msgstr ""
-#: builtin/checkout.c:573
+#: builtin/checkout.c:609
#, c-format
msgid "Reset branch '%s'\n"
msgstr ""
-#: builtin/checkout.c:576
+#: builtin/checkout.c:612
#, c-format
msgid "Already on '%s'\n"
msgstr ""
-#: builtin/checkout.c:580
+#: builtin/checkout.c:616
#, c-format
msgid "Switched to and reset branch '%s'\n"
msgstr ""
-#: builtin/checkout.c:582
+#: builtin/checkout.c:618
#, c-format
msgid "Switched to a new branch '%s'\n"
msgstr ""
-#: builtin/checkout.c:584
+#: builtin/checkout.c:620
#, c-format
msgid "Switched to branch '%s'\n"
msgstr ""
-#: builtin/checkout.c:640
+#: builtin/checkout.c:676
#, c-format
msgid " ... and %d more.\n"
msgstr ""
#. The singular version
-#: builtin/checkout.c:646
+#: builtin/checkout.c:682
#, c-format
msgid ""
"Warning: you are leaving %d commit behind, not connected to\n"
@@ -1760,7 +2650,7 @@ msgid_plural ""
msgstr[0] ""
msgstr[1] ""
-#: builtin/checkout.c:664
+#: builtin/checkout.c:700
#, c-format
msgid ""
"If you want to keep them by creating a new branch, this may be a good time\n"
@@ -1770,97 +2660,184 @@ msgid ""
"\n"
msgstr ""
-#: builtin/checkout.c:694
+#: builtin/checkout.c:730
msgid "internal error in revision walk"
msgstr ""
-#: builtin/checkout.c:698
+#: builtin/checkout.c:734
msgid "Previous HEAD position was"
msgstr ""
-#: builtin/checkout.c:724
+#: builtin/checkout.c:761 builtin/checkout.c:950
msgid "You are on a branch yet to be born"
msgstr ""
#. case (1)
-#: builtin/checkout.c:855
+#: builtin/checkout.c:886
#, c-format
msgid "invalid reference: %s"
msgstr ""
#. case (1): want a tree
-#: builtin/checkout.c:894
+#: builtin/checkout.c:925
#, c-format
msgid "reference is not a tree: %s"
msgstr ""
-#: builtin/checkout.c:974
-msgid "-B cannot be used with -b"
+#: builtin/checkout.c:961
+msgid "paths cannot be used with switching branches"
msgstr ""
-#: builtin/checkout.c:983
-msgid "--patch is incompatible with all other options"
+#: builtin/checkout.c:964 builtin/checkout.c:968
+#, c-format
+msgid "'%s' cannot be used with switching branches"
msgstr ""
-#: builtin/checkout.c:986
-msgid "--detach cannot be used with -b/-B/--orphan"
+#: builtin/checkout.c:972 builtin/checkout.c:975 builtin/checkout.c:980
+#: builtin/checkout.c:983
+#, c-format
+msgid "'%s' cannot be used with '%s'"
msgstr ""
#: builtin/checkout.c:988
-msgid "--detach cannot be used with -t"
+#, c-format
+msgid "Cannot switch branch to a non-commit '%s'"
msgstr ""
-#: builtin/checkout.c:994
-msgid "--track needs a branch name"
+#: builtin/checkout.c:1009 builtin/gc.c:177
+msgid "suppress progress reporting"
msgstr ""
-#: builtin/checkout.c:1001
-msgid "Missing branch name; try -b"
+#: builtin/checkout.c:1010 builtin/checkout.c:1012 builtin/clone.c:89
+#: builtin/remote.c:169 builtin/remote.c:171
+msgid "branch"
+msgstr ""
+
+#: builtin/checkout.c:1011
+msgid "create and checkout a new branch"
+msgstr ""
+
+#: builtin/checkout.c:1013
+msgid "create/reset and checkout a branch"
+msgstr ""
+
+#: builtin/checkout.c:1014
+msgid "create reflog for new branch"
+msgstr ""
+
+#: builtin/checkout.c:1015
+msgid "detach the HEAD at named commit"
+msgstr ""
+
+#: builtin/checkout.c:1016
+msgid "set upstream info for new branch"
msgstr ""
-#: builtin/checkout.c:1007
-msgid "--orphan and -b|-B are mutually exclusive"
+#: builtin/checkout.c:1018
+msgid "new branch"
msgstr ""
-#: builtin/checkout.c:1009
-msgid "--orphan cannot be used with -t"
+#: builtin/checkout.c:1018
+msgid "new unparented branch"
msgstr ""
#: builtin/checkout.c:1019
-msgid "git checkout: -f and -m are incompatible"
+msgid "checkout our version for unmerged files"
+msgstr ""
+
+#: builtin/checkout.c:1021
+msgid "checkout their version for unmerged files"
+msgstr ""
+
+#: builtin/checkout.c:1023
+msgid "force checkout (throw away local modifications)"
+msgstr ""
+
+#: builtin/checkout.c:1024
+msgid "perform a 3-way merge with the new branch"
+msgstr ""
+
+#: builtin/checkout.c:1025 builtin/merge.c:215
+msgid "update ignored files (default)"
+msgstr ""
+
+#: builtin/checkout.c:1026 builtin/log.c:1111 parse-options.h:241
+msgid "style"
+msgstr ""
+
+#: builtin/checkout.c:1027
+msgid "conflict style (merge or diff3)"
+msgstr ""
+
+#: builtin/checkout.c:1030
+msgid "second guess 'git checkout no-such-branch'"
+msgstr ""
+
+#: builtin/checkout.c:1054
+msgid "-b, -B and --orphan are mutually exclusive"
+msgstr ""
+
+#: builtin/checkout.c:1071
+msgid "--track needs a branch name"
msgstr ""
-#: builtin/checkout.c:1053
+#: builtin/checkout.c:1078
+msgid "Missing branch name; try -b"
+msgstr ""
+
+#: builtin/checkout.c:1113
msgid "invalid path specification"
msgstr ""
-#: builtin/checkout.c:1061
+#: builtin/checkout.c:1120
#, c-format
msgid ""
-"git checkout: updating paths is incompatible with switching branches.\n"
+"Cannot update paths and switch to branch '%s' at the same time.\n"
"Did you intend to checkout '%s' which can not be resolved as commit?"
msgstr ""
-#: builtin/checkout.c:1063
-msgid "git checkout: updating paths is incompatible with switching branches."
-msgstr ""
-
-#: builtin/checkout.c:1068
-msgid "git checkout: --detach does not take a path argument"
+#: builtin/checkout.c:1125
+#, c-format
+msgid "git checkout: --detach does not take a path argument '%s'"
msgstr ""
-#: builtin/checkout.c:1071
+#: builtin/checkout.c:1129
msgid ""
"git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
"checking out of the index."
msgstr ""
-#: builtin/checkout.c:1090
-msgid "Cannot switch branch to a non-commit."
+#: builtin/clean.c:19
+msgid "git clean [-d] [-f] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>..."
+msgstr ""
+
+#: builtin/clean.c:51
+msgid "do not print names of files removed"
+msgstr ""
+
+#: builtin/clean.c:53
+msgid "force"
+msgstr ""
+
+#: builtin/clean.c:55
+msgid "remove whole directories"
msgstr ""
-#: builtin/checkout.c:1093
-msgid "--ours/--theirs is incompatible with switching branches."
+#: builtin/clean.c:56 builtin/describe.c:413 builtin/grep.c:802
+#: builtin/ls-files.c:491 builtin/name-rev.c:231 builtin/show-ref.c:199
+msgid "pattern"
+msgstr ""
+
+#: builtin/clean.c:57
+msgid "add <pattern> to ignore rules"
+msgstr ""
+
+#: builtin/clean.c:58
+msgid "remove ignored files, too"
+msgstr ""
+
+#: builtin/clean.c:60
+msgid "remove only ignored files"
msgstr ""
#: builtin/clean.c:78
@@ -1903,14 +2880,102 @@ msgstr ""
msgid "Not removing %s\n"
msgstr ""
-#: builtin/clone.c:243
-#, c-format
-msgid "reference repository '%s' is not a local directory."
+#: builtin/clone.c:36
+msgid "git clone [options] [--] <repo> [<dir>]"
+msgstr ""
+
+#: builtin/clone.c:64 builtin/fetch.c:82 builtin/merge.c:212
+#: builtin/push.c:399
+msgid "force progress reporting"
+msgstr ""
+
+#: builtin/clone.c:66
+msgid "don't create a checkout"
+msgstr ""
+
+#: builtin/clone.c:67 builtin/clone.c:69 builtin/init-db.c:488
+msgid "create a bare repository"
+msgstr ""
+
+#: builtin/clone.c:72
+msgid "create a mirror repository (implies bare)"
+msgstr ""
+
+#: builtin/clone.c:74
+msgid "to clone from a local repository"
+msgstr ""
+
+#: builtin/clone.c:76
+msgid "don't use local hardlinks, always copy"
+msgstr ""
+
+#: builtin/clone.c:78
+msgid "setup as shared repository"
+msgstr ""
+
+#: builtin/clone.c:80 builtin/clone.c:82
+msgid "initialize submodules in the clone"
+msgstr ""
+
+#: builtin/clone.c:83 builtin/init-db.c:485
+msgid "template-directory"
+msgstr ""
+
+#: builtin/clone.c:84 builtin/init-db.c:486
+msgid "directory from which templates will be used"
+msgstr ""
+
+#: builtin/clone.c:86
+msgid "reference repository"
+msgstr ""
+
+#: builtin/clone.c:87 builtin/column.c:26 builtin/merge-file.c:44
+msgid "name"
+msgstr ""
+
+#: builtin/clone.c:88
+msgid "use <name> instead of 'origin' to track upstream"
+msgstr ""
+
+#: builtin/clone.c:90
+msgid "checkout <branch> instead of the remote's HEAD"
+msgstr ""
+
+#: builtin/clone.c:92
+msgid "path to git-upload-pack on the remote"
+msgstr ""
+
+#: builtin/clone.c:93 builtin/fetch.c:83 builtin/grep.c:747
+msgid "depth"
+msgstr ""
+
+#: builtin/clone.c:94
+msgid "create a shallow clone of that depth"
+msgstr ""
+
+#: builtin/clone.c:96
+msgid "clone only one branch, HEAD or --branch"
+msgstr ""
+
+#: builtin/clone.c:97 builtin/init-db.c:494
+msgid "gitdir"
+msgstr ""
+
+#: builtin/clone.c:98 builtin/init-db.c:495
+msgid "separate git dir from working tree"
msgstr ""
-#: builtin/clone.c:302
+#: builtin/clone.c:99
+msgid "key=value"
+msgstr ""
+
+#: builtin/clone.c:100
+msgid "set config inside the new repository"
+msgstr ""
+
+#: builtin/clone.c:243
#, c-format
-msgid "failed to open '%s'"
+msgid "reference repository '%s' is not a local directory."
msgstr ""
#: builtin/clone.c:306
@@ -1918,7 +2983,7 @@ msgstr ""
msgid "failed to create directory '%s'"
msgstr ""
-#: builtin/clone.c:308 builtin/diff.c:75
+#: builtin/clone.c:308 builtin/diff.c:77
#, c-format
msgid "failed to stat '%s'"
msgstr ""
@@ -1933,11 +2998,6 @@ msgstr ""
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'"
@@ -1953,85 +3013,121 @@ msgstr ""
msgid "done.\n"
msgstr ""
-#: builtin/clone.c:440
+#: builtin/clone.c:443
#, c-format
msgid "Could not find remote branch %s to clone."
msgstr ""
-#: builtin/clone.c:549
+#: builtin/clone.c:552
msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n"
msgstr ""
-#: builtin/clone.c:639
+#: builtin/clone.c:642
msgid "Too many arguments."
msgstr ""
-#: builtin/clone.c:643
+#: builtin/clone.c:646
msgid "You must specify a repository to clone."
msgstr ""
-#: builtin/clone.c:654
+#: builtin/clone.c:657
#, c-format
msgid "--bare and --origin %s options are incompatible."
msgstr ""
-#: builtin/clone.c:668
+#: builtin/clone.c:671
#, c-format
msgid "repository '%s' does not exist"
msgstr ""
-#: builtin/clone.c:673
+#: builtin/clone.c:676
msgid "--depth is ignored in local clones; use file:// instead."
msgstr ""
-#: builtin/clone.c:683
+#: builtin/clone.c:686
#, c-format
msgid "destination path '%s' already exists and is not an empty directory."
msgstr ""
-#: builtin/clone.c:693
+#: builtin/clone.c:696
#, c-format
msgid "working tree '%s' already exists."
msgstr ""
-#: builtin/clone.c:706 builtin/clone.c:720
+#: builtin/clone.c:709 builtin/clone.c:723
#, c-format
msgid "could not create leading directories of '%s'"
msgstr ""
-#: builtin/clone.c:709
+#: builtin/clone.c:712
#, c-format
msgid "could not create work tree dir '%s'."
msgstr ""
-#: builtin/clone.c:728
+#: builtin/clone.c:731
#, c-format
msgid "Cloning into bare repository '%s'...\n"
msgstr ""
-#: builtin/clone.c:730
+#: builtin/clone.c:733
#, c-format
msgid "Cloning into '%s'...\n"
msgstr ""
-#: builtin/clone.c:786
+#: builtin/clone.c:789
#, c-format
msgid "Don't know how to clone %s"
msgstr ""
-#: builtin/clone.c:835
+#: builtin/clone.c:838
#, c-format
msgid "Remote branch %s not found in upstream %s"
msgstr ""
-#: builtin/clone.c:842
+#: builtin/clone.c:845
msgid "You appear to have cloned an empty repository."
msgstr ""
+#: builtin/column.c:9
+msgid "git column [options]"
+msgstr ""
+
+#: builtin/column.c:26
+msgid "lookup config vars"
+msgstr ""
+
+#: builtin/column.c:27 builtin/column.c:28
+msgid "layout to use"
+msgstr ""
+
+#: builtin/column.c:29
+msgid "Maximum width"
+msgstr ""
+
+#: builtin/column.c:30
+msgid "Padding space on left border"
+msgstr ""
+
+#: builtin/column.c:31
+msgid "Padding space on right border"
+msgstr ""
+
+#: builtin/column.c:32
+msgid "Padding space between columns"
+msgstr ""
+
#: builtin/column.c:51
msgid "--command must be the first argument"
msgstr ""
+#: builtin/commit.c:33
+msgid "git commit [options] [--] <filepattern>..."
+msgstr ""
+
+#: builtin/commit.c:38
+msgid "git status [options] [--] <filepattern>..."
+msgstr ""
+
#: builtin/commit.c:43
msgid ""
"Your name and email address were configured automatically based\n"
@@ -2063,93 +3159,93 @@ msgid ""
"Otherwise, please use 'git reset'\n"
msgstr ""
-#: builtin/commit.c:253
+#: builtin/commit.c:256
msgid "failed to unpack HEAD tree object"
msgstr ""
-#: builtin/commit.c:295
+#: builtin/commit.c:298
msgid "unable to create temporary index"
msgstr ""
-#: builtin/commit.c:301
+#: builtin/commit.c:304
msgid "interactive add failed"
msgstr ""
-#: builtin/commit.c:334 builtin/commit.c:355 builtin/commit.c:405
+#: builtin/commit.c:337 builtin/commit.c:358 builtin/commit.c:408
msgid "unable to write new_index file"
msgstr ""
-#: builtin/commit.c:386
+#: builtin/commit.c:389
msgid "cannot do a partial commit during a merge."
msgstr ""
-#: builtin/commit.c:388
+#: builtin/commit.c:391
msgid "cannot do a partial commit during a cherry-pick."
msgstr ""
-#: builtin/commit.c:398
+#: builtin/commit.c:401
msgid "cannot read the index"
msgstr ""
-#: builtin/commit.c:418
+#: builtin/commit.c:421
msgid "unable to write temporary index file"
msgstr ""
-#: builtin/commit.c:493 builtin/commit.c:499
+#: builtin/commit.c:510 builtin/commit.c:516
#, c-format
msgid "invalid commit: %s"
msgstr ""
-#: builtin/commit.c:522
+#: builtin/commit.c:539
msgid "malformed --author parameter"
msgstr ""
-#: builtin/commit.c:582
+#: builtin/commit.c:600
#, c-format
msgid "Malformed ident string: '%s'"
msgstr ""
-#: builtin/commit.c:620 builtin/commit.c:653 builtin/commit.c:967
+#: builtin/commit.c:638 builtin/commit.c:671 builtin/commit.c:985
#, c-format
msgid "could not lookup commit %s"
msgstr ""
-#: builtin/commit.c:632 builtin/shortlog.c:296
+#: builtin/commit.c:650 builtin/shortlog.c:296
#, c-format
msgid "(reading log message from standard input)\n"
msgstr ""
-#: builtin/commit.c:634
+#: builtin/commit.c:652
msgid "could not read log from standard input"
msgstr ""
-#: builtin/commit.c:638
+#: builtin/commit.c:656
#, c-format
msgid "could not read log file '%s'"
msgstr ""
-#: builtin/commit.c:644
+#: builtin/commit.c:662
msgid "commit has empty message"
msgstr ""
-#: builtin/commit.c:660
+#: builtin/commit.c:678
msgid "could not read MERGE_MSG"
msgstr ""
-#: builtin/commit.c:664
+#: builtin/commit.c:682
msgid "could not read SQUASH_MSG"
msgstr ""
-#: builtin/commit.c:668
+#: builtin/commit.c:686
#, c-format
msgid "could not read '%s'"
msgstr ""
-#: builtin/commit.c:720
+#: builtin/commit.c:738
msgid "could not write commit template"
msgstr ""
-#: builtin/commit.c:731
+#: builtin/commit.c:749
#, c-format
msgid ""
"\n"
@@ -2159,7 +3255,7 @@ msgid ""
"and try again.\n"
msgstr ""
-#: builtin/commit.c:736
+#: builtin/commit.c:754
#, c-format
msgid ""
"\n"
@@ -2169,177 +3265,490 @@ msgid ""
"and try again.\n"
msgstr ""
-#: builtin/commit.c:748
+#: builtin/commit.c:766
msgid ""
"Please enter the commit message for your changes. Lines starting\n"
"with '#' will be ignored, and an empty message aborts the commit.\n"
msgstr ""
-#: builtin/commit.c:753
+#: builtin/commit.c:771
msgid ""
"Please enter the commit message for your changes. Lines starting\n"
"with '#' will be kept; you may remove them yourself if you want to.\n"
"An empty message aborts the commit.\n"
msgstr ""
-#: builtin/commit.c:766
+#: builtin/commit.c:784
#, c-format
msgid "%sAuthor: %s"
msgstr ""
-#: builtin/commit.c:773
+#: builtin/commit.c:791
#, c-format
msgid "%sCommitter: %s"
msgstr ""
-#: builtin/commit.c:793
+#: builtin/commit.c:811
msgid "Cannot read index"
msgstr ""
-#: builtin/commit.c:830
+#: builtin/commit.c:848
msgid "Error building trees"
msgstr ""
-#: builtin/commit.c:845 builtin/tag.c:361
+#: builtin/commit.c:863 builtin/tag.c:361
#, c-format
msgid "Please supply the message using either -m or -F option.\n"
msgstr ""
-#: builtin/commit.c:942
+#: builtin/commit.c:960
#, c-format
msgid "No existing author found with '%s'"
msgstr ""
-#: builtin/commit.c:957 builtin/commit.c:1157
+#: builtin/commit.c:975 builtin/commit.c:1175
#, c-format
msgid "Invalid untracked files mode '%s'"
msgstr ""
-#: builtin/commit.c:997
+#: builtin/commit.c:1015
msgid "Using both --reset-author and --author does not make sense"
msgstr ""
-#: builtin/commit.c:1008
+#: builtin/commit.c:1026
msgid "You have nothing to amend."
msgstr ""
-#: builtin/commit.c:1011
+#: builtin/commit.c:1029
msgid "You are in the middle of a merge -- cannot amend."
msgstr ""
-#: builtin/commit.c:1013
+#: builtin/commit.c:1031
msgid "You are in the middle of a cherry-pick -- cannot amend."
msgstr ""
-#: builtin/commit.c:1016
+#: builtin/commit.c:1034
msgid "Options --squash and --fixup cannot be used together"
msgstr ""
-#: builtin/commit.c:1026
+#: builtin/commit.c:1044
msgid "Only one of -c/-C/-F/--fixup can be used."
msgstr ""
-#: builtin/commit.c:1028
+#: builtin/commit.c:1046
msgid "Option -m cannot be combined with -c/-C/-F/--fixup."
msgstr ""
-#: builtin/commit.c:1036
+#: builtin/commit.c:1054
msgid "--reset-author can be used only with -C, -c or --amend."
msgstr ""
-#: builtin/commit.c:1053
+#: builtin/commit.c:1071
msgid "Only one of --include/--only/--all/--interactive/--patch can be used."
msgstr ""
-#: builtin/commit.c:1055
+#: builtin/commit.c:1073
msgid "No paths with --include/--only does not make sense."
msgstr ""
-#: builtin/commit.c:1057
+#: builtin/commit.c:1075
msgid "Clever... amending the last one with dirty index."
msgstr ""
-#: builtin/commit.c:1059
+#: builtin/commit.c:1077
msgid "Explicit paths specified without -i nor -o; assuming --only paths..."
msgstr ""
-#: builtin/commit.c:1069 builtin/tag.c:577
+#: builtin/commit.c:1087 builtin/tag.c:577
#, c-format
msgid "Invalid cleanup mode %s"
msgstr ""
-#: builtin/commit.c:1074
+#: builtin/commit.c:1092
msgid "Paths with -a does not make sense."
msgstr ""
-#: builtin/commit.c:1257
+#: builtin/commit.c:1189 builtin/commit.c:1417
+msgid "show status concisely"
+msgstr ""
+
+#: builtin/commit.c:1191 builtin/commit.c:1419
+msgid "show branch information"
+msgstr ""
+
+#: builtin/commit.c:1193 builtin/commit.c:1421 builtin/push.c:389
+msgid "machine-readable output"
+msgstr ""
+
+#: builtin/commit.c:1196 builtin/commit.c:1423
+msgid "terminate entries with NUL"
+msgstr ""
+
+#: builtin/commit.c:1198 builtin/commit.c:1426 builtin/fast-export.c:636
+#: builtin/fast-export.c:639 builtin/tag.c:461
+msgid "mode"
+msgstr ""
+
+#: builtin/commit.c:1199 builtin/commit.c:1426
+msgid "show untracked files, optional modes: all, normal, no. (Default: all)"
+msgstr ""
+
+#: builtin/commit.c:1202
+msgid "show ignored files"
+msgstr ""
+
+#: builtin/commit.c:1203 parse-options.h:151
+msgid "when"
+msgstr ""
+
+#: builtin/commit.c:1204
+msgid ""
+"ignore changes to submodules, optional when: all, dirty, untracked. "
+"(Default: all)"
+msgstr ""
+
+#: builtin/commit.c:1206
+msgid "list untracked files in columns"
+msgstr ""
+
+#: builtin/commit.c:1275
msgid "couldn't look up newly created commit"
msgstr ""
-#: builtin/commit.c:1259
+#: builtin/commit.c:1277
msgid "could not parse newly created commit"
msgstr ""
-#: builtin/commit.c:1300
+#: builtin/commit.c:1318
msgid "detached HEAD"
msgstr ""
-#: builtin/commit.c:1302
+#: builtin/commit.c:1320
msgid " (root-commit)"
msgstr ""
-#: builtin/commit.c:1446
+#: builtin/commit.c:1387
+msgid "suppress summary after successful commit"
+msgstr ""
+
+#: builtin/commit.c:1388
+msgid "show diff in commit message template"
+msgstr ""
+
+#: builtin/commit.c:1390
+msgid "Commit message options"
+msgstr ""
+
+#: builtin/commit.c:1391 builtin/tag.c:459
+msgid "read message from file"
+msgstr ""
+
+#: builtin/commit.c:1392
+msgid "author"
+msgstr ""
+
+#: builtin/commit.c:1392
+msgid "override author for commit"
+msgstr ""
+
+#: builtin/commit.c:1393 builtin/gc.c:178
+msgid "date"
+msgstr ""
+
+#: builtin/commit.c:1393
+msgid "override date for commit"
+msgstr ""
+
+#: builtin/commit.c:1394 builtin/merge.c:206 builtin/notes.c:534
+#: builtin/notes.c:691 builtin/tag.c:457
+msgid "message"
+msgstr ""
+
+#: builtin/commit.c:1394
+msgid "commit message"
+msgstr ""
+
+#: builtin/commit.c:1395
+msgid "reuse and edit message from specified commit"
+msgstr ""
+
+#: builtin/commit.c:1396
+msgid "reuse message from specified commit"
+msgstr ""
+
+#: builtin/commit.c:1397
+msgid "use autosquash formatted message to fixup specified commit"
+msgstr ""
+
+#: builtin/commit.c:1398
+msgid "use autosquash formatted message to squash specified commit"
+msgstr ""
+
+#: builtin/commit.c:1399
+msgid "the commit is authored by me now (used with -C/-c/--amend)"
+msgstr ""
+
+#: builtin/commit.c:1400 builtin/log.c:1068 builtin/revert.c:109
+msgid "add Signed-off-by:"
+msgstr ""
+
+#: builtin/commit.c:1401
+msgid "use specified template file"
+msgstr ""
+
+#: builtin/commit.c:1402
+msgid "force edit of commit"
+msgstr ""
+
+#: builtin/commit.c:1403
+msgid "default"
+msgstr ""
+
+#: builtin/commit.c:1403 builtin/tag.c:462
+msgid "how to strip spaces and #comments from message"
+msgstr ""
+
+#: builtin/commit.c:1404
+msgid "include status in commit message template"
+msgstr ""
+
+#: builtin/commit.c:1405 builtin/merge.c:213 builtin/tag.c:463
+msgid "key id"
+msgstr ""
+
+#: builtin/commit.c:1406 builtin/merge.c:214
+msgid "GPG sign commit"
+msgstr ""
+
+#. end commit message options
+#: builtin/commit.c:1409
+msgid "Commit contents options"
+msgstr ""
+
+#: builtin/commit.c:1410
+msgid "commit all changed files"
+msgstr ""
+
+#: builtin/commit.c:1411
+msgid "add specified files to index for commit"
+msgstr ""
+
+#: builtin/commit.c:1412
+msgid "interactively add files"
+msgstr ""
+
+#: builtin/commit.c:1413
+msgid "interactively add changes"
+msgstr ""
+
+#: builtin/commit.c:1414
+msgid "commit only specified files"
+msgstr ""
+
+#: builtin/commit.c:1415
+msgid "bypass pre-commit hook"
+msgstr ""
+
+#: builtin/commit.c:1416
+msgid "show what would be committed"
+msgstr ""
+
+#: builtin/commit.c:1424
+msgid "amend previous commit"
+msgstr ""
+
+#: builtin/commit.c:1425
+msgid "bypass post-rewrite hook"
+msgstr ""
+
+#: builtin/commit.c:1430
+msgid "ok to record an empty change"
+msgstr ""
+
+#: builtin/commit.c:1433
+msgid "ok to record a change with an empty message"
+msgstr ""
+
+#: builtin/commit.c:1464
msgid "could not parse HEAD commit"
msgstr ""
-#: builtin/commit.c:1484 builtin/merge.c:509
+#: builtin/commit.c:1502 builtin/merge.c:508
#, c-format
msgid "could not open '%s' for reading"
msgstr ""
-#: builtin/commit.c:1491
+#: builtin/commit.c:1509
#, c-format
msgid "Corrupt MERGE_HEAD file (%s)"
msgstr ""
-#: builtin/commit.c:1498
+#: builtin/commit.c:1516
msgid "could not read MERGE_MODE"
msgstr ""
-#: builtin/commit.c:1517
+#: builtin/commit.c:1535
#, c-format
msgid "could not read commit message: %s"
msgstr ""
-#: builtin/commit.c:1531
+#: builtin/commit.c:1549
#, c-format
msgid "Aborting commit; you did not edit the message.\n"
msgstr ""
-#: builtin/commit.c:1536
+#: builtin/commit.c:1554
#, c-format
msgid "Aborting commit due to empty commit message.\n"
msgstr ""
-#: builtin/commit.c:1551 builtin/merge.c:936 builtin/merge.c:961
+#: builtin/commit.c:1569 builtin/merge.c:935 builtin/merge.c:960
msgid "failed to write commit object"
msgstr ""
-#: builtin/commit.c:1572
+#: builtin/commit.c:1590
msgid "cannot lock HEAD ref"
msgstr ""
-#: builtin/commit.c:1576
+#: builtin/commit.c:1594
msgid "cannot update HEAD ref"
msgstr ""
-#: builtin/commit.c:1587
+#: builtin/commit.c:1605
msgid ""
"Repository has been updated, but unable to write\n"
"new_index file. Check that disk is not full or quota is\n"
"not exceeded, and then \"git reset HEAD\" to recover."
msgstr ""
+#: builtin/config.c:7
+msgid "git config [options]"
+msgstr ""
+
+#: builtin/config.c:52
+msgid "Config file location"
+msgstr ""
+
+#: builtin/config.c:53
+msgid "use global config file"
+msgstr ""
+
+#: builtin/config.c:54
+msgid "use system config file"
+msgstr ""
+
+#: builtin/config.c:55
+msgid "use repository config file"
+msgstr ""
+
+#: builtin/config.c:56
+msgid "use given config file"
+msgstr ""
+
+#: builtin/config.c:57
+msgid "Action"
+msgstr ""
+
+#: builtin/config.c:58
+msgid "get value: name [value-regex]"
+msgstr ""
+
+#: builtin/config.c:59
+msgid "get all values: key [value-regex]"
+msgstr ""
+
+#: builtin/config.c:60
+msgid "get values for regexp: name-regex [value-regex]"
+msgstr ""
+
+#: builtin/config.c:61
+msgid "replace all matching variables: name value [value_regex]"
+msgstr ""
+
+#: builtin/config.c:62
+msgid "add a new variable: name value"
+msgstr ""
+
+#: builtin/config.c:63
+msgid "remove a variable: name [value-regex]"
+msgstr ""
+
+#: builtin/config.c:64
+msgid "remove all matches: name [value-regex]"
+msgstr ""
+
+#: builtin/config.c:65
+msgid "rename section: old-name new-name"
+msgstr ""
+
+#: builtin/config.c:66
+msgid "remove a section: name"
+msgstr ""
+
+#: builtin/config.c:67
+msgid "list all"
+msgstr ""
+
+#: builtin/config.c:68
+msgid "open an editor"
+msgstr ""
+
+#: builtin/config.c:69 builtin/config.c:70
+msgid "slot"
+msgstr ""
+
+#: builtin/config.c:69
+msgid "find the color configured: [default]"
+msgstr ""
+
+#: builtin/config.c:70
+msgid "find the color setting: [stdout-is-tty]"
+msgstr ""
+
+#: builtin/config.c:71
+msgid "Type"
+msgstr ""
+
+#: builtin/config.c:72
+msgid "value is \"true\" or \"false\""
+msgstr ""
+
+#: builtin/config.c:73
+msgid "value is decimal number"
+msgstr ""
+
+#: builtin/config.c:74
+msgid "value is --bool or --int"
+msgstr ""
+
+#: builtin/config.c:75
+msgid "value is a path (file or directory name)"
+msgstr ""
+
+#: builtin/config.c:76
+msgid "Other"
+msgstr ""
+
+#: builtin/config.c:77
+msgid "terminate values with NUL byte"
+msgstr ""
+
+#: builtin/config.c:78
+msgid "respect include directives on lookup"
+msgstr ""
+
+#: builtin/count-objects.c:69
+msgid "git count-objects [-v]"
+msgstr ""
+
+#: builtin/describe.c:15
+msgid "git describe [options] <committish>*"
+msgstr ""
+
+#: builtin/describe.c:16
+msgid "git describe [options] --dirty"
+msgstr ""
+
#: builtin/describe.c:234
#, c-format
msgid "annotated tag %s not available"
@@ -2406,6 +3815,50 @@ msgid ""
"gave up search at %s\n"
msgstr ""
+#: builtin/describe.c:403
+msgid "find the tag that comes after the commit"
+msgstr ""
+
+#: builtin/describe.c:404
+msgid "debug search strategy on stderr"
+msgstr ""
+
+#: builtin/describe.c:405
+msgid "use any ref in .git/refs"
+msgstr ""
+
+#: builtin/describe.c:406
+msgid "use any tag in .git/refs/tags"
+msgstr ""
+
+#: builtin/describe.c:407
+msgid "always use long format"
+msgstr ""
+
+#: builtin/describe.c:410
+msgid "only output exact matches"
+msgstr ""
+
+#: builtin/describe.c:412
+msgid "consider <n> most recent tags (default: 10)"
+msgstr ""
+
+#: builtin/describe.c:414
+msgid "only consider tags matching <pattern>"
+msgstr ""
+
+#: builtin/describe.c:416 builtin/name-rev.c:238
+msgid "show abbreviated commit object as fallback"
+msgstr ""
+
+#: builtin/describe.c:417
+msgid "mark"
+msgstr ""
+
+#: builtin/describe.c:418
+msgid "append <mark> on dirty working tree (default: \"-dirty\")"
+msgstr ""
+
#: builtin/describe.c:436
msgid "--long is incompatible with --abbrev=0"
msgstr ""
@@ -2418,191 +3871,429 @@ msgstr ""
msgid "--dirty is incompatible with committishes"
msgstr ""
-#: builtin/diff.c:77
+#: builtin/diff.c:79
#, c-format
msgid "'%s': not a regular file or symlink"
msgstr ""
-#: builtin/diff.c:220
+#: builtin/diff.c:224
#, c-format
msgid "invalid option: %s"
msgstr ""
-#: builtin/diff.c:297
+#: builtin/diff.c:301
msgid "Not a git repository"
msgstr ""
-#: builtin/diff.c:347
+#: builtin/diff.c:344
#, c-format
msgid "invalid object '%s' given."
msgstr ""
-#: builtin/diff.c:352
+#: builtin/diff.c:349
#, c-format
msgid "more than %d trees given: '%s'"
msgstr ""
-#: builtin/diff.c:362
+#: builtin/diff.c:359
#, c-format
msgid "more than two blobs given: '%s'"
msgstr ""
-#: builtin/diff.c:370
+#: builtin/diff.c:367
#, c-format
msgid "unhandled object '%s' given."
msgstr ""
-#: builtin/fetch.c:200
+#: builtin/fast-export.c:22
+msgid "git fast-export [rev-list-opts]"
+msgstr ""
+
+#: builtin/fast-export.c:635
+msgid "show progress after <n> objects"
+msgstr ""
+
+#: builtin/fast-export.c:637
+msgid "select handling of signed tags"
+msgstr ""
+
+#: builtin/fast-export.c:640
+msgid "select handling of tags that tag filtered objects"
+msgstr ""
+
+#: builtin/fast-export.c:643
+msgid "Dump marks to this file"
+msgstr ""
+
+#: builtin/fast-export.c:645
+msgid "Import marks from this file"
+msgstr ""
+
+#: builtin/fast-export.c:647
+msgid "Fake a tagger when tags lack one"
+msgstr ""
+
+#: builtin/fast-export.c:649
+msgid "Output full tree for each commit"
+msgstr ""
+
+#: builtin/fast-export.c:651
+msgid "Use the done feature to terminate the stream"
+msgstr ""
+
+#: builtin/fast-export.c:652
+msgid "Skip output of blob data"
+msgstr ""
+
+#: builtin/fetch.c:20
+msgid "git fetch [<options>] [<repository> [<refspec>...]]"
+msgstr ""
+
+#: builtin/fetch.c:21
+msgid "git fetch [<options>] <group>"
+msgstr ""
+
+#: builtin/fetch.c:22
+msgid "git fetch --multiple [<options>] [(<repository> | <group>)...]"
+msgstr ""
+
+#: builtin/fetch.c:23
+msgid "git fetch --all [<options>]"
+msgstr ""
+
+#: builtin/fetch.c:60
+msgid "fetch from all remotes"
+msgstr ""
+
+#: builtin/fetch.c:62
+msgid "append to .git/FETCH_HEAD instead of overwriting"
+msgstr ""
+
+#: builtin/fetch.c:64
+msgid "path to upload pack on remote end"
+msgstr ""
+
+#: builtin/fetch.c:65
+msgid "force overwrite of local branch"
+msgstr ""
+
+#: builtin/fetch.c:67
+msgid "fetch from multiple remotes"
+msgstr ""
+
+#: builtin/fetch.c:69
+msgid "fetch all tags and associated objects"
+msgstr ""
+
+#: builtin/fetch.c:71
+msgid "do not fetch all tags (--no-tags)"
+msgstr ""
+
+#: builtin/fetch.c:73
+msgid "prune remote-tracking branches no longer on remote"
+msgstr ""
+
+#: builtin/fetch.c:74
+msgid "on-demand"
+msgstr ""
+
+#: builtin/fetch.c:75
+msgid "control recursive fetching of submodules"
+msgstr ""
+
+#: builtin/fetch.c:79
+msgid "keep downloaded pack"
+msgstr ""
+
+#: builtin/fetch.c:81
+msgid "allow updating of HEAD ref"
+msgstr ""
+
+#: builtin/fetch.c:84
+msgid "deepen history of shallow clone"
+msgstr ""
+
+#: builtin/fetch.c:85 builtin/log.c:1083
+msgid "dir"
+msgstr ""
+
+#: builtin/fetch.c:86
+msgid "prepend this to submodule path output"
+msgstr ""
+
+#: builtin/fetch.c:89
+msgid "default mode for recursion"
+msgstr ""
+
+#: builtin/fetch.c:201
msgid "Couldn't find remote ref HEAD"
msgstr ""
-#: builtin/fetch.c:253
+#: builtin/fetch.c:254
#, c-format
msgid "object %s not found"
msgstr ""
-#: builtin/fetch.c:259
+#: builtin/fetch.c:260
msgid "[up to date]"
msgstr ""
-#: builtin/fetch.c:273
+#: builtin/fetch.c:274
#, c-format
msgid "! %-*s %-*s -> %s (can't fetch in current branch)"
msgstr ""
-#: builtin/fetch.c:274 builtin/fetch.c:360
+#: builtin/fetch.c:275 builtin/fetch.c:361
msgid "[rejected]"
msgstr ""
-#: builtin/fetch.c:285
+#: builtin/fetch.c:286
msgid "[tag update]"
msgstr ""
-#: builtin/fetch.c:287 builtin/fetch.c:322 builtin/fetch.c:340
+#: builtin/fetch.c:288 builtin/fetch.c:323 builtin/fetch.c:341
msgid " (unable to update local ref)"
msgstr ""
-#: builtin/fetch.c:305
+#: builtin/fetch.c:306
msgid "[new tag]"
msgstr ""
-#: builtin/fetch.c:308
+#: builtin/fetch.c:309
msgid "[new branch]"
msgstr ""
-#: builtin/fetch.c:311
+#: builtin/fetch.c:312
msgid "[new ref]"
msgstr ""
-#: builtin/fetch.c:356
+#: builtin/fetch.c:357
msgid "unable to update local ref"
msgstr ""
-#: builtin/fetch.c:356
+#: builtin/fetch.c:357
msgid "forced update"
msgstr ""
-#: builtin/fetch.c:362
+#: builtin/fetch.c:363
msgid "(non-fast-forward)"
msgstr ""
-#: builtin/fetch.c:393 builtin/fetch.c:685
+#: builtin/fetch.c:394 builtin/fetch.c:686
#, c-format
msgid "cannot open %s: %s\n"
msgstr ""
-#: builtin/fetch.c:402
+#: builtin/fetch.c:403
#, c-format
msgid "%s did not send all necessary objects\n"
msgstr ""
-#: builtin/fetch.c:488
+#: builtin/fetch.c:489
#, c-format
msgid "From %.*s\n"
msgstr ""
-#: builtin/fetch.c:499
+#: builtin/fetch.c:500
#, 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
+#: builtin/fetch.c:550
#, c-format
msgid " (%s will become dangling)"
msgstr ""
-#: builtin/fetch.c:550
+#: builtin/fetch.c:551
#, c-format
msgid " (%s has become dangling)"
msgstr ""
-#: builtin/fetch.c:557
+#: builtin/fetch.c:558
msgid "[deleted]"
msgstr ""
-#: builtin/fetch.c:558 builtin/remote.c:1055
+#: builtin/fetch.c:559 builtin/remote.c:1055
msgid "(none)"
msgstr ""
-#: builtin/fetch.c:675
+#: builtin/fetch.c:676
#, c-format
msgid "Refusing to fetch into current branch %s of non-bare repository"
msgstr ""
-#: builtin/fetch.c:709
+#: builtin/fetch.c:710
#, c-format
msgid "Don't know how to fetch from %s"
msgstr ""
-#: builtin/fetch.c:786
+#: builtin/fetch.c:787
#, c-format
msgid "Option \"%s\" value \"%s\" is not valid for %s"
msgstr ""
-#: builtin/fetch.c:789
+#: builtin/fetch.c:790
#, c-format
msgid "Option \"%s\" is ignored for %s\n"
msgstr ""
-#: builtin/fetch.c:888
+#: builtin/fetch.c:892
#, c-format
msgid "Fetching %s\n"
msgstr ""
-#: builtin/fetch.c:890 builtin/remote.c:100
+#: builtin/fetch.c:894 builtin/remote.c:100
#, c-format
msgid "Could not fetch %s"
msgstr ""
-#: builtin/fetch.c:907
+#: builtin/fetch.c:913
msgid ""
"No remote repository specified. Please, specify either a URL or a\n"
"remote name from which new revisions should be fetched."
msgstr ""
-#: builtin/fetch.c:927
+#: builtin/fetch.c:933
msgid "You need to specify a tag name."
msgstr ""
-#: builtin/fetch.c:979
+#: builtin/fetch.c:985
msgid "fetch --all does not take a repository argument"
msgstr ""
-#: builtin/fetch.c:981
+#: builtin/fetch.c:987
msgid "fetch --all does not make sense with refspecs"
msgstr ""
-#: builtin/fetch.c:992
+#: builtin/fetch.c:998
#, c-format
msgid "No such remote or remote group: %s"
msgstr ""
-#: builtin/fetch.c:1000
+#: builtin/fetch.c:1006
msgid "Fetching a group and specifying refspecs does not make sense"
msgstr ""
+#: builtin/fmt-merge-msg.c:13
+msgid "git fmt-merge-msg [-m <message>] [--log[=<n>]|--no-log] [--file <file>]"
+msgstr ""
+
+#: builtin/fmt-merge-msg.c:653 builtin/fmt-merge-msg.c:656 builtin/grep.c:786
+#: builtin/merge.c:188 builtin/show-branch.c:656 builtin/show-ref.c:192
+#: builtin/tag.c:448 parse-options.h:133 parse-options.h:235
+msgid "n"
+msgstr ""
+
+#: builtin/fmt-merge-msg.c:654
+msgid "populate log with at most <n> entries from shortlog"
+msgstr ""
+
+#: builtin/fmt-merge-msg.c:657
+msgid "alias for --log (deprecated)"
+msgstr ""
+
+#: builtin/fmt-merge-msg.c:660
+msgid "text"
+msgstr ""
+
+#: builtin/fmt-merge-msg.c:661
+msgid "use <text> as start of message"
+msgstr ""
+
+#: builtin/fmt-merge-msg.c:662
+msgid "file to read from"
+msgstr ""
+
+#: builtin/for-each-ref.c:979
+msgid "git for-each-ref [options] [<pattern>]"
+msgstr ""
+
+#: builtin/for-each-ref.c:994
+msgid "quote placeholders suitably for shells"
+msgstr ""
+
+#: builtin/for-each-ref.c:996
+msgid "quote placeholders suitably for perl"
+msgstr ""
+
+#: builtin/for-each-ref.c:998
+msgid "quote placeholders suitably for python"
+msgstr ""
+
+#: builtin/for-each-ref.c:1000
+msgid "quote placeholders suitably for tcl"
+msgstr ""
+
+#: builtin/for-each-ref.c:1003
+msgid "show only <n> matched refs"
+msgstr ""
+
+#: builtin/for-each-ref.c:1004
+msgid "format"
+msgstr ""
+
+#: builtin/for-each-ref.c:1004
+msgid "format to use for the output"
+msgstr ""
+
+#: builtin/for-each-ref.c:1005
+msgid "key"
+msgstr ""
+
+#: builtin/for-each-ref.c:1006
+msgid "field name to sort on"
+msgstr ""
+
+#: builtin/fsck.c:608
+msgid "git fsck [options] [<object>...]"
+msgstr ""
+
+#: builtin/fsck.c:614
+msgid "show unreachable objects"
+msgstr ""
+
+#: builtin/fsck.c:615
+msgid "show dangling objects"
+msgstr ""
+
+#: builtin/fsck.c:616
+msgid "report tags"
+msgstr ""
+
+#: builtin/fsck.c:617
+msgid "report root nodes"
+msgstr ""
+
+#: builtin/fsck.c:618
+msgid "make index objects head nodes"
+msgstr ""
+
+#: builtin/fsck.c:619
+msgid "make reflogs head nodes (default)"
+msgstr ""
+
+#: builtin/fsck.c:620
+msgid "also consider packs and alternate objects"
+msgstr ""
+
+#: builtin/fsck.c:621
+msgid "enable more strict checking"
+msgstr ""
+
+#: builtin/fsck.c:623
+msgid "write dangling objects in .git/lost-found"
+msgstr ""
+
+#: builtin/fsck.c:624 builtin/prune.c:134
+msgid "show progress"
+msgstr ""
+
+#: builtin/gc.c:22
+msgid "git gc [options]"
+msgstr ""
+
#: builtin/gc.c:63
#, c-format
msgid "Invalid %s: '%s'"
@@ -2613,6 +4304,18 @@ msgstr ""
msgid "insanely long object directory %.*s"
msgstr ""
+#: builtin/gc.c:179
+msgid "prune unreferenced objects"
+msgstr ""
+
+#: builtin/gc.c:181
+msgid "be more thorough (increased runtime)"
+msgstr ""
+
+#: builtin/gc.c:182
+msgid "enable auto-gc mode"
+msgstr ""
+
#: builtin/gc.c:221
#, c-format
msgid "Auto packing the repository for optimum performance.\n"
@@ -2630,362 +4333,625 @@ msgid ""
"There are too many unreachable loose objects; run 'git prune' to remove them."
msgstr ""
+#: builtin/grep.c:22
+msgid "git grep [options] [-e] <pattern> [<rev>...] [[--] <path>...]"
+msgstr ""
+
#: builtin/grep.c:216
#, c-format
msgid "grep: failed to create thread: %s"
msgstr ""
-#: builtin/grep.c:402
+#: builtin/grep.c:454
#, c-format
msgid "Failed to chdir: %s"
msgstr ""
-#: builtin/grep.c:478 builtin/grep.c:512
+#: builtin/grep.c:530 builtin/grep.c:564
#, c-format
msgid "unable to read tree (%s)"
msgstr ""
-#: builtin/grep.c:526
+#: builtin/grep.c:578
#, c-format
msgid "unable to grep from object of type %s"
msgstr ""
-#: builtin/grep.c:584
+#: builtin/grep.c:636
#, c-format
msgid "switch `%c' expects a numerical value"
msgstr ""
-#: builtin/grep.c:601
+#: builtin/grep.c:653
#, c-format
msgid "cannot open '%s'"
msgstr ""
-#: builtin/grep.c:885
+#: builtin/grep.c:728
+msgid "search in index instead of in the work tree"
+msgstr ""
+
+#: builtin/grep.c:730
+msgid "find in contents not managed by git"
+msgstr ""
+
+#: builtin/grep.c:732
+msgid "search in both tracked and untracked files"
+msgstr ""
+
+#: builtin/grep.c:734
+msgid "search also in ignored files"
+msgstr ""
+
+#: builtin/grep.c:737
+msgid "show non-matching lines"
+msgstr ""
+
+#: builtin/grep.c:739
+msgid "case insensitive matching"
+msgstr ""
+
+#: builtin/grep.c:741
+msgid "match patterns only at word boundaries"
+msgstr ""
+
+#: builtin/grep.c:743
+msgid "process binary files as text"
+msgstr ""
+
+#: builtin/grep.c:745
+msgid "don't match patterns in binary files"
+msgstr ""
+
+#: builtin/grep.c:748
+msgid "descend at most <depth> levels"
+msgstr ""
+
+#: builtin/grep.c:752
+msgid "use extended POSIX regular expressions"
+msgstr ""
+
+#: builtin/grep.c:755
+msgid "use basic POSIX regular expressions (default)"
+msgstr ""
+
+#: builtin/grep.c:758
+msgid "interpret patterns as fixed strings"
+msgstr ""
+
+#: builtin/grep.c:761
+msgid "use Perl-compatible regular expressions"
+msgstr ""
+
+#: builtin/grep.c:764
+msgid "show line numbers"
+msgstr ""
+
+#: builtin/grep.c:765
+msgid "don't show filenames"
+msgstr ""
+
+#: builtin/grep.c:766
+msgid "show filenames"
+msgstr ""
+
+#: builtin/grep.c:768
+msgid "show filenames relative to top directory"
+msgstr ""
+
+#: builtin/grep.c:770
+msgid "show only filenames instead of matching lines"
+msgstr ""
+
+#: builtin/grep.c:772
+msgid "synonym for --files-with-matches"
+msgstr ""
+
+#: builtin/grep.c:775
+msgid "show only the names of files without match"
+msgstr ""
+
+#: builtin/grep.c:777
+msgid "print NUL after filenames"
+msgstr ""
+
+#: builtin/grep.c:779
+msgid "show the number of matches instead of matching lines"
+msgstr ""
+
+#: builtin/grep.c:780
+msgid "highlight matches"
+msgstr ""
+
+#: builtin/grep.c:782
+msgid "print empty line between matches from different files"
+msgstr ""
+
+#: builtin/grep.c:784
+msgid "show filename only once above matches from same file"
+msgstr ""
+
+#: builtin/grep.c:787
+msgid "show <n> context lines before and after matches"
+msgstr ""
+
+#: builtin/grep.c:790
+msgid "show <n> context lines before matches"
+msgstr ""
+
+#: builtin/grep.c:792
+msgid "show <n> context lines after matches"
+msgstr ""
+
+#: builtin/grep.c:793
+msgid "shortcut for -C NUM"
+msgstr ""
+
+#: builtin/grep.c:796
+msgid "show a line with the function name before matches"
+msgstr ""
+
+#: builtin/grep.c:798
+msgid "show the surrounding function"
+msgstr ""
+
+#: builtin/grep.c:801
+msgid "read patterns from file"
+msgstr ""
+
+#: builtin/grep.c:803
+msgid "match <pattern>"
+msgstr ""
+
+#: builtin/grep.c:805
+msgid "combine patterns specified with -e"
+msgstr ""
+
+#: builtin/grep.c:817
+msgid "indicate hit with exit status without output"
+msgstr ""
+
+#: builtin/grep.c:819
+msgid "show only matches from files that match all patterns"
+msgstr ""
+
+#: builtin/grep.c:822
+msgid "pager"
+msgstr ""
+
+#: builtin/grep.c:822
+msgid "show matching files in the pager"
+msgstr ""
+
+#: builtin/grep.c:825
+msgid "allow calling of grep(1) (ignored by this build)"
+msgstr ""
+
+#: builtin/grep.c:826 builtin/show-ref.c:201
+msgid "show usage"
+msgstr ""
+
+#: builtin/grep.c:917
msgid "no pattern given."
msgstr ""
-#: builtin/grep.c:899
+#: builtin/grep.c:931
#, c-format
msgid "bad object %s"
msgstr ""
-#: builtin/grep.c:940
+#: builtin/grep.c:972
msgid "--open-files-in-pager only works on the worktree"
msgstr ""
-#: builtin/grep.c:963
+#: builtin/grep.c:995
msgid "--cached or --untracked cannot be used with --no-index."
msgstr ""
-#: builtin/grep.c:968
+#: builtin/grep.c:1000
msgid "--no-index or --untracked cannot be used with revs."
msgstr ""
-#: builtin/grep.c:971
+#: builtin/grep.c:1003
msgid "--[no-]exclude-standard cannot be used for tracked contents."
msgstr ""
-#: builtin/grep.c:979
+#: builtin/grep.c:1011
msgid "both --cached and trees are given."
msgstr ""
-#: builtin/help.c:59
+#: builtin/hash-object.c:60
+msgid ""
+"git hash-object [-t <type>] [-w] [--path=<file>|--no-filters] [--stdin] [--] "
+"<file>..."
+msgstr ""
+
+#: builtin/hash-object.c:61
+msgid "git hash-object --stdin-paths < <list-of-paths>"
+msgstr ""
+
+#: builtin/hash-object.c:72
+msgid "type"
+msgstr ""
+
+#: builtin/hash-object.c:72
+msgid "object type"
+msgstr ""
+
+#: builtin/hash-object.c:73
+msgid "write the object into the object database"
+msgstr ""
+
+#: builtin/hash-object.c:74
+msgid "read the object from stdin"
+msgstr ""
+
+#: builtin/hash-object.c:76
+msgid "store file as is without filters"
+msgstr ""
+
+#: builtin/hash-object.c:77
+msgid "process file as it were from this path"
+msgstr ""
+
+#: builtin/help.c:43
+msgid "print all available commands"
+msgstr ""
+
+#: builtin/help.c:44
+msgid "show man page"
+msgstr ""
+
+#: builtin/help.c:45
+msgid "show manual in web browser"
+msgstr ""
+
+#: builtin/help.c:47
+msgid "show info page"
+msgstr ""
+
+#: builtin/help.c:53
+msgid "git help [--all] [--man|--web|--info] [command]"
+msgstr ""
+
+#: builtin/help.c:65
#, c-format
msgid "unrecognized help format '%s'"
msgstr ""
-#: builtin/help.c:87
+#: builtin/help.c:93
msgid "Failed to start emacsclient."
msgstr ""
-#: builtin/help.c:100
+#: builtin/help.c:106
msgid "Failed to parse emacsclient version."
msgstr ""
-#: builtin/help.c:108
+#: builtin/help.c:114
#, c-format
msgid "emacsclient version '%d' too old (< 22)."
msgstr ""
-#: builtin/help.c:126 builtin/help.c:154 builtin/help.c:163 builtin/help.c:171
+#: builtin/help.c:132 builtin/help.c:160 builtin/help.c:169 builtin/help.c:177
#, c-format
msgid "failed to exec '%s': %s"
msgstr ""
-#: builtin/help.c:211
+#: builtin/help.c:217
#, c-format
msgid ""
"'%s': path for unsupported man viewer.\n"
"Please consider using 'man.<tool>.cmd' instead."
msgstr ""
-#: builtin/help.c:223
+#: builtin/help.c:229
#, c-format
msgid ""
"'%s': cmd for supported man viewer.\n"
"Please consider using 'man.<tool>.path' instead."
msgstr ""
-#: builtin/help.c:287
+#: builtin/help.c:299
msgid "The most commonly used git commands are:"
msgstr ""
-#: builtin/help.c:355
+#: builtin/help.c:367
#, c-format
msgid "'%s': unknown man viewer."
msgstr ""
-#: builtin/help.c:372
+#: builtin/help.c:384
msgid "no man viewer handled the request"
msgstr ""
-#: builtin/help.c:380
+#: builtin/help.c:392
msgid "no info viewer handled the request"
msgstr ""
-#: builtin/help.c:391
-#, c-format
-msgid "'%s': not a documentation directory."
-msgstr ""
-
-#: builtin/help.c:432 builtin/help.c:439
+#: builtin/help.c:447 builtin/help.c:454
#, c-format
msgid "usage: %s%s"
msgstr ""
-#: builtin/help.c:453
+#: builtin/help.c:470
#, c-format
msgid "`git %s' is aliased to `%s'"
msgstr ""
-#: builtin/index-pack.c:169
+#: builtin/index-pack.c:170
#, c-format
msgid "object type mismatch at %s"
msgstr ""
-#: builtin/index-pack.c:189
+#: builtin/index-pack.c:190
msgid "object of unexpected type"
msgstr ""
-#: builtin/index-pack.c:226
+#: builtin/index-pack.c:227
#, c-format
msgid "cannot fill %d byte"
msgid_plural "cannot fill %d bytes"
msgstr[0] ""
msgstr[1] ""
-#: builtin/index-pack.c:236
+#: builtin/index-pack.c:237
msgid "early EOF"
msgstr ""
-#: builtin/index-pack.c:237
+#: builtin/index-pack.c:238
msgid "read error on input"
msgstr ""
-#: builtin/index-pack.c:249
+#: builtin/index-pack.c:250
msgid "used more bytes than were available"
msgstr ""
-#: builtin/index-pack.c:256
+#: builtin/index-pack.c:257
msgid "pack too large for current definition of off_t"
msgstr ""
-#: builtin/index-pack.c:272
+#: builtin/index-pack.c:273
#, c-format
msgid "unable to create '%s'"
msgstr ""
-#: builtin/index-pack.c:277
+#: builtin/index-pack.c:278
#, c-format
msgid "cannot open packfile '%s'"
msgstr ""
-#: builtin/index-pack.c:291
+#: builtin/index-pack.c:292
msgid "pack signature mismatch"
msgstr ""
-#: builtin/index-pack.c:311
+#: builtin/index-pack.c:294
+#, c-format
+msgid "pack version %<PRIu32> unsupported"
+msgstr ""
+
+#: builtin/index-pack.c:312
#, c-format
msgid "pack has bad object at offset %lu: %s"
msgstr ""
-#: builtin/index-pack.c:405
+#: builtin/index-pack.c:434
#, c-format
msgid "inflate returned %d"
msgstr ""
-#: builtin/index-pack.c:450
+#: builtin/index-pack.c:483
msgid "offset value overflow for delta base object"
msgstr ""
-#: builtin/index-pack.c:458
+#: builtin/index-pack.c:491
msgid "delta base offset is out of bound"
msgstr ""
-#: builtin/index-pack.c:466
+#: builtin/index-pack.c:499
#, c-format
msgid "unknown object type %d"
msgstr ""
-#: builtin/index-pack.c:495
+#: builtin/index-pack.c:530
msgid "cannot pread pack file"
msgstr ""
-#: builtin/index-pack.c:497
+#: builtin/index-pack.c:532
#, c-format
msgid "premature end of pack file, %lu byte missing"
msgid_plural "premature end of pack file, %lu bytes missing"
msgstr[0] ""
msgstr[1] ""
-#: builtin/index-pack.c:510
+#: builtin/index-pack.c:558
msgid "serious inflate inconsistency"
msgstr ""
-#: builtin/index-pack.c:583
+#: builtin/index-pack.c:649 builtin/index-pack.c:655 builtin/index-pack.c:678
+#: builtin/index-pack.c:712 builtin/index-pack.c:721
#, c-format
-msgid "cannot read existing object %s"
+msgid "SHA1 COLLISION FOUND WITH %s !"
msgstr ""
-#: builtin/index-pack.c:586
+#: builtin/index-pack.c:652 builtin/pack-objects.c:170
+#: builtin/pack-objects.c:262
#, c-format
-msgid "SHA1 COLLISION FOUND WITH %s !"
+msgid "unable to read %s"
msgstr ""
-#: builtin/index-pack.c:598
+#: builtin/index-pack.c:718
+#, c-format
+msgid "cannot read existing object %s"
+msgstr ""
+
+#: builtin/index-pack.c:732
#, c-format
msgid "invalid blob object %s"
msgstr ""
-#: builtin/index-pack.c:610
+#: builtin/index-pack.c:747
#, c-format
msgid "invalid %s"
msgstr ""
-#: builtin/index-pack.c:612
+#: builtin/index-pack.c:749
msgid "Error in object"
msgstr ""
-#: builtin/index-pack.c:614
+#: builtin/index-pack.c:751
#, c-format
msgid "Not all child objects of %s are reachable"
msgstr ""
-#: builtin/index-pack.c:687 builtin/index-pack.c:713
+#: builtin/index-pack.c:821 builtin/index-pack.c:847
msgid "failed to apply delta"
msgstr ""
-#: builtin/index-pack.c:850
+#: builtin/index-pack.c:986
msgid "Receiving objects"
msgstr ""
-#: builtin/index-pack.c:850
+#: builtin/index-pack.c:986
msgid "Indexing objects"
msgstr ""
-#: builtin/index-pack.c:872
+#: builtin/index-pack.c:1012
msgid "pack is corrupted (SHA1 mismatch)"
msgstr ""
-#: builtin/index-pack.c:877
+#: builtin/index-pack.c:1017
msgid "cannot fstat packfile"
msgstr ""
-#: builtin/index-pack.c:880
+#: builtin/index-pack.c:1020
msgid "pack has junk at the end"
msgstr ""
-#: builtin/index-pack.c:903
+#: builtin/index-pack.c:1031
+msgid "confusion beyond insanity in parse_pack_objects()"
+msgstr ""
+
+#: builtin/index-pack.c:1054
msgid "Resolving deltas"
msgstr ""
-#: builtin/index-pack.c:954
+#: builtin/index-pack.c:1064
+#, c-format
+msgid "unable to create thread: %s"
+msgstr ""
+
+#: builtin/index-pack.c:1106
msgid "confusion beyond insanity"
msgstr ""
-#: builtin/index-pack.c:973
+#: builtin/index-pack.c:1112
+#, c-format
+msgid "completed with %d local objects"
+msgstr ""
+
+#: builtin/index-pack.c:1121
+#, c-format
+msgid "Unexpected tail checksum for %s (disk corruption?)"
+msgstr ""
+
+#: builtin/index-pack.c:1125
#, c-format
msgid "pack has %d unresolved delta"
msgid_plural "pack has %d unresolved deltas"
msgstr[0] ""
msgstr[1] ""
-#: builtin/index-pack.c:998
+#: builtin/index-pack.c:1150
#, c-format
msgid "unable to deflate appended object (%d)"
msgstr ""
-#: builtin/index-pack.c:1077
+#: builtin/index-pack.c:1229
#, c-format
msgid "local object %s is corrupt"
msgstr ""
-#: builtin/index-pack.c:1101
+#: builtin/index-pack.c:1253
msgid "error while closing pack file"
msgstr ""
-#: builtin/index-pack.c:1114
+#: builtin/index-pack.c:1266
#, c-format
msgid "cannot write keep file '%s'"
msgstr ""
-#: builtin/index-pack.c:1122
+#: builtin/index-pack.c:1274
#, c-format
msgid "cannot close written keep file '%s'"
msgstr ""
-#: builtin/index-pack.c:1135
+#: builtin/index-pack.c:1287
msgid "cannot store pack file"
msgstr ""
-#: builtin/index-pack.c:1146
+#: builtin/index-pack.c:1298
msgid "cannot store index file"
msgstr ""
-#: builtin/index-pack.c:1247
+#: builtin/index-pack.c:1331
+#, c-format
+msgid "bad pack.indexversion=%<PRIu32>"
+msgstr ""
+
+#: builtin/index-pack.c:1337
+#, c-format
+msgid "invalid number of threads specified (%d)"
+msgstr ""
+
+#: builtin/index-pack.c:1341 builtin/index-pack.c:1514
+#, c-format
+msgid "no threads support, ignoring %s"
+msgstr ""
+
+#: builtin/index-pack.c:1399
#, c-format
msgid "Cannot open existing pack file '%s'"
msgstr ""
-#: builtin/index-pack.c:1249
+#: builtin/index-pack.c:1401
#, c-format
msgid "Cannot open existing pack idx file for '%s'"
msgstr ""
-#: builtin/index-pack.c:1296
+#: builtin/index-pack.c:1448
#, c-format
msgid "non delta: %d object"
msgid_plural "non delta: %d objects"
msgstr[0] ""
msgstr[1] ""
-#: builtin/index-pack.c:1303
+#: builtin/index-pack.c:1455
#, c-format
msgid "chain length = %d: %lu object"
msgid_plural "chain length = %d: %lu objects"
msgstr[0] ""
msgstr[1] ""
-#: builtin/index-pack.c:1330
+#: builtin/index-pack.c:1482
msgid "Cannot come back to cwd"
msgstr ""
-#: builtin/index-pack.c:1374 builtin/index-pack.c:1377
-#: builtin/index-pack.c:1389 builtin/index-pack.c:1393
+#: builtin/index-pack.c:1526 builtin/index-pack.c:1529
+#: builtin/index-pack.c:1541 builtin/index-pack.c:1545
#, c-format
msgid "bad %s"
msgstr ""
-#: builtin/index-pack.c:1407
+#: builtin/index-pack.c:1559
msgid "--fix-thin cannot be used without --stdin"
msgstr ""
-#: builtin/index-pack.c:1411 builtin/index-pack.c:1421
+#: builtin/index-pack.c:1563 builtin/index-pack.c:1573
#, c-format
msgid "packfile name '%s' does not end with '.pack'"
msgstr ""
-#: builtin/index-pack.c:1430
+#: builtin/index-pack.c:1582
msgid "--verify with no packfile name given"
msgstr ""
@@ -3059,22 +5025,22 @@ msgstr ""
msgid "insane git directory %s"
msgstr ""
-#: builtin/init-db.c:322 builtin/init-db.c:325
+#: builtin/init-db.c:323 builtin/init-db.c:326
#, c-format
msgid "%s already exists"
msgstr ""
-#: builtin/init-db.c:354
+#: builtin/init-db.c:355
#, c-format
msgid "unable to handle file type %d"
msgstr ""
-#: builtin/init-db.c:357
+#: builtin/init-db.c:358
#, c-format
msgid "unable to move %s to %s"
msgstr ""
-#: builtin/init-db.c:362
+#: builtin/init-db.c:363
#, c-format
msgid "Could not create git link %s"
msgstr ""
@@ -3084,151 +5050,453 @@ msgstr ""
#. * existing" or "Initialized empty", the second " shared" or
#. * "", and the last '%s%s' is the verbatim directory name.
#.
-#: builtin/init-db.c:419
+#: builtin/init-db.c:420
#, c-format
msgid "%s%s Git repository in %s%s\n"
msgstr ""
-#: builtin/init-db.c:420
+#: builtin/init-db.c:421
msgid "Reinitialized existing"
msgstr ""
-#: builtin/init-db.c:420
+#: builtin/init-db.c:421
msgid "Initialized empty"
msgstr ""
-#: builtin/init-db.c:421
+#: builtin/init-db.c:422
msgid " shared"
msgstr ""
-#: builtin/init-db.c:440
+#: builtin/init-db.c:441
msgid "cannot tell cwd"
msgstr ""
-#: builtin/init-db.c:521 builtin/init-db.c:528
+#: builtin/init-db.c:467
+msgid ""
+"git init [-q | --quiet] [--bare] [--template=<template-directory>] [--shared"
+"[=<permissions>]] [directory]"
+msgstr ""
+
+#: builtin/init-db.c:490
+msgid "permissions"
+msgstr ""
+
+#: builtin/init-db.c:491
+msgid "specify that the git repository is to be shared amongst several users"
+msgstr ""
+
+#: builtin/init-db.c:493 builtin/prune-packed.c:77
+msgid "be quiet"
+msgstr ""
+
+#: builtin/init-db.c:522 builtin/init-db.c:529
#, c-format
msgid "cannot mkdir %s"
msgstr ""
-#: builtin/init-db.c:532
+#: builtin/init-db.c:533
#, c-format
msgid "cannot chdir to %s"
msgstr ""
-#: builtin/init-db.c:554
+#: builtin/init-db.c:555
#, c-format
msgid ""
"%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-"
"dir=<directory>)"
msgstr ""
-#: builtin/init-db.c:578
+#: builtin/init-db.c:579
msgid "Cannot access current working directory"
msgstr ""
-#: builtin/init-db.c:585
+#: builtin/init-db.c:586
#, c-format
msgid "Cannot access work tree '%s'"
msgstr ""
-#: builtin/log.c:188
+#: builtin/log.c:37
+msgid "git log [<options>] [<since>..<until>] [[--] <path>...]\n"
+msgstr ""
+
+#: builtin/log.c:38
+msgid " or: git show [options] <object>..."
+msgstr ""
+
+#: builtin/log.c:100
+msgid "suppress diff output"
+msgstr ""
+
+#: builtin/log.c:101
+msgid "show source"
+msgstr ""
+
+#: builtin/log.c:102
+msgid "decorate options"
+msgstr ""
+
+#: builtin/log.c:189
#, c-format
msgid "Final output: %d %s\n"
msgstr ""
-#: builtin/log.c:401 builtin/log.c:489
+#: builtin/log.c:403 builtin/log.c:494
#, c-format
msgid "Could not read object %s"
msgstr ""
-#: builtin/log.c:513
+#: builtin/log.c:518
#, c-format
msgid "Unknown type: %d"
msgstr ""
-#: builtin/log.c:602
+#: builtin/log.c:608
msgid "format.headers without value"
msgstr ""
-#: builtin/log.c:676
+#: builtin/log.c:682
msgid "name of output directory is too long"
msgstr ""
-#: builtin/log.c:687
+#: builtin/log.c:693
#, c-format
msgid "Cannot open patch file %s"
msgstr ""
-#: builtin/log.c:701
+#: builtin/log.c:707
msgid "Need exactly one range."
msgstr ""
-#: builtin/log.c:709
+#: builtin/log.c:715
msgid "Not a range."
msgstr ""
-#: builtin/log.c:786
+#: builtin/log.c:789
msgid "Cover letter needs email format"
msgstr ""
-#: builtin/log.c:859
+#: builtin/log.c:862
#, c-format
msgid "insane in-reply-to: %s"
msgstr ""
-#: builtin/log.c:932
+#: builtin/log.c:890
+msgid "git format-patch [options] [<since> | <revision range>]"
+msgstr ""
+
+#: builtin/log.c:935
msgid "Two output directories?"
msgstr ""
-#: builtin/log.c:1153
+#: builtin/log.c:1063
+msgid "use [PATCH n/m] even with a single patch"
+msgstr ""
+
+#: builtin/log.c:1066
+msgid "use [PATCH] even with multiple patches"
+msgstr ""
+
+#: builtin/log.c:1070
+msgid "print patches to standard out"
+msgstr ""
+
+#: builtin/log.c:1072
+msgid "generate a cover letter"
+msgstr ""
+
+#: builtin/log.c:1074
+msgid "use simple number sequence for output file names"
+msgstr ""
+
+#: builtin/log.c:1075
+msgid "sfx"
+msgstr ""
+
+#: builtin/log.c:1076
+msgid "use <sfx> instead of '.patch'"
+msgstr ""
+
+#: builtin/log.c:1078
+msgid "start numbering patches at <n> instead of 1"
+msgstr ""
+
+#: builtin/log.c:1080
+msgid "Use [<prefix>] instead of [PATCH]"
+msgstr ""
+
+#: builtin/log.c:1083
+msgid "store resulting files in <dir>"
+msgstr ""
+
+#: builtin/log.c:1086
+msgid "don't strip/add [PATCH]"
+msgstr ""
+
+#: builtin/log.c:1089
+msgid "don't output binary diffs"
+msgstr ""
+
+#: builtin/log.c:1091
+msgid "don't include a patch matching a commit upstream"
+msgstr ""
+
+#: builtin/log.c:1093
+msgid "show patch format instead of default (patch + stat)"
+msgstr ""
+
+#: builtin/log.c:1095
+msgid "Messaging"
+msgstr ""
+
+#: builtin/log.c:1096
+msgid "header"
+msgstr ""
+
+#: builtin/log.c:1097
+msgid "add email header"
+msgstr ""
+
+#: builtin/log.c:1098 builtin/log.c:1100
+msgid "email"
+msgstr ""
+
+#: builtin/log.c:1098
+msgid "add To: header"
+msgstr ""
+
+#: builtin/log.c:1100
+msgid "add Cc: header"
+msgstr ""
+
+#: builtin/log.c:1102
+msgid "message-id"
+msgstr ""
+
+#: builtin/log.c:1103
+msgid "make first mail a reply to <message-id>"
+msgstr ""
+
+#: builtin/log.c:1104 builtin/log.c:1107
+msgid "boundary"
+msgstr ""
+
+#: builtin/log.c:1105
+msgid "attach the patch"
+msgstr ""
+
+#: builtin/log.c:1108
+msgid "inline the patch"
+msgstr ""
+
+#: builtin/log.c:1112
+msgid "enable message threading, styles: shallow, deep"
+msgstr ""
+
+#: builtin/log.c:1114
+msgid "signature"
+msgstr ""
+
+#: builtin/log.c:1115
+msgid "add a signature"
+msgstr ""
+
+#: builtin/log.c:1117
+msgid "don't print the patch filenames"
+msgstr ""
+
+#: builtin/log.c:1157
#, c-format
msgid "bogus committer info %s"
msgstr ""
-#: builtin/log.c:1198
+#: builtin/log.c:1202
msgid "-n and -k are mutually exclusive."
msgstr ""
-#: builtin/log.c:1200
+#: builtin/log.c:1204
msgid "--subject-prefix and -k are mutually exclusive."
msgstr ""
-#: builtin/log.c:1208
+#: builtin/log.c:1212
msgid "--name-only does not make sense"
msgstr ""
-#: builtin/log.c:1210
+#: builtin/log.c:1214
msgid "--name-status does not make sense"
msgstr ""
-#: builtin/log.c:1212
+#: builtin/log.c:1216
msgid "--check does not make sense"
msgstr ""
-#: builtin/log.c:1235
+#: builtin/log.c:1239
msgid "standard output, or directory, which one?"
msgstr ""
-#: builtin/log.c:1237
+#: builtin/log.c:1241
#, c-format
msgid "Could not create directory '%s'"
msgstr ""
-#: builtin/log.c:1390
+#: builtin/log.c:1394
msgid "Failed to create output files"
msgstr ""
-#: builtin/log.c:1494
+#: builtin/log.c:1443
+msgid "git cherry [-v] [<upstream> [<head> [<limit>]]]"
+msgstr ""
+
+#: builtin/log.c:1498
#, c-format
msgid ""
"Could not find a tracked remote branch, please specify <upstream> manually.\n"
msgstr ""
-#: builtin/log.c:1510 builtin/log.c:1512 builtin/log.c:1524
+#: builtin/log.c:1511 builtin/log.c:1513 builtin/log.c:1525
#, c-format
msgid "Unknown commit %s"
msgstr ""
+#: builtin/ls-files.c:408
+msgid "git ls-files [options] [<file>...]"
+msgstr ""
+
+#: builtin/ls-files.c:463
+msgid "identify the file status with tags"
+msgstr ""
+
+#: builtin/ls-files.c:465
+msgid "use lowercase letters for 'assume unchanged' files"
+msgstr ""
+
+#: builtin/ls-files.c:467
+msgid "show cached files in the output (default)"
+msgstr ""
+
+#: builtin/ls-files.c:469
+msgid "show deleted files in the output"
+msgstr ""
+
+#: builtin/ls-files.c:471
+msgid "show modified files in the output"
+msgstr ""
+
+#: builtin/ls-files.c:473
+msgid "show other files in the output"
+msgstr ""
+
+#: builtin/ls-files.c:475
+msgid "show ignored files in the output"
+msgstr ""
+
+#: builtin/ls-files.c:478
+msgid "show staged contents' object name in the output"
+msgstr ""
+
+#: builtin/ls-files.c:480
+msgid "show files on the filesystem that need to be removed"
+msgstr ""
+
+#: builtin/ls-files.c:482
+msgid "show 'other' directories' name only"
+msgstr ""
+
+#: builtin/ls-files.c:485
+msgid "don't show empty directories"
+msgstr ""
+
+#: builtin/ls-files.c:488
+msgid "show unmerged files in the output"
+msgstr ""
+
+#: builtin/ls-files.c:490
+msgid "show resolve-undo information"
+msgstr ""
+
+#: builtin/ls-files.c:492
+msgid "skip files matching pattern"
+msgstr ""
+
+#: builtin/ls-files.c:495
+msgid "exclude patterns are read from <file>"
+msgstr ""
+
+#: builtin/ls-files.c:498
+msgid "read additional per-directory exclude patterns in <file>"
+msgstr ""
+
+#: builtin/ls-files.c:500
+msgid "add the standard git exclusions"
+msgstr ""
+
+#: builtin/ls-files.c:503
+msgid "make the output relative to the project top directory"
+msgstr ""
+
+#: builtin/ls-files.c:506
+msgid "if any <file> is not in the index, treat this as an error"
+msgstr ""
+
+#: builtin/ls-files.c:507
+msgid "tree-ish"
+msgstr ""
+
+#: builtin/ls-files.c:508
+msgid "pretend that paths removed since <tree-ish> are still present"
+msgstr ""
+
+#: builtin/ls-files.c:510
+msgid "show debugging data"
+msgstr ""
+
+#: builtin/ls-tree.c:27
+msgid "git ls-tree [<options>] <tree-ish> [<path>...]"
+msgstr ""
+
+#: builtin/ls-tree.c:125
+msgid "only show trees"
+msgstr ""
+
+#: builtin/ls-tree.c:127
+msgid "recurse into subtrees"
+msgstr ""
+
+#: builtin/ls-tree.c:129
+msgid "show trees when recursing"
+msgstr ""
+
+#: builtin/ls-tree.c:132
+msgid "terminate entries with NUL byte"
+msgstr ""
+
+#: builtin/ls-tree.c:133
+msgid "include object size"
+msgstr ""
+
+#: builtin/ls-tree.c:135 builtin/ls-tree.c:137
+msgid "list only filenames"
+msgstr ""
+
+#: builtin/ls-tree.c:140
+msgid "use full path names"
+msgstr ""
+
+#: builtin/ls-tree.c:142
+msgid "list entire tree; not just current directory (implies --full-name)"
+msgstr ""
+
+#: builtin/merge.c:43
+msgid "git merge [options] [<commit>...]"
+msgstr ""
+
+#: builtin/merge.c:44
+msgid "git merge [options] <msg> HEAD <commit>"
+msgstr ""
+
+#: builtin/merge.c:45
+msgid "git merge --abort"
+msgstr ""
+
#: builtin/merge.c:90
msgid "switch `m' requires a value"
msgstr ""
@@ -3248,6 +5516,66 @@ msgstr ""
msgid "Available custom strategies are:"
msgstr ""
+#: builtin/merge.c:183
+msgid "do not show a diffstat at the end of the merge"
+msgstr ""
+
+#: builtin/merge.c:186
+msgid "show a diffstat at the end of the merge"
+msgstr ""
+
+#: builtin/merge.c:187
+msgid "(synonym to --stat)"
+msgstr ""
+
+#: builtin/merge.c:189
+msgid "add (at most <n>) entries from shortlog to merge commit message"
+msgstr ""
+
+#: builtin/merge.c:192
+msgid "create a single commit instead of doing a merge"
+msgstr ""
+
+#: builtin/merge.c:194
+msgid "perform a commit if the merge succeeds (default)"
+msgstr ""
+
+#: builtin/merge.c:196
+msgid "edit message before committing"
+msgstr ""
+
+#: builtin/merge.c:198
+msgid "allow fast-forward (default)"
+msgstr ""
+
+#: builtin/merge.c:200
+msgid "abort if fast-forward is not possible"
+msgstr ""
+
+#: builtin/merge.c:202 builtin/notes.c:867 builtin/revert.c:112
+msgid "strategy"
+msgstr ""
+
+#: builtin/merge.c:203
+msgid "merge strategy to use"
+msgstr ""
+
+#: builtin/merge.c:204
+msgid "option=value"
+msgstr ""
+
+#: builtin/merge.c:205
+msgid "option for selected merge strategy"
+msgstr ""
+
+#: builtin/merge.c:207
+msgid "merge commit message (for a non-fast-forward merge)"
+msgstr ""
+
+#: builtin/merge.c:211
+msgid "abort the current in-progress merge"
+msgstr ""
+
#: builtin/merge.c:240
msgid "could not run stash."
msgstr ""
@@ -3287,53 +5615,49 @@ msgstr ""
msgid "No merge message -- not updating HEAD\n"
msgstr ""
-#: builtin/merge.c:437
+#: builtin/merge.c:436
#, c-format
msgid "'%s' does not point to a commit"
msgstr ""
-#: builtin/merge.c:536
+#: builtin/merge.c:535
#, c-format
msgid "Bad branch.%s.mergeoptions string: %s"
msgstr ""
-#: builtin/merge.c:629
+#: builtin/merge.c:628
msgid "git write-tree failed to write a tree"
msgstr ""
-#: builtin/merge.c:679
+#: builtin/merge.c:678
msgid "failed to read the cache"
msgstr ""
-#: builtin/merge.c:697
-msgid "Unable to write index."
-msgstr ""
-
-#: builtin/merge.c:710
+#: builtin/merge.c:709
msgid "Not handling anything other than two heads merge."
msgstr ""
-#: builtin/merge.c:724
+#: builtin/merge.c:723
#, c-format
msgid "Unknown option for merge-recursive: -X%s"
msgstr ""
-#: builtin/merge.c:738
+#: builtin/merge.c:737
#, c-format
msgid "unable to write %s"
msgstr ""
-#: builtin/merge.c:877
+#: builtin/merge.c:876
#, c-format
msgid "Could not read from '%s'"
msgstr ""
-#: builtin/merge.c:886
+#: builtin/merge.c:885
#, c-format
msgid "Not committing merge; use 'git commit' to complete the merge.\n"
msgstr ""
-#: builtin/merge.c:892
+#: builtin/merge.c:891
msgid ""
"Please enter a commit message to explain why this merge is necessary,\n"
"especially if it merges an updated upstream into a topic branch.\n"
@@ -3342,144 +5666,242 @@ msgid ""
"the commit.\n"
msgstr ""
-#: builtin/merge.c:916
+#: builtin/merge.c:915
msgid "Empty commit message."
msgstr ""
-#: builtin/merge.c:928
+#: builtin/merge.c:927
#, c-format
msgid "Wonderful.\n"
msgstr ""
-#: builtin/merge.c:993
+#: builtin/merge.c:992
#, c-format
msgid "Automatic merge failed; fix conflicts and then commit the result.\n"
msgstr ""
-#: builtin/merge.c:1009
+#: builtin/merge.c:1008
#, c-format
msgid "'%s' is not a commit"
msgstr ""
-#: builtin/merge.c:1050
+#: builtin/merge.c:1049
msgid "No current branch."
msgstr ""
-#: builtin/merge.c:1052
+#: builtin/merge.c:1051
msgid "No remote for the current branch."
msgstr ""
-#: builtin/merge.c:1054
+#: builtin/merge.c:1053
msgid "No default upstream defined for the current branch."
msgstr ""
-#: builtin/merge.c:1059
+#: builtin/merge.c:1058
#, c-format
msgid "No remote tracking branch for %s from %s"
msgstr ""
-#: builtin/merge.c:1146 builtin/merge.c:1303
+#: builtin/merge.c:1145 builtin/merge.c:1302
#, c-format
msgid "%s - not something we can merge"
msgstr ""
-#: builtin/merge.c:1214
+#: builtin/merge.c:1213
msgid "There is no merge to abort (MERGE_HEAD missing)."
msgstr ""
-#: builtin/merge.c:1230 git-pull.sh:31
+#: builtin/merge.c:1229 git-pull.sh:31
msgid ""
"You have not concluded your merge (MERGE_HEAD exists).\n"
"Please, commit your changes before you can merge."
msgstr ""
-#: builtin/merge.c:1233 git-pull.sh:34
+#: builtin/merge.c:1232 git-pull.sh:34
msgid "You have not concluded your merge (MERGE_HEAD exists)."
msgstr ""
-#: builtin/merge.c:1237
+#: builtin/merge.c:1236
msgid ""
"You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
"Please, commit your changes before you can merge."
msgstr ""
-#: builtin/merge.c:1240
+#: builtin/merge.c:1239
msgid "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)."
msgstr ""
-#: builtin/merge.c:1249
+#: builtin/merge.c:1248
msgid "You cannot combine --squash with --no-ff."
msgstr ""
-#: builtin/merge.c:1254
+#: builtin/merge.c:1253
msgid "You cannot combine --no-ff with --ff-only."
msgstr ""
-#: builtin/merge.c:1261
+#: builtin/merge.c:1260
msgid "No commit specified and merge.defaultToUpstream not set."
msgstr ""
-#: builtin/merge.c:1293
+#: builtin/merge.c:1292
msgid "Can merge only exactly one commit into empty head"
msgstr ""
-#: builtin/merge.c:1296
+#: builtin/merge.c:1295
msgid "Squash commit into empty head not supported yet"
msgstr ""
-#: builtin/merge.c:1298
+#: builtin/merge.c:1297
msgid "Non-fast-forward commit does not make sense into an empty head"
msgstr ""
-#: builtin/merge.c:1413
+#: builtin/merge.c:1412
#, c-format
msgid "Updating %s..%s\n"
msgstr ""
-#: builtin/merge.c:1451
+#: builtin/merge.c:1450
#, c-format
msgid "Trying really trivial in-index merge...\n"
msgstr ""
-#: builtin/merge.c:1458
+#: builtin/merge.c:1457
#, c-format
msgid "Nope.\n"
msgstr ""
-#: builtin/merge.c:1490
+#: builtin/merge.c:1489
msgid "Not possible to fast-forward, aborting."
msgstr ""
-#: builtin/merge.c:1513 builtin/merge.c:1592
+#: builtin/merge.c:1512 builtin/merge.c:1591
#, c-format
msgid "Rewinding the tree to pristine...\n"
msgstr ""
-#: builtin/merge.c:1517
+#: builtin/merge.c:1516
#, c-format
msgid "Trying merge strategy %s...\n"
msgstr ""
-#: builtin/merge.c:1583
+#: builtin/merge.c:1582
#, c-format
msgid "No merge strategy handled the merge.\n"
msgstr ""
-#: builtin/merge.c:1585
+#: builtin/merge.c:1584
#, c-format
msgid "Merge with strategy %s failed.\n"
msgstr ""
-#: builtin/merge.c:1594
+#: builtin/merge.c:1593
#, c-format
msgid "Using the %s to prepare resolving by hand.\n"
msgstr ""
-#: builtin/merge.c:1606
+#: builtin/merge.c:1605
#, c-format
msgid "Automatic merge went well; stopped before committing as requested\n"
msgstr ""
+#: builtin/merge-base.c:26
+msgid "git merge-base [-a|--all] <commit> <commit>..."
+msgstr ""
+
+#: builtin/merge-base.c:27
+msgid "git merge-base [-a|--all] --octopus <commit>..."
+msgstr ""
+
+#: builtin/merge-base.c:28
+msgid "git merge-base --independent <commit>..."
+msgstr ""
+
+#: builtin/merge-base.c:29
+msgid "git merge-base --is-ancestor <commit> <commit>"
+msgstr ""
+
+#: builtin/merge-base.c:98
+msgid "output all common ancestors"
+msgstr ""
+
+#: builtin/merge-base.c:99
+msgid "find ancestors for a single n-way merge"
+msgstr ""
+
+#: builtin/merge-base.c:100
+msgid "list revs not reachable from others"
+msgstr ""
+
+#: builtin/merge-base.c:102
+msgid "is the first one ancestor of the other?"
+msgstr ""
+
+#: builtin/merge-file.c:8
+msgid ""
+"git merge-file [options] [-L name1 [-L orig [-L name2]]] file1 orig_file "
+"file2"
+msgstr ""
+
+#: builtin/merge-file.c:33
+msgid "send results to standard output"
+msgstr ""
+
+#: builtin/merge-file.c:34
+msgid "use a diff3 based merge"
+msgstr ""
+
+#: builtin/merge-file.c:35
+msgid "for conflicts, use our version"
+msgstr ""
+
+#: builtin/merge-file.c:37
+msgid "for conflicts, use their version"
+msgstr ""
+
+#: builtin/merge-file.c:39
+msgid "for conflicts, use a union version"
+msgstr ""
+
+#: builtin/merge-file.c:42
+msgid "for conflicts, use this marker size"
+msgstr ""
+
+#: builtin/merge-file.c:43
+msgid "do not warn about conflicts"
+msgstr ""
+
+#: builtin/merge-file.c:45
+msgid "set labels for file1/orig_file/file2"
+msgstr ""
+
+#: builtin/mktree.c:67
+msgid "git mktree [-z] [--missing] [--batch]"
+msgstr ""
+
+#: builtin/mktree.c:153
+msgid "input is NUL terminated"
+msgstr ""
+
+#: builtin/mktree.c:154 builtin/write-tree.c:24
+msgid "allow missing objects"
+msgstr ""
+
+#: builtin/mktree.c:155
+msgid "allow creation of more than one tree"
+msgstr ""
+
+#: builtin/mv.c:14
+msgid "git mv [options] <source>... <destination>"
+msgstr ""
+
+#: builtin/mv.c:64
+msgid "force move/rename even if target exists"
+msgstr ""
+
+#: builtin/mv.c:65
+msgid "skip move/rename errors"
+msgstr ""
+
#: builtin/mv.c:108
#, c-format
msgid "Checking rename of '%s' to '%s'\n"
@@ -3542,6 +5964,147 @@ msgstr ""
msgid "renaming '%s' failed"
msgstr ""
+#: builtin/name-rev.c:175
+msgid "git name-rev [options] <commit>..."
+msgstr ""
+
+#: builtin/name-rev.c:176
+msgid "git name-rev [options] --all"
+msgstr ""
+
+#: builtin/name-rev.c:177
+msgid "git name-rev [options] --stdin"
+msgstr ""
+
+#: builtin/name-rev.c:229
+msgid "print only names (no SHA-1)"
+msgstr ""
+
+#: builtin/name-rev.c:230
+msgid "only use tags to name the commits"
+msgstr ""
+
+#: builtin/name-rev.c:232
+msgid "only use refs matching <pattern>"
+msgstr ""
+
+#: builtin/name-rev.c:234
+msgid "list all commits reachable from all refs"
+msgstr ""
+
+#: builtin/name-rev.c:235
+msgid "read from stdin"
+msgstr ""
+
+#: builtin/name-rev.c:236
+msgid "allow to print `undefined` names"
+msgstr ""
+
+#: builtin/notes.c:23
+msgid "git notes [--ref <notes_ref>] [list [<object>]]"
+msgstr ""
+
+#: builtin/notes.c:24
+msgid ""
+"git notes [--ref <notes_ref>] add [-f] [-m <msg> | -F <file> | (-c | -C) "
+"<object>] [<object>]"
+msgstr ""
+
+#: builtin/notes.c:25
+msgid "git notes [--ref <notes_ref>] copy [-f] <from-object> <to-object>"
+msgstr ""
+
+#: builtin/notes.c:26
+msgid ""
+"git notes [--ref <notes_ref>] append [-m <msg> | -F <file> | (-c | -C) "
+"<object>] [<object>]"
+msgstr ""
+
+#: builtin/notes.c:27
+msgid "git notes [--ref <notes_ref>] edit [<object>]"
+msgstr ""
+
+#: builtin/notes.c:28
+msgid "git notes [--ref <notes_ref>] show [<object>]"
+msgstr ""
+
+#: builtin/notes.c:29
+msgid ""
+"git notes [--ref <notes_ref>] merge [-v | -q] [-s <strategy> ] <notes_ref>"
+msgstr ""
+
+#: builtin/notes.c:30
+msgid "git notes merge --commit [-v | -q]"
+msgstr ""
+
+#: builtin/notes.c:31
+msgid "git notes merge --abort [-v | -q]"
+msgstr ""
+
+#: builtin/notes.c:32
+msgid "git notes [--ref <notes_ref>] remove [<object>...]"
+msgstr ""
+
+#: builtin/notes.c:33
+msgid "git notes [--ref <notes_ref>] prune [-n | -v]"
+msgstr ""
+
+#: builtin/notes.c:34
+msgid "git notes [--ref <notes_ref>] get-ref"
+msgstr ""
+
+#: builtin/notes.c:39
+msgid "git notes [list [<object>]]"
+msgstr ""
+
+#: builtin/notes.c:44
+msgid "git notes add [<options>] [<object>]"
+msgstr ""
+
+#: builtin/notes.c:49
+msgid "git notes copy [<options>] <from-object> <to-object>"
+msgstr ""
+
+#: builtin/notes.c:50
+msgid "git notes copy --stdin [<from-object> <to-object>]..."
+msgstr ""
+
+#: builtin/notes.c:55
+msgid "git notes append [<options>] [<object>]"
+msgstr ""
+
+#: builtin/notes.c:60
+msgid "git notes edit [<object>]"
+msgstr ""
+
+#: builtin/notes.c:65
+msgid "git notes show [<object>]"
+msgstr ""
+
+#: builtin/notes.c:70
+msgid "git notes merge [<options>] <notes_ref>"
+msgstr ""
+
+#: builtin/notes.c:71
+msgid "git notes merge --commit [<options>]"
+msgstr ""
+
+#: builtin/notes.c:72
+msgid "git notes merge --abort [<options>]"
+msgstr ""
+
+#: builtin/notes.c:77
+msgid "git notes remove [<object>]"
+msgstr ""
+
+#: builtin/notes.c:82
+msgid "git notes prune [<options>]"
+msgstr ""
+
+#: builtin/notes.c:87
+msgid "git notes get-ref"
+msgstr ""
+
#: builtin/notes.c:139
#, c-format
msgid "unable to start 'show' for object '%s'"
@@ -3649,6 +6212,31 @@ msgstr ""
msgid "No note found for object %s."
msgstr ""
+#: builtin/notes.c:535 builtin/notes.c:692
+msgid "note contents as a string"
+msgstr ""
+
+#: builtin/notes.c:538 builtin/notes.c:695
+msgid "note contents in a file"
+msgstr ""
+
+#: builtin/notes.c:540 builtin/notes.c:543 builtin/notes.c:697
+#: builtin/notes.c:700 builtin/tag.c:476
+msgid "object"
+msgstr ""
+
+#: builtin/notes.c:541 builtin/notes.c:698
+msgid "reuse and edit specified note object"
+msgstr ""
+
+#: builtin/notes.c:544 builtin/notes.c:701
+msgid "reuse specified note object"
+msgstr ""
+
+#: builtin/notes.c:546 builtin/notes.c:614
+msgid "replace existing notes"
+msgstr ""
+
#: builtin/notes.c:580
#, c-format
msgid ""
@@ -3661,6 +6249,14 @@ msgstr ""
msgid "Overwriting existing notes for object %s\n"
msgstr ""
+#: builtin/notes.c:615
+msgid "read objects from stdin"
+msgstr ""
+
+#: builtin/notes.c:617
+msgid "load rewriting config for <command> (implies --stdin)"
+msgstr ""
+
#: builtin/notes.c:635
msgid "too few parameters"
msgstr ""
@@ -3684,36 +6280,251 @@ msgid ""
"Please use 'git notes add -f -m/-F/-c/-C' instead.\n"
msgstr ""
+#: builtin/notes.c:864
+msgid "General options"
+msgstr ""
+
+#: builtin/notes.c:866
+msgid "Merge options"
+msgstr ""
+
+#: builtin/notes.c:868
+msgid ""
+"resolve notes conflicts using the given strategy (manual/ours/theirs/union/"
+"cat_sort_uniq)"
+msgstr ""
+
+#: builtin/notes.c:870
+msgid "Committing unmerged notes"
+msgstr ""
+
+#: builtin/notes.c:872
+msgid "finalize notes merge by committing unmerged notes"
+msgstr ""
+
+#: builtin/notes.c:874
+msgid "Aborting notes merge resolution"
+msgstr ""
+
+#: builtin/notes.c:876
+msgid "abort notes merge"
+msgstr ""
+
#: builtin/notes.c:971
#, c-format
msgid "Object %s has no note\n"
msgstr ""
+#: builtin/notes.c:983
+msgid "attempt to remove non-existent note is not an error"
+msgstr ""
+
+#: builtin/notes.c:986
+msgid "read object names from the standard input"
+msgstr ""
+
+#: builtin/notes.c:1067
+msgid "notes_ref"
+msgstr ""
+
+#: builtin/notes.c:1068
+msgid "use notes from <notes_ref>"
+msgstr ""
+
#: builtin/notes.c:1103 builtin/remote.c:1598
#, c-format
msgid "Unknown subcommand: %s"
msgstr ""
-#: builtin/pack-objects.c:2337
+#: builtin/pack-objects.c:23
+msgid "git pack-objects --stdout [options...] [< ref-list | < object-list]"
+msgstr ""
+
+#: builtin/pack-objects.c:24
+msgid "git pack-objects [options...] base-name [< ref-list | < object-list]"
+msgstr ""
+
+#: builtin/pack-objects.c:183 builtin/pack-objects.c:186
+#, c-format
+msgid "deflate error (%d)"
+msgstr ""
+
+#: builtin/pack-objects.c:2398
#, c-format
msgid "unsupported index version %s"
msgstr ""
-#: builtin/pack-objects.c:2341
+#: builtin/pack-objects.c:2402
#, c-format
msgid "bad index version '%s'"
msgstr ""
-#: builtin/pack-objects.c:2364
+#: builtin/pack-objects.c:2425
#, c-format
msgid "option %s does not accept negative form"
msgstr ""
-#: builtin/pack-objects.c:2368
+#: builtin/pack-objects.c:2429
#, c-format
msgid "unable to parse value '%s' for option %s"
msgstr ""
+#: builtin/pack-objects.c:2448
+msgid "do not show progress meter"
+msgstr ""
+
+#: builtin/pack-objects.c:2450
+msgid "show progress meter"
+msgstr ""
+
+#: builtin/pack-objects.c:2452
+msgid "show progress meter during object writing phase"
+msgstr ""
+
+#: builtin/pack-objects.c:2455
+msgid "similar to --all-progress when progress meter is shown"
+msgstr ""
+
+#: builtin/pack-objects.c:2456
+msgid "version[,offset]"
+msgstr ""
+
+#: builtin/pack-objects.c:2457
+msgid "write the pack index file in the specified idx format version"
+msgstr ""
+
+#: builtin/pack-objects.c:2460
+msgid "maximum size of each output pack file"
+msgstr ""
+
+#: builtin/pack-objects.c:2462
+msgid "ignore borrowed objects from alternate object store"
+msgstr ""
+
+#: builtin/pack-objects.c:2464
+msgid "ignore packed objects"
+msgstr ""
+
+#: builtin/pack-objects.c:2466
+msgid "limit pack window by objects"
+msgstr ""
+
+#: builtin/pack-objects.c:2468
+msgid "limit pack window by memory in addition to object limit"
+msgstr ""
+
+#: builtin/pack-objects.c:2470
+msgid "maximum length of delta chain allowed in the resulting pack"
+msgstr ""
+
+#: builtin/pack-objects.c:2472
+msgid "reuse existing deltas"
+msgstr ""
+
+#: builtin/pack-objects.c:2474
+msgid "reuse existing objects"
+msgstr ""
+
+#: builtin/pack-objects.c:2476
+msgid "use OFS_DELTA objects"
+msgstr ""
+
+#: builtin/pack-objects.c:2478
+msgid "use threads when searching for best delta matches"
+msgstr ""
+
+#: builtin/pack-objects.c:2480
+msgid "do not create an empty pack output"
+msgstr ""
+
+#: builtin/pack-objects.c:2482
+msgid "read revision arguments from standard input"
+msgstr ""
+
+#: builtin/pack-objects.c:2484
+msgid "limit the objects to those that are not yet packed"
+msgstr ""
+
+#: builtin/pack-objects.c:2487
+msgid "include objects reachable from any reference"
+msgstr ""
+
+#: builtin/pack-objects.c:2490
+msgid "include objects referred by reflog entries"
+msgstr ""
+
+#: builtin/pack-objects.c:2493
+msgid "output pack to stdout"
+msgstr ""
+
+#: builtin/pack-objects.c:2495
+msgid "include tag objects that refer to objects to be packed"
+msgstr ""
+
+#: builtin/pack-objects.c:2497
+msgid "keep unreachable objects"
+msgstr ""
+
+#: builtin/pack-objects.c:2498 parse-options.h:141
+msgid "time"
+msgstr ""
+
+#: builtin/pack-objects.c:2499
+msgid "unpack unreachable objects newer than <time>"
+msgstr ""
+
+#: builtin/pack-objects.c:2502
+msgid "create thin packs"
+msgstr ""
+
+#: builtin/pack-objects.c:2504
+msgid "ignore packs that have companion .keep file"
+msgstr ""
+
+#: builtin/pack-objects.c:2506
+msgid "pack compression level"
+msgstr ""
+
+#: builtin/pack-objects.c:2508
+msgid "do not hide commits by grafts"
+msgstr ""
+
+#: builtin/pack-refs.c:6
+msgid "git pack-refs [options]"
+msgstr ""
+
+#: builtin/pack-refs.c:14
+msgid "pack everything"
+msgstr ""
+
+#: builtin/pack-refs.c:15
+msgid "prune loose refs (default)"
+msgstr ""
+
+#: builtin/prune-packed.c:7
+msgid "git prune-packed [-n|--dry-run] [-q|--quiet]"
+msgstr ""
+
+#: builtin/prune.c:12
+msgid "git prune [-n] [-v] [--expire <time>] [--] [<head>...]"
+msgstr ""
+
+#: builtin/prune.c:132
+msgid "do not remove, show only"
+msgstr ""
+
+#: builtin/prune.c:133
+msgid "report pruned objects"
+msgstr ""
+
+#: builtin/prune.c:136
+msgid "expire objects older than <time>"
+msgstr ""
+
+#: builtin/push.c:14
+msgid "git push [<options>] [<repository> [<refspec>...]]"
+msgstr ""
+
#: builtin/push.c:45
msgid "tag shorthand without <tag>"
msgstr ""
@@ -3775,12 +6586,30 @@ msgid ""
"to update which remote branch."
msgstr ""
-#: builtin/push.c:174
+#: builtin/push.c:151
+msgid ""
+"push.default is unset; its implicit value is changing in\n"
+"Git 2.0 from 'matching' to 'simple'. To squelch this message\n"
+"and maintain the current behavior after the default changes, use:\n"
+"\n"
+" git config --global push.default matching\n"
+"\n"
+"To squelch this message and adopt the new behavior now, use:\n"
+"\n"
+" git config --global push.default simple\n"
+"\n"
+"See 'git help config' and search for 'push.default' for further "
+"information.\n"
+"(the 'simple' mode was introduced in Git 1.7.11. Use the similar mode\n"
+"'current' instead of 'simple' if you sometimes use older versions of Git)"
+msgstr ""
+
+#: builtin/push.c:199
msgid ""
"You didn't specify any refspecs to push, and push.default is \"nothing\"."
msgstr ""
-#: builtin/push.c:181
+#: builtin/push.c:206
msgid ""
"Updates were rejected because the tip of your current branch is behind\n"
"its remote counterpart. Merge the remote changes (e.g. 'git pull')\n"
@@ -3788,15 +6617,15 @@ msgid ""
"See the 'Note about fast-forwards' in 'git push --help' for details."
msgstr ""
-#: builtin/push.c:187
+#: builtin/push.c:212
msgid ""
"Updates were rejected because a pushed branch tip is behind its remote\n"
"counterpart. If you did not intend to push that branch, you may want to\n"
-"specify branches to push or set the 'push.default' configuration\n"
-"variable to 'current' or 'upstream' to push only the current branch."
+"specify branches to push or set the 'push.default' configuration variable\n"
+"to 'simple', 'current' or 'upstream' to push only the current branch."
msgstr ""
-#: builtin/push.c:193
+#: builtin/push.c:218
msgid ""
"Updates were rejected because a pushed branch tip is behind its remote\n"
"counterpart. Check out this branch and merge the remote changes\n"
@@ -3804,22 +6633,22 @@ msgid ""
"See the 'Note about fast-forwards' in 'git push --help' for details."
msgstr ""
-#: builtin/push.c:233
+#: builtin/push.c:258
#, c-format
msgid "Pushing to %s\n"
msgstr ""
-#: builtin/push.c:237
+#: builtin/push.c:262
#, c-format
msgid "failed to push some refs to '%s'"
msgstr ""
-#: builtin/push.c:269
+#: builtin/push.c:294
#, c-format
msgid "bad repository '%s'"
msgstr ""
-#: builtin/push.c:270
+#: builtin/push.c:295
msgid ""
"No configured push destination.\n"
"Either specify the URL from the command-line or configure a remote "
@@ -3832,34 +6661,232 @@ msgid ""
" git push <name>\n"
msgstr ""
-#: builtin/push.c:285
+#: builtin/push.c:310
msgid "--all and --tags are incompatible"
msgstr ""
-#: builtin/push.c:286
+#: builtin/push.c:311
msgid "--all can't be combined with refspecs"
msgstr ""
-#: builtin/push.c:291
+#: builtin/push.c:316
msgid "--mirror and --tags are incompatible"
msgstr ""
-#: builtin/push.c:292
+#: builtin/push.c:317
msgid "--mirror can't be combined with refspecs"
msgstr ""
-#: builtin/push.c:297
+#: builtin/push.c:322
msgid "--all and --mirror are incompatible"
msgstr ""
-#: builtin/push.c:385
-msgid "--delete is incompatible with --all, --mirror and --tags"
+#: builtin/push.c:382
+msgid "repository"
+msgstr ""
+
+#: builtin/push.c:383
+msgid "push all refs"
+msgstr ""
+
+#: builtin/push.c:384
+msgid "mirror all refs"
+msgstr ""
+
+#: builtin/push.c:386
+msgid "delete refs"
msgstr ""
#: builtin/push.c:387
+msgid "push tags (can't be used with --all or --mirror)"
+msgstr ""
+
+#: builtin/push.c:390
+msgid "force updates"
+msgstr ""
+
+#: builtin/push.c:391
+msgid "check"
+msgstr ""
+
+#: builtin/push.c:392
+msgid "control recursive pushing of submodules"
+msgstr ""
+
+#: builtin/push.c:394
+msgid "use thin pack"
+msgstr ""
+
+#: builtin/push.c:395 builtin/push.c:396
+msgid "receive pack program"
+msgstr ""
+
+#: builtin/push.c:397
+msgid "set upstream for git pull/status"
+msgstr ""
+
+#: builtin/push.c:400
+msgid "prune locally removed refs"
+msgstr ""
+
+#: builtin/push.c:410
+msgid "--delete is incompatible with --all, --mirror and --tags"
+msgstr ""
+
+#: builtin/push.c:412
msgid "--delete doesn't make sense without any refs"
msgstr ""
+#: builtin/read-tree.c:36
+msgid ""
+"git read-tree [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>] "
+"[-u [--exclude-per-directory=<gitignore>] | -i]] [--no-sparse-checkout] [--"
+"index-output=<file>] (--empty | <tree-ish1> [<tree-ish2> [<tree-ish3>]])"
+msgstr ""
+
+#: builtin/read-tree.c:108
+msgid "write resulting index to <file>"
+msgstr ""
+
+#: builtin/read-tree.c:111
+msgid "only empty the index"
+msgstr ""
+
+#: builtin/read-tree.c:113
+msgid "Merging"
+msgstr ""
+
+#: builtin/read-tree.c:115
+msgid "perform a merge in addition to a read"
+msgstr ""
+
+#: builtin/read-tree.c:117
+msgid "3-way merge if no file level merging required"
+msgstr ""
+
+#: builtin/read-tree.c:119
+msgid "3-way merge in presence of adds and removes"
+msgstr ""
+
+#: builtin/read-tree.c:121
+msgid "same as -m, but discard unmerged entries"
+msgstr ""
+
+#: builtin/read-tree.c:122
+msgid "<subdirectory>/"
+msgstr ""
+
+#: builtin/read-tree.c:123
+msgid "read the tree into the index under <subdirectory>/"
+msgstr ""
+
+#: builtin/read-tree.c:126
+msgid "update working tree with merge result"
+msgstr ""
+
+#: builtin/read-tree.c:128
+msgid "gitignore"
+msgstr ""
+
+#: builtin/read-tree.c:129
+msgid "allow explicitly ignored files to be overwritten"
+msgstr ""
+
+#: builtin/read-tree.c:132
+msgid "don't check the working tree after merging"
+msgstr ""
+
+#: builtin/read-tree.c:133
+msgid "don't update the index or the work tree"
+msgstr ""
+
+#: builtin/read-tree.c:135
+msgid "skip applying sparse checkout filter"
+msgstr ""
+
+#: builtin/read-tree.c:137
+msgid "debug unpack-trees"
+msgstr ""
+
+#: builtin/remote.c:11
+msgid "git remote [-v | --verbose]"
+msgstr ""
+
+#: builtin/remote.c:12
+msgid ""
+"git remote add [-t <branch>] [-m <master>] [-f] [--tags|--no-tags] [--"
+"mirror=<fetch|push>] <name> <url>"
+msgstr ""
+
+#: builtin/remote.c:13 builtin/remote.c:32
+msgid "git remote rename <old> <new>"
+msgstr ""
+
+#: builtin/remote.c:14 builtin/remote.c:37
+msgid "git remote remove <name>"
+msgstr ""
+
+#: builtin/remote.c:15
+msgid "git remote set-head <name> (-a | -d | <branch>)"
+msgstr ""
+
+#: builtin/remote.c:16
+msgid "git remote [-v | --verbose] show [-n] <name>"
+msgstr ""
+
+#: builtin/remote.c:17
+msgid "git remote prune [-n | --dry-run] <name>"
+msgstr ""
+
+#: builtin/remote.c:18
+msgid ""
+"git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]"
+msgstr ""
+
+#: builtin/remote.c:19
+msgid "git remote set-branches [--add] <name> <branch>..."
+msgstr ""
+
+#: builtin/remote.c:20 builtin/remote.c:68
+msgid "git remote set-url [--push] <name> <newurl> [<oldurl>]"
+msgstr ""
+
+#: builtin/remote.c:21 builtin/remote.c:69
+msgid "git remote set-url --add <name> <newurl>"
+msgstr ""
+
+#: builtin/remote.c:22 builtin/remote.c:70
+msgid "git remote set-url --delete <name> <url>"
+msgstr ""
+
+#: builtin/remote.c:27
+msgid "git remote add [<options>] <name> <url>"
+msgstr ""
+
+#: builtin/remote.c:42
+msgid "git remote set-head <name> (-a | -d | <branch>])"
+msgstr ""
+
+#: builtin/remote.c:47
+msgid "git remote set-branches <name> <branch>..."
+msgstr ""
+
+#: builtin/remote.c:48
+msgid "git remote set-branches --add <name> <branch>..."
+msgstr ""
+
+#: builtin/remote.c:53
+msgid "git remote show [<options>] <name>"
+msgstr ""
+
+#: builtin/remote.c:58
+msgid "git remote prune [<options>] <name>"
+msgstr ""
+
+#: builtin/remote.c:63
+msgid "git remote update [<options>] [<group> | <remote>]..."
+msgstr ""
+
#: builtin/remote.c:98
#, c-format
msgid "Updating %s"
@@ -3876,6 +6903,34 @@ msgstr ""
msgid "unknown mirror argument: %s"
msgstr ""
+#: builtin/remote.c:163
+msgid "fetch the remote branches"
+msgstr ""
+
+#: builtin/remote.c:165
+msgid "import all tags and associated objects when fetching"
+msgstr ""
+
+#: builtin/remote.c:168
+msgid "or do not fetch any tag at all (--no-tags)"
+msgstr ""
+
+#: builtin/remote.c:170
+msgid "branch(es) to track"
+msgstr ""
+
+#: builtin/remote.c:171
+msgid "master branch"
+msgstr ""
+
+#: builtin/remote.c:172
+msgid "push|fetch"
+msgstr ""
+
+#: builtin/remote.c:173
+msgid "set up remote as a mirror to push to or fetch from"
+msgstr ""
+
#: builtin/remote.c:185
msgid "specifying a master branch makes no sense with --mirror"
msgstr ""
@@ -4065,6 +7120,10 @@ msgstr ""
msgid " %-*s pushes to %s"
msgstr ""
+#: builtin/remote.c:1091
+msgid "do not query remotes"
+msgstr ""
+
#: builtin/remote.c:1118
#, c-format
msgid "* remote %s"
@@ -4123,6 +7182,14 @@ msgid_plural " Local refs configured for 'git push'%s:"
msgstr[0] ""
msgstr[1] ""
+#: builtin/remote.c:1199
+msgid "set refs/remotes/<name>/HEAD according to remote"
+msgstr ""
+
+#: builtin/remote.c:1201
+msgid "delete refs/remotes/<name>/HEAD"
+msgstr ""
+
#: builtin/remote.c:1216
msgid "Cannot determine remote HEAD"
msgstr ""
@@ -4176,15 +7243,35 @@ msgstr ""
msgid " * [pruned] %s"
msgstr ""
+#: builtin/remote.c:1321
+msgid "prune remotes after fetching"
+msgstr ""
+
#: builtin/remote.c:1387 builtin/remote.c:1461
#, c-format
msgid "No such remote '%s'"
msgstr ""
+#: builtin/remote.c:1407
+msgid "add branch"
+msgstr ""
+
#: builtin/remote.c:1414
msgid "no remote specified"
msgstr ""
+#: builtin/remote.c:1436
+msgid "manipulate push URLs"
+msgstr ""
+
+#: builtin/remote.c:1438
+msgid "add URL"
+msgstr ""
+
+#: builtin/remote.c:1440
+msgid "delete URLs"
+msgstr ""
+
#: builtin/remote.c:1447
msgid "--add --delete doesn't make sense"
msgstr ""
@@ -4203,6 +7290,55 @@ msgstr ""
msgid "Will not delete all non-push URLs"
msgstr ""
+#: builtin/remote.c:1569
+msgid "be verbose; must be placed before a subcommand"
+msgstr ""
+
+#: builtin/replace.c:17
+msgid "git replace [-f] <object> <replacement>"
+msgstr ""
+
+#: builtin/replace.c:18
+msgid "git replace -d <object>..."
+msgstr ""
+
+#: builtin/replace.c:19
+msgid "git replace -l [<pattern>]"
+msgstr ""
+
+#: builtin/replace.c:118
+msgid "list replace refs"
+msgstr ""
+
+#: builtin/replace.c:119
+msgid "delete replace refs"
+msgstr ""
+
+#: builtin/replace.c:120
+msgid "replace the ref if it exists"
+msgstr ""
+
+#: builtin/rerere.c:11
+msgid "git rerere [clear | forget path... | status | remaining | diff | gc]"
+msgstr ""
+
+#: builtin/rerere.c:56
+msgid "register clean resolutions in index"
+msgstr ""
+
+#: builtin/reset.c:25
+msgid ""
+"git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]"
+msgstr ""
+
+#: builtin/reset.c:26
+msgid "git reset [-q] <commit> [--] <paths>..."
+msgstr ""
+
+#: builtin/reset.c:27
+msgid "git reset --patch [<commit>] [--] [<paths>...]"
+msgstr ""
+
#: builtin/reset.c:33
msgid "mixed"
msgstr ""
@@ -4258,51 +7394,168 @@ msgstr ""
msgid "Cannot do a %s reset in the middle of a merge."
msgstr ""
-#: builtin/reset.c:297
+#: builtin/reset.c:238
+msgid "be quiet, only report errors"
+msgstr ""
+
+#: builtin/reset.c:240
+msgid "reset HEAD and index"
+msgstr ""
+
+#: builtin/reset.c:241
+msgid "reset only HEAD"
+msgstr ""
+
+#: builtin/reset.c:243 builtin/reset.c:245
+msgid "reset HEAD, index and working tree"
+msgstr ""
+
+#: builtin/reset.c:247
+msgid "reset HEAD but keep local changes"
+msgstr ""
+
+#: builtin/reset.c:303
#, c-format
msgid "Could not parse object '%s'."
msgstr ""
-#: builtin/reset.c:302
+#: builtin/reset.c:308
msgid "--patch is incompatible with --{hard,mixed,soft}"
msgstr ""
-#: builtin/reset.c:311
+#: builtin/reset.c:317
msgid "--mixed with paths is deprecated; use 'git reset -- <paths>' instead."
msgstr ""
-#: builtin/reset.c:313
+#: builtin/reset.c:319
#, c-format
msgid "Cannot do %s reset with paths."
msgstr ""
-#: builtin/reset.c:325
+#: builtin/reset.c:331
#, c-format
msgid "%s reset is not allowed in a bare repository"
msgstr ""
-#: builtin/reset.c:341
+#: builtin/reset.c:347
#, c-format
msgid "Could not reset index file to revision '%s'."
msgstr ""
+#: builtin/rev-parse.c:339
+msgid "git rev-parse --parseopt [options] -- [<args>...]"
+msgstr ""
+
+#: builtin/rev-parse.c:344
+msgid "keep the `--` passed as an arg"
+msgstr ""
+
+#: builtin/rev-parse.c:346
+msgid "stop parsing after the first non-option argument"
+msgstr ""
+
+#: builtin/rev-parse.c:464
+msgid ""
+"git rev-parse --parseopt [options] -- [<args>...]\n"
+" or: git rev-parse --sq-quote [<arg>...]\n"
+" or: git rev-parse [options] [<arg>...]\n"
+"\n"
+"Run \"git rev-parse --parseopt -h\" for more information on the first usage."
+msgstr ""
+
+#: builtin/revert.c:22
+msgid "git revert [options] <commit-ish>"
+msgstr ""
+
+#: builtin/revert.c:23
+msgid "git revert <subcommand>"
+msgstr ""
+
+#: builtin/revert.c:28
+msgid "git cherry-pick [options] <commit-ish>"
+msgstr ""
+
+#: builtin/revert.c:29
+msgid "git cherry-pick <subcommand>"
+msgstr ""
+
#: builtin/revert.c:70 builtin/revert.c:92
#, c-format
msgid "%s: %s cannot be used with %s"
msgstr ""
-#: builtin/revert.c:131
+#: builtin/revert.c:103
+msgid "end revert or cherry-pick sequence"
+msgstr ""
+
+#: builtin/revert.c:104
+msgid "resume revert or cherry-pick sequence"
+msgstr ""
+
+#: builtin/revert.c:105
+msgid "cancel revert or cherry-pick sequence"
+msgstr ""
+
+#: builtin/revert.c:106
+msgid "don't automatically commit"
+msgstr ""
+
+#: builtin/revert.c:107
+msgid "edit the commit message"
+msgstr ""
+
+#: builtin/revert.c:110
+msgid "parent number"
+msgstr ""
+
+#: builtin/revert.c:112
+msgid "merge strategy"
+msgstr ""
+
+#: builtin/revert.c:113
+msgid "option"
+msgstr ""
+
+#: builtin/revert.c:114
+msgid "option for merge strategy"
+msgstr ""
+
+#: builtin/revert.c:125
+msgid "append commit name"
+msgstr ""
+
+#: builtin/revert.c:126
+msgid "allow fast-forward"
+msgstr ""
+
+#: builtin/revert.c:127
+msgid "preserve initially empty commits"
+msgstr ""
+
+#: builtin/revert.c:128
+msgid "allow commits with empty messages"
+msgstr ""
+
+#: builtin/revert.c:129
+msgid "keep redundant, empty commits"
+msgstr ""
+
+#: builtin/revert.c:133
msgid "program error"
msgstr ""
-#: builtin/revert.c:221
+#: builtin/revert.c:223
msgid "revert failed"
msgstr ""
-#: builtin/revert.c:236
+#: builtin/revert.c:238
msgid "cherry-pick failed"
msgstr ""
+#: builtin/rm.c:14
+msgid "git rm [options] [--] <file>..."
+msgstr ""
+
#: builtin/rm.c:109
#, c-format
msgid ""
@@ -4324,6 +7577,26 @@ msgid ""
"(use --cached to keep the file, or -f to force removal)"
msgstr ""
+#: builtin/rm.c:134
+msgid "do not list removed files"
+msgstr ""
+
+#: builtin/rm.c:135
+msgid "only remove from the index"
+msgstr ""
+
+#: builtin/rm.c:136
+msgid "override the up-to-date check"
+msgstr ""
+
+#: builtin/rm.c:137
+msgid "allow recursive removal"
+msgstr ""
+
+#: builtin/rm.c:139
+msgid "exit with a zero status even if nothing matched"
+msgstr ""
+
#: builtin/rm.c:194
#, c-format
msgid "not removing '%s' recursively without -r"
@@ -4334,11 +7607,192 @@ msgstr ""
msgid "git rm: unable to remove %s"
msgstr ""
+#: builtin/shortlog.c:13
+msgid "git shortlog [-n] [-s] [-e] [-w] [rev-opts] [--] [<commit-id>... ]"
+msgstr ""
+
#: builtin/shortlog.c:157
#, c-format
msgid "Missing author: %s"
msgstr ""
+#: builtin/shortlog.c:253
+msgid "sort output according to the number of commits per author"
+msgstr ""
+
+#: builtin/shortlog.c:255
+msgid "Suppress commit descriptions, only provides commit count"
+msgstr ""
+
+#: builtin/shortlog.c:257
+msgid "Show the email address of each author"
+msgstr ""
+
+#: builtin/shortlog.c:258
+msgid "w[,i1[,i2]]"
+msgstr ""
+
+#: builtin/shortlog.c:259
+msgid "Linewrap output"
+msgstr ""
+
+#: builtin/show-branch.c:9
+msgid ""
+"git show-branch [-a|--all] [-r|--remotes] [--topo-order | --date-order] [--"
+"current] [--color[=<when>] | --no-color] [--sparse] [--more=<n> | --list | --"
+"independent | --merge-base] [--no-name | --sha1-name] [--topics] [(<rev> | "
+"<glob>)...]"
+msgstr ""
+
+#: builtin/show-branch.c:10
+msgid "git show-branch (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]"
+msgstr ""
+
+#: builtin/show-branch.c:651
+msgid "show remote-tracking and local branches"
+msgstr ""
+
+#: builtin/show-branch.c:653
+msgid "show remote-tracking branches"
+msgstr ""
+
+#: builtin/show-branch.c:655
+msgid "color '*!+-' corresponding to the branch"
+msgstr ""
+
+#: builtin/show-branch.c:657
+msgid "show <n> more commits after the common ancestor"
+msgstr ""
+
+#: builtin/show-branch.c:659
+msgid "synonym to more=-1"
+msgstr ""
+
+#: builtin/show-branch.c:660
+msgid "suppress naming strings"
+msgstr ""
+
+#: builtin/show-branch.c:662
+msgid "include the current branch"
+msgstr ""
+
+#: builtin/show-branch.c:664
+msgid "name commits with their object names"
+msgstr ""
+
+#: builtin/show-branch.c:666
+msgid "show possible merge bases"
+msgstr ""
+
+#: builtin/show-branch.c:668
+msgid "show refs unreachable from any other ref"
+msgstr ""
+
+#: builtin/show-branch.c:670
+msgid "show commits in topological order"
+msgstr ""
+
+#: builtin/show-branch.c:672
+msgid "show only commits not on the first branch"
+msgstr ""
+
+#: builtin/show-branch.c:674
+msgid "show merges reachable from only one tip"
+msgstr ""
+
+#: builtin/show-branch.c:676
+msgid "show commits where no parent comes before its children"
+msgstr ""
+
+#: builtin/show-branch.c:678
+msgid "<n>[,<base>]"
+msgstr ""
+
+#: builtin/show-branch.c:679
+msgid "show <n> most recent ref-log entries starting at base"
+msgstr ""
+
+#: builtin/show-ref.c:10
+msgid ""
+"git show-ref [-q|--quiet] [--verify] [--head] [-d|--dereference] [-s|--hash"
+"[=<n>]] [--abbrev[=<n>]] [--tags] [--heads] [--] [pattern*] "
+msgstr ""
+
+#: builtin/show-ref.c:11
+msgid "git show-ref --exclude-existing[=pattern] < ref-list"
+msgstr ""
+
+#: builtin/show-ref.c:182
+msgid "only show tags (can be combined with heads)"
+msgstr ""
+
+#: builtin/show-ref.c:183
+msgid "only show heads (can be combined with tags)"
+msgstr ""
+
+#: builtin/show-ref.c:184
+msgid "stricter reference checking, requires exact ref path"
+msgstr ""
+
+#: builtin/show-ref.c:187 builtin/show-ref.c:189
+msgid "show the HEAD reference"
+msgstr ""
+
+#: builtin/show-ref.c:191
+msgid "dereference tags into object IDs"
+msgstr ""
+
+#: builtin/show-ref.c:193
+msgid "only show SHA1 hash using <n> digits"
+msgstr ""
+
+#: builtin/show-ref.c:197
+msgid "do not print results to stdout (useful with --verify)"
+msgstr ""
+
+#: builtin/show-ref.c:199
+msgid "show refs from stdin that aren't in local repository"
+msgstr ""
+
+#: builtin/symbolic-ref.c:7
+msgid "git symbolic-ref [options] name [ref]"
+msgstr ""
+
+#: builtin/symbolic-ref.c:38
+msgid "suppress error message for non-symbolic (detached) refs"
+msgstr ""
+
+#: builtin/symbolic-ref.c:39
+msgid "shorten ref output"
+msgstr ""
+
+#: builtin/symbolic-ref.c:40 builtin/update-ref.c:18
+msgid "reason"
+msgstr ""
+
+#: builtin/symbolic-ref.c:40 builtin/update-ref.c:18
+msgid "reason of the update"
+msgstr ""
+
+#: builtin/tag.c:22
+msgid ""
+"git tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]"
+msgstr ""
+
+#: builtin/tag.c:23
+msgid "git tag -d <tagname>..."
+msgstr ""
+
+#: builtin/tag.c:24
+msgid ""
+"git tag -l [-n[<num>]] [--contains <commit>] [--points-at <object>] \n"
+"\t\t[<pattern>...]"
+msgstr ""
+
+#: builtin/tag.c:26
+msgid "git tag -v <tagname>..."
+msgstr ""
+
#: builtin/tag.c:60
#, c-format
msgid "malformed object at '%s'"
@@ -4417,6 +7871,62 @@ msgstr ""
msgid "malformed object name '%s'"
msgstr ""
+#: builtin/tag.c:447
+msgid "list tag names"
+msgstr ""
+
+#: builtin/tag.c:449
+msgid "print <n> lines of each tag message"
+msgstr ""
+
+#: builtin/tag.c:451
+msgid "delete tags"
+msgstr ""
+
+#: builtin/tag.c:452
+msgid "verify tags"
+msgstr ""
+
+#: builtin/tag.c:454
+msgid "Tag creation options"
+msgstr ""
+
+#: builtin/tag.c:456
+msgid "annotated tag, needs a message"
+msgstr ""
+
+#: builtin/tag.c:458
+msgid "tag message"
+msgstr ""
+
+#: builtin/tag.c:460
+msgid "annotated and GPG-signed tag"
+msgstr ""
+
+#: builtin/tag.c:464
+msgid "use another key to sign the tag"
+msgstr ""
+
+#: builtin/tag.c:465
+msgid "replace the tag if exists"
+msgstr ""
+
+#: builtin/tag.c:466
+msgid "show tag list in columns"
+msgstr ""
+
+#: builtin/tag.c:468
+msgid "Tag listing options"
+msgstr ""
+
+#: builtin/tag.c:471
+msgid "print only tags that contain the commit"
+msgstr ""
+
+#: builtin/tag.c:477
+msgid "print only tags of the object"
+msgstr ""
+
#: builtin/tag.c:506
msgid "--column and -n are incompatible"
msgstr ""
@@ -4466,24 +7976,180 @@ msgstr ""
msgid "Updated tag '%s' (was %s)\n"
msgstr ""
-#: git.c:16
-msgid "See 'git help <command>' for more information on a specific command."
+#: builtin/update-index.c:401
+msgid "git update-index [options] [--] [<file>...]"
msgstr ""
-#: parse-options.h:133 parse-options.h:235
-msgid "n"
+#: builtin/update-index.c:717
+msgid "continue refresh even when index needs update"
msgstr ""
-#: parse-options.h:141
-msgid "time"
+#: builtin/update-index.c:720
+msgid "refresh: ignore submodules"
msgstr ""
-#: parse-options.h:149
-msgid "file"
+#: builtin/update-index.c:723
+msgid "do not ignore new files"
msgstr ""
-#: parse-options.h:151
-msgid "when"
+#: builtin/update-index.c:725
+msgid "let files replace directories and vice-versa"
+msgstr ""
+
+#: builtin/update-index.c:727
+msgid "notice files missing from worktree"
+msgstr ""
+
+#: builtin/update-index.c:729
+msgid "refresh even if index contains unmerged entries"
+msgstr ""
+
+#: builtin/update-index.c:732
+msgid "refresh stat information"
+msgstr ""
+
+#: builtin/update-index.c:736
+msgid "like --refresh, but ignore assume-unchanged setting"
+msgstr ""
+
+#: builtin/update-index.c:740
+msgid "<mode> <object> <path>"
+msgstr ""
+
+#: builtin/update-index.c:741
+msgid "add the specified entry to the index"
+msgstr ""
+
+#: builtin/update-index.c:745
+msgid "(+/-)x"
+msgstr ""
+
+#: builtin/update-index.c:746
+msgid "override the executable bit of the listed files"
+msgstr ""
+
+#: builtin/update-index.c:750
+msgid "mark files as \"not changing\""
+msgstr ""
+
+#: builtin/update-index.c:753
+msgid "clear assumed-unchanged bit"
+msgstr ""
+
+#: builtin/update-index.c:756
+msgid "mark files as \"index-only\""
+msgstr ""
+
+#: builtin/update-index.c:759
+msgid "clear skip-worktree bit"
+msgstr ""
+
+#: builtin/update-index.c:762
+msgid "add to index only; do not add content to object database"
+msgstr ""
+
+#: builtin/update-index.c:764
+msgid "remove named paths even if present in worktree"
+msgstr ""
+
+#: builtin/update-index.c:766
+msgid "with --stdin: input lines are terminated by null bytes"
+msgstr ""
+
+#: builtin/update-index.c:768
+msgid "read list of paths to be updated from standard input"
+msgstr ""
+
+#: builtin/update-index.c:772
+msgid "add entries from standard input to the index"
+msgstr ""
+
+#: builtin/update-index.c:776
+msgid "repopulate stages #2 and #3 for the listed paths"
+msgstr ""
+
+#: builtin/update-index.c:780
+msgid "only update entries that differ from HEAD"
+msgstr ""
+
+#: builtin/update-index.c:784
+msgid "ignore files missing from worktree"
+msgstr ""
+
+#: builtin/update-index.c:787
+msgid "report actions to standard output"
+msgstr ""
+
+#: builtin/update-index.c:789
+msgid "(for porcelains) forget saved unresolved conflicts"
+msgstr ""
+
+#: builtin/update-index.c:793
+msgid "write index in this format"
+msgstr ""
+
+#: builtin/update-ref.c:7
+msgid "git update-ref [options] -d <refname> [<oldval>]"
+msgstr ""
+
+#: builtin/update-ref.c:8
+msgid "git update-ref [options] <refname> <newval> [<oldval>]"
+msgstr ""
+
+#: builtin/update-ref.c:19
+msgid "delete the reference"
+msgstr ""
+
+#: builtin/update-ref.c:21
+msgid "update <refname> not the one it points to"
+msgstr ""
+
+#: builtin/update-server-info.c:6
+msgid "git update-server-info [--force]"
+msgstr ""
+
+#: builtin/update-server-info.c:14
+msgid "update the info files from scratch"
+msgstr ""
+
+#: builtin/verify-pack.c:56
+msgid "git verify-pack [-v|--verbose] [-s|--stat-only] <pack>..."
+msgstr ""
+
+#: builtin/verify-pack.c:66
+msgid "verbose"
+msgstr ""
+
+#: builtin/verify-pack.c:68
+msgid "show statistics only"
+msgstr ""
+
+#: builtin/verify-tag.c:17
+msgid "git verify-tag [-v|--verbose] <tag>..."
+msgstr ""
+
+#: builtin/verify-tag.c:73
+msgid "print tag contents"
+msgstr ""
+
+#: builtin/write-tree.c:13
+msgid "git write-tree [--missing-ok] [--prefix=<prefix>/]"
+msgstr ""
+
+#: builtin/write-tree.c:26
+msgid "<prefix>/"
+msgstr ""
+
+#: builtin/write-tree.c:27
+msgid "write tree object for a subdirectory <prefix>"
+msgstr ""
+
+#: builtin/write-tree.c:30
+msgid "only useful for debugging"
+msgstr ""
+
+#: git.c:16
+msgid "See 'git help <command>' for more information on a specific command."
msgstr ""
#: parse-options.h:156
@@ -4599,9 +8265,9 @@ msgstr ""
#: git-am.sh:105
#, sh-format
msgid ""
-"When you have resolved this problem run \"$cmdline --resolved\".\n"
-"If you would prefer to skip this patch, instead run \"$cmdline --skip\".\n"
-"To restore the original branch and stop patching run \"$cmdline --abort\"."
+"When you have resolved this problem, run \"$cmdline --resolved\".\n"
+"If you prefer to skip this patch, run \"$cmdline --skip\" instead.\n"
+"To restore the original branch and stop patching, run \"$cmdline --abort\"."
msgstr ""
#: git-am.sh:121
@@ -4612,6 +8278,10 @@ msgstr ""
msgid "Repository lacks necessary blobs to fall back on 3-way merge."
msgstr ""
+#: git-am.sh:139
+msgid "Using index info to reconstruct a base tree..."
+msgstr ""
+
#: git-am.sh:154
msgid ""
"Did you hand edit your patch?\n"
@@ -4622,42 +8292,48 @@ msgstr ""
msgid "Falling back to patching base and 3-way merge..."
msgstr ""
-#: git-am.sh:275
+#: git-am.sh:179
+msgid "Failed to merge in the changes."
+msgstr ""
+
+#: git-am.sh:274
msgid "Only one StGIT patch series can be applied at once"
msgstr ""
-#: git-am.sh:362
+#: git-am.sh:361
#, sh-format
msgid "Patch format $patch_format is not supported."
msgstr ""
-#: git-am.sh:364
+#: git-am.sh:363
msgid "Patch format detection failed."
msgstr ""
-#: git-am.sh:418
-msgid "-d option is no longer supported. Do not use."
+#: git-am.sh:389
+msgid ""
+"The -b/--binary option has been a no-op for long time, and\n"
+"it will be removed. Please do not use it anymore."
msgstr ""
-#: git-am.sh:481
+#: git-am.sh:477
#, sh-format
msgid "previous rebase directory $dotest still exists but mbox given."
msgstr ""
-#: git-am.sh:486
+#: git-am.sh:482
msgid "Please make up your mind. --skip or --abort?"
msgstr ""
-#: git-am.sh:513
+#: git-am.sh:509
msgid "Resolve operation not in progress, we are not resuming."
msgstr ""
-#: git-am.sh:579
+#: git-am.sh:575
#, sh-format
msgid "Dirty index: cannot apply patches (dirty: $files)"
msgstr ""
-#: git-am.sh:671
+#: git-am.sh:679
#, sh-format
msgid ""
"Patch is empty. Was it split wrong?\n"
@@ -4665,53 +8341,60 @@ msgid ""
"To restore the original branch and stop patching run \"$cmdline --abort\"."
msgstr ""
-#: git-am.sh:708
+#: git-am.sh:706
msgid "Patch does not have a valid e-mail address."
msgstr ""
-#: git-am.sh:755
+#: git-am.sh:753
msgid "cannot be interactive without stdin connected to a terminal."
msgstr ""
-#: git-am.sh:759
+#: git-am.sh:757
msgid "Commit Body is:"
msgstr ""
#. TRANSLATORS: Make sure to include [y], [n], [e], [v] and [a]
#. in your translation. The program will only accept English
#. input at this point.
-#: git-am.sh:766
+#: git-am.sh:764
msgid "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all "
msgstr ""
-#: git-am.sh:802
+#: git-am.sh:800
#, sh-format
msgid "Applying: $FIRSTLINE"
msgstr ""
-#: git-am.sh:823
+#: git-am.sh:821
msgid ""
"No changes - did you forget to use 'git add'?\n"
"If there is nothing left to stage, chances are that something else\n"
"already introduced the same changes; you might want to skip this patch."
msgstr ""
-#: git-am.sh:831
+#: git-am.sh:829
msgid ""
"You still have unmerged paths in your index\n"
"did you forget to use 'git add'?"
msgstr ""
-#: git-am.sh:847
+#: git-am.sh:845
msgid "No changes -- Patch already applied."
msgstr ""
-#: git-am.sh:857
+#: git-am.sh:855
#, sh-format
msgid "Patch failed at $msgnum $FIRSTLINE"
msgstr ""
-#: git-am.sh:873
+#: git-am.sh:858
+#, sh-format
+msgid ""
+"The copy of the patch that failed is found in:\n"
+" $dotest/patch"
+msgstr ""
+
+#: git-am.sh:876
msgid "applying to an empty history"
msgstr ""
@@ -4894,6 +8577,112 @@ msgstr ""
msgid "Cannot rebase onto multiple branches"
msgstr ""
+#: git-rebase.sh:52
+msgid ""
+"When you have resolved this problem, run \"git rebase --continue\".\n"
+"If you prefer to skip this patch, run \"git rebase --skip\" instead.\n"
+"To check out the original branch and stop rebasing, run \"git rebase --abort"
+"\"."
+msgstr ""
+
+#: git-rebase.sh:159
+msgid "The pre-rebase hook refused to rebase."
+msgstr ""
+
+#: git-rebase.sh:164
+msgid "It looks like git-am is in progress. Cannot rebase."
+msgstr ""
+
+#: git-rebase.sh:295
+msgid "The --exec option must be used with the --interactive option"
+msgstr ""
+
+#: git-rebase.sh:300
+msgid "No rebase in progress?"
+msgstr ""
+
+#: git-rebase.sh:313
+msgid "Cannot read HEAD"
+msgstr ""
+
+#: git-rebase.sh:316
+msgid ""
+"You must edit all merge conflicts and then\n"
+"mark them as resolved using git add"
+msgstr ""
+
+#: git-rebase.sh:334
+#, sh-format
+msgid "Could not move back to $head_name"
+msgstr ""
+
+#: git-rebase.sh:350
+#, sh-format
+msgid ""
+"It seems that there is already a $state_dir_base directory, and\n"
+"I wonder if you are in the middle of another rebase. If that is the\n"
+"case, please try\n"
+"\t$cmd_live_rebase\n"
+"If that is not the case, please\n"
+"\t$cmd_clear_stale_rebase\n"
+"and run me again. I am stopping in case you still have something\n"
+"valuable there."
+msgstr ""
+
+#: git-rebase.sh:395
+#, sh-format
+msgid "invalid upstream $upstream_name"
+msgstr ""
+
+#: git-rebase.sh:419
+#, sh-format
+msgid "$onto_name: there are more than one merge bases"
+msgstr ""
+
+#: git-rebase.sh:422 git-rebase.sh:426
+#, sh-format
+msgid "$onto_name: there is no merge base"
+msgstr ""
+
+#: git-rebase.sh:431
+#, sh-format
+msgid "Does not point to a valid commit: $onto_name"
+msgstr ""
+
+#: git-rebase.sh:454
+#, sh-format
+msgid "fatal: no such branch: $branch_name"
+msgstr ""
+
+#: git-rebase.sh:474
+msgid "Please commit or stash them."
+msgstr ""
+
+#: git-rebase.sh:492
+#, sh-format
+msgid "Current branch $branch_name is up to date."
+msgstr ""
+
+#: git-rebase.sh:495
+#, sh-format
+msgid "Current branch $branch_name is up to date, rebase forced."
+msgstr ""
+
+#: git-rebase.sh:506
+#, sh-format
+msgid "Changes from $mb to $onto:"
+msgstr ""
+
+#. Detach HEAD and reset the tree
+#: git-rebase.sh:515
+msgid "First, rewinding head to replay your work on top of it..."
+msgstr ""
+
+#: git-rebase.sh:523
+#, sh-format
+msgid "Fast-forwarded $branch_name to $onto_name."
+msgstr ""
+
#: git-stash.sh:51
msgid "git stash clear with parameters is unimplemented"
msgstr ""
@@ -4999,59 +8788,59 @@ msgstr ""
msgid "Cannot unstage modified files"
msgstr ""
-#: git-stash.sh:474
+#: git-stash.sh:475
msgid "Index was not unstashed."
msgstr ""
-#: git-stash.sh:491
+#: git-stash.sh:492
#, sh-format
msgid "Dropped ${REV} ($s)"
msgstr ""
-#: git-stash.sh:492
+#: git-stash.sh:493
#, sh-format
msgid "${REV}: Could not drop stash entry"
msgstr ""
-#: git-stash.sh:499
+#: git-stash.sh:500
msgid "No branch name specified"
msgstr ""
-#: git-stash.sh:570
+#: git-stash.sh:571
msgid "(To restore them type \"git stash apply\")"
msgstr ""
-#: git-submodule.sh:56
+#: git-submodule.sh:88
#, sh-format
msgid "cannot strip one component off url '$remoteurl'"
msgstr ""
-#: git-submodule.sh:109
+#: git-submodule.sh:167
#, sh-format
msgid "No submodule mapping found in .gitmodules for path '$sm_path'"
msgstr ""
-#: git-submodule.sh:150
+#: git-submodule.sh:211
#, sh-format
msgid "Clone of '$url' into submodule path '$sm_path' failed"
msgstr ""
-#: git-submodule.sh:160
+#: git-submodule.sh:223
#, sh-format
msgid "Gitdir '$a' is part of the submodule path '$b' or vice versa"
msgstr ""
-#: git-submodule.sh:249
+#: git-submodule.sh:312
#, sh-format
msgid "repo URL: '$repo' must be absolute or begin with ./|../"
msgstr ""
-#: git-submodule.sh:266
+#: git-submodule.sh:329
#, sh-format
msgid "'$sm_path' already exists in the index"
msgstr ""
-#: git-submodule.sh:270
+#: git-submodule.sh:333
#, sh-format
msgid ""
"The following path is ignored by one of your .gitignore files:\n"
@@ -5059,155 +8848,151 @@ msgid ""
"Use -f if you really want to add it."
msgstr ""
-#: git-submodule.sh:281
+#: git-submodule.sh:344
#, sh-format
msgid "Adding existing repo at '$sm_path' to the index"
msgstr ""
-#: git-submodule.sh:283
+#: git-submodule.sh:346
#, sh-format
msgid "'$sm_path' already exists and is not a valid git repo"
msgstr ""
-#: git-submodule.sh:297
+#: git-submodule.sh:360
#, sh-format
msgid "Unable to checkout submodule '$sm_path'"
msgstr ""
-#: git-submodule.sh:302
+#: git-submodule.sh:365
#, sh-format
msgid "Failed to add submodule '$sm_path'"
msgstr ""
-#: git-submodule.sh:307
+#: git-submodule.sh:370
#, sh-format
msgid "Failed to register submodule '$sm_path'"
msgstr ""
-#: git-submodule.sh:349
+#: git-submodule.sh:413
#, sh-format
msgid "Entering '$prefix$sm_path'"
msgstr ""
-#: git-submodule.sh:363
+#: git-submodule.sh:427
#, sh-format
msgid "Stopping at '$sm_path'; script returned non-zero status."
msgstr ""
-#: git-submodule.sh:406
+#: git-submodule.sh:471
#, sh-format
msgid "No url found for submodule path '$sm_path' in .gitmodules"
msgstr ""
-#: git-submodule.sh:415
+#: git-submodule.sh:480
#, sh-format
msgid "Failed to register url for submodule path '$sm_path'"
msgstr ""
-#: git-submodule.sh:417
+#: git-submodule.sh:482
#, sh-format
msgid "Submodule '$name' ($url) registered for path '$sm_path'"
msgstr ""
-#: git-submodule.sh:425
+#: git-submodule.sh:490
#, sh-format
msgid "Failed to register update mode for submodule path '$sm_path'"
msgstr ""
-#: git-submodule.sh:524
+#: git-submodule.sh:590
#, sh-format
msgid ""
"Submodule path '$sm_path' not initialized\n"
"Maybe you want to use 'update --init'?"
msgstr ""
-#: git-submodule.sh:537
+#: git-submodule.sh:603
#, sh-format
msgid "Unable to find current revision in submodule path '$sm_path'"
msgstr ""
-#: git-submodule.sh:556
+#: git-submodule.sh:622
#, sh-format
msgid "Unable to fetch in submodule path '$sm_path'"
msgstr ""
-#: git-submodule.sh:570
+#: git-submodule.sh:636
#, sh-format
msgid "Unable to rebase '$sha1' in submodule path '$sm_path'"
msgstr ""
-#: git-submodule.sh:571
+#: git-submodule.sh:637
#, sh-format
msgid "Submodule path '$sm_path': rebased into '$sha1'"
msgstr ""
-#: git-submodule.sh:576
+#: git-submodule.sh:642
#, sh-format
msgid "Unable to merge '$sha1' in submodule path '$sm_path'"
msgstr ""
-#: git-submodule.sh:577
+#: git-submodule.sh:643
#, sh-format
msgid "Submodule path '$sm_path': merged in '$sha1'"
msgstr ""
-#: git-submodule.sh:582
+#: git-submodule.sh:648
#, sh-format
msgid "Unable to checkout '$sha1' in submodule path '$sm_path'"
msgstr ""
-#: git-submodule.sh:583
+#: git-submodule.sh:649
#, sh-format
msgid "Submodule path '$sm_path': checked out '$sha1'"
msgstr ""
-#: git-submodule.sh:605 git-submodule.sh:928
+#: git-submodule.sh:671 git-submodule.sh:995
#, sh-format
msgid "Failed to recurse into submodule path '$sm_path'"
msgstr ""
-#: git-submodule.sh:713
-msgid "--cached cannot be used with --files"
+#: git-submodule.sh:779
+msgid "The --cached option cannot be used with the --files option"
msgstr ""
#. unexpected type
-#: git-submodule.sh:753
+#: git-submodule.sh:819
#, sh-format
msgid "unexpected mode $mod_dst"
msgstr ""
-#: git-submodule.sh:771
+#: git-submodule.sh:837
#, sh-format
msgid " Warn: $name doesn't contain commit $sha1_src"
msgstr ""
-#: git-submodule.sh:774
+#: git-submodule.sh:840
#, sh-format
msgid " Warn: $name doesn't contain commit $sha1_dst"
msgstr ""
-#: git-submodule.sh:777
+#: git-submodule.sh:843
#, sh-format
msgid " Warn: $name doesn't contain commits $sha1_src and $sha1_dst"
msgstr ""
-#: git-submodule.sh:802
+#: git-submodule.sh:868
msgid "blob"
msgstr ""
-#: git-submodule.sh:803
-msgid "submodule"
-msgstr ""
-
-#: git-submodule.sh:840
+#: git-submodule.sh:906
msgid "# Submodules changed but not updated:"
msgstr ""
-#: git-submodule.sh:842
+#: git-submodule.sh:908
msgid "# Submodule changes to be committed:"
msgstr ""
-#: git-submodule.sh:974
+#: git-submodule.sh:1054
#, sh-format
msgid "Synchronizing submodule url for '$name'"
msgstr ""
diff --git a/po/sv.po b/po/sv.po
index b0ff6f9..7ce7e58 100644
--- a/po/sv.po
+++ b/po/sv.po
@@ -5,10 +5,10 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: git 1.7.10\n"
+"Project-Id-Version: git 1.7.12\n"
"Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2012-06-08 10:20+0800\n"
-"PO-Revision-Date: 2012-07-01 22:59+0100\n"
+"POT-Creation-Date: 2012-09-15 10:21+0800\n"
+"PO-Revision-Date: 2012-10-02 08:15+0100\n"
"Last-Translator: Peter Krefting <peter@softwolves.pp.se>\n"
"Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n"
"Language: sv\n"
@@ -38,6 +38,94 @@ msgstr ""
"lämpligt för att ange lösning och checka in,\n"
"eller använd \"git commit -a\"."
+#: archive.c:10
+msgid "git archive [options] <tree-ish> [<path>...]"
+msgstr "git archive [flaggor] <träd-igt> [<sökväg>...]"
+
+#: archive.c:11
+msgid "git archive --list"
+msgstr "git archive --list"
+
+#: archive.c:12
+msgid ""
+"git archive --remote <repo> [--exec <cmd>] [options] <tree-ish> [<path>...]"
+msgstr ""
+"git archive --remote <arkiv> [--exec <kmd>] [flaggor] <träd-igt> "
+"[<sökväg>...]"
+
+#: archive.c:13
+msgid "git archive --remote <repo> [--exec <cmd>] --list"
+msgstr "git archive --remote <arkiv> [--exec <kmd>] --list"
+
+#: archive.c:322
+msgid "fmt"
+msgstr "fmt"
+
+#: archive.c:322
+msgid "archive format"
+msgstr "arkivformat"
+
+#: archive.c:323 builtin/log.c:1079
+msgid "prefix"
+msgstr "prefix"
+
+#: archive.c:324
+msgid "prepend prefix to each pathname in the archive"
+msgstr "lägg till prefix till varje sökväg i arkivet"
+
+# %s är ett verb ("Untracked"/"Ignored"); lägg till ett -e.
+#: archive.c:325 builtin/archive.c:91 builtin/blame.c:2332
+#: builtin/blame.c:2333 builtin/config.c:56 builtin/fast-export.c:642
+#: builtin/fast-export.c:644 builtin/grep.c:800 builtin/hash-object.c:77
+#: builtin/ls-files.c:494 builtin/ls-files.c:497 builtin/notes.c:537
+#: builtin/notes.c:694 builtin/read-tree.c:107 parse-options.h:149
+msgid "file"
+msgstr "fil"
+
+#: archive.c:326 builtin/archive.c:92
+msgid "write the archive to this file"
+msgstr "skriv arkivet till filen"
+
+#: archive.c:328
+msgid "read .gitattributes in working directory"
+msgstr "läs .gitattributes i arbetskatalogen"
+
+#: archive.c:329
+msgid "report archived files on stderr"
+msgstr "rapportera arkiverade filer på standard fel"
+
+#: archive.c:330
+msgid "store only"
+msgstr "endast spara"
+
+#: archive.c:331
+msgid "compress faster"
+msgstr "komprimera snabbare"
+
+#: archive.c:339
+msgid "compress better"
+msgstr "komprimera bättre"
+
+#: archive.c:342
+msgid "list supported archive formats"
+msgstr "visa understödda arkivformat"
+
+#: archive.c:344 builtin/archive.c:93 builtin/clone.c:85
+msgid "repo"
+msgstr "arkiv"
+
+#: archive.c:345 builtin/archive.c:94
+msgid "retrieve the archive from remote repository <repo>"
+msgstr "hämta arkivet från fjärrarkivet <arkiv>"
+
+#: archive.c:346 builtin/archive.c:95 builtin/notes.c:616
+msgid "command"
+msgstr "kommando"
+
+#: archive.c:347 builtin/archive.c:96
+msgid "path to the remote git-upload-archive command"
+msgstr "sökväg till kommandot git-upload-archive på fjärren"
+
#: bundle.c:36
#, c-format
msgid "'%s' does not look like a v2 bundle file"
@@ -48,7 +136,7 @@ msgstr "'%s' ser inte ut som en v2-bundle-fil"
msgid "unrecognized header: %s%s (%d)"
msgstr "okänt huvud: %s%s (%d)"
-#: bundle.c:89 builtin/commit.c:696
+#: bundle.c:89 builtin/commit.c:714
#, c-format
msgid "could not open '%s'"
msgstr "kunde inte öppna \"%s\""
@@ -57,8 +145,8 @@ msgstr "kunde inte öppna \"%s\""
msgid "Repository lacks these prerequisite commits:"
msgstr "Arkivet saknar dessa nödvändiga incheckningar:"
-#: bundle.c:164 sequencer.c:550 sequencer.c:982 builtin/log.c:289
-#: builtin/log.c:720 builtin/log.c:1309 builtin/log.c:1528 builtin/merge.c:347
+#: bundle.c:164 sequencer.c:557 sequencer.c:989 builtin/log.c:290
+#: builtin/log.c:727 builtin/log.c:1313 builtin/log.c:1529 builtin/merge.c:347
#: builtin/shortlog.c:181
msgid "revision walk setup failed"
msgstr "misslyckades skapa revisionstraversering"
@@ -71,44 +159,48 @@ msgstr[0] "Paketet (bundlen) innehåller %d referens"
msgstr[1] "Paketet (bundlen) innehåller %d referenser"
#: bundle.c:192
+msgid "The bundle records a complete history."
+msgstr "Paketet (bundlen) beskriver en komplett historik."
+
+#: bundle.c:195
#, c-format
msgid "The bundle requires this ref"
msgid_plural "The bundle requires these %d refs"
msgstr[0] "Paketet (bundlen) kräver denna referens"
msgstr[1] "Paketet (bundlen) kräver dessa %d referenser"
-#: bundle.c:290
+#: bundle.c:294
msgid "rev-list died"
msgstr "rev-list dog"
-#: bundle.c:296 builtin/log.c:1205 builtin/shortlog.c:284
+#: bundle.c:300 builtin/log.c:1209 builtin/shortlog.c:284
#, c-format
msgid "unrecognized argument: %s"
msgstr "okänt argument: %s"
-#: bundle.c:331
+#: bundle.c:335
#, c-format
msgid "ref '%s' is excluded by the rev-list options"
msgstr "referensen \"%s\" exkluderas av argumenten till rev-list"
-#: bundle.c:376
+#: bundle.c:380
msgid "Refusing to create empty bundle."
msgstr "Vägrar skapa ett tomt paket (bundle)."
-#: bundle.c:394
+#: bundle.c:398
msgid "Could not spawn pack-objects"
msgstr "Kunde inte starta pack-objects"
-#: bundle.c:412
+#: bundle.c:416
msgid "pack-objects died"
msgstr "pack-objects misslyckades"
-#: bundle.c:415
+#: bundle.c:419
#, c-format
msgid "cannot create '%s'"
msgstr "kan inte skapa \"%s\""
-#: bundle.c:437
+#: bundle.c:441
msgid "index-pack died"
msgstr "index-pack dog"
@@ -226,32 +318,32 @@ msgstr ""
"Hittade fel i konfigurationsvariabeln \"diff.dirstat\":\n"
"%s"
-#: diff.c:1400
-msgid " 0 files changed\n"
-msgstr " 0 filer ändrade\n"
+#: diff.c:1401
+msgid " 0 files changed"
+msgstr " 0 filer ändrade"
-#: diff.c:1404
+#: diff.c:1405
#, c-format
msgid " %d file changed"
msgid_plural " %d files changed"
msgstr[0] " %d fil ändrad"
msgstr[1] " %d filer ändrade"
-#: diff.c:1421
+#: diff.c:1422
#, c-format
msgid ", %d insertion(+)"
msgid_plural ", %d insertions(+)"
msgstr[0] ", %d tillägg(+)"
msgstr[1] ", %d tillägg(+)"
-#: diff.c:1432
+#: diff.c:1433
#, c-format
msgid ", %d deletion(-)"
msgid_plural ", %d deletions(-)"
msgstr[0] ", %d borttagning(-)"
msgstr[1] ", %d borttagningar(-)"
-#: diff.c:3478
+#: diff.c:3460
#, c-format
msgid ""
"Failed to parse --dirstat/-X option parameter:\n"
@@ -287,16 +379,16 @@ msgstr "\"%s\": %s"
msgid "'%s': short read %s"
msgstr "\"%s\": kort läsning %s"
-#: help.c:207
+#: help.c:212
#, c-format
msgid "available git commands in '%s'"
msgstr "git-kommandon tillgängliga i \"%s\""
-#: help.c:214
+#: help.c:219
msgid "git commands available from elsewhere on your $PATH"
msgstr "git-kommandon från andra platser i din $PATH"
-#: help.c:270
+#: help.c:275
#, c-format
msgid ""
"'%s' appears to be a git command, but we were not\n"
@@ -305,11 +397,11 @@ msgstr ""
"\"%s\" verkar vara ett git-kommando, men vi kan inte\n"
"köra det. Kanske git-%s är trasigt?"
-#: help.c:327
+#: help.c:332
msgid "Uh oh. Your system reports no Git commands at all."
msgstr "Oj då. Ditt system rapporterar inga Git-kommandon alls."
-#: help.c:349
+#: help.c:354
#, c-format
msgid ""
"WARNING: You called a Git command named '%s', which does not exist.\n"
@@ -318,17 +410,17 @@ msgstr ""
"VARNING: Du anropade ett Git-kommando vid namn \"%s\", som inte finns.\n"
"Fortsätter under förutsättningen att du menade \"%s\""
-#: help.c:354
+#: help.c:359
#, c-format
msgid "in %0.1f seconds automatically..."
msgstr "automatiskt om %0.1f sekunder..."
-#: help.c:361
+#: help.c:366
#, c-format
msgid "git: '%s' is not a git command. See 'git --help'."
msgstr "git: \"%s\" är inte ett git-kommando. Se \"git --help\"."
-#: help.c:365
+#: help.c:370
msgid ""
"\n"
"Did you mean this?"
@@ -342,35 +434,289 @@ msgstr[1] ""
"\n"
"Menade du ett av dessa?"
-#: parse-options.c:493
+#: merge-recursive.c:190
+#, c-format
+msgid "(bad commit)\n"
+msgstr "(felaktig incheckning)\n"
+
+#: merge-recursive.c:206
+#, c-format
+msgid "addinfo_cache failed for path '%s'"
+msgstr "addinfo_cache misslyckades för sökvägen \"%s\""
+
+#: merge-recursive.c:268
+msgid "error building trees"
+msgstr "fel vid byggande av träd"
+
+#: merge-recursive.c:672
+#, c-format
+msgid "failed to create path '%s'%s"
+msgstr "misslyckades skapa sökvägen \"%s\"%s"
+
+#: merge-recursive.c:683
+#, c-format
+msgid "Removing %s to make room for subdirectory\n"
+msgstr "Tar bort %s för att göra plats för underkatalog\n"
+
+#. something else exists
+#. .. but not some other error (who really cares what?)
+#: merge-recursive.c:697 merge-recursive.c:718
+msgid ": perhaps a D/F conflict?"
+msgstr ": kanske en K/F-konflikt?"
+
+#: merge-recursive.c:708
+#, c-format
+msgid "refusing to lose untracked file at '%s'"
+msgstr "vägrar förlora ospårad fil vid \"%s\""
+
+#: merge-recursive.c:748
+#, c-format
+msgid "cannot read object %s '%s'"
+msgstr "kan inte läsa objektet %s: \"%s\""
+
+#: merge-recursive.c:750
+#, c-format
+msgid "blob expected for %s '%s'"
+msgstr "blob förväntades för %s \"%s\""
+
+#: merge-recursive.c:773 builtin/clone.c:302
+#, c-format
+msgid "failed to open '%s'"
+msgstr "misslyckades öppna \"%s\""
+
+#: merge-recursive.c:781
+#, c-format
+msgid "failed to symlink '%s'"
+msgstr "misslyckades ta skapa symboliska länken \"%s\""
+
+#: merge-recursive.c:784
+#, c-format
+msgid "do not know what to do with %06o %s '%s'"
+msgstr "vet inte hur %06o %s \"%s\" skall hanteras"
+
+#: merge-recursive.c:922
+msgid "Failed to execute internal merge"
+msgstr "Misslyckades exekvera intern sammanslagning"
+
+#: merge-recursive.c:926
+#, c-format
+msgid "Unable to add %s to database"
+msgstr "Kunde inte lägga till %s till databasen"
+
+#: merge-recursive.c:942
+msgid "unsupported object type in the tree"
+msgstr "objekttyp som ej stöds upptäcktes i trädet"
+
+#: merge-recursive.c:1021 merge-recursive.c:1035
+#, c-format
+msgid ""
+"CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left "
+"in tree."
+msgstr ""
+"KONFLIKT (%s/radera): %s raderad i %s och %s i %s. Versionen %s av %s lämnad "
+"i trädet."
+
+#: merge-recursive.c:1027 merge-recursive.c:1040
+#, c-format
+msgid ""
+"CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left "
+"in tree at %s."
+msgstr ""
+"KONFLIKT (%s/radera): %s raderad i %s och %s i %s. Versionen %s av %s lämnad "
+"i trädet vid %s."
+
+#: merge-recursive.c:1081
+msgid "rename"
+msgstr "namnbyte"
+
+#: merge-recursive.c:1081
+msgid "renamed"
+msgstr "namnbytt"
+
+#: merge-recursive.c:1137
+#, c-format
+msgid "%s is a directory in %s adding as %s instead"
+msgstr "%s är en katalog i %s lägger till som %s istället"
+
+#: merge-recursive.c:1159
+#, c-format
+msgid ""
+"CONFLICT (rename/rename): Rename \"%s\"->\"%s\" in branch \"%s\" rename \"%s"
+"\"->\"%s\" in \"%s\"%s"
+msgstr ""
+"KONFLIKT (namnbyte/namnbyte): Namnbyte \"%s\"->\"%s\" på grenen \"%s\" "
+"namnbyte \"%s\"->\"%s\" i \"%s\"%s"
+
+#: merge-recursive.c:1164
+msgid " (left unresolved)"
+msgstr " (lämnad olöst)"
+
+#: merge-recursive.c:1218
+#, c-format
+msgid "CONFLICT (rename/rename): Rename %s->%s in %s. Rename %s->%s in %s"
+msgstr ""
+"KONFLIKT (namnbyte/namnbyte): Namnbyte %s->%s i %s. Namnbyte %s->%s i %s"
+
+#: merge-recursive.c:1248
+#, c-format
+msgid "Renaming %s to %s and %s to %s instead"
+msgstr "Byter namn på %s till %s och %s till %s istället"
+
+#: merge-recursive.c:1447
+#, c-format
+msgid "CONFLICT (rename/add): Rename %s->%s in %s. %s added in %s"
+msgstr "KONFLIKT (namnbyte/tillägg): Namnbyte %s->%s i %s. %s tillagd i %s"
+
+#: merge-recursive.c:1457
+#, c-format
+msgid "Adding merged %s"
+msgstr "Lägger till sammanslagen %s"
+
+#: merge-recursive.c:1462 merge-recursive.c:1660
+#, c-format
+msgid "Adding as %s instead"
+msgstr "Lägger till som %s iställer"
+
+#: merge-recursive.c:1513
+#, c-format
+msgid "cannot read object %s"
+msgstr "kan inte läsa objektet %s"
+
+#: merge-recursive.c:1516
+#, c-format
+msgid "object %s is not a blob"
+msgstr "objektet %s är inte en blob"
+
+#: merge-recursive.c:1564
+msgid "modify"
+msgstr "ändra"
+
+#: merge-recursive.c:1564
+msgid "modified"
+msgstr "ändrad"
+
+#: merge-recursive.c:1574
+msgid "content"
+msgstr "innehåll"
+
+#: merge-recursive.c:1581
+msgid "add/add"
+msgstr "tillägg/tillägg"
+
+#: merge-recursive.c:1615
+#, c-format
+msgid "Skipped %s (merged same as existing)"
+msgstr "Hoppade över %s (sammanslagen samma som befintlig)"
+
+#: merge-recursive.c:1629
+#, c-format
+msgid "Auto-merging %s"
+msgstr "Slår ihop %s automatiskt"
+
+#: merge-recursive.c:1633 git-submodule.sh:869
+msgid "submodule"
+msgstr "undermodul"
+
+#: merge-recursive.c:1634
+#, c-format
+msgid "CONFLICT (%s): Merge conflict in %s"
+msgstr "KONFLIKT (%s): Sammanslagningskonflikt i %s"
+
+#: merge-recursive.c:1724
+#, c-format
+msgid "Removing %s"
+msgstr "Tar bort %s"
+
+#: merge-recursive.c:1749
+msgid "file/directory"
+msgstr "fil/katalog"
+
+#: merge-recursive.c:1755
+msgid "directory/file"
+msgstr "katalog/fil"
+
+#: merge-recursive.c:1760
+#, c-format
+msgid "CONFLICT (%s): There is a directory with name %s in %s. Adding %s as %s"
+msgstr ""
+"KONFLIKT (%s): Det finns en katalog med namnet %s i %s. Lägger till %s som %s"
+
+#: merge-recursive.c:1770
+#, c-format
+msgid "Adding %s"
+msgstr "Lägger till %s"
+
+#: merge-recursive.c:1787
+msgid "Fatal merge failure, shouldn't happen."
+msgstr "Ödesdigert sammanslagningsfel, borde inte inträffa."
+
+#: merge-recursive.c:1806
+msgid "Already up-to-date!"
+msgstr "Redan à jour!"
+
+#: merge-recursive.c:1815
+#, c-format
+msgid "merging of trees %s and %s failed"
+msgstr "sammanslagning av träden %s och %s misslyckades"
+
+#: merge-recursive.c:1845
+#, c-format
+msgid "Unprocessed path??? %s"
+msgstr "Obehandlad sökväg??? %s"
+
+#: merge-recursive.c:1890
+msgid "Merging:"
+msgstr "Slår ihop:"
+
+#: merge-recursive.c:1903
+#, c-format
+msgid "found %u common ancestor:"
+msgid_plural "found %u common ancestors:"
+msgstr[0] "hittade %u gemensam förfader:"
+msgstr[1] "hittade %u gemensamma förfäder:"
+
+#: merge-recursive.c:1940
+msgid "merge returned no commit"
+msgstr "sammanslagningen returnerade ingen incheckning"
+
+#: merge-recursive.c:1997
+#, c-format
+msgid "Could not parse object '%s'"
+msgstr "Kunde inte tolka objektet \"%s\""
+
+#: merge-recursive.c:2009 builtin/merge.c:696
+msgid "Unable to write index."
+msgstr "Kunde inte skriva indexet."
+
+#: parse-options.c:494
msgid "..."
msgstr "..."
-#: parse-options.c:511
+#: parse-options.c:512
#, c-format
msgid "usage: %s"
msgstr "användning: %s"
#. TRANSLATORS: the colon here should align with the
#. one in "usage: %s" translation
-#: parse-options.c:515
+#: parse-options.c:516
#, c-format
msgid " or: %s"
msgstr " eller: %s"
-#: parse-options.c:518
+#: parse-options.c:519
#, c-format
msgid " %s"
msgstr " %s"
-#: remote.c:1629
+#: remote.c:1632
#, c-format
msgid "Your branch is ahead of '%s' by %d commit.\n"
msgid_plural "Your branch is ahead of '%s' by %d commits.\n"
msgstr[0] "Din gren ligger före \"%s\" med %d incheckning.\n"
msgstr[1] "Din gren ligger före \"%s\" med %d incheckningar.\n"
-#: remote.c:1635
+#: remote.c:1638
#, c-format
msgid "Your branch is behind '%s' by %d commit, and can be fast-forwarded.\n"
msgid_plural ""
@@ -380,7 +726,7 @@ msgstr[0] ""
msgstr[1] ""
"Din gren ligger efter \"%s\" med %d incheckningar, och kan snabbspolas.\n"
-#: remote.c:1643
+#: remote.c:1646
#, c-format
msgid ""
"Your branch and '%s' have diverged,\n"
@@ -395,14 +741,14 @@ msgstr[1] ""
"Din gren och \"%s\" har divergerat,\n"
"och har %d respektive %d olika incheckningar.\n"
-#: sequencer.c:121 builtin/merge.c:865 builtin/merge.c:978
-#: builtin/merge.c:1088 builtin/merge.c:1098
+#: sequencer.c:121 builtin/merge.c:864 builtin/merge.c:977
+#: builtin/merge.c:1087 builtin/merge.c:1097
#, c-format
msgid "Could not open '%s' for writing"
msgstr "Kunde inte öppna \"%s\" för skrivning"
-#: sequencer.c:123 builtin/merge.c:333 builtin/merge.c:868
-#: builtin/merge.c:1090 builtin/merge.c:1103
+#: sequencer.c:123 builtin/merge.c:333 builtin/merge.c:867
+#: builtin/merge.c:1089 builtin/merge.c:1102
#, c-format
msgid "Could not write to '%s'"
msgstr "Kunde inte skriva till \"%s\""
@@ -425,7 +771,7 @@ msgstr ""
"med \"git add <sökvägar>\" eller \"git rm <sökvägar>\"\n"
"och checka in resultatet med \"git commit\""
-#: sequencer.c:160 sequencer.c:758 sequencer.c:841
+#: sequencer.c:160 sequencer.c:765 sequencer.c:848
#, c-format
msgid "Could not write to %s"
msgstr "Kunde inte skriva till %s"
@@ -461,452 +807,574 @@ msgstr "Kunde inte bestämma HEAD:s incheckning\n"
msgid "Unable to update cache tree\n"
msgstr "Kan inte uppdatera cacheträd\n"
-#: sequencer.c:324
+#: sequencer.c:327
#, c-format
msgid "Could not parse commit %s\n"
msgstr "Kunde inte tolka incheckningen %s\n"
-#: sequencer.c:329
+#: sequencer.c:332
#, c-format
msgid "Could not parse parent commit %s\n"
msgstr "Kunde inte tolka föräldraincheckningen %s\n"
-#: sequencer.c:395
+#: sequencer.c:398
msgid "Your index file is unmerged."
msgstr "Din indexfil har inte slagits ihop."
-#: sequencer.c:398
+#: sequencer.c:401
msgid "You do not have a valid HEAD"
msgstr "Du har ingen giltig HEAD"
-#: sequencer.c:413
+#: sequencer.c:416
#, c-format
msgid "Commit %s is a merge but no -m option was given."
msgstr "Incheckning %s är en sammanslagning, men flaggan -m angavs inte."
-#: sequencer.c:421
+#: sequencer.c:424
#, c-format
msgid "Commit %s does not have parent %d"
msgstr "Incheckning %s har inte förälder %d"
-#: sequencer.c:425
+#: sequencer.c:428
#, c-format
msgid "Mainline was specified but commit %s is not a merge."
msgstr "Huvudlinje angavs, men incheckningen %s är inte en sammanslagning"
#. TRANSLATORS: The first %s will be "revert" or
#. "cherry-pick", the second %s a SHA1
-#: sequencer.c:436
+#: sequencer.c:439
#, c-format
msgid "%s: cannot parse parent commit %s"
msgstr "%s: kan inte tolka föräldraincheckningen %s"
-#: sequencer.c:440
+#: sequencer.c:443
#, c-format
msgid "Cannot get commit message for %s"
msgstr "Kan inte hämta incheckningsmeddelande för %s"
-#: sequencer.c:524
+#: sequencer.c:527
#, c-format
msgid "could not revert %s... %s"
msgstr "kunde inte ångra %s... %s"
-#: sequencer.c:525
+#: sequencer.c:528
#, c-format
msgid "could not apply %s... %s"
msgstr "kunde inte tillämpa %s... %s"
-#: sequencer.c:553
+#: sequencer.c:560
msgid "empty commit set passed"
msgstr "den angivna uppsättningen incheckningar är tom"
-#: sequencer.c:561
+#: sequencer.c:568
#, c-format
msgid "git %s: failed to read the index"
msgstr "git %s: misslyckades läsa indexet"
-#: sequencer.c:566
+#: sequencer.c:573
#, c-format
msgid "git %s: failed to refresh the index"
msgstr "git %s: misslyckades uppdatera indexet"
-#: sequencer.c:624
+#: sequencer.c:631
#, c-format
msgid "Cannot %s during a %s"
msgstr "kan inte %s under en %s"
-#: sequencer.c:646
+#: sequencer.c:653
#, c-format
msgid "Could not parse line %d."
msgstr "Kan inte tolka rad %d."
-#: sequencer.c:651
+#: sequencer.c:658
msgid "No commits parsed."
msgstr "Inga incheckningar lästes."
-#: sequencer.c:664
+#: sequencer.c:671
#, c-format
msgid "Could not open %s"
msgstr "Kunde inte öppna %s"
-#: sequencer.c:668
+#: sequencer.c:675
#, c-format
msgid "Could not read %s."
msgstr "kunde inte läsa %s."
-#: sequencer.c:675
+#: sequencer.c:682
#, c-format
msgid "Unusable instruction sheet: %s"
msgstr "Oanvändbart manus: %s"
-#: sequencer.c:703
+#: sequencer.c:710
#, c-format
msgid "Invalid key: %s"
msgstr "Felaktig nyckel: %s"
-#: sequencer.c:706
+#: sequencer.c:713
#, c-format
msgid "Invalid value for %s: %s"
msgstr "Felaktigt värde för %s: %s"
-#: sequencer.c:718
+#: sequencer.c:725
#, c-format
msgid "Malformed options sheet: %s"
msgstr "Trasigt manus: %s"
-#: sequencer.c:739
+#: sequencer.c:746
msgid "a cherry-pick or revert is already in progress"
msgstr "en \"cherry-pick\" eller \"revert\" pågår redan"
-#: sequencer.c:740
+#: sequencer.c:747
msgid "try \"git cherry-pick (--continue | --quit | --abort)\""
msgstr "testa \"git cherry-pick (--continue | --quit | --abort)\""
-#: sequencer.c:744
+#: sequencer.c:751
#, c-format
msgid "Could not create sequencer directory %s"
msgstr "Kunde inte skapa \"sequencer\"-katalogen \"%s\""
-#: sequencer.c:760 sequencer.c:845
+#: sequencer.c:767 sequencer.c:852
#, c-format
msgid "Error wrapping up %s."
msgstr "Fel vid ombrytning av %s."
-#: sequencer.c:779 sequencer.c:913
+#: sequencer.c:786 sequencer.c:920
msgid "no cherry-pick or revert in progress"
msgstr "ingen \"cherry-pick\" eller \"revert\" pågår"
-#: sequencer.c:781
+#: sequencer.c:788
msgid "cannot resolve HEAD"
msgstr "kan inte bestämma HEAD"
-#: sequencer.c:783
+#: sequencer.c:790
msgid "cannot abort from a branch yet to be born"
msgstr "kan inte avbryta från en gren som ännu inte är född"
-#: sequencer.c:805 builtin/apply.c:3697
+#: sequencer.c:812 builtin/apply.c:4005
#, c-format
msgid "cannot open %s: %s"
msgstr "kan inte öppna %s: %s"
-#: sequencer.c:808
+#: sequencer.c:815
#, c-format
msgid "cannot read %s: %s"
msgstr "kan inte läsa %s: %s"
-#: sequencer.c:809
+#: sequencer.c:816
msgid "unexpected end of file"
msgstr "oväntat filslut"
-#: sequencer.c:815
+#: sequencer.c:822
#, c-format
msgid "stored pre-cherry-pick HEAD file '%s' is corrupt"
msgstr "sparad HEAD-fil från före \"cherry-pick\", \"%s\", är trasig"
-#: sequencer.c:838
+#: sequencer.c:845
#, c-format
msgid "Could not format %s."
msgstr "Kunde inte formatera %s."
-#: sequencer.c:1000
+#: sequencer.c:1007
msgid "Can't revert as initial commit"
msgstr "Kan inte ångra som första incheckning"
-#: sequencer.c:1001
+#: sequencer.c:1008
msgid "Can't cherry-pick into empty head"
msgstr "Kan inte göra \"cherry-pick\" i ett tomt huvud"
-#: sha1_name.c:864
+#: sha1_name.c:1044
msgid "HEAD does not point to a branch"
msgstr "HEAD pekar inte på en gren"
-#: sha1_name.c:867
+#: sha1_name.c:1047
#, c-format
msgid "No such branch: '%s'"
msgstr "Okänd gren: \"%s\""
-#: sha1_name.c:869
+#: sha1_name.c:1049
#, c-format
msgid "No upstream configured for branch '%s'"
msgstr "Ingen standarduppström angiven för grenen \"%s\""
-#: sha1_name.c:872
+#: sha1_name.c:1052
#, c-format
msgid "Upstream branch '%s' not stored as a remote-tracking branch"
msgstr "Uppströmsgrenen \"%s\" är inte lagrad som en fjärrspårande gren"
-#: wrapper.c:413
+#: wrapper.c:408
+#, c-format
+msgid "unable to access '%s': %s"
+msgstr "kan inte komma åt \"%s\": %s"
+
+#: wrapper.c:426
#, c-format
msgid "unable to look up current user in the passwd file: %s"
msgstr "kan inte slå upp aktuell användare i passwd-filen: %s"
-#: wrapper.c:414
+#: wrapper.c:427
msgid "no such user"
msgstr "okänd användare"
-#: wt-status.c:135
+#: wt-status.c:140
msgid "Unmerged paths:"
msgstr "Ej sammanslagna sökvägar:"
-#: wt-status.c:141 wt-status.c:158
+#: wt-status.c:167 wt-status.c:194
#, c-format
msgid " (use \"git reset %s <file>...\" to unstage)"
msgstr " (använd \"git reset %s <fil>...\" för att ta bort från kö)"
-#: wt-status.c:143 wt-status.c:160
+#: wt-status.c:169 wt-status.c:196
msgid " (use \"git rm --cached <file>...\" to unstage)"
msgstr " (använd \"git rm --cached <fil>...\" för att ta bort från kö)"
-#: wt-status.c:144
+#: wt-status.c:173
+msgid " (use \"git add <file>...\" to mark resolution)"
+msgstr " (använd \"git add <fil>...\" för att ange lösning)"
+
+#: wt-status.c:175 wt-status.c:179
msgid " (use \"git add/rm <file>...\" as appropriate to mark resolution)"
msgstr " (använd \"git add/rm <fil>...\" som lämpligt för att ange lösning)"
-#: wt-status.c:152
+#: wt-status.c:177
+msgid " (use \"git rm <file>...\" to mark resolution)"
+msgstr " (använd \"git rm <fil>...\" för att ange lösning)"
+
+#: wt-status.c:188
msgid "Changes to be committed:"
msgstr "Ändringar att checka in:"
-#: wt-status.c:170
+#: wt-status.c:206
msgid "Changes not staged for commit:"
msgstr "Ändringar ej i incheckningskön:"
-#: wt-status.c:174
+#: wt-status.c:210
msgid " (use \"git add <file>...\" to update what will be committed)"
msgstr ""
" (använd \"git add <fil>...\" för att uppdatera vad som skall checkas in)"
-#: wt-status.c:176
+#: wt-status.c:212
msgid " (use \"git add/rm <file>...\" to update what will be committed)"
msgstr ""
" (använd \"git add/rm <fil>...\" för att uppdatera vad som skall checkas in)"
-#: wt-status.c:177
+#: wt-status.c:213
msgid ""
" (use \"git checkout -- <file>...\" to discard changes in working directory)"
msgstr ""
" (använd \"git checkout -- <fil>...\" för att förkasta ändringar i "
"arbetskatalogen)"
-#: wt-status.c:179
+#: wt-status.c:215
msgid " (commit or discard the untracked or modified content in submodules)"
msgstr ""
" (checka in eller förkasta ospårat eller ändrat innehåll i undermoduler)"
-# %s är ett verb ("Untracked"/"Ignored"); lägg till ett -e.
-#: wt-status.c:188
-#, c-format
-msgid "%s files:"
-msgstr "%se filer:"
-
-#: wt-status.c:191
+#: wt-status.c:227
#, c-format
msgid " (use \"git %s <file>...\" to include in what will be committed)"
msgstr ""
-" (använd \"git %s <fil>...\" för att ta med i vad som skall checkas in)"
+" (använd \"git %s <fil>...\" för att ta med i det som skall checkas in)"
-#: wt-status.c:208
+#: wt-status.c:244
msgid "bug"
msgstr "programfel"
-#: wt-status.c:213
+#: wt-status.c:249
msgid "both deleted:"
msgstr "borttaget av bägge:"
-#: wt-status.c:214
+#: wt-status.c:250
msgid "added by us:"
msgstr "tillagt av oss:"
-#: wt-status.c:215
+#: wt-status.c:251
msgid "deleted by them:"
msgstr "borttaget av dem:"
-#: wt-status.c:216
+#: wt-status.c:252
msgid "added by them:"
msgstr "tillagt av dem:"
-#: wt-status.c:217
+#: wt-status.c:253
msgid "deleted by us:"
msgstr "borttaget av oss:"
-#: wt-status.c:218
+#: wt-status.c:254
msgid "both added:"
msgstr "tillagt av bägge:"
-#: wt-status.c:219
+#: wt-status.c:255
msgid "both modified:"
msgstr "ändrat av bägge:"
-#: wt-status.c:249
+#: wt-status.c:285
msgid "new commits, "
msgstr "nya incheckningar, "
-#: wt-status.c:251
+#: wt-status.c:287
msgid "modified content, "
msgstr "ändrat innehåll, "
-#: wt-status.c:253
+#: wt-status.c:289
msgid "untracked content, "
msgstr "ospårat innehåll, "
-#: wt-status.c:267
+#: wt-status.c:303
#, c-format
msgid "new file: %s"
msgstr "ny fil: %s"
-#: wt-status.c:270
+#: wt-status.c:306
#, c-format
msgid "copied: %s -> %s"
msgstr "kopierad: %s -> %s"
-#: wt-status.c:273
+#: wt-status.c:309
#, c-format
msgid "deleted: %s"
msgstr "borttagen: %s"
-#: wt-status.c:276
+#: wt-status.c:312
#, c-format
msgid "modified: %s"
msgstr "ändrad: %s"
-#: wt-status.c:279
+#: wt-status.c:315
#, c-format
msgid "renamed: %s -> %s"
msgstr "namnbyte: %s -> %s"
-#: wt-status.c:282
+#: wt-status.c:318
#, c-format
msgid "typechange: %s"
msgstr "typbyte: %s"
-#: wt-status.c:285
+#: wt-status.c:321
#, c-format
msgid "unknown: %s"
msgstr "okänd: %s"
-#: wt-status.c:288
+#: wt-status.c:324
#, c-format
msgid "unmerged: %s"
msgstr "osammansl.: %s"
-#: wt-status.c:291
+#: wt-status.c:327
#, c-format
msgid "bug: unhandled diff status %c"
msgstr "programfel: diff-status %c ej hanterad"
-#: wt-status.c:737
+#: wt-status.c:785
+msgid "You have unmerged paths."
+msgstr "Du har ej sammanslagna sökvägar."
+
+#: wt-status.c:788 wt-status.c:912
+msgid " (fix conflicts and run \"git commit\")"
+msgstr " (rätta konflikter och kör \"git commit\")"
+
+#: wt-status.c:791
+msgid "All conflicts fixed but you are still merging."
+msgstr "Alla konflikter har rättats men du är fortfarande i en sammanslagning."
+
+#: wt-status.c:794
+msgid " (use \"git commit\" to conclude merge)"
+msgstr " (använd \"git commit\" för att slutföra sammanslagningen)"
+
+#: wt-status.c:804
+msgid "You are in the middle of an am session."
+msgstr "Du är i mitten av en körning av \"git am\"."
+
+#: wt-status.c:807
+msgid "The current patch is empty."
+msgstr "Aktuell patch är tom."
+
+#: wt-status.c:811
+msgid " (fix conflicts and then run \"git am --resolved\")"
+msgstr " (rätta konflikter och kör sedan \"git am --resolved\")"
+
+#: wt-status.c:813
+msgid " (use \"git am --skip\" to skip this patch)"
+msgstr " (använd \"git am --skip\" för att hoppa över patchen)"
+
+#: wt-status.c:815
+msgid " (use \"git am --abort\" to restore the original branch)"
+msgstr " (använd \"git am --abort\" för att återställa ursprungsgrenen)"
+
+#: wt-status.c:873 wt-status.c:883
+msgid "You are currently rebasing."
+msgstr "Du håller på med en ombasering."
+
+#: wt-status.c:876
+msgid " (fix conflicts and then run \"git rebase --continue\")"
+msgstr " (rätta konflikter och kör sedan \"git rebase --continue\")"
+
+#: wt-status.c:878
+msgid " (use \"git rebase --skip\" to skip this patch)"
+msgstr " (använd \"git rebase --skip\" för att hoppa över patchen)"
+
+#: wt-status.c:880
+msgid " (use \"git rebase --abort\" to check out the original branch)"
+msgstr " (använd \"git rebase --abort\" för att checka ut ursprungsgrenen)"
+
+#: wt-status.c:886
+msgid " (all conflicts fixed: run \"git rebase --continue\")"
+msgstr " (alla konflikter rättade: kör \"git rebase --continue\")"
+
+#: wt-status.c:888
+msgid "You are currently splitting a commit during a rebase."
+msgstr "Du håller på att dela upp en incheckning i en ombasering."
+
+#: wt-status.c:891
+msgid " (Once your working directory is clean, run \"git rebase --continue\")"
+msgstr " (Så fort din arbetskatalog är ren, kör \"git rebase --continue\")"
+
+#: wt-status.c:893
+msgid "You are currently editing a commit during a rebase."
+msgstr "Du håller på att redigera en incheckning under en ombasering."
+
+#: wt-status.c:896
+msgid " (use \"git commit --amend\" to amend the current commit)"
+msgstr ""
+" (använd \"git commit --amend\" för att lägga till på aktuell incheckning)"
+
+#: wt-status.c:898
+msgid ""
+" (use \"git rebase --continue\" once you are satisfied with your changes)"
+msgstr " (använd \"git rebase --continue\" när du är nöjd med dina ändringar)"
+
+#: wt-status.c:908
+msgid "You are currently cherry-picking."
+msgstr "Du håller på med en \"cherry-pick\"."
+
+#: wt-status.c:915
+msgid " (all conflicts fixed: run \"git commit\")"
+msgstr " (alla konflikter har rättats: kör \"git commit\")"
+
+#: wt-status.c:924
+msgid "You are currently bisecting."
+msgstr "Du håller på med en \"bisect\"."
+
+#: wt-status.c:927
+msgid " (use \"git bisect reset\" to get back to the original branch)"
+msgstr ""
+" (använd \"git bisect reset\" för att komma tillbaka till ursprungsgrenen)"
+
+#: wt-status.c:978
msgid "On branch "
msgstr "PÃ¥ grenen "
-#: wt-status.c:744
+#: wt-status.c:985
msgid "Not currently on any branch."
msgstr "Inte på någon gren för närvarande."
-#: wt-status.c:755
+#: wt-status.c:997
msgid "Initial commit"
msgstr "Första incheckning"
-#: wt-status.c:769
-msgid "Untracked"
-msgstr "Ospårad"
+#: wt-status.c:1011
+msgid "Untracked files"
+msgstr "Ospårade filer"
-#: wt-status.c:771
-msgid "Ignored"
-msgstr "Ignorerad"
+#: wt-status.c:1013
+msgid "Ignored files"
+msgstr "Ignorerade filer"
# %s är nästa sträng eller tom.
-#: wt-status.c:773
+#: wt-status.c:1015
#, c-format
msgid "Untracked files not listed%s"
msgstr "Ospårade filer visas ej%s"
-#: wt-status.c:775
+#: wt-status.c:1017
msgid " (use -u option to show untracked files)"
msgstr " (använd flaggan -u för att visa ospårade filer)"
-#: wt-status.c:781
+#: wt-status.c:1023
msgid "No changes"
msgstr "Inga ändringar"
-#: wt-status.c:785
+#: wt-status.c:1028
#, c-format
-msgid "no changes added to commit%s\n"
-msgstr "inga ändringar att checka in%s\n"
+msgid "no changes added to commit (use \"git add\" and/or \"git commit -a\")\n"
+msgstr ""
+"inga ändringar att checka in (använd \"git add\" och/eller \"git commit -a"
+"\")\n"
-#: wt-status.c:787
-msgid " (use \"git add\" and/or \"git commit -a\")"
-msgstr " (använd \"git add\" och/eller \"git commit -a\")"
+#: wt-status.c:1031
+#, c-format
+msgid "no changes added to commit\n"
+msgstr "inga ändringar att checka in\n"
-#: wt-status.c:789
+#: wt-status.c:1034
#, c-format
-msgid "nothing added to commit but untracked files present%s\n"
-msgstr "inget köat för incheckning, men ospårade filer finns%s\n"
+msgid ""
+"nothing added to commit but untracked files present (use \"git add\" to "
+"track)\n"
+msgstr ""
+"inget köat för incheckning, men ospårade filer finns (spåra med \"git add"
+"\")\n"
-#: wt-status.c:791
-msgid " (use \"git add\" to track)"
-msgstr " (använd \"git add\" för att spåra)"
+#: wt-status.c:1037
+#, c-format
+msgid "nothing added to commit but untracked files present\n"
+msgstr "inget köat för incheckning, men ospårade filer finns\n"
-#: wt-status.c:793 wt-status.c:796 wt-status.c:799
+#: wt-status.c:1040
#, c-format
-msgid "nothing to commit%s\n"
-msgstr "inget att checka in%s\n"
+msgid "nothing to commit (create/copy files and use \"git add\" to track)\n"
+msgstr "inget att checka in (skapa/kopiera filer och spåra med \"git add\")\n"
-#: wt-status.c:794
-msgid " (create/copy files and use \"git add\" to track)"
-msgstr " (skapa/kopiera filer och använd \"git add\" för att spåra)"
+#: wt-status.c:1043 wt-status.c:1048
+#, c-format
+msgid "nothing to commit\n"
+msgstr "inget att checka in\n"
-#: wt-status.c:797
-msgid " (use -u to show untracked files)"
-msgstr " (använd -u för att visa ospårade filer)"
+#: wt-status.c:1046
+#, c-format
+msgid "nothing to commit (use -u to show untracked files)\n"
+msgstr "inget att checka in (använd -u för att visa ospårade filer)\n"
-#: wt-status.c:800
-msgid " (working directory clean)"
-msgstr " (arbetskatalogen ren)"
+#: wt-status.c:1050
+#, c-format
+msgid "nothing to commit, working directory clean\n"
+msgstr "inget att checka in, arbetskatalogen ren\n"
-#: wt-status.c:908
+#: wt-status.c:1158
msgid "HEAD (no branch)"
msgstr "HEAD (ingen gren)"
-#: wt-status.c:914
+#: wt-status.c:1164
msgid "Initial commit on "
msgstr "Första incheckning på "
-#: wt-status.c:929
+#: wt-status.c:1179
msgid "behind "
msgstr "efter "
-#: wt-status.c:932 wt-status.c:935
+#: wt-status.c:1182 wt-status.c:1185
msgid "ahead "
msgstr "före "
-#: wt-status.c:937
+#: wt-status.c:1187
msgid ", behind "
msgstr ", efter "
+#: compat/precompose_utf8.c:58 builtin/clone.c:341
+#, c-format
+msgid "failed to unlink '%s'"
+msgstr "misslyckades ta bort länken \"%s\""
+
+#: builtin/add.c:19
+msgid "git add [options] [--] <filepattern>..."
+msgstr "git add [flaggor] [--] <filmönster>..."
+
#: builtin/add.c:62
#, c-format
msgid "unexpected diff status %c"
msgstr "diff-status %c förväntades inte"
-#: builtin/add.c:67 builtin/commit.c:226
+#: builtin/add.c:67 builtin/commit.c:229
msgid "updating files failed"
msgstr "misslyckades uppdatera filer"
@@ -924,7 +1392,7 @@ msgstr "Sökvägen \"%s\" är i undermodulen \"%.*s\""
msgid "Unstaged changes after refreshing the index:"
msgstr "Ospårade ändringar efter att ha uppdaterat indexet:"
-#: builtin/add.c:195 builtin/add.c:456 builtin/rm.c:186
+#: builtin/add.c:195 builtin/add.c:460 builtin/rm.c:186
#, c-format
msgid "pathspec '%s' did not match any files"
msgstr "sökvägsangivelsen \"%s\" motsvarade inte några filer"
@@ -961,110 +1429,162 @@ msgstr "Tom patch. Avbryter."
msgid "Could not apply '%s'"
msgstr "Kunde inte tillämpa \"%s\""
-#: builtin/add.c:312
+#: builtin/add.c:313
msgid "The following paths are ignored by one of your .gitignore files:\n"
msgstr "Följande sökvägar ignoreras av en av dina .gitignore-filer:\n"
-#: builtin/add.c:352
+#: builtin/add.c:319 builtin/clean.c:52 builtin/fetch.c:78 builtin/mv.c:63
+#: builtin/prune-packed.c:76 builtin/push.c:388 builtin/remote.c:1253
+#: builtin/rm.c:133
+msgid "dry run"
+msgstr "testkörning"
+
+#: builtin/add.c:320 builtin/apply.c:4354 builtin/commit.c:1187
+#: builtin/count-objects.c:82 builtin/fsck.c:613 builtin/log.c:1477
+#: builtin/mv.c:62 builtin/read-tree.c:112
+msgid "be verbose"
+msgstr "var pratsam"
+
+#: builtin/add.c:322
+msgid "interactive picking"
+msgstr "plocka interaktivt"
+
+#: builtin/add.c:323 builtin/checkout.c:1028 builtin/reset.c:248
+msgid "select hunks interactively"
+msgstr "välj stycken interaktivt"
+
+#: builtin/add.c:324
+msgid "edit current diff and apply"
+msgstr "redigera aktuell diff och applicera"
+
+#: builtin/add.c:325
+msgid "allow adding otherwise ignored files"
+msgstr "tillåt lägga till annars ignorerade filer"
+
+#: builtin/add.c:326
+msgid "update tracked files"
+msgstr "uppdatera spårade filer"
+
+#: builtin/add.c:327
+msgid "record only the fact that the path will be added later"
+msgstr "registrera endast att sökvägen kommer läggas till senare"
+
+#: builtin/add.c:328
+msgid "add changes from all tracked and untracked files"
+msgstr "lägg till ändringar från alla spårade och ospårade filer"
+
+#: builtin/add.c:329
+msgid "don't add, only refresh the index"
+msgstr "lägg inte till, uppdatera endast indexet"
+
+#: builtin/add.c:330
+msgid "just skip files which cannot be added because of errors"
+msgstr "hoppa bara över filer som inte kan läggas till på grund av fel"
+
+#: builtin/add.c:331
+msgid "check if - even missing - files are ignored in dry run"
+msgstr "se om - även saknade - filer ignoreras i testkörning"
+
+#: builtin/add.c:353
#, c-format
msgid "Use -f if you really want to add them.\n"
msgstr "Använd -f om du verkligen vill lägga till dem.\n"
-#: builtin/add.c:353
+#: builtin/add.c:354
msgid "no files added"
msgstr "inga filer har lagts till"
-#: builtin/add.c:359
+#: builtin/add.c:360
msgid "adding files failed"
msgstr "misslyckades lägga till filer"
-#: builtin/add.c:391
+#: builtin/add.c:392
msgid "-A and -u are mutually incompatible"
msgstr "-A och -u är ömsesidigt inkompatibla"
-#: builtin/add.c:393
+#: builtin/add.c:394
msgid "Option --ignore-missing can only be used together with --dry-run"
msgstr "Flaggan --ignore-missing kan endast användas tillsammans med --dry-run"
-#: builtin/add.c:413
+#: builtin/add.c:414
#, c-format
msgid "Nothing specified, nothing added.\n"
msgstr "Inget angivet, inget tillagt.\n"
-#: builtin/add.c:414
+#: builtin/add.c:415
#, c-format
msgid "Maybe you wanted to say 'git add .'?\n"
msgstr "Kanske menade du att skriva \"git add .\"?\n"
-#: builtin/add.c:420 builtin/clean.c:95 builtin/commit.c:286 builtin/mv.c:82
+#: builtin/add.c:421 builtin/clean.c:95 builtin/commit.c:289 builtin/mv.c:82
#: builtin/rm.c:162
msgid "index file corrupt"
msgstr "indexfilen trasig"
-#: builtin/add.c:476 builtin/apply.c:4108 builtin/mv.c:229 builtin/rm.c:260
+#: builtin/add.c:481 builtin/apply.c:4450 builtin/mv.c:229 builtin/rm.c:260
msgid "Unable to write new index file"
msgstr "Kunde inte skriva ny indexfil"
-#: builtin/apply.c:53
+#: builtin/apply.c:57
msgid "git apply [options] [<patch>...]"
msgstr "git apply [flaggor] [<patch>...]"
-#: builtin/apply.c:106
+#: builtin/apply.c:110
#, c-format
msgid "unrecognized whitespace option '%s'"
msgstr "okänt alternativ för whitespace: \"%s\""
-#: builtin/apply.c:121
+#: builtin/apply.c:125
#, c-format
msgid "unrecognized whitespace ignore option '%s'"
msgstr "okänt alternativ för ignore-whitespace: \"%s\""
-#: builtin/apply.c:815
+#: builtin/apply.c:823
#, c-format
msgid "Cannot prepare timestamp regexp %s"
msgstr "Kan inte förbereda reguljärt uttryck för tidsstämpeln %s"
-#: builtin/apply.c:824
+#: builtin/apply.c:832
#, c-format
msgid "regexec returned %d for input: %s"
msgstr "regexec returnerade %d för indata: %s"
-#: builtin/apply.c:905
+#: builtin/apply.c:913
#, c-format
msgid "unable to find filename in patch at line %d"
msgstr "kan inte hitta filnamn i patchen på rad %d"
-#: builtin/apply.c:937
+#: builtin/apply.c:945
#, c-format
msgid "git apply: bad git-diff - expected /dev/null, got %s on line %d"
msgstr "git apply: dålig git-diff - förväntade /dev/null, fick %s på rad %d"
-#: builtin/apply.c:941
+#: builtin/apply.c:949
#, c-format
msgid "git apply: bad git-diff - inconsistent new filename on line %d"
msgstr "git apply: dålig git-diff - motsägande nytt filnamn på rad %d"
-#: builtin/apply.c:942
+#: builtin/apply.c:950
#, c-format
msgid "git apply: bad git-diff - inconsistent old filename on line %d"
msgstr "git apply: dålig git-diff - motsägande gammalt filnamn på rad %d"
-#: builtin/apply.c:949
+#: builtin/apply.c:957
#, c-format
msgid "git apply: bad git-diff - expected /dev/null on line %d"
msgstr "git apply: dålig git-diff - förväntade /dev/null på rad %d"
-#: builtin/apply.c:1394
+#: builtin/apply.c:1420
#, c-format
msgid "recount: unexpected line: %.*s"
msgstr "recount: förväntade rad: %.*s"
-#: builtin/apply.c:1451
+#: builtin/apply.c:1477
#, c-format
msgid "patch fragment without header at line %d: %.*s"
msgstr "patch-fragment utan huvud på rad %d: %.*s"
-#: builtin/apply.c:1468
+#: builtin/apply.c:1494
#, c-format
msgid ""
"git diff header lacks filename information when removing %d leading pathname "
@@ -1080,82 +1600,82 @@ msgstr[1] ""
"sökvägskomponenter\n"
"tas bort (rad %d)"
-#: builtin/apply.c:1628
+#: builtin/apply.c:1654
msgid "new file depends on old contents"
msgstr "ny fil beror på gammalt innehåll"
-#: builtin/apply.c:1630
+#: builtin/apply.c:1656
msgid "deleted file still has contents"
msgstr "borttagen fil har fortfarande innehåll"
-#: builtin/apply.c:1656
+#: builtin/apply.c:1682
#, c-format
msgid "corrupt patch at line %d"
msgstr "trasig patch på rad %d"
-#: builtin/apply.c:1692
+#: builtin/apply.c:1718
#, c-format
msgid "new file %s depends on old contents"
msgstr "nya filen %s beror på gammalt innehåll"
-#: builtin/apply.c:1694
+#: builtin/apply.c:1720
#, c-format
msgid "deleted file %s still has contents"
msgstr "borttagna filen %s har fortfarande innehåll"
-#: builtin/apply.c:1697
+#: builtin/apply.c:1723
#, c-format
msgid "** warning: file %s becomes empty but is not deleted"
msgstr "** varning: filen %s blir tom men har inte tagits bort"
-#: builtin/apply.c:1843
+#: builtin/apply.c:1869
#, c-format
msgid "corrupt binary patch at line %d: %.*s"
msgstr "trasig binärpatch på rad %d: %.*s"
#. there has to be one hunk (forward hunk)
-#: builtin/apply.c:1872
+#: builtin/apply.c:1898
#, c-format
msgid "unrecognized binary patch at line %d"
msgstr "binärpatchen på rad %d känns inte igen"
-#: builtin/apply.c:1958
+#: builtin/apply.c:1984
#, c-format
msgid "patch with only garbage at line %d"
msgstr "patch med bara skräp på rad %d"
-#: builtin/apply.c:2048
+#: builtin/apply.c:2074
#, c-format
msgid "unable to read symlink %s"
msgstr "kunde inte läsa symboliska länken %s"
-#: builtin/apply.c:2052
+#: builtin/apply.c:2078
#, c-format
msgid "unable to open or read %s"
msgstr "kunde inte öppna eller läsa %s"
-#: builtin/apply.c:2123
+#: builtin/apply.c:2149
msgid "oops"
msgstr "hoppsan"
-#: builtin/apply.c:2645
+#: builtin/apply.c:2671
#, c-format
msgid "invalid start of line: '%c'"
msgstr "felaktig inledning på rad: \"%c\""
-#: builtin/apply.c:2763
+#: builtin/apply.c:2789
#, c-format
msgid "Hunk #%d succeeded at %d (offset %d line)."
msgid_plural "Hunk #%d succeeded at %d (offset %d lines)."
msgstr[0] "Stycke %d lyckades på %d (offset %d rad)."
msgstr[1] "Stycke %d lyckades på %d (offset %d rader)."
-#: builtin/apply.c:2775
+#: builtin/apply.c:2801
#, c-format
msgid "Context reduced to (%ld/%ld) to apply fragment at %d"
msgstr "Sammanhang reducerat till (%ld/%ld) för att tillämpa fragment vid %d"
-#: builtin/apply.c:2781
+#: builtin/apply.c:2807
#, c-format
msgid ""
"while searching for:\n"
@@ -1164,313 +1684,318 @@ msgstr ""
"vid sökning efter:\n"
"%.*s"
-#: builtin/apply.c:2800
+#: builtin/apply.c:2826
#, c-format
msgid "missing binary patch data for '%s'"
msgstr "saknar binära patchdata för \"%s\""
-#: builtin/apply.c:2903
+#: builtin/apply.c:2929
#, c-format
msgid "binary patch does not apply to '%s'"
msgstr "binärpatchen kan inte tillämpas på \"%s\""
-#: builtin/apply.c:2909
+#: builtin/apply.c:2935
#, c-format
msgid "binary patch to '%s' creates incorrect result (expecting %s, got %s)"
msgstr "binärpatchen på \"%s\" ger felaktigt resultat (förväntade %s, fick %s)"
-#: builtin/apply.c:2930
+#: builtin/apply.c:2956
#, c-format
msgid "patch failed: %s:%ld"
msgstr "patch misslyckades: %s:%ld"
-#: builtin/apply.c:3045
+#: builtin/apply.c:3078
#, c-format
-msgid "patch %s has been renamed/deleted"
-msgstr "patchen %s har ändrat namn/tagits bort"
+msgid "cannot checkout %s"
+msgstr "kan inte checka ut %s"
-#: builtin/apply.c:3052 builtin/apply.c:3069
+#: builtin/apply.c:3123 builtin/apply.c:3132 builtin/apply.c:3176
#, c-format
msgid "read of %s failed"
msgstr "misslyckades läsa %s"
-#: builtin/apply.c:3084
-msgid "removal patch leaves file contents"
-msgstr "patch för borttagning lämnar kvar filinnehåll"
-
-#: builtin/apply.c:3105
+#: builtin/apply.c:3156 builtin/apply.c:3378
#, c-format
-msgid "%s: already exists in working directory"
-msgstr "%s: finns redan i arbetskatalogen"
+msgid "path %s has been renamed/deleted"
+msgstr "sökvägen %s har ändrat namn/tagits bort"
-#: builtin/apply.c:3143
+#: builtin/apply.c:3237 builtin/apply.c:3392
#, c-format
-msgid "%s: has been deleted/renamed"
-msgstr "%s: har tagits bort/ändrat namn"
+msgid "%s: does not exist in index"
+msgstr "%s: finns inte i indexet"
-#: builtin/apply.c:3148 builtin/apply.c:3179
+#: builtin/apply.c:3241 builtin/apply.c:3384 builtin/apply.c:3406
#, c-format
msgid "%s: %s"
msgstr "%s: %s"
-#: builtin/apply.c:3159
-#, c-format
-msgid "%s: does not exist in index"
-msgstr "%s: finns inte i indexet"
-
-#: builtin/apply.c:3173
+#: builtin/apply.c:3246 builtin/apply.c:3400
#, c-format
msgid "%s: does not match index"
msgstr "%s: motsvarar inte indexet"
-#: builtin/apply.c:3190
+#: builtin/apply.c:3348
+msgid "removal patch leaves file contents"
+msgstr "patch för borttagning lämnar kvar filinnehåll"
+
+#: builtin/apply.c:3417
#, c-format
msgid "%s: wrong type"
msgstr "%s: fel typ"
-#: builtin/apply.c:3192
+#: builtin/apply.c:3419
#, c-format
msgid "%s has type %o, expected %o"
msgstr "%s har typen %o, förväntade %o"
-#: builtin/apply.c:3247
+#: builtin/apply.c:3520
#, c-format
msgid "%s: already exists in index"
msgstr "%s: finns redan i indexet"
-#: builtin/apply.c:3267
+#: builtin/apply.c:3523
+#, c-format
+msgid "%s: already exists in working directory"
+msgstr "%s: finns redan i arbetskatalogen"
+
+#: builtin/apply.c:3543
#, c-format
msgid "new mode (%o) of %s does not match old mode (%o)"
msgstr "nytt läge (%o) för %s motsvarar inte gammalt läge (%o)"
-#: builtin/apply.c:3272
+#: builtin/apply.c:3548
#, c-format
msgid "new mode (%o) of %s does not match old mode (%o) of %s"
msgstr "nytt läge (%o) för %s motsvarar inte gammalt läge (%o) för %s"
-#: builtin/apply.c:3280
+#: builtin/apply.c:3556
#, c-format
msgid "%s: patch does not apply"
msgstr "%s: patchen kan inte tillämpas"
-#: builtin/apply.c:3293
+#: builtin/apply.c:3569
#, c-format
msgid "Checking patch %s..."
msgstr "Kontrollerar patchen %s..."
-#: builtin/apply.c:3348 builtin/checkout.c:212 builtin/reset.c:158
+#: builtin/apply.c:3624 builtin/checkout.c:215 builtin/reset.c:158
#, c-format
msgid "make_cache_entry failed for path '%s'"
msgstr "make_cache_entry misslyckades för sökvägen \"%s\""
-#: builtin/apply.c:3491
+#: builtin/apply.c:3767
#, c-format
msgid "unable to remove %s from index"
msgstr "kan inte ta bort %s från indexet"
-#: builtin/apply.c:3518
+#: builtin/apply.c:3795
#, c-format
msgid "corrupt patch for subproject %s"
msgstr "trasig patch för underprojektet %s"
-#: builtin/apply.c:3522
+#: builtin/apply.c:3799
#, c-format
msgid "unable to stat newly created file '%s'"
msgstr "kan inte ta status på nyligen skapade filen \"%s\""
-#: builtin/apply.c:3527
+#: builtin/apply.c:3804
#, c-format
msgid "unable to create backing store for newly created file %s"
msgstr "kan inte skapa säkerhetsminne för nyligen skapade filen %s"
-#: builtin/apply.c:3530
+#: builtin/apply.c:3807 builtin/apply.c:3915
#, c-format
msgid "unable to add cache entry for %s"
msgstr "kan inte lägga till cachepost för %s"
-#: builtin/apply.c:3563
+#: builtin/apply.c:3840
#, c-format
msgid "closing file '%s'"
msgstr "stänger filen \"%s\""
-#: builtin/apply.c:3612
+#: builtin/apply.c:3889
#, c-format
msgid "unable to write file '%s' mode %o"
msgstr "kan inte skriva filen \"%s\" läge %o"
-#: builtin/apply.c:3668
+#: builtin/apply.c:3976
#, c-format
msgid "Applied patch %s cleanly."
msgstr "Tillämpade patchen %s rent."
-#: builtin/apply.c:3676
+#: builtin/apply.c:3984
msgid "internal error"
msgstr "internt fel"
#. Say this even without --verbose
-#: builtin/apply.c:3679
+#: builtin/apply.c:3987
#, c-format
msgid "Applying patch %%s with %d reject..."
msgid_plural "Applying patch %%s with %d rejects..."
msgstr[0] "Tillämpade patchen %%s med %d refuserad..."
msgstr[1] "Tillämpade patchen %%s med %d refuserade..."
-#: builtin/apply.c:3689
+#: builtin/apply.c:3997
#, c-format
msgid "truncating .rej filename to %.*s.rej"
msgstr "trunkerar .rej-filnamnet till %.*s.rej"
-#: builtin/apply.c:3710
+#: builtin/apply.c:4018
#, c-format
msgid "Hunk #%d applied cleanly."
msgstr "Stycke %d tillämpades rent."
-#: builtin/apply.c:3713
+#: builtin/apply.c:4021
#, c-format
msgid "Rejected hunk #%d."
msgstr "Refuserar stycke %d."
-#: builtin/apply.c:3844
+#: builtin/apply.c:4171
msgid "unrecognized input"
msgstr "indata känns inte igen"
-#: builtin/apply.c:3855
+#: builtin/apply.c:4182
msgid "unable to read index file"
msgstr "kan inte läsa indexfilen"
-#: builtin/apply.c:3970 builtin/apply.c:3973
+#: builtin/apply.c:4301 builtin/apply.c:4304 builtin/clone.c:91
+#: builtin/fetch.c:63
msgid "path"
msgstr "sökväg"
-#: builtin/apply.c:3971
+#: builtin/apply.c:4302
msgid "don't apply changes matching the given path"
msgstr "tillämpa inte ändringar som motsvarar given sökväg"
-#: builtin/apply.c:3974
+#: builtin/apply.c:4305
msgid "apply changes matching the given path"
msgstr "tillämpa ändringar som motsvarar given sökväg"
-#: builtin/apply.c:3976
+#: builtin/apply.c:4307
msgid "num"
msgstr "antal"
-#: builtin/apply.c:3977
+#: builtin/apply.c:4308
msgid "remove <num> leading slashes from traditional diff paths"
msgstr "ta bort <antal> inledande snedstreck från traditionella diff-sökvägar"
-#: builtin/apply.c:3980
+#: builtin/apply.c:4311
msgid "ignore additions made by the patch"
msgstr "ignorera tillägg gjorda av patchen"
-#: builtin/apply.c:3982
+#: builtin/apply.c:4313
msgid "instead of applying the patch, output diffstat for the input"
msgstr "istället för att tillämpa patchen, skriv ut diffstat för indata"
-#: builtin/apply.c:3986
-msgid "shows number of added and deleted lines in decimal notation"
-msgstr "visar antal tillagda och borttagna rader decimalt"
+#: builtin/apply.c:4317
+msgid "show number of added and deleted lines in decimal notation"
+msgstr "visa antal tillagda och borttagna rader decimalt"
-#: builtin/apply.c:3988
+#: builtin/apply.c:4319
msgid "instead of applying the patch, output a summary for the input"
msgstr "istället för att tillämpa patchen, skriv ut en summering av indata"
-#: builtin/apply.c:3990
+#: builtin/apply.c:4321
msgid "instead of applying the patch, see if the patch is applicable"
msgstr "istället för att tillämpa patchen, se om patchen kan tillämpas"
-#: builtin/apply.c:3992
+#: builtin/apply.c:4323
msgid "make sure the patch is applicable to the current index"
msgstr "se till att patchen kan tillämpas på aktuellt index"
-#: builtin/apply.c:3994
+#: builtin/apply.c:4325
msgid "apply a patch without touching the working tree"
msgstr "tillämpa en patch utan att röra arbetskatalogen"
-#: builtin/apply.c:3996
+#: builtin/apply.c:4327
msgid "also apply the patch (use with --stat/--summary/--check)"
msgstr "tillämpa också patchen (använd med --stat/--summary/--check)"
-#: builtin/apply.c:3998
+#: builtin/apply.c:4329
+msgid "attempt three-way merge if a patch does not apply"
+msgstr "försök en trevägssammanslagning om patchen inte kan tillämpas"
+
+#: builtin/apply.c:4331
msgid "build a temporary index based on embedded index information"
msgstr "bygg ett temporärt index baserat på inbyggd indexinformation"
-#: builtin/apply.c:4000
+#: builtin/apply.c:4333 builtin/checkout-index.c:197 builtin/ls-files.c:460
msgid "paths are separated with NUL character"
msgstr "sökvägar avdelas med NUL-tecken"
-#: builtin/apply.c:4003
+#: builtin/apply.c:4336
msgid "ensure at least <n> lines of context match"
msgstr "se till att åtminstone <n> rader sammanhang är lika"
-#: builtin/apply.c:4004
+#: builtin/apply.c:4337
msgid "action"
msgstr "åtgärd"
-#: builtin/apply.c:4005
+#: builtin/apply.c:4338
msgid "detect new or modified lines that have whitespace errors"
msgstr "detektera nya eller ändrade rader som har fel i blanktecken"
-#: builtin/apply.c:4008 builtin/apply.c:4011
+#: builtin/apply.c:4341 builtin/apply.c:4344
msgid "ignore changes in whitespace when finding context"
msgstr "ignorera ändringar i blanktecken för sammanhang"
-#: builtin/apply.c:4014
+#: builtin/apply.c:4347
msgid "apply the patch in reverse"
msgstr "tillämpa patchen baklänges"
-#: builtin/apply.c:4016
+#: builtin/apply.c:4349
msgid "don't expect at least one line of context"
msgstr "förvänta inte minst en rad sammanhang"
-#: builtin/apply.c:4018
+#: builtin/apply.c:4351
msgid "leave the rejected hunks in corresponding *.rej files"
msgstr "lämna refuserade stycken i motsvarande *.rej-filer"
-#: builtin/apply.c:4020
+#: builtin/apply.c:4353
msgid "allow overlapping hunks"
msgstr "tillåt överlappande stycken"
-#: builtin/apply.c:4021
-msgid "be verbose"
-msgstr "var pratsam"
-
-#: builtin/apply.c:4023
+#: builtin/apply.c:4356
msgid "tolerate incorrectly detected missing new-line at the end of file"
msgstr "tolerera felaktigt detekterade saknade nyradstecken vid filslut"
-#: builtin/apply.c:4026
+#: builtin/apply.c:4359
msgid "do not trust the line counts in the hunk headers"
msgstr "lite inte på antalet linjer i styckehuvuden"
-#: builtin/apply.c:4028
+#: builtin/apply.c:4361
msgid "root"
msgstr "rot"
-#: builtin/apply.c:4029
+#: builtin/apply.c:4362
msgid "prepend <root> to all filenames"
msgstr "lägg till <rot> i alla filnamn"
-#: builtin/apply.c:4050
+#: builtin/apply.c:4384
+msgid "--3way outside a repository"
+msgstr "--3way utanför arkiv"
+
+#: builtin/apply.c:4392
msgid "--index outside a repository"
msgstr "--index utanför arkiv"
-#: builtin/apply.c:4053
+#: builtin/apply.c:4395
msgid "--cached outside a repository"
msgstr "--cached utanför arkiv"
-#: builtin/apply.c:4069
+#: builtin/apply.c:4411
#, c-format
msgid "can't open patch '%s'"
msgstr "kan inte öppna patchen \"%s\""
-#: builtin/apply.c:4083
+#: builtin/apply.c:4425
#, c-format
msgid "squelched %d whitespace error"
msgid_plural "squelched %d whitespace errors"
msgstr[0] "undertryckte %d fel i blanksteg"
msgstr[1] "undertryckte %d fel i blanksteg"
-#: builtin/apply.c:4089 builtin/apply.c:4099
+#: builtin/apply.c:4431 builtin/apply.c:4441
#, c-format
msgid "%d line adds whitespace errors."
msgid_plural "%d lines add whitespace errors."
@@ -1512,7 +2037,135 @@ msgstr "git archive: protokollfel"
msgid "git archive: expected a flush"
msgstr "git archive: förväntade en tömning (flush)"
-#: builtin/branch.c:144
+#: builtin/bisect--helper.c:7
+msgid "git bisect--helper --next-all [--no-checkout]"
+msgstr "git bisect--helper --next-all [--no-checkout]"
+
+#: builtin/bisect--helper.c:17
+msgid "perform 'git bisect next'"
+msgstr "utför 'git bisect next'"
+
+#: builtin/bisect--helper.c:19
+msgid "update BISECT_HEAD instead of checking out the current commit"
+msgstr "uppdatera BISECT_HEAD istället för att checka ut aktuell incheckning"
+
+#: builtin/blame.c:25
+msgid "git blame [options] [rev-opts] [rev] [--] file"
+msgstr "git blame [flaggor] [rev-flaggor] [rev] [--] fil"
+
+#: builtin/blame.c:30 builtin/shortlog.c:15
+msgid "[rev-opts] are documented in git-rev-list(1)"
+msgstr "[rev-flaggor] dokumenteras i git-rev-list(1)"
+
+#: builtin/blame.c:2316
+msgid "Show blame entries as we find them, incrementally"
+msgstr "Visa klandringsposter när vi hittar dem, interaktivt"
+
+#: builtin/blame.c:2317
+msgid "Show blank SHA-1 for boundary commits (Default: off)"
+msgstr "Visa blank SHA-1 för gränsincheckningar (Standard: av)"
+
+#: builtin/blame.c:2318
+msgid "Do not treat root commits as boundaries (Default: off)"
+msgstr "Behandla inte rotincheckningar som gränser (Standard: av)"
+
+#: builtin/blame.c:2319
+msgid "Show work cost statistics"
+msgstr "Visa statistik över arbetskostnad"
+
+#: builtin/blame.c:2320
+msgid "Show output score for blame entries"
+msgstr "Visa utdatapoäng för klandringsposter"
+
+#: builtin/blame.c:2321
+msgid "Show original filename (Default: auto)"
+msgstr "Visa originalfilnamn (Standard: auto)"
+
+#: builtin/blame.c:2322
+msgid "Show original linenumber (Default: off)"
+msgstr "Visa ursprungligt radnummer (Standard: av)"
+
+#: builtin/blame.c:2323
+msgid "Show in a format designed for machine consumption"
+msgstr "Visa i ett format avsett för maskinkonsumtion"
+
+#: builtin/blame.c:2324
+msgid "Show porcelain format with per-line commit information"
+msgstr "Visa porslinsformat med per-rad-incheckningsinformation"
+
+#: builtin/blame.c:2325
+msgid "Use the same output mode as git-annotate (Default: off)"
+msgstr "Använd samma utdataläge som git-annotate (Standard: av)"
+
+#: builtin/blame.c:2326
+msgid "Show raw timestamp (Default: off)"
+msgstr "Visa rå tidsstämpel (Standard: av)"
+
+#: builtin/blame.c:2327
+msgid "Show long commit SHA1 (Default: off)"
+msgstr "Visa lång inchecknings-SHA1 (Standard: av)"
+
+#: builtin/blame.c:2328
+msgid "Suppress author name and timestamp (Default: off)"
+msgstr "Undertryck författarnamn och tidsstämpel (Standard: av)"
+
+#: builtin/blame.c:2329
+msgid "Show author email instead of name (Default: off)"
+msgstr "Visa författarens e-post istället för namn (Standard: av)"
+
+#: builtin/blame.c:2330
+msgid "Ignore whitespace differences"
+msgstr "Ignorera ändringar i blanksteg"
+
+#: builtin/blame.c:2331
+msgid "Spend extra cycles to find better match"
+msgstr "Slösa extra cykler med att hitta bättre träff"
+
+#: builtin/blame.c:2332
+msgid "Use revisions from <file> instead of calling git-rev-list"
+msgstr "Använd revisioner från <fil> istället för att anropa git-rev-list"
+
+#: builtin/blame.c:2333
+msgid "Use <file>'s contents as the final image"
+msgstr "Använd <fil>s innehåll som slutgiltig bild"
+
+#: builtin/blame.c:2334 builtin/blame.c:2335
+msgid "score"
+msgstr "poäng"
+
+#: builtin/blame.c:2334
+msgid "Find line copies within and across files"
+msgstr "Hitta kopierade rader inuti och mellan filer"
+
+#: builtin/blame.c:2335
+msgid "Find line movements within and across files"
+msgstr "Hitta flyttade rader inuti och mellan filer"
+
+#: builtin/blame.c:2336
+msgid "n,m"
+msgstr "n,m"
+
+#: builtin/blame.c:2336
+msgid "Process only line range n,m, counting from 1"
+msgstr "Behandla endast radintervallet n,m, med början på 1"
+
+#: builtin/branch.c:23
+msgid "git branch [options] [-r | -a] [--merged | --no-merged]"
+msgstr "git branch [flaggor] [-r | -a] [--merged | --no-merged]"
+
+#: builtin/branch.c:24
+msgid "git branch [options] [-l] [-f] <branchname> [<start-point>]"
+msgstr "git branch [flaggor] [-l] [-f] <grennamn> [<startpunkt>]"
+
+#: builtin/branch.c:25
+msgid "git branch [options] [-r] (-d | -D) <branchname>..."
+msgstr "git branch [flaggor] [-r] (-d | -D) <grennamn>..."
+
+#: builtin/branch.c:26
+msgid "git branch [options] (-m | -M) [<oldbranch>] <newbranch>"
+msgstr "git branch [flaggor] (-m | -M) [<gammal_gren>] <ny_gren>"
+
+#: builtin/branch.c:145
#, c-format
msgid ""
"deleting branch '%s' that has been merged to\n"
@@ -1521,7 +2174,7 @@ msgstr ""
"tar bort grenen \"%s\" som har slagits ihop med\n"
" \"%s\", men ännu inte slagits ihop med HEAD."
-#: builtin/branch.c:148
+#: builtin/branch.c:149
#, c-format
msgid ""
"not deleting branch '%s' that is not yet merged to\n"
@@ -1530,35 +2183,35 @@ msgstr ""
"tar inte bort grenen \"%s\" som inte har slagits ihop med\n"
" \"%s\", trots att den har slagits ihop med HEAD."
-#: builtin/branch.c:180
+#: builtin/branch.c:181
msgid "cannot use -a with -d"
msgstr "kan inte ange -a med -d"
-#: builtin/branch.c:186
+#: builtin/branch.c:187
msgid "Couldn't look up commit object for HEAD"
msgstr "Kunde inte slå upp incheckningsobjekt för HEAD"
-#: builtin/branch.c:191
+#: builtin/branch.c:192
#, c-format
msgid "Cannot delete the branch '%s' which you are currently on."
msgstr "Kan inte ta bort grenen \"%s\" som du befinner dig på för närvarande."
-#: builtin/branch.c:202
+#: builtin/branch.c:203
#, c-format
msgid "remote branch '%s' not found."
msgstr "fjärrgrenen \"%s\" hittades inte."
-#: builtin/branch.c:203
+#: builtin/branch.c:204
#, c-format
msgid "branch '%s' not found."
msgstr "grenen \"%s\" hittades inte."
-#: builtin/branch.c:210
+#: builtin/branch.c:211
#, c-format
msgid "Couldn't look up commit object for '%s'"
msgstr "Kunde inte slå upp incheckningsobjekt för \"%s\""
-#: builtin/branch.c:216
+#: builtin/branch.c:217
#, c-format
msgid ""
"The branch '%s' is not fully merged.\n"
@@ -1567,129 +2220,259 @@ msgstr ""
"Grenen \"%s\" har inte slagits samman i sin helhet.\n"
"Om du är säker på att du vill ta bort den, kör \"git branch -D %s\"."
-#: builtin/branch.c:225
+#: builtin/branch.c:226
#, c-format
msgid "Error deleting remote branch '%s'"
msgstr "Fel vid borttagning av fjärrgrenen \"%s\""
-#: builtin/branch.c:226
+#: builtin/branch.c:227
#, c-format
msgid "Error deleting branch '%s'"
msgstr "Fel vid borttagning av grenen \"%s\""
-#: builtin/branch.c:233
+#: builtin/branch.c:234
#, c-format
msgid "Deleted remote branch %s (was %s).\n"
msgstr "Tog bort fjärrgrenen %s (var %s).\n"
-#: builtin/branch.c:234
+#: builtin/branch.c:235
#, c-format
msgid "Deleted branch %s (was %s).\n"
msgstr "Tog bort grenen %s (var %s).\n"
-#: builtin/branch.c:239
+#: builtin/branch.c:240
msgid "Update of config-file failed"
msgstr "Misslyckades uppdatera konfigurationsfil"
-#: builtin/branch.c:337
+#: builtin/branch.c:338
#, c-format
msgid "branch '%s' does not point at a commit"
msgstr "grenen \"%s\" pekar inte på en incheckning"
-#: builtin/branch.c:409
+#: builtin/branch.c:410
#, c-format
msgid "[%s: behind %d]"
msgstr "[%s: bakom %d] "
-#: builtin/branch.c:411
+#: builtin/branch.c:412
#, c-format
msgid "[behind %d]"
msgstr "[bakom %d] "
-#: builtin/branch.c:415
+#: builtin/branch.c:416
#, c-format
msgid "[%s: ahead %d]"
msgstr "[%s: före %d] "
-#: builtin/branch.c:417
+#: builtin/branch.c:418
#, c-format
msgid "[ahead %d]"
msgstr "[före %d] "
-#: builtin/branch.c:420
+#: builtin/branch.c:421
#, c-format
msgid "[%s: ahead %d, behind %d]"
msgstr "[%s: före %d, bakom %d] "
-#: builtin/branch.c:423
+#: builtin/branch.c:424
#, c-format
msgid "[ahead %d, behind %d]"
msgstr "[före %d, bakom %d] "
-#: builtin/branch.c:535
+#: builtin/branch.c:537
msgid "(no branch)"
msgstr "(ingen gren)"
-#: builtin/branch.c:600
+#: builtin/branch.c:602
msgid "some refs could not be read"
msgstr "vissa referenser kunde inte läsas"
-#: builtin/branch.c:613
+#: builtin/branch.c:615
msgid "cannot rename the current branch while not on any."
msgstr ""
"kunde inte byta namn på aktuell gren när du inte befinner dig på någon."
-#: builtin/branch.c:623
+#: builtin/branch.c:625
#, c-format
msgid "Invalid branch name: '%s'"
msgstr "Felaktigt namn på gren: \"%s\""
-#: builtin/branch.c:638
+#: builtin/branch.c:640
msgid "Branch rename failed"
msgstr "Misslyckades byta namn på gren"
-#: builtin/branch.c:642
+#: builtin/branch.c:644
#, c-format
msgid "Renamed a misnamed branch '%s' away"
msgstr "Bytte bort namn på en felaktigt namngiven gren \"%s\""
-#: builtin/branch.c:646
+#: builtin/branch.c:648
#, c-format
msgid "Branch renamed to %s, but HEAD is not updated!"
msgstr "Grenen namnbytt till %s, men HEAD har inte uppdaterats!"
-#: builtin/branch.c:653
+#: builtin/branch.c:655
msgid "Branch is renamed, but update of config-file failed"
msgstr "Grenen namnbytt, men misslyckades uppdatera konfigurationsfilen"
-#: builtin/branch.c:668
+#: builtin/branch.c:670
#, c-format
msgid "malformed object name %s"
msgstr "felformat objektnamn %s"
-#: builtin/branch.c:692
+#: builtin/branch.c:694
#, c-format
msgid "could not write branch description template: %s"
msgstr "kunde inte skriva grenbeskrivningsmall: %s"
-#: builtin/branch.c:783
+#: builtin/branch.c:724
+msgid "Generic options"
+msgstr "Allmänna flaggor"
+
+#: builtin/branch.c:726
+msgid "show hash and subject, give twice for upstream branch"
+msgstr "visa hash och ärenderad, ange två gånger för uppströmsgren"
+
+#: builtin/branch.c:727
+msgid "suppress informational messages"
+msgstr "undertryck informationsmeddelanden"
+
+#: builtin/branch.c:728
+msgid "set up tracking mode (see git-pull(1))"
+msgstr "ställ in spårningsläge (se git-pull(1))"
+
+#: builtin/branch.c:730
+msgid "change upstream info"
+msgstr "ändra uppströmsinformation"
+
+#: builtin/branch.c:734
+msgid "use colored output"
+msgstr "använd färgad utdata"
+
+#: builtin/branch.c:735
+msgid "act on remote-tracking branches"
+msgstr "arbeta på fjärrspårande grenar"
+
+#: builtin/branch.c:738 builtin/branch.c:744 builtin/branch.c:765
+#: builtin/branch.c:771 builtin/commit.c:1395 builtin/commit.c:1396
+#: builtin/commit.c:1397 builtin/commit.c:1398 builtin/tag.c:470
+msgid "commit"
+msgstr "incheckning"
+
+#: builtin/branch.c:739 builtin/branch.c:745
+msgid "print only branches that contain the commit"
+msgstr "visa endast grenar som innehåller incheckningen"
+
+#: builtin/branch.c:751
+msgid "Specific git-branch actions:"
+msgstr "Specifika git-branch-åtgärder:"
+
+#: builtin/branch.c:752
+msgid "list both remote-tracking and local branches"
+msgstr "visa både fjärrspårande och lokala grenar"
+
+#: builtin/branch.c:754
+msgid "delete fully merged branch"
+msgstr "ta bort helt sammanslagen gren"
+
+#: builtin/branch.c:755
+msgid "delete branch (even if not merged)"
+msgstr "ta bort gren (även om inte helt sammanslagen)"
+
+#: builtin/branch.c:756
+msgid "move/rename a branch and its reflog"
+msgstr "flytta/ta bort en gren och dess reflogg"
+
+#: builtin/branch.c:757
+msgid "move/rename a branch, even if target exists"
+msgstr "flytta/ta bort en gren, även om målet finns"
+
+#: builtin/branch.c:758
+msgid "list branch names"
+msgstr "lista namn på grenar"
+
+#: builtin/branch.c:759
+msgid "create the branch's reflog"
+msgstr "skapa grenens reflogg"
+
+#: builtin/branch.c:761
+msgid "edit the description for the branch"
+msgstr "redigera beskrivning för grenen"
+
+#: builtin/branch.c:762
+msgid "force creation (when already exists)"
+msgstr "tvinga skapande (när den redan finns)"
+
+#: builtin/branch.c:765
+msgid "print only not merged branches"
+msgstr "visa endast ej sammanslagna grenar"
+
+#: builtin/branch.c:771
+msgid "print only merged branches"
+msgstr "visa endast sammanslagna grenar"
+
+#: builtin/branch.c:775
+msgid "list branches in columns"
+msgstr "visa grenar i spalter"
+
+#: builtin/branch.c:788
msgid "Failed to resolve HEAD as a valid ref."
msgstr "Misslyckades slå upp HEAD som giltig referens"
-#: builtin/branch.c:788 builtin/clone.c:558
+#: builtin/branch.c:793 builtin/clone.c:561
msgid "HEAD not found below refs/heads!"
msgstr "HEAD hittades inte under refs/heads!"
-#: builtin/branch.c:808
+#: builtin/branch.c:813
msgid "--column and --verbose are incompatible"
msgstr "--column och --verbose är inkompatibla"
-#: builtin/branch.c:857
+#: builtin/branch.c:864
+#, c-format
+msgid "branch '%s' does not exist"
+msgstr "grenen \"%s\" finns inte"
+
+#: builtin/branch.c:876
+#, c-format
+msgid "Branch '%s' has no upstream information"
+msgstr "Grenen \"%s\" har ingen uppströmsinformation"
+
+#: builtin/branch.c:891
msgid "-a and -r options to 'git branch' do not make sense with a branch name"
msgstr ""
"flaggorna -a och -r på \"git branch\" kan inte anges tillsammans med ett "
"grennamn"
+#: builtin/branch.c:894
+#, c-format
+msgid ""
+"The --set-upstream flag is deprecated and will be removed. Consider using --"
+"track or --set-upstream-to\n"
+msgstr ""
+"Flaggan --set-upstream rekommenderas ej och kommer tas bort. Använd --track "
+"eller --set-upstream-to\n"
+
+#: builtin/branch.c:911
+#, c-format
+msgid ""
+"\n"
+"If you wanted to make '%s' track '%s', do this:\n"
+"\n"
+msgstr ""
+"\n"
+"Om du vill göra så att \"%s\" spårar \"%s\" gör du så här:\n"
+"\n"
+
+#: builtin/branch.c:912
+#, c-format
+msgid " git branch -d %s\n"
+msgstr " git branch -d %s\n"
+
+#: builtin/branch.c:913
+#, c-format
+msgid " git branch --set-upstream-to %s\n"
+msgstr " git branch --set-upstream-to %s\n"
+
#: builtin/bundle.c:47
#, c-format
msgid "%s is okay\n"
@@ -1703,99 +2486,227 @@ msgstr "Behöver ett arkiv för att skapa ett paket (bundle)."
msgid "Need a repository to unbundle."
msgstr "Behöver ett arkiv för att packa upp ett paket (bundle)."
-#: builtin/checkout.c:113 builtin/checkout.c:146
+#: builtin/cat-file.c:247
+msgid "git cat-file (-t|-s|-e|-p|<type>|--textconv) <object>"
+msgstr "git cat-file (-t|-s|-e|-p|<typ>|--textconv) <objekt>"
+
+#: builtin/cat-file.c:248
+msgid "git cat-file (--batch|--batch-check) < <list_of_objects>"
+msgstr "git cat-file (--batch|--batch-check) < <objektlista>"
+
+#: builtin/cat-file.c:266
+msgid "<type> can be one of: blob, tree, commit, tag"
+msgstr "<typ> kan vara en av: blob, tree, commit, tag"
+
+#: builtin/cat-file.c:267
+msgid "show object type"
+msgstr "visa objekttyp"
+
+#: builtin/cat-file.c:268
+msgid "show object size"
+msgstr "visa objektstorlek"
+
+#: builtin/cat-file.c:270
+msgid "exit with zero when there's no error"
+msgstr "avsluta med noll när det inte uppstått något fel"
+
+#: builtin/cat-file.c:271
+msgid "pretty-print object's content"
+msgstr "visa objektets innehåll snyggt"
+
+#: builtin/cat-file.c:273
+msgid "for blob objects, run textconv on object's content"
+msgstr "för blob-objekt, kör textconv på objektets innehåll"
+
+#: builtin/cat-file.c:275
+msgid "show info and content of objects fed from the standard input"
+msgstr "visa information och innehåll för objekt som listas på standard in"
+
+#: builtin/cat-file.c:278
+msgid "show info about objects fed from the standard input"
+msgstr "visa information för objekt som listas på standard in"
+
+#: builtin/check-attr.c:11
+msgid "git check-attr [-a | --all | attr...] [--] pathname..."
+msgstr "git check-attr [-a | --all | attr...] [--] sökväg..."
+
+#: builtin/check-attr.c:12
+msgid "git check-attr --stdin [-a | --all | attr...] < <list-of-paths>"
+msgstr "git check-attr --stdin [-a | --all | attr...] < <sökvägslista>"
+
+#: builtin/check-attr.c:19
+msgid "report all attributes set on file"
+msgstr "visa alla attribut som satts på filen"
+
+#: builtin/check-attr.c:20
+msgid "use .gitattributes only from the index"
+msgstr "använd .gitattributes endast från indexet"
+
+#: builtin/check-attr.c:21 builtin/hash-object.c:75
+msgid "read file names from stdin"
+msgstr "läs filnamn från standard in"
+
+#: builtin/check-attr.c:23
+msgid "input paths are terminated by a null character"
+msgstr "sökvägar avdelas med null-tecken"
+
+#: builtin/checkout-index.c:126
+msgid "git checkout-index [options] [--] [<file>...]"
+msgstr "git checkout-index [flaggor] [--] [<fil>...]"
+
+#: builtin/checkout-index.c:187
+msgid "check out all files in the index"
+msgstr "checka ut alla filer i indexet"
+
+#: builtin/checkout-index.c:188
+msgid "force overwrite of existing files"
+msgstr "tvinga överskrivning av befintliga filer"
+
+#: builtin/checkout-index.c:190
+msgid "no warning for existing files and files not in index"
+msgstr "ingen varning för existerande filer och filer ej i indexet"
+
+#: builtin/checkout-index.c:192
+msgid "don't checkout new files"
+msgstr "checka inte ut nya filer"
+
+#: builtin/checkout-index.c:194
+msgid "update stat information in the index file"
+msgstr "uppdatera stat-information i indexfilen"
+
+#: builtin/checkout-index.c:200
+msgid "read list of paths from the standard input"
+msgstr "läs listan över sökvägar från standard in"
+
+#: builtin/checkout-index.c:202
+msgid "write the content to temporary files"
+msgstr "skriv innehåll till temporära filer"
+
+#: builtin/checkout-index.c:203 builtin/column.c:30
+msgid "string"
+msgstr "sträng"
+
+#: builtin/checkout-index.c:204
+msgid "when creating files, prepend <string>"
+msgstr "när filer skapas, lägg till <sträng> först"
+
+#: builtin/checkout-index.c:207
+msgid "copy out the files from named stage"
+msgstr "kopiera ut filer från namngiven etapp"
+
+#: builtin/checkout.c:25
+msgid "git checkout [options] <branch>"
+msgstr "git checkout [flaggor] <gren>"
+
+#: builtin/checkout.c:26
+msgid "git checkout [options] [<branch>] -- <file>..."
+msgstr "git checkout [flaggor] [<gren>] -- <fil>..."
+
+#: builtin/checkout.c:116 builtin/checkout.c:149
#, c-format
msgid "path '%s' does not have our version"
msgstr "sökvägen \"%s\" har inte vår version"
-#: builtin/checkout.c:115 builtin/checkout.c:148
+#: builtin/checkout.c:118 builtin/checkout.c:151
#, c-format
msgid "path '%s' does not have their version"
msgstr "sökvägen \"%s\" har inte deras version"
-#: builtin/checkout.c:131
+#: builtin/checkout.c:134
#, c-format
msgid "path '%s' does not have all necessary versions"
msgstr "sökvägen \"%s\" innehåller inte alla nödvändiga versioner"
-#: builtin/checkout.c:175
+#: builtin/checkout.c:178
#, c-format
msgid "path '%s' does not have necessary versions"
msgstr "sökvägen \"%s\" innehåller inte nödvändiga versioner"
-#: builtin/checkout.c:192
+#: builtin/checkout.c:195
#, c-format
msgid "path '%s': cannot merge"
msgstr "sökväg \"%s\": kan inte slå ihop"
-#: builtin/checkout.c:209
+#: builtin/checkout.c:212
#, c-format
msgid "Unable to add merge result for '%s'"
msgstr "Kunde inte lägga till sammanslagningsresultat för \"%s\""
-#: builtin/checkout.c:234 builtin/checkout.c:392
+#: builtin/checkout.c:236 builtin/checkout.c:239 builtin/checkout.c:242
+#: builtin/checkout.c:245
+#, c-format
+msgid "'%s' cannot be used with updating paths"
+msgstr "\"%s\" kan inte användas vid uppdatering av sökvägar"
+
+#: builtin/checkout.c:248 builtin/checkout.c:251
+#, c-format
+msgid "'%s' cannot be used with %s"
+msgstr "\"%s\" kan inte användas med %s"
+
+#: builtin/checkout.c:254
+#, c-format
+msgid "Cannot update paths and switch to branch '%s' at the same time."
+msgstr "Kan inte uppdatera sökvägar och växla till grenen \"%s\" samtidigt."
+
+#: builtin/checkout.c:265 builtin/checkout.c:426
msgid "corrupt index file"
msgstr "indexfilen är trasig"
-#: builtin/checkout.c:264 builtin/checkout.c:271
+#: builtin/checkout.c:295 builtin/checkout.c:302
#, c-format
msgid "path '%s' is unmerged"
msgstr "sökvägen \"%s\" har inte slagits ihop"
-#: builtin/checkout.c:302 builtin/checkout.c:498 builtin/clone.c:583
-#: builtin/merge.c:812
+#: builtin/checkout.c:333 builtin/checkout.c:534 builtin/clone.c:586
+#: builtin/merge.c:811
msgid "unable to write new index file"
msgstr "kunde inte skriva ny indexfil"
-#: builtin/checkout.c:319 builtin/diff.c:302 builtin/merge.c:408
-msgid "diff_setup_done failed"
-msgstr "diff_setup_done misslyckades"
-
-#: builtin/checkout.c:414
+#: builtin/checkout.c:448
msgid "you need to resolve your current index first"
msgstr "du måste lösa ditt befintliga index först"
-#: builtin/checkout.c:533
+#: builtin/checkout.c:569
#, c-format
msgid "Can not do reflog for '%s'\n"
msgstr "Kan inte skapa referenslog för \"%s\"\n"
-#: builtin/checkout.c:566
+#: builtin/checkout.c:602
msgid "HEAD is now at"
msgstr "HEAD är nu på"
-#: builtin/checkout.c:573
+#: builtin/checkout.c:609
#, c-format
msgid "Reset branch '%s'\n"
msgstr "Återställ gren \"%s\"\n"
-#: builtin/checkout.c:576
+#: builtin/checkout.c:612
#, c-format
msgid "Already on '%s'\n"
msgstr "Redan på \"%s\"\n"
-#: builtin/checkout.c:580
+#: builtin/checkout.c:616
#, c-format
msgid "Switched to and reset branch '%s'\n"
msgstr "Växlade till och nollställde grenen \"%s\"\n"
-#: builtin/checkout.c:582
+#: builtin/checkout.c:618
#, c-format
msgid "Switched to a new branch '%s'\n"
msgstr "Växlade till en ny gren \"%s\"\n"
-#: builtin/checkout.c:584
+#: builtin/checkout.c:620
#, c-format
msgid "Switched to branch '%s'\n"
msgstr "Växlade till grenen \"%s\"\n"
-#: builtin/checkout.c:640
+#: builtin/checkout.c:676
#, c-format
msgid " ... and %d more.\n"
msgstr " ... och %d till.\n"
#. The singular version
-#: builtin/checkout.c:646
+#: builtin/checkout.c:682
#, c-format
msgid ""
"Warning: you are leaving %d commit behind, not connected to\n"
@@ -1818,7 +2729,7 @@ msgstr[1] ""
"\n"
"%s\n"
-#: builtin/checkout.c:664
+#: builtin/checkout.c:700
#, c-format
msgid ""
"If you want to keep them by creating a new branch, this may be a good time\n"
@@ -1833,88 +2744,150 @@ msgstr ""
" git branch nytt_grennamn %s\n"
"\n"
-#: builtin/checkout.c:694
+#: builtin/checkout.c:730
msgid "internal error in revision walk"
msgstr "internt fel vid genomgång av revisioner (revision walk)"
-#: builtin/checkout.c:698
+#: builtin/checkout.c:734
msgid "Previous HEAD position was"
msgstr "Tidigare position för HEAD var"
-#: builtin/checkout.c:724
+#: builtin/checkout.c:761 builtin/checkout.c:950
msgid "You are on a branch yet to be born"
msgstr "Du är på en gren som ännu inte är född"
#. case (1)
-#: builtin/checkout.c:855
+#: builtin/checkout.c:886
#, c-format
msgid "invalid reference: %s"
msgstr "felaktig referens: %s"
#. case (1): want a tree
-#: builtin/checkout.c:894
+#: builtin/checkout.c:925
#, c-format
msgid "reference is not a tree: %s"
msgstr "referensen är inte ett träd: %s"
-#: builtin/checkout.c:974
-msgid "-B cannot be used with -b"
-msgstr "-B kan inte användas med -b"
+#: builtin/checkout.c:961
+msgid "paths cannot be used with switching branches"
+msgstr "sökvägar kan inte användas vid byte av gren"
-#: builtin/checkout.c:983
-msgid "--patch is incompatible with all other options"
-msgstr "--patch är inkompatibel med alla andra flaggor"
+#: builtin/checkout.c:964 builtin/checkout.c:968
+#, c-format
+msgid "'%s' cannot be used with switching branches"
+msgstr "\"%s\" kan inte användas vid byte av gren"
-#: builtin/checkout.c:986
-msgid "--detach cannot be used with -b/-B/--orphan"
-msgstr "--detcah kan inte användas med -b/-B/--orphan"
+#: builtin/checkout.c:972 builtin/checkout.c:975 builtin/checkout.c:980
+#: builtin/checkout.c:983
+#, c-format
+msgid "'%s' cannot be used with '%s'"
+msgstr "\"%s\" kan inte användas med \"%s\""
#: builtin/checkout.c:988
-msgid "--detach cannot be used with -t"
-msgstr "--detach kan inte användas med -t"
+#, c-format
+msgid "Cannot switch branch to a non-commit '%s'"
+msgstr "Kan inte växla gren till icke-incheckningen \"%s\""
-#: builtin/checkout.c:994
-msgid "--track needs a branch name"
-msgstr "--track behöver ett namn på en gren"
+#: builtin/checkout.c:1009 builtin/gc.c:177
+msgid "suppress progress reporting"
+msgstr "undertryck förloppsrapportering"
-#: builtin/checkout.c:1001
-msgid "Missing branch name; try -b"
-msgstr "Grennamn saknas; försök med -b"
+#: builtin/checkout.c:1010 builtin/checkout.c:1012 builtin/clone.c:89
+#: builtin/remote.c:169 builtin/remote.c:171
+msgid "branch"
+msgstr "gren"
-#: builtin/checkout.c:1007
-msgid "--orphan and -b|-B are mutually exclusive"
-msgstr "--orphan och -b|-B kan inte användas samtidigt"
+#: builtin/checkout.c:1011
+msgid "create and checkout a new branch"
+msgstr "skapa och checka ut en ny gren"
-#: builtin/checkout.c:1009
-msgid "--orphan cannot be used with -t"
-msgstr "--orphan kan inte användas med -t"
+#: builtin/checkout.c:1013
+msgid "create/reset and checkout a branch"
+msgstr "skapa/nollställ och checka ut en gren"
+
+#: builtin/checkout.c:1014
+msgid "create reflog for new branch"
+msgstr "skapa reflogg för ny gren"
+
+#: builtin/checkout.c:1015
+msgid "detach the HEAD at named commit"
+msgstr "koppla från HEAD vid namngiven incheckning"
+
+#: builtin/checkout.c:1016
+msgid "set upstream info for new branch"
+msgstr "sätt uppströmsinformation för ny gren"
+
+#: builtin/checkout.c:1018
+msgid "new branch"
+msgstr "ny gren"
+
+#: builtin/checkout.c:1018
+msgid "new unparented branch"
+msgstr "ny gren utan förälder"
#: builtin/checkout.c:1019
-msgid "git checkout: -f and -m are incompatible"
-msgstr "git checkout: -f och -m är inkompatibla"
+msgid "checkout our version for unmerged files"
+msgstr "checka ut vår version för ej sammanslagna filer"
+
+#: builtin/checkout.c:1021
+msgid "checkout their version for unmerged files"
+msgstr "checka ut deras version för ej sammanslagna filer"
+
+#: builtin/checkout.c:1023
+msgid "force checkout (throw away local modifications)"
+msgstr "tvinga utcheckning (kasta bort lokala ändringar)"
+
+#: builtin/checkout.c:1024
+msgid "perform a 3-way merge with the new branch"
+msgstr "utför en 3-vägssammanslagning för den nya grenen"
+
+#: builtin/checkout.c:1025 builtin/merge.c:215
+msgid "update ignored files (default)"
+msgstr "uppdatera ignorerade filer (standard)"
+
+#: builtin/checkout.c:1026 builtin/log.c:1111 parse-options.h:241
+msgid "style"
+msgstr "stil"
+
+#: builtin/checkout.c:1027
+msgid "conflict style (merge or diff3)"
+msgstr "konfliktstil (merge eller diff3)"
+
+#: builtin/checkout.c:1030
+msgid "second guess 'git checkout no-such-branch'"
+msgstr "förutspå \"git checkout gren-saknas\""
+
+#: builtin/checkout.c:1054
+msgid "-b, -B and --orphan are mutually exclusive"
+msgstr "-b, -B och --orphan är ömsesidigt uteslutande"
+
+#: builtin/checkout.c:1071
+msgid "--track needs a branch name"
+msgstr "--track behöver ett namn på en gren"
+
+#: builtin/checkout.c:1078
+msgid "Missing branch name; try -b"
+msgstr "Grennamn saknas; försök med -b"
-#: builtin/checkout.c:1053
+#: builtin/checkout.c:1113
msgid "invalid path specification"
msgstr "felaktig sökvägsangivelse"
-#: builtin/checkout.c:1061
+#: builtin/checkout.c:1120
#, c-format
msgid ""
-"git checkout: updating paths is incompatible with switching branches.\n"
+"Cannot update paths and switch to branch '%s' at the same time.\n"
"Did you intend to checkout '%s' which can not be resolved as commit?"
msgstr ""
-"git checkout: uppdatera sökvägar är inkompatibelt med att växla gren.\n"
-"Ville du checka ut \"%s\" som inte kan lösas som en sammanslaning?"
+"Kan inte uppdatera sökvägar och växla till grenen \"%s\" samtidigt.\n"
+"Ville du checka ut \"%s\" som inte kan lösas som en utcheckning?"
-#: builtin/checkout.c:1063
-msgid "git checkout: updating paths is incompatible with switching branches."
-msgstr "git checkout: uppdatera sökvägar är inkompatibelt med att växla gren."
-
-#: builtin/checkout.c:1068
-msgid "git checkout: --detach does not take a path argument"
-msgstr "git checkout: --detach tar inte en sökväg som argument"
+#: builtin/checkout.c:1125
+#, c-format
+msgid "git checkout: --detach does not take a path argument '%s'"
+msgstr "git checkout: --detach tar inte en sökväg som argument \"%s\""
-#: builtin/checkout.c:1071
+#: builtin/checkout.c:1129
msgid ""
"git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
"checking out of the index."
@@ -1922,13 +2895,39 @@ msgstr ""
"git checkout: --ours/--theirs, --force och --merge är inkompatibla när\n"
"du checkar ut från indexet."
-#: builtin/checkout.c:1090
-msgid "Cannot switch branch to a non-commit."
-msgstr "Kan inte växla gren på en icke-incheckning."
+#: builtin/clean.c:19
+msgid "git clean [-d] [-f] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>..."
+msgstr ""
+"git clean [-d] [-f] [-n] [-q] [-e <mönster>] [-x | -X] [--] <sökvägar>..."
+
+#: builtin/clean.c:51
+msgid "do not print names of files removed"
+msgstr "skriv inte ut namn på borttagna filer"
+
+#: builtin/clean.c:53
+msgid "force"
+msgstr "tvinga"
+
+#: builtin/clean.c:55
+msgid "remove whole directories"
+msgstr "ta bort hela kataloger"
+
+#: builtin/clean.c:56 builtin/describe.c:413 builtin/grep.c:802
+#: builtin/ls-files.c:491 builtin/name-rev.c:231 builtin/show-ref.c:199
+msgid "pattern"
+msgstr "mönster"
+
+#: builtin/clean.c:57
+msgid "add <pattern> to ignore rules"
+msgstr "lägg till <mönster> till ignoreringsregler"
+
+#: builtin/clean.c:58
+msgid "remove ignored files, too"
+msgstr "ta även bort ignorerade filer"
-#: builtin/checkout.c:1093
-msgid "--ours/--theirs is incompatible with switching branches."
-msgstr "--ours/--theirs är inkompatibla med att byta gren."
+#: builtin/clean.c:60
+msgid "remove only ignored files"
+msgstr "ta endast bort ignorerade filer"
#: builtin/clean.c:78
msgid "-x and -X cannot be used together"
@@ -1974,22 +2973,110 @@ msgstr "Skulle inte ta bort %s\n"
msgid "Not removing %s\n"
msgstr "Tar inte bort %s\n"
+#: builtin/clone.c:36
+msgid "git clone [options] [--] <repo> [<dir>]"
+msgstr "git clone [flaggor] [--] <arkiv> [<kat>]"
+
+#: builtin/clone.c:64 builtin/fetch.c:82 builtin/merge.c:212
+#: builtin/push.c:399
+msgid "force progress reporting"
+msgstr "tvinga förloppsrapportering"
+
+#: builtin/clone.c:66
+msgid "don't create a checkout"
+msgstr "skapa inte någon utcheckning"
+
+#: builtin/clone.c:67 builtin/clone.c:69 builtin/init-db.c:488
+msgid "create a bare repository"
+msgstr "skapa ett naket (\"bare\") arkiv"
+
+#: builtin/clone.c:72
+msgid "create a mirror repository (implies bare)"
+msgstr "skapa ett spegelarkiv (implicerar \"bare\")"
+
+#: builtin/clone.c:74
+msgid "to clone from a local repository"
+msgstr "för att klona från ett lokalt arkiv"
+
+#: builtin/clone.c:76
+msgid "don't use local hardlinks, always copy"
+msgstr "skapa inte lokala hårda länkar, kopiera alltid"
+
+#: builtin/clone.c:78
+msgid "setup as shared repository"
+msgstr "skapa som ett delat arkiv"
+
+#: builtin/clone.c:80 builtin/clone.c:82
+msgid "initialize submodules in the clone"
+msgstr "initiera undermoduler i klonen"
+
+#: builtin/clone.c:83 builtin/init-db.c:485
+msgid "template-directory"
+msgstr "mallkatalog"
+
+#: builtin/clone.c:84 builtin/init-db.c:486
+msgid "directory from which templates will be used"
+msgstr "katalog att använda mallar från"
+
+#: builtin/clone.c:86
+msgid "reference repository"
+msgstr "referensarkiv"
+
+#: builtin/clone.c:87 builtin/column.c:26 builtin/merge-file.c:44
+msgid "name"
+msgstr "namn"
+
+#: builtin/clone.c:88
+msgid "use <name> instead of 'origin' to track upstream"
+msgstr "använd <namn> istället för \"origin\" för att spåra uppströms"
+
+#: builtin/clone.c:90
+msgid "checkout <branch> instead of the remote's HEAD"
+msgstr "checka ut <gren> istället för fjärrens HEAD"
+
+#: builtin/clone.c:92
+msgid "path to git-upload-pack on the remote"
+msgstr "sökväg till git-upload-pack på fjärren"
+
+#: builtin/clone.c:93 builtin/fetch.c:83 builtin/grep.c:747
+msgid "depth"
+msgstr "djup"
+
+#: builtin/clone.c:94
+msgid "create a shallow clone of that depth"
+msgstr "skapa en grund klon på detta djup"
+
+#: builtin/clone.c:96
+msgid "clone only one branch, HEAD or --branch"
+msgstr "klona endast en gren, HEAD eller --branch"
+
+#: builtin/clone.c:97 builtin/init-db.c:494
+msgid "gitdir"
+msgstr "gitkat"
+
+#: builtin/clone.c:98 builtin/init-db.c:495
+msgid "separate git dir from working tree"
+msgstr "separera gitkatalogen från arbetskatalogen"
+
+#: builtin/clone.c:99
+msgid "key=value"
+msgstr "nyckel=värde"
+
+#: builtin/clone.c:100
+msgid "set config inside the new repository"
+msgstr "ställ in konfiguration i det nya arkivet"
+
#: builtin/clone.c:243
#, c-format
msgid "reference repository '%s' is not a local directory."
msgstr "referensarkivet \"%s\" är inte en lokal katalog."
-#: builtin/clone.c:302
-#, c-format
-msgid "failed to open '%s'"
-msgstr "misslyckades öppna \"%s\""
-
#: builtin/clone.c:306
#, c-format
msgid "failed to create directory '%s'"
msgstr "misslyckades skapa katalogen \"%s\""
-#: builtin/clone.c:308 builtin/diff.c:75
+#: builtin/clone.c:308 builtin/diff.c:77
#, c-format
msgid "failed to stat '%s'"
msgstr "misslyckades ta status på \"%s\""
@@ -2004,11 +3091,6 @@ msgstr "%s finns och är ingen katalog"
msgid "failed to stat %s\n"
msgstr "misslyckades ta status på %s\n"
-#: builtin/clone.c:341
-#, c-format
-msgid "failed to unlink '%s'"
-msgstr "misslyckades ta bort länken \"%s\""
-
#: builtin/clone.c:346
#, c-format
msgid "failed to create link '%s'"
@@ -2024,86 +3106,122 @@ msgstr "misslyckades kopiera filen till \"%s\""
msgid "done.\n"
msgstr "klart.\n"
-#: builtin/clone.c:440
+#: builtin/clone.c:443
#, c-format
msgid "Could not find remote branch %s to clone."
msgstr "Kunde inte hitta fjärrgrenen %s för att klona."
-#: builtin/clone.c:549
+#: builtin/clone.c:552
msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n"
msgstr ""
"HEAD hos fjärren pekar på en obefintlig referens, kan inte checka ut.\n"
-#: builtin/clone.c:639
+#: builtin/clone.c:642
msgid "Too many arguments."
msgstr "För många argument."
-#: builtin/clone.c:643
+#: builtin/clone.c:646
msgid "You must specify a repository to clone."
msgstr "Du måste ange ett arkiv att klona."
-#: builtin/clone.c:654
+#: builtin/clone.c:657
#, c-format
msgid "--bare and --origin %s options are incompatible."
msgstr "flaggorna --bare och --origin %s är inkompatibla."
-#: builtin/clone.c:668
+#: builtin/clone.c:671
#, c-format
msgid "repository '%s' does not exist"
msgstr "arkivet \"%s\" finns inte"
-#: builtin/clone.c:673
+#: builtin/clone.c:676
msgid "--depth is ignored in local clones; use file:// instead."
msgstr "--depth ignoreras i lokala kloningar; använd file:// istället"
-#: builtin/clone.c:683
+#: builtin/clone.c:686
#, c-format
msgid "destination path '%s' already exists and is not an empty directory."
msgstr "destinationssökvägen \"%s\" finns redan och är inte en tom katalog."
-#: builtin/clone.c:693
+#: builtin/clone.c:696
#, c-format
msgid "working tree '%s' already exists."
msgstr "arbetsträdet \"%s\" finns redan."
-#: builtin/clone.c:706 builtin/clone.c:720
+#: builtin/clone.c:709 builtin/clone.c:723
#, c-format
msgid "could not create leading directories of '%s'"
msgstr "kunde inte skapa inledande kataloger för \"%s\""
-#: builtin/clone.c:709
+#: builtin/clone.c:712
#, c-format
msgid "could not create work tree dir '%s'."
msgstr "kunde inte skapa arbetskatalogen \"%s\""
-#: builtin/clone.c:728
+#: builtin/clone.c:731
#, c-format
msgid "Cloning into bare repository '%s'...\n"
msgstr "Klonar till ett naket arkiv \"%s\"...\n"
-#: builtin/clone.c:730
+#: builtin/clone.c:733
#, c-format
msgid "Cloning into '%s'...\n"
msgstr "Klonar till \"%s\"...\n"
-#: builtin/clone.c:786
+#: builtin/clone.c:789
#, c-format
msgid "Don't know how to clone %s"
msgstr "Vet inte hur man klonar %s"
-#: builtin/clone.c:835
+#: builtin/clone.c:838
#, c-format
msgid "Remote branch %s not found in upstream %s"
msgstr "Fjärrgrenen %s hittades inte i uppströmsarkivet %s"
-#: builtin/clone.c:842
+#: builtin/clone.c:845
msgid "You appear to have cloned an empty repository."
msgstr "Du verkar ha klonat ett tomt arkiv."
+#: builtin/column.c:9
+msgid "git column [options]"
+msgstr "git column [flaggor]"
+
+#: builtin/column.c:26
+msgid "lookup config vars"
+msgstr "slå upp konfigurationsvariabler"
+
+#: builtin/column.c:27 builtin/column.c:28
+msgid "layout to use"
+msgstr "utseende att använda"
+
+#: builtin/column.c:29
+msgid "Maximum width"
+msgstr "Maximal bredd"
+
+#: builtin/column.c:30
+msgid "Padding space on left border"
+msgstr "Spaltfyllnad i vänsterkanten"
+
+#: builtin/column.c:31
+msgid "Padding space on right border"
+msgstr "Spaltfyllnad i högerkanten"
+
+#: builtin/column.c:32
+msgid "Padding space between columns"
+msgstr "Spaltfyllnad mellan spalter"
+
#: builtin/column.c:51
msgid "--command must be the first argument"
msgstr "--command måste vara första argument"
+#: builtin/commit.c:33
+msgid "git commit [options] [--] <filepattern>..."
+msgstr "git commit [flaggor] [--] <filmöster>..."
+
+#: builtin/commit.c:38
+msgid "git status [options] [--] <filepattern>..."
+msgstr "git status [flaggor] [--] <filmönster>..."
+
#: builtin/commit.c:43
msgid ""
"Your name and email address were configured automatically based\n"
@@ -2155,93 +3273,93 @@ msgstr ""
"\n"
"Annars använder du \"git reset\"\n"
-#: builtin/commit.c:253
+#: builtin/commit.c:256
msgid "failed to unpack HEAD tree object"
msgstr "misslyckades packa upp HEAD:s trädobjekt"
-#: builtin/commit.c:295
+#: builtin/commit.c:298
msgid "unable to create temporary index"
msgstr "kunde inte skapa temporär indexfil"
-#: builtin/commit.c:301
+#: builtin/commit.c:304
msgid "interactive add failed"
msgstr "interaktiv tilläggning misslyckades"
-#: builtin/commit.c:334 builtin/commit.c:355 builtin/commit.c:405
+#: builtin/commit.c:337 builtin/commit.c:358 builtin/commit.c:408
msgid "unable to write new_index file"
msgstr "kunde inte skriva filen new_index"
-#: builtin/commit.c:386
+#: builtin/commit.c:389
msgid "cannot do a partial commit during a merge."
msgstr "kan inte utföra en delvis incheckning under en sammanslagning."
-#: builtin/commit.c:388
+#: builtin/commit.c:391
msgid "cannot do a partial commit during a cherry-pick."
msgstr "kan inte utföra en delvis incheckning under en cherry-pick."
-#: builtin/commit.c:398
+#: builtin/commit.c:401
msgid "cannot read the index"
msgstr "kan inte läsa indexet"
-#: builtin/commit.c:418
+#: builtin/commit.c:421
msgid "unable to write temporary index file"
msgstr "kunde inte skriva temporär indexfil"
-#: builtin/commit.c:493 builtin/commit.c:499
+#: builtin/commit.c:510 builtin/commit.c:516
#, c-format
msgid "invalid commit: %s"
msgstr "felaktig incheckning: %s"
-#: builtin/commit.c:522
+#: builtin/commit.c:539
msgid "malformed --author parameter"
msgstr "felformad \"--author\"-flagga"
-#: builtin/commit.c:582
+#: builtin/commit.c:600
#, c-format
msgid "Malformed ident string: '%s'"
msgstr "Felaktig indragningssträng: \"%s\""
-#: builtin/commit.c:620 builtin/commit.c:653 builtin/commit.c:967
+#: builtin/commit.c:638 builtin/commit.c:671 builtin/commit.c:985
#, c-format
msgid "could not lookup commit %s"
msgstr "kunde inte slå upp incheckningen %s"
-#: builtin/commit.c:632 builtin/shortlog.c:296
+#: builtin/commit.c:650 builtin/shortlog.c:296
#, c-format
msgid "(reading log message from standard input)\n"
msgstr "(läser loggmeddelande från standard in)\n"
-#: builtin/commit.c:634
+#: builtin/commit.c:652
msgid "could not read log from standard input"
msgstr "kunde inte läsa logg från standard in"
-#: builtin/commit.c:638
+#: builtin/commit.c:656
#, c-format
msgid "could not read log file '%s'"
msgstr "kunde inte läsa loggfilen \"%s\""
-#: builtin/commit.c:644
+#: builtin/commit.c:662
msgid "commit has empty message"
msgstr "incheckningen har ett tomt meddelande"
-#: builtin/commit.c:660
+#: builtin/commit.c:678
msgid "could not read MERGE_MSG"
msgstr "kunde inte läsa MERGE_MSG"
-#: builtin/commit.c:664
+#: builtin/commit.c:682
msgid "could not read SQUASH_MSG"
msgstr "kunde inte läsa SQUASH_MSG"
-#: builtin/commit.c:668
+#: builtin/commit.c:686
#, c-format
msgid "could not read '%s'"
msgstr "kunde inte läsa \"%s\""
-#: builtin/commit.c:720
+#: builtin/commit.c:738
msgid "could not write commit template"
msgstr "kunde inte skriva incheckningsmall"
-#: builtin/commit.c:731
+#: builtin/commit.c:749
#, c-format
msgid ""
"\n"
@@ -2256,7 +3374,7 @@ msgstr ""
"\t%s\n"
"och försöker igen.\n"
-#: builtin/commit.c:736
+#: builtin/commit.c:754
#, c-format
msgid ""
"\n"
@@ -2271,7 +3389,7 @@ msgstr ""
"\t%s\n"
"och försöker igen.\n"
-#: builtin/commit.c:748
+#: builtin/commit.c:766
msgid ""
"Please enter the commit message for your changes. Lines starting\n"
"with '#' will be ignored, and an empty message aborts the commit.\n"
@@ -2279,7 +3397,7 @@ msgstr ""
"Ange incheckningsmeddelandet för dina ändringar. Rader som inleds\n"
"med \"#\" kommer ignoreras, och ett tomt meddelande avbryter incheckningen.\n"
-#: builtin/commit.c:753
+#: builtin/commit.c:771
msgid ""
"Please enter the commit message for your changes. Lines starting\n"
"with '#' will be kept; you may remove them yourself if you want to.\n"
@@ -2289,159 +3407,349 @@ msgstr ""
"med \"#\" kommer behållas; du kan själv ta bort dem om du vill.\n"
"Ett tomt meddelande avbryter incheckningen.\n"
-#: builtin/commit.c:766
+#: builtin/commit.c:784
#, c-format
msgid "%sAuthor: %s"
msgstr "%sFörfattare: %s"
-#: builtin/commit.c:773
+#: builtin/commit.c:791
#, c-format
msgid "%sCommitter: %s"
msgstr "%sIncheckare: %s"
-#: builtin/commit.c:793
+#: builtin/commit.c:811
msgid "Cannot read index"
msgstr "Kan inte läsa indexet"
-#: builtin/commit.c:830
+#: builtin/commit.c:848
msgid "Error building trees"
msgstr "Fel vid byggande av träd"
-#: builtin/commit.c:845 builtin/tag.c:361
+#: builtin/commit.c:863 builtin/tag.c:361
#, c-format
msgid "Please supply the message using either -m or -F option.\n"
msgstr "Ange meddelandet en av flaggorna -m eller -F.\n"
-#: builtin/commit.c:942
+#: builtin/commit.c:960
#, c-format
msgid "No existing author found with '%s'"
msgstr "Hittade ingen befintlig författare med \"%s\""
-#: builtin/commit.c:957 builtin/commit.c:1157
+#: builtin/commit.c:975 builtin/commit.c:1175
#, c-format
msgid "Invalid untracked files mode '%s'"
msgstr "Ogiltigt läge för ospårade filer: \"%s\""
-#: builtin/commit.c:997
+#: builtin/commit.c:1015
msgid "Using both --reset-author and --author does not make sense"
msgstr "Kan inte använda både --reset-author och --author"
-#: builtin/commit.c:1008
+#: builtin/commit.c:1026
msgid "You have nothing to amend."
msgstr "Du har inget att utöka."
-#: builtin/commit.c:1011
+#: builtin/commit.c:1029
msgid "You are in the middle of a merge -- cannot amend."
msgstr "Du är i mitten av en sammanslagning -- kan inte utöka."
-#: builtin/commit.c:1013
+#: builtin/commit.c:1031
msgid "You are in the middle of a cherry-pick -- cannot amend."
msgstr "Du är i mitten av en cherry-pick -- kan inte utöka."
-#: builtin/commit.c:1016
+#: builtin/commit.c:1034
msgid "Options --squash and --fixup cannot be used together"
msgstr "Flaggorna --squash och --fixup kan inte användas samtidigt"
-#: builtin/commit.c:1026
+#: builtin/commit.c:1044
msgid "Only one of -c/-C/-F/--fixup can be used."
msgstr "Endast en av -c/-C/-F/--fixup kan användas."
-#: builtin/commit.c:1028
+#: builtin/commit.c:1046
msgid "Option -m cannot be combined with -c/-C/-F/--fixup."
msgstr "Flaggan -m kan inte kombineras med -c/-C/-F/--fixup."
-#: builtin/commit.c:1036
+#: builtin/commit.c:1054
msgid "--reset-author can be used only with -C, -c or --amend."
msgstr "--reset-author kan endast användas med -C, -c eller --amend."
-#: builtin/commit.c:1053
+#: builtin/commit.c:1071
msgid "Only one of --include/--only/--all/--interactive/--patch can be used."
msgstr ""
"Endast en av --include/--only/--all/--interactive/--patch kan användas."
-#: builtin/commit.c:1055
+#: builtin/commit.c:1073
msgid "No paths with --include/--only does not make sense."
msgstr "Du måste ange sökvägar tillsammans med --include/--only."
-#: builtin/commit.c:1057
+#: builtin/commit.c:1075
msgid "Clever... amending the last one with dirty index."
msgstr "Smart... utöka den senaste med smutsigt index."
-#: builtin/commit.c:1059
+#: builtin/commit.c:1077
msgid "Explicit paths specified without -i nor -o; assuming --only paths..."
msgstr "Explicita sökvägar angavs utan -i eller -o; antar --only sökvägar..."
-#: builtin/commit.c:1069 builtin/tag.c:577
+#: builtin/commit.c:1087 builtin/tag.c:577
#, c-format
msgid "Invalid cleanup mode %s"
msgstr "Felaktigt städningsläge %s"
-#: builtin/commit.c:1074
+#: builtin/commit.c:1092
msgid "Paths with -a does not make sense."
msgstr "Kan inte ange sökvägar med -a."
-#: builtin/commit.c:1257
+#: builtin/commit.c:1189 builtin/commit.c:1417
+msgid "show status concisely"
+msgstr "vis koncis status"
+
+#: builtin/commit.c:1191 builtin/commit.c:1419
+msgid "show branch information"
+msgstr "visa information om gren"
+
+#: builtin/commit.c:1193 builtin/commit.c:1421 builtin/push.c:389
+msgid "machine-readable output"
+msgstr "maskinläsbar utdata"
+
+#: builtin/commit.c:1196 builtin/commit.c:1423
+msgid "terminate entries with NUL"
+msgstr "terminera poster med NUL"
+
+#: builtin/commit.c:1198 builtin/commit.c:1426 builtin/fast-export.c:636
+#: builtin/fast-export.c:639 builtin/tag.c:461
+msgid "mode"
+msgstr "läge"
+
+#: builtin/commit.c:1199 builtin/commit.c:1426
+msgid "show untracked files, optional modes: all, normal, no. (Default: all)"
+msgstr "visa ospårade filer, valfria lägen: alla, normal, no. (Standard: all)"
+
+#: builtin/commit.c:1202
+msgid "show ignored files"
+msgstr "visa ignorerade filer"
+
+#: builtin/commit.c:1203 parse-options.h:151
+msgid "when"
+msgstr "när"
+
+#: builtin/commit.c:1204
+msgid ""
+"ignore changes to submodules, optional when: all, dirty, untracked. "
+"(Default: all)"
+msgstr ""
+"ignorera ändringar i undermoduler, valfritt när: all, dirty, untracked. "
+"(Default: all)"
+
+#: builtin/commit.c:1206
+msgid "list untracked files in columns"
+msgstr "visa ospårade filer i spalter"
+
+#: builtin/commit.c:1275
msgid "couldn't look up newly created commit"
msgstr "kunde inte slå upp en precis skapad incheckning"
-#: builtin/commit.c:1259
+#: builtin/commit.c:1277
msgid "could not parse newly created commit"
msgstr "kunde inte tolka en precis skapad incheckning"
-#: builtin/commit.c:1300
+#: builtin/commit.c:1318
msgid "detached HEAD"
msgstr "frånkopplad HEAD"
-#: builtin/commit.c:1302
+#: builtin/commit.c:1320
msgid " (root-commit)"
msgstr " (rotincheckning)"
-#: builtin/commit.c:1446
+#: builtin/commit.c:1387
+msgid "suppress summary after successful commit"
+msgstr "undertryck sammanfattning efter framgångsrik incheckning"
+
+#: builtin/commit.c:1388
+msgid "show diff in commit message template"
+msgstr "visa diff i mallen för incheckningsmeddelandet"
+
+#: builtin/commit.c:1390
+msgid "Commit message options"
+msgstr "Alternativ för incheckningsmeddelande"
+
+#: builtin/commit.c:1391 builtin/tag.c:459
+msgid "read message from file"
+msgstr "läs meddelande från fil"
+
+#: builtin/commit.c:1392
+msgid "author"
+msgstr "författare"
+
+#: builtin/commit.c:1392
+msgid "override author for commit"
+msgstr "överstyr författare för incheckningen"
+
+#: builtin/commit.c:1393 builtin/gc.c:178
+msgid "date"
+msgstr "datum"
+
+#: builtin/commit.c:1393
+msgid "override date for commit"
+msgstr "överstyr datum för inchecknignen"
+
+#: builtin/commit.c:1394 builtin/merge.c:206 builtin/notes.c:534
+#: builtin/notes.c:691 builtin/tag.c:457
+msgid "message"
+msgstr "meddelande"
+
+#: builtin/commit.c:1394
+msgid "commit message"
+msgstr "incheckningsmeddelande"
+
+#: builtin/commit.c:1395
+msgid "reuse and edit message from specified commit"
+msgstr "återanvänd och redigera meddelande från angiven incheckning"
+
+#: builtin/commit.c:1396
+msgid "reuse message from specified commit"
+msgstr "återanvänd meddelande från angiven incheckning"
+
+#: builtin/commit.c:1397
+msgid "use autosquash formatted message to fixup specified commit"
+msgstr ""
+"använd autosquash-formaterat meddelande för att fixa angiven incheckning"
+
+#: builtin/commit.c:1398
+msgid "use autosquash formatted message to squash specified commit"
+msgstr ""
+"använd autosquash-formaterat meddelande för att slå ihop med angiven "
+"incheckning"
+
+#: builtin/commit.c:1399
+msgid "the commit is authored by me now (used with -C/-c/--amend)"
+msgstr "jag är nu författare av incheckningen (används med -C/-c/--amend)"
+
+#: builtin/commit.c:1400 builtin/log.c:1068 builtin/revert.c:109
+msgid "add Signed-off-by:"
+msgstr "lägg till Signed-off-by:"
+
+#: builtin/commit.c:1401
+msgid "use specified template file"
+msgstr "använd angiven mallfil"
+
+#: builtin/commit.c:1402
+msgid "force edit of commit"
+msgstr "tvinga redigering av incheckning"
+
+#: builtin/commit.c:1403
+msgid "default"
+msgstr "standard"
+
+#: builtin/commit.c:1403 builtin/tag.c:462
+msgid "how to strip spaces and #comments from message"
+msgstr "hur blanksteg och #kommentarer skall tas bort från meddelande"
+
+#: builtin/commit.c:1404
+msgid "include status in commit message template"
+msgstr "inkludera status i mallen för incheckningsmeddelandet"
+
+#: builtin/commit.c:1405 builtin/merge.c:213 builtin/tag.c:463
+msgid "key id"
+msgstr "nyckel-id"
+
+#: builtin/commit.c:1406 builtin/merge.c:214
+msgid "GPG sign commit"
+msgstr "GPG-signera incheckning"
+
+#. end commit message options
+#: builtin/commit.c:1409
+msgid "Commit contents options"
+msgstr "Alternativ för incheckningens innehåll"
+
+#: builtin/commit.c:1410
+msgid "commit all changed files"
+msgstr "checka in alla ändrade filer"
+
+#: builtin/commit.c:1411
+msgid "add specified files to index for commit"
+msgstr "lägg till angivna filer till indexet för incheckning"
+
+#: builtin/commit.c:1412
+msgid "interactively add files"
+msgstr "lägg till filer interaktivt"
+
+#: builtin/commit.c:1413
+msgid "interactively add changes"
+msgstr "lägg till ändringar interaktivt"
+
+#: builtin/commit.c:1414
+msgid "commit only specified files"
+msgstr "checka endast in angivna filer"
+
+#: builtin/commit.c:1415
+msgid "bypass pre-commit hook"
+msgstr "förbigå pre-commit-krok"
+
+#: builtin/commit.c:1416
+msgid "show what would be committed"
+msgstr "visa vad som skulle checkas in"
+
+#: builtin/commit.c:1424
+msgid "amend previous commit"
+msgstr "lägg till föregående incheckning"
+
+#: builtin/commit.c:1425
+msgid "bypass post-rewrite hook"
+msgstr "förbigå post-rewrite-krok"
+
+#: builtin/commit.c:1430
+msgid "ok to record an empty change"
+msgstr "ok att registrera en tom ändring"
+
+#: builtin/commit.c:1433
+msgid "ok to record a change with an empty message"
+msgstr "ok att registrera en ändring med tomt meddelande"
+
+#: builtin/commit.c:1464
msgid "could not parse HEAD commit"
msgstr "kunde inte tolka HEAD:s incheckning"
-#: builtin/commit.c:1484 builtin/merge.c:509
+#: builtin/commit.c:1502 builtin/merge.c:508
#, c-format
msgid "could not open '%s' for reading"
msgstr "kunde inte öppna \"%s\" för läsning"
-#: builtin/commit.c:1491
+#: builtin/commit.c:1509
#, c-format
msgid "Corrupt MERGE_HEAD file (%s)"
msgstr "Trasig MERGE_HEAD-fil (%s)"
-#: builtin/commit.c:1498
+#: builtin/commit.c:1516
msgid "could not read MERGE_MODE"
msgstr "kunde inte läsa MERGE_MODE"
-#: builtin/commit.c:1517
+#: builtin/commit.c:1535
#, c-format
msgid "could not read commit message: %s"
msgstr "kunde inte läsa incheckningsmeddelande: %s"
-#: builtin/commit.c:1531
+#: builtin/commit.c:1549
#, c-format
msgid "Aborting commit; you did not edit the message.\n"
msgstr "Avbryter incheckning; meddelandet inte redigerat.\n"
-#: builtin/commit.c:1536
+#: builtin/commit.c:1554
#, c-format
msgid "Aborting commit due to empty commit message.\n"
msgstr "Avbryter på grund av tomt incheckningsmeddelande.\n"
-#: builtin/commit.c:1551 builtin/merge.c:936 builtin/merge.c:961
+#: builtin/commit.c:1569 builtin/merge.c:935 builtin/merge.c:960
msgid "failed to write commit object"
msgstr "kunde inte skriva incheckningsobjekt"
-#: builtin/commit.c:1572
+#: builtin/commit.c:1590
msgid "cannot lock HEAD ref"
msgstr "kunde inte låsa HEAD-referens"
-#: builtin/commit.c:1576
+#: builtin/commit.c:1594
msgid "cannot update HEAD ref"
msgstr "kunde inte uppdatera HEAD-referens"
-#: builtin/commit.c:1587
+#: builtin/commit.c:1605
msgid ""
"Repository has been updated, but unable to write\n"
"new_index file. Check that disk is not full or quota is\n"
@@ -2452,6 +3760,134 @@ msgstr ""
"att kvoten inte har överskridits, och kör sedan\n"
"\"git reset HEAD\" för att återställa."
+#: builtin/config.c:7
+msgid "git config [options]"
+msgstr "git config [flaggor]"
+
+#: builtin/config.c:52
+msgid "Config file location"
+msgstr "Konfigurationsfilens plats"
+
+#: builtin/config.c:53
+msgid "use global config file"
+msgstr "använd global konfigurationsfil"
+
+#: builtin/config.c:54
+msgid "use system config file"
+msgstr "använd systemets konfigurationsfil"
+
+#: builtin/config.c:55
+msgid "use repository config file"
+msgstr "använd arkivets konfigurationsfil"
+
+#: builtin/config.c:56
+msgid "use given config file"
+msgstr "använd angiven konfigurationsil"
+
+#: builtin/config.c:57
+msgid "Action"
+msgstr "Åtgärd"
+
+#: builtin/config.c:58
+msgid "get value: name [value-regex]"
+msgstr "hämta värde: namn [värde-reguttr]"
+
+#: builtin/config.c:59
+msgid "get all values: key [value-regex]"
+msgstr "hämta alla värden: nyckel [värde-reguttr]"
+
+#: builtin/config.c:60
+msgid "get values for regexp: name-regex [value-regex]"
+msgstr "hämta värden för reguttr: namn-reguttr [värde-reguttr]"
+
+#: builtin/config.c:61
+msgid "replace all matching variables: name value [value_regex]"
+msgstr "ersätt alla motsvarande variabler: namn värde [värde-reguttr]"
+
+#: builtin/config.c:62
+msgid "add a new variable: name value"
+msgstr "lägg till en ny variabel: namn värde"
+
+#: builtin/config.c:63
+msgid "remove a variable: name [value-regex]"
+msgstr "ta bort en variabel: namn [värde-reguttr]"
+
+#: builtin/config.c:64
+msgid "remove all matches: name [value-regex]"
+msgstr "ta bort alla träffar: namn [värde-reguttr]"
+
+#: builtin/config.c:65
+msgid "rename section: old-name new-name"
+msgstr "byt namn på sektion: gammalt-namn nytt-namn"
+
+#: builtin/config.c:66
+msgid "remove a section: name"
+msgstr "ta bort en sektion: namn"
+
+#: builtin/config.c:67
+msgid "list all"
+msgstr "visa alla"
+
+#: builtin/config.c:68
+msgid "open an editor"
+msgstr "öppna textredigeringsprogram"
+
+#: builtin/config.c:69 builtin/config.c:70
+msgid "slot"
+msgstr "plats"
+
+#: builtin/config.c:69
+msgid "find the color configured: [default]"
+msgstr "hitta den inställda färgen: [default]"
+
+#: builtin/config.c:70
+msgid "find the color setting: [stdout-is-tty]"
+msgstr "hitta färginställningen: [stdout-is-tty]"
+
+#: builtin/config.c:71
+msgid "Type"
+msgstr "Typ"
+
+#: builtin/config.c:72
+msgid "value is \"true\" or \"false\""
+msgstr "värdet är \"true\" eller \"false\""
+
+#: builtin/config.c:73
+msgid "value is decimal number"
+msgstr "värdet är ett decimalt tal"
+
+#: builtin/config.c:74
+msgid "value is --bool or --int"
+msgstr "värdet är --bool eller --int"
+
+#: builtin/config.c:75
+msgid "value is a path (file or directory name)"
+msgstr "värdet är en sökväg (fil- eller katalognamn)"
+
+#: builtin/config.c:76
+msgid "Other"
+msgstr "Andra"
+
+#: builtin/config.c:77
+msgid "terminate values with NUL byte"
+msgstr "terminera värden med NUL-byte"
+
+#: builtin/config.c:78
+msgid "respect include directives on lookup"
+msgstr "respektera inkluderingsdirektiv vid uppslag"
+
+#: builtin/count-objects.c:69
+msgid "git count-objects [-v]"
+msgstr "git count-objects [-v]"
+
+#: builtin/describe.c:15
+msgid "git describe [options] <committish>*"
+msgstr "git describe [flaggor] <incheckning-igt>*"
+
+#: builtin/describe.c:16
+msgid "git describe [options] --dirty"
+msgstr "git describe [flaggor] --dirty"
+
#: builtin/describe.c:234
#, c-format
msgid "annotated tag %s not available"
@@ -2524,6 +3960,50 @@ msgstr ""
"mer än %i taggar hittades; listar de %i senaste\n"
"gav upp sökningen vid %s\n"
+#: builtin/describe.c:403
+msgid "find the tag that comes after the commit"
+msgstr "hitta taggen som kommer efter incheckningen"
+
+#: builtin/describe.c:404
+msgid "debug search strategy on stderr"
+msgstr "felsök sökstrategin på standard fel"
+
+#: builtin/describe.c:405
+msgid "use any ref in .git/refs"
+msgstr "använd alla referenser i .git/refs"
+
+#: builtin/describe.c:406
+msgid "use any tag in .git/refs/tags"
+msgstr "använd alla taggar i .git/refs/tags"
+
+#: builtin/describe.c:407
+msgid "always use long format"
+msgstr "använd alltid långt format"
+
+#: builtin/describe.c:410
+msgid "only output exact matches"
+msgstr "skriv endast ut exakta träffar"
+
+#: builtin/describe.c:412
+msgid "consider <n> most recent tags (default: 10)"
+msgstr "överväg de <n> nyaste taggarna (standard: 10)"
+
+#: builtin/describe.c:414
+msgid "only consider tags matching <pattern>"
+msgstr "överväg endast taggar som motsvarar <mönster>"
+
+#: builtin/describe.c:416 builtin/name-rev.c:238
+msgid "show abbreviated commit object as fallback"
+msgstr "visa förkortade incheckningsobjekt som standard"
+
+#: builtin/describe.c:417
+msgid "mark"
+msgstr "märke"
+
+#: builtin/describe.c:418
+msgid "append <mark> on dirty working tree (default: \"-dirty\")"
+msgstr "lägg till <märke> på lortigt arbetsträd (standard: \"-dirty\")"
+
#: builtin/describe.c:436
msgid "--long is incompatible with --abbrev=0"
msgstr "--long är inkompatibel med --abbrev=0"
@@ -2536,110 +4016,230 @@ msgstr "Inga namn hittades, kan inte beskriva något."
msgid "--dirty is incompatible with committishes"
msgstr "--dirty är inkompatibelt med \"committish\"-värden"
-#: builtin/diff.c:77
+#: builtin/diff.c:79
#, c-format
msgid "'%s': not a regular file or symlink"
msgstr "\"%s\": inte en normal fil eller symbolisk länk"
-#: builtin/diff.c:220
+#: builtin/diff.c:224
#, c-format
msgid "invalid option: %s"
msgstr "ogiltig flagga: %s"
-#: builtin/diff.c:297
+#: builtin/diff.c:301
msgid "Not a git repository"
msgstr "Inte ett git-arkiv"
-#: builtin/diff.c:347
+#: builtin/diff.c:344
#, c-format
msgid "invalid object '%s' given."
msgstr "objektet \"%s\" som angavs är felaktigt."
-#: builtin/diff.c:352
+#: builtin/diff.c:349
#, c-format
msgid "more than %d trees given: '%s'"
msgstr "mer än %d träd angavs: \"%s\""
-#: builtin/diff.c:362
+#: builtin/diff.c:359
#, c-format
msgid "more than two blobs given: '%s'"
msgstr "mer än två blobbar angavs: \"%s\""
-#: builtin/diff.c:370
+#: builtin/diff.c:367
#, c-format
msgid "unhandled object '%s' given."
msgstr "ej hanterat objekt \"%s\" angavs."
-#: builtin/fetch.c:200
+#: builtin/fast-export.c:22
+msgid "git fast-export [rev-list-opts]"
+msgstr "git fast-export [rev-list-flaggor]"
+
+#: builtin/fast-export.c:635
+msgid "show progress after <n> objects"
+msgstr "visa förlopp efter <n> objekt"
+
+#: builtin/fast-export.c:637
+msgid "select handling of signed tags"
+msgstr "välj hantering av signerade taggar"
+
+#: builtin/fast-export.c:640
+msgid "select handling of tags that tag filtered objects"
+msgstr "välj hantering av taggar som har taggfiltrerade objekt"
+
+#: builtin/fast-export.c:643
+msgid "Dump marks to this file"
+msgstr "Dump märken till filen"
+
+#: builtin/fast-export.c:645
+msgid "Import marks from this file"
+msgstr "Importera märken från filen"
+
+#: builtin/fast-export.c:647
+msgid "Fake a tagger when tags lack one"
+msgstr "Fejka taggare när taggen saknar en"
+
+#: builtin/fast-export.c:649
+msgid "Output full tree for each commit"
+msgstr "Skriv ut hela trädet för varje incheckning"
+
+#: builtin/fast-export.c:651
+msgid "Use the done feature to terminate the stream"
+msgstr "Använd done-funktionen för att avsluta strömmen"
+
+#: builtin/fast-export.c:652
+msgid "Skip output of blob data"
+msgstr "Hoppa över skrivning av blob-data"
+
+#: builtin/fetch.c:20
+msgid "git fetch [<options>] [<repository> [<refspec>...]]"
+msgstr "git fetch [<flaggor>] [<arkiv> [<refspec>...]]"
+
+#: builtin/fetch.c:21
+msgid "git fetch [<options>] <group>"
+msgstr "git fetch [<flaggor>] <grupp>"
+
+#: builtin/fetch.c:22
+msgid "git fetch --multiple [<options>] [(<repository> | <group>)...]"
+msgstr "git fetch --multiple [<flaggor>] [(<arkiv> | <grupp>)...]"
+
+#: builtin/fetch.c:23
+msgid "git fetch --all [<options>]"
+msgstr "git fetch --all [<flaggor>]"
+
+#: builtin/fetch.c:60
+msgid "fetch from all remotes"
+msgstr "hämta från alla fjärrar"
+
+#: builtin/fetch.c:62
+msgid "append to .git/FETCH_HEAD instead of overwriting"
+msgstr "lägg till i .git/FETCH_HEAD istället för att skriva över"
+
+#: builtin/fetch.c:64
+msgid "path to upload pack on remote end"
+msgstr "sökväg till upload pack på fjärren"
+
+#: builtin/fetch.c:65
+msgid "force overwrite of local branch"
+msgstr "tvinga överskrivning av lokal gren"
+
+#: builtin/fetch.c:67
+msgid "fetch from multiple remotes"
+msgstr "hämta från flera fjärrar"
+
+#: builtin/fetch.c:69
+msgid "fetch all tags and associated objects"
+msgstr "hämta alla taggar och associerade objekt"
+
+#: builtin/fetch.c:71
+msgid "do not fetch all tags (--no-tags)"
+msgstr "hämta inte alla taggar (--no-tags)"
+
+#: builtin/fetch.c:73
+msgid "prune remote-tracking branches no longer on remote"
+msgstr "rensa fjärrspårande grenar ej längre på fjärren"
+
+#: builtin/fetch.c:74
+msgid "on-demand"
+msgstr "on-demand"
+
+#: builtin/fetch.c:75
+msgid "control recursive fetching of submodules"
+msgstr "styr rekursiv hämtning av undermoduler"
+
+#: builtin/fetch.c:79
+msgid "keep downloaded pack"
+msgstr "behåll hämtade paket"
+
+#: builtin/fetch.c:81
+msgid "allow updating of HEAD ref"
+msgstr "tillåt uppdatering av HEAD-referens"
+
+#: builtin/fetch.c:84
+msgid "deepen history of shallow clone"
+msgstr "fördjupa historik för grund klon"
+
+#: builtin/fetch.c:85 builtin/log.c:1083
+msgid "dir"
+msgstr "kat"
+
+#: builtin/fetch.c:86
+msgid "prepend this to submodule path output"
+msgstr "lägg till i början av undermodulens sökvägsutdata"
+
+#: builtin/fetch.c:89
+msgid "default mode for recursion"
+msgstr "standardläge för rekursion"
+
+#: builtin/fetch.c:201
msgid "Couldn't find remote ref HEAD"
msgstr "Kunde inte hitta fjärr-referensen HEAD"
-#: builtin/fetch.c:253
+#: builtin/fetch.c:254
#, c-format
msgid "object %s not found"
msgstr "objektet %s hittades inte"
-#: builtin/fetch.c:259
+#: builtin/fetch.c:260
msgid "[up to date]"
msgstr "[àjour]"
-#: builtin/fetch.c:273
+#: builtin/fetch.c:274
#, 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
+#: builtin/fetch.c:275 builtin/fetch.c:361
msgid "[rejected]"
msgstr "[refuserad]"
-#: builtin/fetch.c:285
+#: builtin/fetch.c:286
msgid "[tag update]"
msgstr "[uppdaterad tagg]"
-#: builtin/fetch.c:287 builtin/fetch.c:322 builtin/fetch.c:340
+#: builtin/fetch.c:288 builtin/fetch.c:323 builtin/fetch.c:341
msgid " (unable to update local ref)"
msgstr " (kunde inte uppdatera lokal ref)"
-#: builtin/fetch.c:305
+#: builtin/fetch.c:306
msgid "[new tag]"
msgstr "[ny tagg]"
-#: builtin/fetch.c:308
+#: builtin/fetch.c:309
msgid "[new branch]"
msgstr "[ny gren]"
-#: builtin/fetch.c:311
+#: builtin/fetch.c:312
msgid "[new ref]"
msgstr "[ny ref]"
-#: builtin/fetch.c:356
+#: builtin/fetch.c:357
msgid "unable to update local ref"
msgstr "kunde inte uppdatera lokal ref"
-#: builtin/fetch.c:356
+#: builtin/fetch.c:357
msgid "forced update"
msgstr "tvingad uppdatering"
-#: builtin/fetch.c:362
+#: builtin/fetch.c:363
msgid "(non-fast-forward)"
msgstr "(ej snabbspolad)"
-#: builtin/fetch.c:393 builtin/fetch.c:685
+#: builtin/fetch.c:394 builtin/fetch.c:686
#, c-format
msgid "cannot open %s: %s\n"
msgstr "kan inte öppna %s: %s\n"
-#: builtin/fetch.c:402
+#: builtin/fetch.c:403
#, 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
+#: builtin/fetch.c:489
#, c-format
msgid "From %.*s\n"
msgstr "Från %.*s\n"
-#: builtin/fetch.c:499
+#: builtin/fetch.c:500
#, c-format
msgid ""
"some local refs could not be updated; try running\n"
@@ -2648,55 +4248,55 @@ 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
+#: builtin/fetch.c:550
#, c-format
msgid " (%s will become dangling)"
msgstr " (%s kommer bli dinglande)"
-#: builtin/fetch.c:550
+#: builtin/fetch.c:551
#, c-format
msgid " (%s has become dangling)"
msgstr " (%s har blivit dinglande)"
-#: builtin/fetch.c:557
+#: builtin/fetch.c:558
msgid "[deleted]"
msgstr "[borttagen]"
-#: builtin/fetch.c:558 builtin/remote.c:1055
+#: builtin/fetch.c:559 builtin/remote.c:1055
msgid "(none)"
msgstr "(ingen)"
-#: builtin/fetch.c:675
+#: builtin/fetch.c:676
#, 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
+#: builtin/fetch.c:710
#, 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
+#: builtin/fetch.c:787
#, 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
+#: builtin/fetch.c:790
#, c-format
msgid "Option \"%s\" is ignored for %s\n"
msgstr "Flaggan \"%s\" ignoreras för %s\n"
-#: builtin/fetch.c:888
+#: builtin/fetch.c:892
#, c-format
msgid "Fetching %s\n"
msgstr "Hämtar %s\n"
-#: builtin/fetch.c:890 builtin/remote.c:100
+#: builtin/fetch.c:894 builtin/remote.c:100
#, c-format
msgid "Could not fetch %s"
msgstr "Kunde inte hämta %s"
-#: builtin/fetch.c:907
+#: builtin/fetch.c:913
msgid ""
"No remote repository specified. Please, specify either a URL or a\n"
"remote name from which new revisions should be fetched."
@@ -2704,27 +4304,146 @@ msgstr ""
"Inget fjärrarkiv angavs. Ange antingen en URL eller namnet på ett\n"
"fjärrarkiv som nya incheckningar skall hämtas från."
-#: builtin/fetch.c:927
+#: builtin/fetch.c:933
msgid "You need to specify a tag name."
msgstr "Du måste ange namnet på en tagg."
-#: builtin/fetch.c:979
+#: builtin/fetch.c:985
msgid "fetch --all does not take a repository argument"
msgstr "fetch --all tar inte namnet på ett arkiv som argument"
-#: builtin/fetch.c:981
+#: builtin/fetch.c:987
msgid "fetch --all does not make sense with refspecs"
msgstr "fetch --all kan inte anges med referensspecifikationer"
-#: builtin/fetch.c:992
+#: builtin/fetch.c:998
#, c-format
msgid "No such remote or remote group: %s"
msgstr "Fjärren eller fjärrgruppen finns inte: %s"
-#: builtin/fetch.c:1000
+#: builtin/fetch.c:1006
msgid "Fetching a group and specifying refspecs does not make sense"
msgstr "Kan inte hämta från grupp och ange referensspecifikationer"
+#: builtin/fmt-merge-msg.c:13
+msgid "git fmt-merge-msg [-m <message>] [--log[=<n>]|--no-log] [--file <file>]"
+msgstr ""
+"git fmt-merge-msg [-m <meddelande>] [--log[=<n>]|--no-log] [--file <fil>]"
+
+#: builtin/fmt-merge-msg.c:653 builtin/fmt-merge-msg.c:656 builtin/grep.c:786
+#: builtin/merge.c:188 builtin/show-branch.c:656 builtin/show-ref.c:192
+#: builtin/tag.c:448 parse-options.h:133 parse-options.h:235
+msgid "n"
+msgstr "n"
+
+#: builtin/fmt-merge-msg.c:654
+msgid "populate log with at most <n> entries from shortlog"
+msgstr "fyll i loggen med som mest <n> poster från shortlog"
+
+#: builtin/fmt-merge-msg.c:657
+msgid "alias for --log (deprecated)"
+msgstr "alias för --log (avråds)"
+
+#: builtin/fmt-merge-msg.c:660
+msgid "text"
+msgstr "text"
+
+#: builtin/fmt-merge-msg.c:661
+msgid "use <text> as start of message"
+msgstr "inled meddelande med <text>"
+
+#: builtin/fmt-merge-msg.c:662
+msgid "file to read from"
+msgstr "fil att läsa från"
+
+#: builtin/for-each-ref.c:979
+msgid "git for-each-ref [options] [<pattern>]"
+msgstr "git for-each-ref [flaggor] [<mönster>]"
+
+#: builtin/for-each-ref.c:994
+msgid "quote placeholders suitably for shells"
+msgstr "citera platshållare passande för skal"
+
+#: builtin/for-each-ref.c:996
+msgid "quote placeholders suitably for perl"
+msgstr "citera platshållare passande för perl"
+
+#: builtin/for-each-ref.c:998
+msgid "quote placeholders suitably for python"
+msgstr "citera platshållare passande för python"
+
+#: builtin/for-each-ref.c:1000
+msgid "quote placeholders suitably for tcl"
+msgstr "citera platshållare passande för tcl"
+
+#: builtin/for-each-ref.c:1003
+msgid "show only <n> matched refs"
+msgstr "visa endast <n> träffade refs"
+
+#: builtin/for-each-ref.c:1004
+msgid "format"
+msgstr "format"
+
+#: builtin/for-each-ref.c:1004
+msgid "format to use for the output"
+msgstr "format att använda för utdata"
+
+#: builtin/for-each-ref.c:1005
+msgid "key"
+msgstr "nyckel"
+
+#: builtin/for-each-ref.c:1006
+msgid "field name to sort on"
+msgstr "fältnamn att sortera på"
+
+#: builtin/fsck.c:608
+msgid "git fsck [options] [<object>...]"
+msgstr "git fsck [flaggor] [<objekt>...]"
+
+#: builtin/fsck.c:614
+msgid "show unreachable objects"
+msgstr "visa onåbara objekt"
+
+#: builtin/fsck.c:615
+msgid "show dangling objects"
+msgstr "visa dinglande objekt"
+
+#: builtin/fsck.c:616
+msgid "report tags"
+msgstr "rapportera taggar"
+
+#: builtin/fsck.c:617
+msgid "report root nodes"
+msgstr "rapportera rotnoder"
+
+#: builtin/fsck.c:618
+msgid "make index objects head nodes"
+msgstr "gör indexojekt till huvudnoder"
+
+#: builtin/fsck.c:619
+msgid "make reflogs head nodes (default)"
+msgstr "gör refloggar till huvudnoder (standard)"
+
+#: builtin/fsck.c:620
+msgid "also consider packs and alternate objects"
+msgstr "ta även hänsyn till paket och alternativa objekt"
+
+#: builtin/fsck.c:621
+msgid "enable more strict checking"
+msgstr "aktivera striktare kontroll"
+
+#: builtin/fsck.c:623
+msgid "write dangling objects in .git/lost-found"
+msgstr "skriv dinglande objekt i .git/lost-found"
+
+#: builtin/fsck.c:624 builtin/prune.c:134
+msgid "show progress"
+msgstr "visa förlopp"
+
+#: builtin/gc.c:22
+msgid "git gc [options]"
+msgstr "git gc [flaggor]"
+
#: builtin/gc.c:63
#, c-format
msgid "Invalid %s: '%s'"
@@ -2735,6 +4454,18 @@ msgstr "Felaktigt %s: \"%s\""
msgid "insanely long object directory %.*s"
msgstr "tokigt lång objektkatalog %.*s"
+#: builtin/gc.c:179
+msgid "prune unreferenced objects"
+msgstr "rensa ej refererade objekt"
+
+#: builtin/gc.c:181
+msgid "be more thorough (increased runtime)"
+msgstr "var mer grundlig (ökar körtiden)"
+
+#: builtin/gc.c:182
+msgid "enable auto-gc mode"
+msgstr "aktivera auto-gc-läge"
+
#: builtin/gc.c:221
#, c-format
msgid "Auto packing the repository for optimum performance.\n"
@@ -2756,89 +4487,314 @@ 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:22
+msgid "git grep [options] [-e] <pattern> [<rev>...] [[--] <path>...]"
+msgstr "git grep [flaggor] [-e] <mönster> [<rev>...] [[--] <sökväg>...]"
+
#: builtin/grep.c:216
#, c-format
msgid "grep: failed to create thread: %s"
msgstr "grep: misslyckades skapa tråd. %s"
-#: builtin/grep.c:402
+#: builtin/grep.c:454
#, c-format
msgid "Failed to chdir: %s"
msgstr "Kunde inte byta katalog (chdir): %s"
-#: builtin/grep.c:478 builtin/grep.c:512
+#: builtin/grep.c:530 builtin/grep.c:564
#, c-format
msgid "unable to read tree (%s)"
msgstr "kunde inte läsa träd (%s)"
-#: builtin/grep.c:526
+#: builtin/grep.c:578
#, c-format
msgid "unable to grep from object of type %s"
msgstr "Kunde inte \"grep\" från objekt av typen %s"
-#: builtin/grep.c:584
+#: builtin/grep.c:636
#, c-format
msgid "switch `%c' expects a numerical value"
msgstr "flaggan \"%c\" antar ett numeriskt värde"
-#: builtin/grep.c:601
+#: builtin/grep.c:653
#, c-format
msgid "cannot open '%s'"
msgstr "kan inte öppna \"%s\""
-#: builtin/grep.c:885
+#: builtin/grep.c:728
+msgid "search in index instead of in the work tree"
+msgstr "sök i indexet istället för i arbetskatalogen"
+
+#: builtin/grep.c:730
+msgid "find in contents not managed by git"
+msgstr "sök i innehål som inte hanteras av git"
+
+#: builtin/grep.c:732
+msgid "search in both tracked and untracked files"
+msgstr "sök i både spårade och ospårade filer"
+
+#: builtin/grep.c:734
+msgid "search also in ignored files"
+msgstr "sök även i ignorerade filer"
+
+#: builtin/grep.c:737
+msgid "show non-matching lines"
+msgstr "vis rader som inte träffas"
+
+#: builtin/grep.c:739
+msgid "case insensitive matching"
+msgstr "skiftlägesokänslig sökning"
+
+#: builtin/grep.c:741
+msgid "match patterns only at word boundaries"
+msgstr "matcha endast mönster vid ordgränser"
+
+#: builtin/grep.c:743
+msgid "process binary files as text"
+msgstr "hantera binärfiler som text"
+
+#: builtin/grep.c:745
+msgid "don't match patterns in binary files"
+msgstr "träffa inte mönster i binärfiler"
+
+#: builtin/grep.c:748
+msgid "descend at most <depth> levels"
+msgstr "gå som mest ned <djup> nivåer"
+
+#: builtin/grep.c:752
+msgid "use extended POSIX regular expressions"
+msgstr "använd utökade POSIX-reguljära uttryck"
+
+#: builtin/grep.c:755
+msgid "use basic POSIX regular expressions (default)"
+msgstr "använd grundläggande POSIX-reguljära uttryck (standard)"
+
+#: builtin/grep.c:758
+msgid "interpret patterns as fixed strings"
+msgstr "tolka mönster som fixerade strängar"
+
+#: builtin/grep.c:761
+msgid "use Perl-compatible regular expressions"
+msgstr "använd Perlkompatibla reguljära uttryck"
+
+#: builtin/grep.c:764
+msgid "show line numbers"
+msgstr "visa radnummer"
+
+#: builtin/grep.c:765
+msgid "don't show filenames"
+msgstr "visa inte filnamn"
+
+# %s är ett verb ("Untracked"/"Ignored"); lägg till ett -e.
+#: builtin/grep.c:766
+msgid "show filenames"
+msgstr "visa filnamn"
+
+#: builtin/grep.c:768
+msgid "show filenames relative to top directory"
+msgstr "visa filnamn relativa till toppkatalogen"
+
+#: builtin/grep.c:770
+msgid "show only filenames instead of matching lines"
+msgstr "visa endast filnamn istället för träffade rader"
+
+#: builtin/grep.c:772
+msgid "synonym for --files-with-matches"
+msgstr "synonym för --files-with-matches"
+
+#: builtin/grep.c:775
+msgid "show only the names of files without match"
+msgstr "visa endast namn på filer utan träffar"
+
+#: builtin/grep.c:777
+msgid "print NUL after filenames"
+msgstr "skriv NUL efter filnamn"
+
+#: builtin/grep.c:779
+msgid "show the number of matches instead of matching lines"
+msgstr "visa antal träffar istället för träffade rader"
+
+#: builtin/grep.c:780
+msgid "highlight matches"
+msgstr "ljusmarkera träffar"
+
+#: builtin/grep.c:782
+msgid "print empty line between matches from different files"
+msgstr "skriv tomma rader mellan träffar från olika filer"
+
+#: builtin/grep.c:784
+msgid "show filename only once above matches from same file"
+msgstr "visa filnamn endast en gång ovanför träffar från samma fil"
+
+#: builtin/grep.c:787
+msgid "show <n> context lines before and after matches"
+msgstr "visa <n> rader sammanhang före och efter träffar"
+
+#: builtin/grep.c:790
+msgid "show <n> context lines before matches"
+msgstr "visa <n> rader sammanhang före träffar"
+
+#: builtin/grep.c:792
+msgid "show <n> context lines after matches"
+msgstr "visa <n> rader sammanhang efter träffar"
+
+#: builtin/grep.c:793
+msgid "shortcut for -C NUM"
+msgstr "genväg för -C NUM"
+
+#: builtin/grep.c:796
+msgid "show a line with the function name before matches"
+msgstr "visa en rad med funktionsnamnet före träffen"
+
+#: builtin/grep.c:798
+msgid "show the surrounding function"
+msgstr "visa den omkringliggande funktionen"
+
+#: builtin/grep.c:801
+msgid "read patterns from file"
+msgstr "läs mönster från fil"
+
+#: builtin/grep.c:803
+msgid "match <pattern>"
+msgstr "träffa <mönster>"
+
+#: builtin/grep.c:805
+msgid "combine patterns specified with -e"
+msgstr "kombinera mönster som anges med -e"
+
+#: builtin/grep.c:817
+msgid "indicate hit with exit status without output"
+msgstr "ange träff med slutstatuskod utan utdata"
+
+#: builtin/grep.c:819
+msgid "show only matches from files that match all patterns"
+msgstr "visa endast träffar från filer som träffar alla mönster"
+
+#: builtin/grep.c:822
+msgid "pager"
+msgstr "bläddrare"
+
+#: builtin/grep.c:822
+msgid "show matching files in the pager"
+msgstr "visa träffade filer i filbläddraren"
+
+#: builtin/grep.c:825
+msgid "allow calling of grep(1) (ignored by this build)"
+msgstr "tillåt anropa grep(1) (ignoreras av detta bygge)"
+
+#: builtin/grep.c:826 builtin/show-ref.c:201
+msgid "show usage"
+msgstr "visa användning"
+
+#: builtin/grep.c:917
msgid "no pattern given."
msgstr "inget mönster angavs."
-#: builtin/grep.c:899
+#: builtin/grep.c:931
#, c-format
msgid "bad object %s"
msgstr "felaktigt objekt %s"
-#: builtin/grep.c:940
+#: builtin/grep.c:972
msgid "--open-files-in-pager only works on the worktree"
msgstr "--open-files-in-pager fungerar endast i arbetskatalogen"
-#: builtin/grep.c:963
+#: builtin/grep.c:995
msgid "--cached or --untracked cannot be used with --no-index."
msgstr "--cached och --untracked kan inte användas med --no-index."
-#: builtin/grep.c:968
+#: builtin/grep.c:1000
msgid "--no-index or --untracked cannot be used with revs."
msgstr "--no-index och --untracked kan inte användas med revisioner."
-#: builtin/grep.c:971
+#: builtin/grep.c:1003
msgid "--[no-]exclude-standard cannot be used for tracked contents."
msgstr "--[no-]exclude-standard kan inte användas för spårat innehåll."
-#: builtin/grep.c:979
+#: builtin/grep.c:1011
msgid "both --cached and trees are given."
msgstr "både --cached och träd angavs."
-#: builtin/help.c:59
+#: builtin/hash-object.c:60
+msgid ""
+"git hash-object [-t <type>] [-w] [--path=<file>|--no-filters] [--stdin] [--] "
+"<file>..."
+msgstr ""
+"git hash-object [-t <typ>] [-w] [--path=<fil>|--no-filters] [--stdin] [--] "
+"<fil>..."
+
+#: builtin/hash-object.c:61
+msgid "git hash-object --stdin-paths < <list-of-paths>"
+msgstr "git hash-object --stdin-paths < <sökvägslista>"
+
+#: builtin/hash-object.c:72
+msgid "type"
+msgstr "typ"
+
+#: builtin/hash-object.c:72
+msgid "object type"
+msgstr "objekttyp"
+
+#: builtin/hash-object.c:73
+msgid "write the object into the object database"
+msgstr "skriv objektet till objektdatabasen"
+
+#: builtin/hash-object.c:74
+msgid "read the object from stdin"
+msgstr "läs objektet från standard in"
+
+#: builtin/hash-object.c:76
+msgid "store file as is without filters"
+msgstr "spara filen som den är utan filer"
+
+#: builtin/hash-object.c:77
+msgid "process file as it were from this path"
+msgstr "hantera filen som om den kom från sökvägen"
+
+#: builtin/help.c:43
+msgid "print all available commands"
+msgstr "visa alla tillgängliga kommandon"
+
+#: builtin/help.c:44
+msgid "show man page"
+msgstr "visa manualsida"
+
+#: builtin/help.c:45
+msgid "show manual in web browser"
+msgstr "visa manual i webbläsare"
+
+#: builtin/help.c:47
+msgid "show info page"
+msgstr "visa info-sida"
+
+#: builtin/help.c:53
+msgid "git help [--all] [--man|--web|--info] [command]"
+msgstr "git help [--all] [--man|--web|--info] [kommando]"
+
+#: builtin/help.c:65
#, c-format
msgid "unrecognized help format '%s'"
msgstr "okänt hjälpformat: %s"
-#: builtin/help.c:87
+#: builtin/help.c:93
msgid "Failed to start emacsclient."
msgstr "Misslyckades starta emacsclient."
-#: builtin/help.c:100
+#: builtin/help.c:106
msgid "Failed to parse emacsclient version."
msgstr "Kunde inte tolka emacsclient-version."
-#: builtin/help.c:108
+#: builtin/help.c:114
#, c-format
msgid "emacsclient version '%d' too old (< 22)."
msgstr "emacsclient version \"%d\" för gammal (< 22)."
-#: builtin/help.c:126 builtin/help.c:154 builtin/help.c:163 builtin/help.c:171
+#: builtin/help.c:132 builtin/help.c:160 builtin/help.c:169 builtin/help.c:177
#, c-format
msgid "failed to exec '%s': %s"
msgstr "exec misslyckades för \"%s\": %s"
-#: builtin/help.c:211
+#: builtin/help.c:217
#, c-format
msgid ""
"'%s': path for unsupported man viewer.\n"
@@ -2847,7 +4803,7 @@ msgstr ""
"\"%s\": sökväg för man-visare som ej stöds.\n"
"Använd \"man.<verktyg>.cmd\" istället."
-#: builtin/help.c:223
+#: builtin/help.c:229
#, c-format
msgid ""
"'%s': cmd for supported man viewer.\n"
@@ -2856,266 +4812,307 @@ msgstr ""
"\"%s\": kommando för man-visare som stöds.\n"
"Använd \"man.<verktyg>.path\" istället."
-#: builtin/help.c:287
+#: builtin/help.c:299
msgid "The most commonly used git commands are:"
msgstr "De mest använda git-kommandona är:"
-#: builtin/help.c:355
+#: builtin/help.c:367
#, c-format
msgid "'%s': unknown man viewer."
msgstr "\"%s\": okänd man-visare."
-#: builtin/help.c:372
+#: builtin/help.c:384
msgid "no man viewer handled the request"
msgstr "ingen man-visare hanterade förfrågan"
-#: builtin/help.c:380
+#: builtin/help.c:392
msgid "no info viewer handled the request"
msgstr "ingen info-visare hanterade förfrågan"
-#: builtin/help.c:391
-#, c-format
-msgid "'%s': not a documentation directory."
-msgstr "\"%s\": inte en dokumentationskatalog."
-
-#: builtin/help.c:432 builtin/help.c:439
+#: builtin/help.c:447 builtin/help.c:454
#, c-format
msgid "usage: %s%s"
msgstr "användning: %s%s"
-#: builtin/help.c:453
+#: builtin/help.c:470
#, c-format
msgid "`git %s' is aliased to `%s'"
msgstr "\"git %s\" är ett alias för \"%s\""
-#: builtin/index-pack.c:169
+#: builtin/index-pack.c:170
#, c-format
msgid "object type mismatch at %s"
msgstr "objekttyp stämmer inte överens vid %s"
-#: builtin/index-pack.c:189
+#: builtin/index-pack.c:190
msgid "object of unexpected type"
msgstr "objekt av oväntad typ"
-#: builtin/index-pack.c:226
+#: builtin/index-pack.c:227
#, c-format
msgid "cannot fill %d byte"
msgid_plural "cannot fill %d bytes"
msgstr[0] "kan inte fylla %d byte"
msgstr[1] "kan inte fylla %d byte"
-#: builtin/index-pack.c:236
+#: builtin/index-pack.c:237
msgid "early EOF"
msgstr "tidigt filslut"
-#: builtin/index-pack.c:237
+#: builtin/index-pack.c:238
msgid "read error on input"
msgstr "indataläsfel"
-#: builtin/index-pack.c:249
+#: builtin/index-pack.c:250
msgid "used more bytes than were available"
msgstr "använde fler byte än tillgängligt"
-#: builtin/index-pack.c:256
+#: builtin/index-pack.c:257
msgid "pack too large for current definition of off_t"
msgstr "paket för stort för nuvarande definition av off_t"
-#: builtin/index-pack.c:272
+#: builtin/index-pack.c:273
#, c-format
msgid "unable to create '%s'"
msgstr "kunde inte skapa \"%s\""
-#: builtin/index-pack.c:277
+#: builtin/index-pack.c:278
#, c-format
msgid "cannot open packfile '%s'"
msgstr "kan inte öppna paketfilen \"%s\""
-#: builtin/index-pack.c:291
+#: builtin/index-pack.c:292
msgid "pack signature mismatch"
msgstr "paketsignatur stämmer inte överens"
-#: builtin/index-pack.c:311
+#: builtin/index-pack.c:294
+#, c-format
+msgid "pack version %<PRIu32> unsupported"
+msgstr "paketversion %<PRIu32> stöds ej"
+
+#: builtin/index-pack.c:312
#, c-format
msgid "pack has bad object at offset %lu: %s"
msgstr "paketet har felaktigt objekt vid index %lu: %s"
-#: builtin/index-pack.c:405
+#: builtin/index-pack.c:434
#, c-format
msgid "inflate returned %d"
msgstr "inflate returnerade %d"
-#: builtin/index-pack.c:450
+#: builtin/index-pack.c:483
msgid "offset value overflow for delta base object"
msgstr "indexvärdespill för deltabasobjekt"
-#: builtin/index-pack.c:458
+#: builtin/index-pack.c:491
msgid "delta base offset is out of bound"
msgstr "deltabasindex utanför gränsen"
-#: builtin/index-pack.c:466
+#: builtin/index-pack.c:499
#, c-format
msgid "unknown object type %d"
msgstr "okänd objekttyp %d"
-#: builtin/index-pack.c:495
+#: builtin/index-pack.c:530
msgid "cannot pread pack file"
msgstr "kan inte utföra \"pread\" på paketfil"
-#: builtin/index-pack.c:497
+#: builtin/index-pack.c:532
#, c-format
msgid "premature end of pack file, %lu byte missing"
msgid_plural "premature end of pack file, %lu bytes missing"
msgstr[0] "för tidigt slut på paketfilen, %lu byte saknas"
msgstr[1] "för tidigt slut på paketfilen, %lu byte saknas"
-#: builtin/index-pack.c:510
+#: builtin/index-pack.c:558
msgid "serious inflate inconsistency"
msgstr "allvarlig inflate-inkonsekvens"
-#: builtin/index-pack.c:583
-#, c-format
-msgid "cannot read existing object %s"
-msgstr "kan inte läsa befintligt objekt %s"
-
-#: builtin/index-pack.c:586
+#: builtin/index-pack.c:649 builtin/index-pack.c:655 builtin/index-pack.c:678
+#: builtin/index-pack.c:712 builtin/index-pack.c:721
#, c-format
msgid "SHA1 COLLISION FOUND WITH %s !"
msgstr "SHA1-KOLLISION UPPTÄCKT VID %s !"
-#: builtin/index-pack.c:598
+#: builtin/index-pack.c:652 builtin/pack-objects.c:170
+#: builtin/pack-objects.c:262
+#, c-format
+msgid "unable to read %s"
+msgstr "kunde inte läsa %s"
+
+#: builtin/index-pack.c:718
+#, c-format
+msgid "cannot read existing object %s"
+msgstr "kan inte läsa befintligt objekt %s"
+
+#: builtin/index-pack.c:732
#, c-format
msgid "invalid blob object %s"
msgstr "ogiltigt blob-objekt %s"
-#: builtin/index-pack.c:610
+#: builtin/index-pack.c:747
#, c-format
msgid "invalid %s"
msgstr "ogiltigt %s"
-#: builtin/index-pack.c:612
+#: builtin/index-pack.c:749
msgid "Error in object"
msgstr "Fel i objekt"
-#: builtin/index-pack.c:614
+#: builtin/index-pack.c:751
#, c-format
msgid "Not all child objects of %s are reachable"
msgstr "Inte alla barnobjekt för %s kan nås"
-#: builtin/index-pack.c:687 builtin/index-pack.c:713
+#: builtin/index-pack.c:821 builtin/index-pack.c:847
msgid "failed to apply delta"
msgstr "misslyckades tillämpa delta"
-#: builtin/index-pack.c:850
+#: builtin/index-pack.c:986
msgid "Receiving objects"
-msgstr "Tar bort objeckt"
+msgstr "Tar emot objekt"
-#: builtin/index-pack.c:850
+#: builtin/index-pack.c:986
msgid "Indexing objects"
msgstr "Skapar index för objekt"
-#: builtin/index-pack.c:872
+#: builtin/index-pack.c:1012
msgid "pack is corrupted (SHA1 mismatch)"
msgstr "paketet är trasigt (SHA1 stämmer inte)"
-#: builtin/index-pack.c:877
+#: builtin/index-pack.c:1017
msgid "cannot fstat packfile"
msgstr "kan inte utföra \"fstat\" på paketfil"
-#: builtin/index-pack.c:880
+#: builtin/index-pack.c:1020
msgid "pack has junk at the end"
msgstr "paket har skräp i slutet"
-#: builtin/index-pack.c:903
+#: builtin/index-pack.c:1031
+msgid "confusion beyond insanity in parse_pack_objects()"
+msgstr "förvirrad bortom vanvett i parse_pack_objects()"
+
+#: builtin/index-pack.c:1054
msgid "Resolving deltas"
msgstr "Analyserar delta"
-#: builtin/index-pack.c:954
+#: builtin/index-pack.c:1064
+#, c-format
+msgid "unable to create thread: %s"
+msgstr "kunde inte skapa tråd: %s"
+
+#: builtin/index-pack.c:1106
msgid "confusion beyond insanity"
msgstr "förvirrad bortom vanvett"
-#: builtin/index-pack.c:973
+#: builtin/index-pack.c:1112
+#, c-format
+msgid "completed with %d local objects"
+msgstr "slutfördes med %d lokala objekt"
+
+#: builtin/index-pack.c:1121
+#, c-format
+msgid "Unexpected tail checksum for %s (disk corruption?)"
+msgstr "Oväntad svanschecksumma för %s (trasig disk?)"
+
+#: builtin/index-pack.c:1125
#, c-format
msgid "pack has %d unresolved delta"
msgid_plural "pack has %d unresolved deltas"
msgstr[0] "paketet har %d oanalyserat delta"
msgstr[1] "paketet har %d oanalyserade delta"
-#: builtin/index-pack.c:998
+#: builtin/index-pack.c:1150
#, c-format
msgid "unable to deflate appended object (%d)"
msgstr "kunde inte utföra \"deflate\" på tillagt objekt (%d)"
-#: builtin/index-pack.c:1077
+#: builtin/index-pack.c:1229
#, c-format
msgid "local object %s is corrupt"
msgstr "lokalt objekt %s är trasigt"
-#: builtin/index-pack.c:1101
+#: builtin/index-pack.c:1253
msgid "error while closing pack file"
msgstr "fel vid stängning av paketfil"
-#: builtin/index-pack.c:1114
+#: builtin/index-pack.c:1266
#, c-format
msgid "cannot write keep file '%s'"
msgstr "kan inte ta skriva \"keep\"-fil \"%s\""
-#: builtin/index-pack.c:1122
+#: builtin/index-pack.c:1274
#, c-format
msgid "cannot close written keep file '%s'"
msgstr "akn inte stänga skriven \"keep\"-fil \"%s\""
-#: builtin/index-pack.c:1135
+#: builtin/index-pack.c:1287
msgid "cannot store pack file"
msgstr "kan inte spara paketfil"
-#: builtin/index-pack.c:1146
+#: builtin/index-pack.c:1298
msgid "cannot store index file"
msgstr "kan inte spara indexfil"
-#: builtin/index-pack.c:1247
+#: builtin/index-pack.c:1331
+#, c-format
+msgid "bad pack.indexversion=%<PRIu32>"
+msgstr "felaktig pack.indexversion=%<PRIu32>"
+
+#: builtin/index-pack.c:1337
+#, c-format
+msgid "invalid number of threads specified (%d)"
+msgstr "felaktigt antal trådar angivet (%d)"
+
+#: builtin/index-pack.c:1341 builtin/index-pack.c:1514
+#, c-format
+msgid "no threads support, ignoring %s"
+msgstr "trådstöd saknas, ignorerar %s"
+
+#: builtin/index-pack.c:1399
#, c-format
msgid "Cannot open existing pack file '%s'"
msgstr "Kan inte öppna befintlig paketfil \"%s\""
-#: builtin/index-pack.c:1249
+#: builtin/index-pack.c:1401
#, c-format
msgid "Cannot open existing pack idx file for '%s'"
msgstr "Kan inte öppna befintligt paket-idx-fil för \"%s\""
-#: builtin/index-pack.c:1296
+#: builtin/index-pack.c:1448
#, c-format
msgid "non delta: %d object"
msgid_plural "non delta: %d objects"
msgstr[0] "icke-delta: %d objekt"
msgstr[1] "icke-delta: %d objekt"
-#: builtin/index-pack.c:1303
+#: builtin/index-pack.c:1455
#, c-format
msgid "chain length = %d: %lu object"
msgid_plural "chain length = %d: %lu objects"
msgstr[0] "kedjelängd = %d: %lu objekt"
msgstr[1] "kedjelängd = %d: %lu objekt"
-#: builtin/index-pack.c:1330
+#: builtin/index-pack.c:1482
msgid "Cannot come back to cwd"
msgstr "Kan inte gå tillbaka till arbetskatalogen (cwd)"
-#: builtin/index-pack.c:1374 builtin/index-pack.c:1377
-#: builtin/index-pack.c:1389 builtin/index-pack.c:1393
+#: builtin/index-pack.c:1526 builtin/index-pack.c:1529
+#: builtin/index-pack.c:1541 builtin/index-pack.c:1545
#, c-format
msgid "bad %s"
msgstr "felaktig %s"
-#: builtin/index-pack.c:1407
+#: builtin/index-pack.c:1559
msgid "--fix-thin cannot be used without --stdin"
msgstr "--fix-thin kan inte användas med --stdin"
-#: builtin/index-pack.c:1411 builtin/index-pack.c:1421
+#: builtin/index-pack.c:1563 builtin/index-pack.c:1573
#, c-format
msgid "packfile name '%s' does not end with '.pack'"
msgstr "paketfilnamnet \"%s\" slutar inte med \".pack\""
-#: builtin/index-pack.c:1430
+#: builtin/index-pack.c:1582
msgid "--verify with no packfile name given"
msgstr "--verify angavs utan paketfilnamn"
@@ -3189,22 +5186,22 @@ msgstr "kopierade inte mallar från felaktig formatversion %d från \"%s\""
msgid "insane git directory %s"
msgstr "tokig git-katalog %s"
-#: builtin/init-db.c:322 builtin/init-db.c:325
+#: builtin/init-db.c:323 builtin/init-db.c:326
#, c-format
msgid "%s already exists"
msgstr "%s finns redan"
-#: builtin/init-db.c:354
+#: builtin/init-db.c:355
#, c-format
msgid "unable to handle file type %d"
msgstr "kan inte hantera filtyp %d"
-#: builtin/init-db.c:357
+#: builtin/init-db.c:358
#, c-format
msgid "unable to move %s to %s"
msgstr "kan inte flytta %s till %s"
-#: builtin/init-db.c:362
+#: builtin/init-db.c:363
#, c-format
msgid "Could not create git link %s"
msgstr "Kunde inte skapa gitlänk %s"
@@ -3214,38 +5211,58 @@ msgstr "Kunde inte skapa gitlänk %s"
#. * existing" or "Initialized empty", the second " shared" or
#. * "", and the last '%s%s' is the verbatim directory name.
#.
-#: builtin/init-db.c:419
+#: builtin/init-db.c:420
#, c-format
msgid "%s%s Git repository in %s%s\n"
msgstr "%s%s Git-arkiv i %s%s\n"
-#: builtin/init-db.c:420
+#: builtin/init-db.c:421
msgid "Reinitialized existing"
msgstr "Ominitierade befintligt"
-#: builtin/init-db.c:420
+#: builtin/init-db.c:421
msgid "Initialized empty"
msgstr "Initierade tomt"
-#: builtin/init-db.c:421
+#: builtin/init-db.c:422
msgid " shared"
msgstr " delat"
-#: builtin/init-db.c:440
+#: builtin/init-db.c:441
msgid "cannot tell cwd"
msgstr "kan inte läsa aktuell katalog (cwd)"
-#: builtin/init-db.c:521 builtin/init-db.c:528
+#: builtin/init-db.c:467
+msgid ""
+"git init [-q | --quiet] [--bare] [--template=<template-directory>] [--shared"
+"[=<permissions>]] [directory]"
+msgstr ""
+"git init [-q | --quiet] [--bare] [--template=<mallkatalog>] [--shared"
+"[=<behörigheter>]] [katalog]"
+
+#: builtin/init-db.c:490
+msgid "permissions"
+msgstr "behörigheter"
+
+#: builtin/init-db.c:491
+msgid "specify that the git repository is to be shared amongst several users"
+msgstr "ange att git-arkivet skall delas bland flera användare"
+
+#: builtin/init-db.c:493 builtin/prune-packed.c:77
+msgid "be quiet"
+msgstr "var tyst"
+
+#: builtin/init-db.c:522 builtin/init-db.c:529
#, c-format
msgid "cannot mkdir %s"
msgstr "kan inte skapa katalogen (mkdir) %s"
-#: builtin/init-db.c:532
+#: builtin/init-db.c:533
#, c-format
msgid "cannot chdir to %s"
msgstr "kan inte byta katalog (chdir) till %s"
-#: builtin/init-db.c:554
+#: builtin/init-db.c:555
#, c-format
msgid ""
"%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-"
@@ -3254,113 +5271,397 @@ msgstr ""
"%s (eller --work-tree=<katalog>) inte tillåtet utan att ange %s (eller --git-"
"dir=<katalog>)"
-#: builtin/init-db.c:578
+#: builtin/init-db.c:579
msgid "Cannot access current working directory"
msgstr "Kan inte komma åt aktuell arbetskatalog"
-#: builtin/init-db.c:585
+#: builtin/init-db.c:586
#, c-format
msgid "Cannot access work tree '%s'"
msgstr "Kan inte komma åt arbetskatalogen \"%s\""
-#: builtin/log.c:188
+#: builtin/log.c:37
+msgid "git log [<options>] [<since>..<until>] [[--] <path>...]\n"
+msgstr "git log [<flaggor>] [<sedan>..<till>] [[--] <sökväg>...]\n"
+
+#: builtin/log.c:38
+msgid " or: git show [options] <object>..."
+msgstr " eller: git show [flaggor] <objekt>..."
+
+#: builtin/log.c:100
+msgid "suppress diff output"
+msgstr "undertryck diff-utdata"
+
+#: builtin/log.c:101
+msgid "show source"
+msgstr "visa källkod"
+
+#: builtin/log.c:102
+msgid "decorate options"
+msgstr "dekoreringsflaggor"
+
+#: builtin/log.c:189
#, c-format
msgid "Final output: %d %s\n"
msgstr "Slututdata: %d %s\n"
-#: builtin/log.c:401 builtin/log.c:489
+#: builtin/log.c:403 builtin/log.c:494
#, c-format
msgid "Could not read object %s"
msgstr "Kunde inte läsa objektet %s"
-#: builtin/log.c:513
+#: builtin/log.c:518
#, c-format
msgid "Unknown type: %d"
msgstr "Okänd typ: %d"
-#: builtin/log.c:602
+#: builtin/log.c:608
msgid "format.headers without value"
msgstr "format.headers utan värde"
-#: builtin/log.c:676
+#: builtin/log.c:682
msgid "name of output directory is too long"
msgstr "namnet på utdatakatalogen är för långt"
-#: builtin/log.c:687
+#: builtin/log.c:693
#, c-format
msgid "Cannot open patch file %s"
msgstr "Kan inte öppna patchfilen %s"
-#: builtin/log.c:701
+#: builtin/log.c:707
msgid "Need exactly one range."
msgstr "Behöver precis ett intervall."
-#: builtin/log.c:709
+#: builtin/log.c:715
msgid "Not a range."
msgstr "Inte ett intervall."
-#: builtin/log.c:786
+#: builtin/log.c:789
msgid "Cover letter needs email format"
msgstr "Omslagsbrevet behöver e-postformat"
-#: builtin/log.c:859
+#: builtin/log.c:862
#, c-format
msgid "insane in-reply-to: %s"
msgstr "tokigt in-reply-to: %s"
-#: builtin/log.c:932
+#: builtin/log.c:890
+msgid "git format-patch [options] [<since> | <revision range>]"
+msgstr "git format-patch [flaggor] [<sedan> | <revisionsintervall>]"
+
+#: builtin/log.c:935
msgid "Two output directories?"
msgstr "Två utdatakataloger?"
-#: builtin/log.c:1153
+#: builtin/log.c:1063
+msgid "use [PATCH n/m] even with a single patch"
+msgstr "använd [PATCH n/m] även för en ensam patch"
+
+#: builtin/log.c:1066
+msgid "use [PATCH] even with multiple patches"
+msgstr "använd [PATCH] även för flera patchar"
+
+#: builtin/log.c:1070
+msgid "print patches to standard out"
+msgstr "skriv patcharna på stnadard ut"
+
+#: builtin/log.c:1072
+msgid "generate a cover letter"
+msgstr "generera ett följebrev"
+
+#: builtin/log.c:1074
+msgid "use simple number sequence for output file names"
+msgstr "använd enkel nummersekvens för utdatafilnamn"
+
+#: builtin/log.c:1075
+msgid "sfx"
+msgstr "sfx"
+
+#: builtin/log.c:1076
+msgid "use <sfx> instead of '.patch'"
+msgstr "använd <sfx> istället för \".patch\""
+
+#: builtin/log.c:1078
+msgid "start numbering patches at <n> instead of 1"
+msgstr "börja numrera patchar på <n> istället för 1"
+
+#: builtin/log.c:1080
+msgid "Use [<prefix>] instead of [PATCH]"
+msgstr "Använd [<prefix>] istället för [PATCH]"
+
+#: builtin/log.c:1083
+msgid "store resulting files in <dir>"
+msgstr "spara filerna i <katalog>"
+
+#: builtin/log.c:1086
+msgid "don't strip/add [PATCH]"
+msgstr "ta inte bort eller lägg till [PATCH]"
+
+#: builtin/log.c:1089
+msgid "don't output binary diffs"
+msgstr "skriv inte binära diffar"
+
+#: builtin/log.c:1091
+msgid "don't include a patch matching a commit upstream"
+msgstr "ta inte med patchar som motsvarar en uppströmsincheckning"
+
+#: builtin/log.c:1093
+msgid "show patch format instead of default (patch + stat)"
+msgstr "visa patchformat istället för standard (patch + stat)"
+
+#: builtin/log.c:1095
+msgid "Messaging"
+msgstr "E-post"
+
+#: builtin/log.c:1096
+msgid "header"
+msgstr "huvud"
+
+#: builtin/log.c:1097
+msgid "add email header"
+msgstr "lägg till e-posthuvud"
+
+#: builtin/log.c:1098 builtin/log.c:1100
+msgid "email"
+msgstr "epost"
+
+#: builtin/log.c:1098
+msgid "add To: header"
+msgstr "Lägg till mottagarhuvud (\"To:\")"
+
+#: builtin/log.c:1100
+msgid "add Cc: header"
+msgstr "Lägg till kopiehuvud (\"Cc:\")"
+
+#: builtin/log.c:1102
+msgid "message-id"
+msgstr "meddelande-id"
+
+#: builtin/log.c:1103
+msgid "make first mail a reply to <message-id>"
+msgstr "Gör det första brevet ett svar till <meddelande-id>"
+
+#: builtin/log.c:1104 builtin/log.c:1107
+msgid "boundary"
+msgstr "gräns"
+
+#: builtin/log.c:1105
+msgid "attach the patch"
+msgstr "bifoga patchen"
+
+#: builtin/log.c:1108
+msgid "inline the patch"
+msgstr "gör patchen ett inline-objekt"
+
+#: builtin/log.c:1112
+msgid "enable message threading, styles: shallow, deep"
+msgstr "aktivera brevtrådning, typer: shallow, deep"
+
+#: builtin/log.c:1114
+msgid "signature"
+msgstr "signatur"
+
+#: builtin/log.c:1115
+msgid "add a signature"
+msgstr "lägg till signatur"
+
+#: builtin/log.c:1117
+msgid "don't print the patch filenames"
+msgstr "visa inte filnamn för patchar"
+
+#: builtin/log.c:1157
#, c-format
msgid "bogus committer info %s"
msgstr "felaktig incheckarinformation %s"
-#: builtin/log.c:1198
+#: builtin/log.c:1202
msgid "-n and -k are mutually exclusive."
msgstr "-n och -k kan inte användas samtidigt."
-#: builtin/log.c:1200
+#: builtin/log.c:1204
msgid "--subject-prefix and -k are mutually exclusive."
msgstr "--subject-prefix och -k kan inte användas samtidigt."
-#: builtin/log.c:1208
+#: builtin/log.c:1212
msgid "--name-only does not make sense"
msgstr "kan inte använda --name-only"
-#: builtin/log.c:1210
+#: builtin/log.c:1214
msgid "--name-status does not make sense"
msgstr "kan inte använda --name-status"
-#: builtin/log.c:1212
+#: builtin/log.c:1216
msgid "--check does not make sense"
msgstr "kan inte använda --check"
-#: builtin/log.c:1235
+#: builtin/log.c:1239
msgid "standard output, or directory, which one?"
msgstr "standard ut, eller katalog, vilken skall det vara?"
-#: builtin/log.c:1237
+#: builtin/log.c:1241
#, c-format
msgid "Could not create directory '%s'"
msgstr "Kunde inte skapa katalogen \"%s\""
-#: builtin/log.c:1390
+#: builtin/log.c:1394
msgid "Failed to create output files"
msgstr "Misslyckades skapa utdatafiler"
-#: builtin/log.c:1494
+#: builtin/log.c:1443
+msgid "git cherry [-v] [<upstream> [<head> [<limit>]]]"
+msgstr "git cherry [-v] [<uppström> [<huvud> [<gräns>]]]"
+
+#: builtin/log.c:1498
#, c-format
msgid ""
"Could not find a tracked remote branch, please specify <upstream> manually.\n"
msgstr "Kunde inte hitta en spårad fjärrgren, ange <uppström> manuellt.\n"
-#: builtin/log.c:1510 builtin/log.c:1512 builtin/log.c:1524
+#: builtin/log.c:1511 builtin/log.c:1513 builtin/log.c:1525
#, c-format
msgid "Unknown commit %s"
msgstr "Okänd incheckning %s"
+#: builtin/ls-files.c:408
+msgid "git ls-files [options] [<file>...]"
+msgstr "git ls-files [flaggor] [<fil>...]"
+
+#: builtin/ls-files.c:463
+msgid "identify the file status with tags"
+msgstr "identifiera filstatus med taggar"
+
+#: builtin/ls-files.c:465
+msgid "use lowercase letters for 'assume unchanged' files"
+msgstr "använd små bokstäver för \"anta oförändrade\"-filer"
+
+#: builtin/ls-files.c:467
+msgid "show cached files in the output (default)"
+msgstr "visa cachade filer i utdata (standard)"
+
+#: builtin/ls-files.c:469
+msgid "show deleted files in the output"
+msgstr "visa borttagna filer i utdata"
+
+#: builtin/ls-files.c:471
+msgid "show modified files in the output"
+msgstr "visa modifierade filer i utdata"
+
+#: builtin/ls-files.c:473
+msgid "show other files in the output"
+msgstr "visa andra filer i utdata"
+
+#: builtin/ls-files.c:475
+msgid "show ignored files in the output"
+msgstr "visa ignorerade filer i utdata"
+
+#: builtin/ls-files.c:478
+msgid "show staged contents' object name in the output"
+msgstr "visa köat innehålls objektnamn i utdata"
+
+#: builtin/ls-files.c:480
+msgid "show files on the filesystem that need to be removed"
+msgstr "visa filer i filsystemet som behöver tas bort"
+
+#: builtin/ls-files.c:482
+msgid "show 'other' directories' name only"
+msgstr "visa endast namn för \"andra\" kataloger"
+
+#: builtin/ls-files.c:485
+msgid "don't show empty directories"
+msgstr "visa inte tomma kataloger"
+
+#: builtin/ls-files.c:488
+msgid "show unmerged files in the output"
+msgstr "visa ej sammanslagna filer i utdata"
+
+#: builtin/ls-files.c:490
+msgid "show resolve-undo information"
+msgstr "visa \"resolve-undo\"-information"
+
+#: builtin/ls-files.c:492
+msgid "skip files matching pattern"
+msgstr "hoppa över filer som motsvarar mönster"
+
+#: builtin/ls-files.c:495
+msgid "exclude patterns are read from <file>"
+msgstr "exkludera mönster som läses från <fil>"
+
+#: builtin/ls-files.c:498
+msgid "read additional per-directory exclude patterns in <file>"
+msgstr "läs ytterligare per-katalog-exkluderingsmönster från <fil>"
+
+#: builtin/ls-files.c:500
+msgid "add the standard git exclusions"
+msgstr "lägg till git:s standardexkluderingar"
+
+#: builtin/ls-files.c:503
+msgid "make the output relative to the project top directory"
+msgstr "gör utdata relativ till projektets toppkatalog"
+
+#: builtin/ls-files.c:506
+msgid "if any <file> is not in the index, treat this as an error"
+msgstr "om en <fil> inte är indexet, betrakta det som ett fel"
+
+#: builtin/ls-files.c:507
+msgid "tree-ish"
+msgstr "träd-igt"
+
+#: builtin/ls-files.c:508
+msgid "pretend that paths removed since <tree-ish> are still present"
+msgstr "låtsas att sökvägar borttagna sedan <träd-igt> fortfarande finns"
+
+#: builtin/ls-files.c:510
+msgid "show debugging data"
+msgstr "visa felsökningsutdata"
+
+#: builtin/ls-tree.c:27
+msgid "git ls-tree [<options>] <tree-ish> [<path>...]"
+msgstr "git ls-tree [<flaggor>] <träd-igt> [<sökväg>...]"
+
+#: builtin/ls-tree.c:125
+msgid "only show trees"
+msgstr "visa endast träd"
+
+#: builtin/ls-tree.c:127
+msgid "recurse into subtrees"
+msgstr "rekursera ner i underträd"
+
+#: builtin/ls-tree.c:129
+msgid "show trees when recursing"
+msgstr "visa träd medan rekursering"
+
+#: builtin/ls-tree.c:132
+msgid "terminate entries with NUL byte"
+msgstr "terminera poster med NUL-byte"
+
+#: builtin/ls-tree.c:133
+msgid "include object size"
+msgstr "inkludera objektstorlek"
+
+#: builtin/ls-tree.c:135 builtin/ls-tree.c:137
+msgid "list only filenames"
+msgstr "visa endast filnamn"
+
+#: builtin/ls-tree.c:140
+msgid "use full path names"
+msgstr "använd fullständiga sökvägsnamn"
+
+#: builtin/ls-tree.c:142
+msgid "list entire tree; not just current directory (implies --full-name)"
+msgstr "visa hela trädet; inte bara aktuell katalog (implicerar --full-name)"
+
+#: builtin/merge.c:43
+msgid "git merge [options] [<commit>...]"
+msgstr "git merge [flaggor] [<incheckning>...]"
+
+#: builtin/merge.c:44
+msgid "git merge [options] <msg> HEAD <commit>"
+msgstr "git merge [flaggor] <meddelande> HEAD <incheckning>"
+
+#: builtin/merge.c:45
+msgid "git merge --abort"
+msgstr "git merge --abort"
+
#: builtin/merge.c:90
msgid "switch `m' requires a value"
msgstr "flaggan \"m\" behöver ett värde"
@@ -3380,6 +5681,67 @@ msgstr "Tillgängliga strategier är:"
msgid "Available custom strategies are:"
msgstr "Tillgängliga skräddarsydda strategier är:"
+#: builtin/merge.c:183
+msgid "do not show a diffstat at the end of the merge"
+msgstr "visa inte en diffstat när sammanslagningen är färdig"
+
+#: builtin/merge.c:186
+msgid "show a diffstat at the end of the merge"
+msgstr "visa en diffstat när sammanslagningen är färdig"
+
+#: builtin/merge.c:187
+msgid "(synonym to --stat)"
+msgstr "(synonym till --stat)"
+
+#: builtin/merge.c:189
+msgid "add (at most <n>) entries from shortlog to merge commit message"
+msgstr ""
+"lägg till (som mest <n>) poster från shortlog till incheckningsmeddelandet"
+
+#: builtin/merge.c:192
+msgid "create a single commit instead of doing a merge"
+msgstr "skapa en ensam incheckning istället för en sammanslagning"
+
+#: builtin/merge.c:194
+msgid "perform a commit if the merge succeeds (default)"
+msgstr "utför en incheckning om sammanslagningen lyckades (standard)"
+
+#: builtin/merge.c:196
+msgid "edit message before committing"
+msgstr "redigera meddelande innan incheckning"
+
+#: builtin/merge.c:198
+msgid "allow fast-forward (default)"
+msgstr "tillåt snabbspolning (standard)"
+
+#: builtin/merge.c:200
+msgid "abort if fast-forward is not possible"
+msgstr "avbryt om snabbspolning inte är möjlig"
+
+#: builtin/merge.c:202 builtin/notes.c:867 builtin/revert.c:112
+msgid "strategy"
+msgstr "strategi"
+
+#: builtin/merge.c:203
+msgid "merge strategy to use"
+msgstr "sammanslagninsstrategi att använda"
+
+#: builtin/merge.c:204
+msgid "option=value"
+msgstr "alternativ=värde"
+
+#: builtin/merge.c:205
+msgid "option for selected merge strategy"
+msgstr "alternativ för vald sammanslagningsstrategi"
+
+#: builtin/merge.c:207
+msgid "merge commit message (for a non-fast-forward merge)"
+msgstr "incheckningsmeddelande för (icke snabbspolande) sammanslagning"
+
+#: builtin/merge.c:211
+msgid "abort the current in-progress merge"
+msgstr "avbryt den pågående sammanslagningen"
+
#: builtin/merge.c:240
msgid "could not run stash."
msgstr "kunde köra stash."
@@ -3419,55 +5781,51 @@ msgstr "Avslutar SQUASH_MSG"
msgid "No merge message -- not updating HEAD\n"
msgstr "Inget sammanslagningsmeddelande -- uppdaterar inte HEAD\n"
-#: builtin/merge.c:437
+#: builtin/merge.c:436
#, c-format
msgid "'%s' does not point to a commit"
msgstr "\"%s\" verkar inte peka på en incheckning"
-#: builtin/merge.c:536
+#: builtin/merge.c:535
#, c-format
msgid "Bad branch.%s.mergeoptions string: %s"
msgstr "Felaktig branch.%s.mergeoptions-sträng: %s"
-#: builtin/merge.c:629
+#: builtin/merge.c:628
msgid "git write-tree failed to write a tree"
msgstr "git write-tree misslyckades skriva ett träd"
-#: builtin/merge.c:679
+#: builtin/merge.c:678
msgid "failed to read the cache"
msgstr "misslyckads läsa cachen"
-#: builtin/merge.c:697
-msgid "Unable to write index."
-msgstr "Kunde inte skriva indexet."
-
-#: builtin/merge.c:710
+#: builtin/merge.c:709
msgid "Not handling anything other than two heads merge."
msgstr "Hanterar inte något annat än en sammanslagning av två huvuden."
-#: builtin/merge.c:724
+#: builtin/merge.c:723
#, c-format
msgid "Unknown option for merge-recursive: -X%s"
msgstr "Felaktig flagga för merge-recursive: -X%s"
-#: builtin/merge.c:738
+#: builtin/merge.c:737
#, c-format
msgid "unable to write %s"
msgstr "kunde inte skriva %s"
-#: builtin/merge.c:877
+#: builtin/merge.c:876
#, c-format
msgid "Could not read from '%s'"
msgstr "Kunde inte läsa från \"%s\""
-#: builtin/merge.c:886
+#: builtin/merge.c:885
#, c-format
msgid "Not committing merge; use 'git commit' to complete the merge.\n"
msgstr ""
"Checkar inte in sammanslagningen; använd \"git commit\" för att slutföra "
"den.\n"
-#: builtin/merge.c:892
+#: builtin/merge.c:891
msgid ""
"Please enter a commit message to explain why this merge is necessary,\n"
"especially if it merges an updated upstream into a topic branch.\n"
@@ -3482,53 +5840,53 @@ msgstr ""
"Rader som inleds med \"#\" kommer ignoreras, och ett tomt meddelande\n"
"avbryter incheckningen.\n"
-#: builtin/merge.c:916
+#: builtin/merge.c:915
msgid "Empty commit message."
msgstr "Tomt incheckningsmeddelande."
-#: builtin/merge.c:928
+#: builtin/merge.c:927
#, c-format
msgid "Wonderful.\n"
msgstr "Underbart.\n"
-#: builtin/merge.c:993
+#: builtin/merge.c:992
#, c-format
msgid "Automatic merge failed; fix conflicts and then commit the result.\n"
msgstr ""
"Kunde inte slå ihop automatiskt; fixa konflikter och checka in resultatet.\n"
-#: builtin/merge.c:1009
+#: builtin/merge.c:1008
#, c-format
msgid "'%s' is not a commit"
msgstr "\"%s\" är inte en incheckning"
-#: builtin/merge.c:1050
+#: builtin/merge.c:1049
msgid "No current branch."
msgstr "Inte på någon gren."
-#: builtin/merge.c:1052
+#: builtin/merge.c:1051
msgid "No remote for the current branch."
msgstr "Ingen fjärr för aktuell gren."
-#: builtin/merge.c:1054
+#: builtin/merge.c:1053
msgid "No default upstream defined for the current branch."
msgstr "Ingen standarduppström angiven för aktuell gren."
-#: builtin/merge.c:1059
+#: builtin/merge.c:1058
#, c-format
msgid "No remote tracking branch for %s from %s"
msgstr "Ingen fjärrspårande gren för %s från %s"
-#: builtin/merge.c:1146 builtin/merge.c:1303
+#: builtin/merge.c:1145 builtin/merge.c:1302
#, c-format
msgid "%s - not something we can merge"
msgstr "%s - inte något vi kan slå ihop"
-#: builtin/merge.c:1214
+#: builtin/merge.c:1213
msgid "There is no merge to abort (MERGE_HEAD missing)."
msgstr "Det finns ingen sammanslagning att avbryta (MERGE_HEAD saknas)."
-#: builtin/merge.c:1230 git-pull.sh:31
+#: builtin/merge.c:1229 git-pull.sh:31
msgid ""
"You have not concluded your merge (MERGE_HEAD exists).\n"
"Please, commit your changes before you can merge."
@@ -3536,11 +5894,11 @@ msgstr ""
"Du har inte avslutat sammanslagningen (MERGE_HEAD finns).\n"
"Checka in dina ändringar innan du kan slå ihop."
-#: builtin/merge.c:1233 git-pull.sh:34
+#: builtin/merge.c:1232 git-pull.sh:34
msgid "You have not concluded your merge (MERGE_HEAD exists)."
msgstr "Du har inte avslutat sammanslagningen (MERGE_HEAD finns)."
-#: builtin/merge.c:1237
+#: builtin/merge.c:1236
msgid ""
"You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
"Please, commit your changes before you can merge."
@@ -3548,84 +5906,183 @@ msgstr ""
"Du har inte avslutat din \"cherry-pick\" (CHERRY_PICK_HEAD finns).\n"
"Checka in dina ändringar innan du kan slå ihop."
-#: builtin/merge.c:1240
+#: builtin/merge.c:1239
msgid "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)."
msgstr "Du har inte avslutat din \"cherry-pick\" (CHERRY_PICK_HEAD finns)."
-#: builtin/merge.c:1249
+#: builtin/merge.c:1248
msgid "You cannot combine --squash with --no-ff."
msgstr "Du kan inte kombinera --squash med --no-ff."
-#: builtin/merge.c:1254
+#: builtin/merge.c:1253
msgid "You cannot combine --no-ff with --ff-only."
msgstr "Du kan inte kombinera --no-ff med --ff-only."
-#: builtin/merge.c:1261
+#: builtin/merge.c:1260
msgid "No commit specified and merge.defaultToUpstream not set."
msgstr "Ingen incheckning angiven och merge.defaultToUpstream är ej satt."
-#: builtin/merge.c:1293
+#: builtin/merge.c:1292
msgid "Can merge only exactly one commit into empty head"
msgstr "Kan endast slå ihop en enda incheckning i ett tomt huvud."
-#: builtin/merge.c:1296
+#: builtin/merge.c:1295
msgid "Squash commit into empty head not supported yet"
msgstr "Stöder inte en tillplattningsincheckning på ett tomt huvud ännu"
-#: builtin/merge.c:1298
+#: builtin/merge.c:1297
msgid "Non-fast-forward commit does not make sense into an empty head"
msgstr "Icke-snabbspolad incheckning kan inte användas med ett tomt huvud"
-#: builtin/merge.c:1413
+#: builtin/merge.c:1412
#, c-format
msgid "Updating %s..%s\n"
msgstr "Uppdaterar %s..%s\n"
-#: builtin/merge.c:1451
+#: builtin/merge.c:1450
#, c-format
msgid "Trying really trivial in-index merge...\n"
msgstr "Försöker riktigt enkel sammanslagning i indexet...\n"
-#: builtin/merge.c:1458
+#: builtin/merge.c:1457
#, c-format
msgid "Nope.\n"
msgstr "Nej.\n"
-#: builtin/merge.c:1490
+#: builtin/merge.c:1489
msgid "Not possible to fast-forward, aborting."
msgstr "Kan inte snabbspola, avbryter."
-#: builtin/merge.c:1513 builtin/merge.c:1592
+#: builtin/merge.c:1512 builtin/merge.c:1591
#, c-format
msgid "Rewinding the tree to pristine...\n"
msgstr "Återspolar trädet till orört...\n"
-#: builtin/merge.c:1517
+#: builtin/merge.c:1516
#, c-format
msgid "Trying merge strategy %s...\n"
msgstr "Försöker sammanslagninsstrategin %s...\n"
-#: builtin/merge.c:1583
+#: builtin/merge.c:1582
#, c-format
msgid "No merge strategy handled the merge.\n"
msgstr "Ingen sammanslagningsstrategi hanterade sammanslagningen.\n"
-#: builtin/merge.c:1585
+#: builtin/merge.c:1584
#, c-format
msgid "Merge with strategy %s failed.\n"
-msgstr "Sammanslaning med strategin %s misslyckades.\n"
+msgstr "Sammanslagning med strategin %s misslyckades.\n"
-#: builtin/merge.c:1594
+#: builtin/merge.c:1593
#, c-format
msgid "Using the %s to prepare resolving by hand.\n"
msgstr "Använder %s för att förbereda lösning för hand.\n"
-#: builtin/merge.c:1606
+#: builtin/merge.c:1605
#, c-format
msgid "Automatic merge went well; stopped before committing as requested\n"
msgstr ""
"Automatisk sammanslagning lyckades; stoppar före incheckning som önskat\n"
+#: builtin/merge-base.c:26
+msgid "git merge-base [-a|--all] <commit> <commit>..."
+msgstr "git merge-base [-a|--all] <incheckning> <incheckning>..."
+
+#: builtin/merge-base.c:27
+msgid "git merge-base [-a|--all] --octopus <commit>..."
+msgstr "git merge-base [-a|--all] --octopus <incheckning>..."
+
+#: builtin/merge-base.c:28
+msgid "git merge-base --independent <commit>..."
+msgstr "git merge-base --independent <incheckning>..."
+
+#: builtin/merge-base.c:29
+msgid "git merge-base --is-ancestor <commit> <commit>"
+msgstr "git merge-base --is-ancestor <incheckning> <incheckning>"
+
+#: builtin/merge-base.c:98
+msgid "output all common ancestors"
+msgstr "skriv ut alla gemensamma anfäder"
+
+#: builtin/merge-base.c:99
+msgid "find ancestors for a single n-way merge"
+msgstr "hitta anfader för enkel n-vägssammanslagning"
+
+#: builtin/merge-base.c:100
+msgid "list revs not reachable from others"
+msgstr "visa revisioner som inte kan nås från andra"
+
+#: builtin/merge-base.c:102
+msgid "is the first one ancestor of the other?"
+msgstr "är den första anfader till den andra?"
+
+#: builtin/merge-file.c:8
+msgid ""
+"git merge-file [options] [-L name1 [-L orig [-L name2]]] file1 orig_file "
+"file2"
+msgstr ""
+"git merge-file [alternativ] [-L namn1 [-L orig [-L namn2]]] fil1 origfil fil2"
+
+#: builtin/merge-file.c:33
+msgid "send results to standard output"
+msgstr "sänd resultat till standard ut"
+
+#: builtin/merge-file.c:34
+msgid "use a diff3 based merge"
+msgstr "använd diff3-baserad sammanslagning"
+
+#: builtin/merge-file.c:35
+msgid "for conflicts, use our version"
+msgstr "för konflikter, använd vår version"
+
+#: builtin/merge-file.c:37
+msgid "for conflicts, use their version"
+msgstr "för konflikter, använd deras version"
+
+#: builtin/merge-file.c:39
+msgid "for conflicts, use a union version"
+msgstr "för konflikter, använd en förenad version"
+
+#: builtin/merge-file.c:42
+msgid "for conflicts, use this marker size"
+msgstr "för konflikter, använd denna markörstorlek"
+
+#: builtin/merge-file.c:43
+msgid "do not warn about conflicts"
+msgstr "varna inte om konflikter"
+
+#: builtin/merge-file.c:45
+msgid "set labels for file1/orig_file/file2"
+msgstr "sätt etiketter för fil1/origfil/fil2"
+
+#: builtin/mktree.c:67
+msgid "git mktree [-z] [--missing] [--batch]"
+msgstr "git mktree [-z] [--missing] [--batch]"
+
+#: builtin/mktree.c:153
+msgid "input is NUL terminated"
+msgstr "indata är NUL-terminerad"
+
+#: builtin/mktree.c:154 builtin/write-tree.c:24
+msgid "allow missing objects"
+msgstr "tillåt saknade objekt"
+
+#: builtin/mktree.c:155
+msgid "allow creation of more than one tree"
+msgstr "tillåt skapa mer än ett träd"
+
+#: builtin/mv.c:14
+msgid "git mv [options] <source>... <destination>"
+msgstr "git mv [flaggor] <källa>... <mål>"
+
+#: builtin/mv.c:64
+msgid "force move/rename even if target exists"
+msgstr "tvinga flytta/ändra namn även om målet finns"
+
+#: builtin/mv.c:65
+msgid "skip move/rename errors"
+msgstr "hoppa över fel vid flytt/namnändring"
+
#: builtin/mv.c:108
#, c-format
msgid "Checking rename of '%s' to '%s'\n"
@@ -3688,6 +6145,154 @@ msgstr "Byter namn på %s till %s\n"
msgid "renaming '%s' failed"
msgstr "misslyckades byta namn på \"%s\""
+#: builtin/name-rev.c:175
+msgid "git name-rev [options] <commit>..."
+msgstr "git name-rev [flaggor] <incheckning>..."
+
+#: builtin/name-rev.c:176
+msgid "git name-rev [options] --all"
+msgstr "git name-rev [flaggor] --all"
+
+#: builtin/name-rev.c:177
+msgid "git name-rev [options] --stdin"
+msgstr "git name-rev [flaggor] --stdin"
+
+#: builtin/name-rev.c:229
+msgid "print only names (no SHA-1)"
+msgstr "skriv endast namn (ingen SHA-1)"
+
+#: builtin/name-rev.c:230
+msgid "only use tags to name the commits"
+msgstr "använd endast taggar för att namnge incheckningar"
+
+#: builtin/name-rev.c:232
+msgid "only use refs matching <pattern>"
+msgstr "använd endast referenser som motsvarar <mönster>"
+
+#: builtin/name-rev.c:234
+msgid "list all commits reachable from all refs"
+msgstr "lista alla incheckningar som kan nås alla referenser"
+
+#: builtin/name-rev.c:235
+msgid "read from stdin"
+msgstr "läs från standard in"
+
+#: builtin/name-rev.c:236
+msgid "allow to print `undefined` names"
+msgstr "tillåt att skriva \"odefinierade\" namn"
+
+#: builtin/notes.c:23
+msgid "git notes [--ref <notes_ref>] [list [<object>]]"
+msgstr "git notes [--ref <anteckningsref>] [list [<objekt>]]"
+
+#: builtin/notes.c:24
+msgid ""
+"git notes [--ref <notes_ref>] add [-f] [-m <msg> | -F <file> | (-c | -C) "
+"<object>] [<object>]"
+msgstr ""
+"git notes [--ref <anteckningsref>] add [-f] [-m <medd> | -F <fil> | (-c | -"
+"C) <objekt>] [<objekt>]"
+
+#: builtin/notes.c:25
+msgid "git notes [--ref <notes_ref>] copy [-f] <from-object> <to-object>"
+msgstr ""
+"git notes [--ref <anteckningsref>] copy [-f] <från-objekt> <till-objekt>"
+
+#: builtin/notes.c:26
+msgid ""
+"git notes [--ref <notes_ref>] append [-m <msg> | -F <file> | (-c | -C) "
+"<object>] [<object>]"
+msgstr ""
+"git notes [--ref <anteckningsref>] append [-m <medd> | -F <fil> | (-c | -C) "
+"<objekt>] [<objekt>]"
+
+#: builtin/notes.c:27
+msgid "git notes [--ref <notes_ref>] edit [<object>]"
+msgstr "git notes [--ref <anteckningsref>] edit [<objekt>]"
+
+#: builtin/notes.c:28
+msgid "git notes [--ref <notes_ref>] show [<object>]"
+msgstr "git notes [--ref <anteckningsref>] show [<objekt>]"
+
+#: builtin/notes.c:29
+msgid ""
+"git notes [--ref <notes_ref>] merge [-v | -q] [-s <strategy> ] <notes_ref>"
+msgstr ""
+"git notes [--ref <anteckningsref>] merge [-v | -q] [-s <strategi> ] "
+"<anteckningsref>"
+
+#: builtin/notes.c:30
+msgid "git notes merge --commit [-v | -q]"
+msgstr "git notes merge --commit [-v | -q]"
+
+#: builtin/notes.c:31
+msgid "git notes merge --abort [-v | -q]"
+msgstr "git notes merge --abort [-v | -q]"
+
+#: builtin/notes.c:32
+msgid "git notes [--ref <notes_ref>] remove [<object>...]"
+msgstr "git notes [--ref <anteckningsref>] remove [<objekt>...]"
+
+#: builtin/notes.c:33
+msgid "git notes [--ref <notes_ref>] prune [-n | -v]"
+msgstr "git notes [--ref <anteckningsref>] prune [-n | -v]"
+
+#: builtin/notes.c:34
+msgid "git notes [--ref <notes_ref>] get-ref"
+msgstr "git notes [--ref <anteckningsref>] get-ref"
+
+#: builtin/notes.c:39
+msgid "git notes [list [<object>]]"
+msgstr "git notes [list [<objekt>]]"
+
+#: builtin/notes.c:44
+msgid "git notes add [<options>] [<object>]"
+msgstr "git notes add [<flaggor>] [<objekt>]"
+
+#: builtin/notes.c:49
+msgid "git notes copy [<options>] <from-object> <to-object>"
+msgstr "git notes copy [<flaggor>] <från-objekt> <till-objekt>"
+
+#: builtin/notes.c:50
+msgid "git notes copy --stdin [<from-object> <to-object>]..."
+msgstr "git notes copy --stdin [<från-objekt> <till-objekt>]..."
+
+#: builtin/notes.c:55
+msgid "git notes append [<options>] [<object>]"
+msgstr "git notes append [<flaggor>] [<objekt>]"
+
+#: builtin/notes.c:60
+msgid "git notes edit [<object>]"
+msgstr "git notes edit [<objekt>]"
+
+#: builtin/notes.c:65
+msgid "git notes show [<object>]"
+msgstr "git notes show [<objekt>]"
+
+#: builtin/notes.c:70
+msgid "git notes merge [<options>] <notes_ref>"
+msgstr "git notes merge [<flaggor>] <anteckningsref>"
+
+#: builtin/notes.c:71
+msgid "git notes merge --commit [<options>]"
+msgstr "git notes merge --commit [<flaggor>]"
+
+#: builtin/notes.c:72
+msgid "git notes merge --abort [<options>]"
+msgstr "git notes merge --abort [<flaggor>]"
+
+#: builtin/notes.c:77
+msgid "git notes remove [<object>]"
+msgstr "git notes remove [<objekt>]"
+
+#: builtin/notes.c:82
+msgid "git notes prune [<options>]"
+msgstr "git notes prune [<flaggor>]"
+
+#: builtin/notes.c:87
+msgid "git notes get-ref"
+msgstr "git notes get-ref"
+
#: builtin/notes.c:139
#, c-format
msgid "unable to start 'show' for object '%s'"
@@ -3795,6 +6400,31 @@ msgstr "för många parametrar"
msgid "No note found for object %s."
msgstr "Inga anteckningar hittades för objektet %s."
+#: builtin/notes.c:535 builtin/notes.c:692
+msgid "note contents as a string"
+msgstr "anteckningsinnehåll som sträng"
+
+#: builtin/notes.c:538 builtin/notes.c:695
+msgid "note contents in a file"
+msgstr "anteckningsinnehåll i en fil"
+
+#: builtin/notes.c:540 builtin/notes.c:543 builtin/notes.c:697
+#: builtin/notes.c:700 builtin/tag.c:476
+msgid "object"
+msgstr "objekt"
+
+#: builtin/notes.c:541 builtin/notes.c:698
+msgid "reuse and edit specified note object"
+msgstr "återanvänd och redigera angivet anteckningsobjekt"
+
+#: builtin/notes.c:544 builtin/notes.c:701
+msgid "reuse specified note object"
+msgstr "återanvänd angivet anteckningsobjekt"
+
+#: builtin/notes.c:546 builtin/notes.c:614
+msgid "replace existing notes"
+msgstr "ersätt befintliga anteckningar"
+
#: builtin/notes.c:580
#, c-format
msgid ""
@@ -3809,6 +6439,14 @@ msgstr ""
msgid "Overwriting existing notes for object %s\n"
msgstr "Skriver över befintliga anteckningar för objektet %s\n"
+#: builtin/notes.c:615
+msgid "read objects from stdin"
+msgstr "läs objekt från standard in"
+
+#: builtin/notes.c:617
+msgid "load rewriting config for <command> (implies --stdin)"
+msgstr "läs omskrivningsinställning för <kommando> (implicerar --stdin)"
+
#: builtin/notes.c:635
msgid "too few parameters"
msgstr "för få parametrar"
@@ -3836,36 +6474,255 @@ msgstr ""
"Flaggorna -m/-F/-c/-C rekommenderas inte för underkommandot \"edit\".\n"
"Använd \"git notes add -f -m/-F/-c/-C\" istället.\n"
+#: builtin/notes.c:864
+msgid "General options"
+msgstr "Allmänna flaggor"
+
+#: builtin/notes.c:866
+msgid "Merge options"
+msgstr "Flaggor för sammanslagning"
+
+#: builtin/notes.c:868
+msgid ""
+"resolve notes conflicts using the given strategy (manual/ours/theirs/union/"
+"cat_sort_uniq)"
+msgstr ""
+"läs konflikter i anteckningar med angiven strategi (manual/ours/theirs/union/"
+"cat_sort_uniq)"
+
+#: builtin/notes.c:870
+msgid "Committing unmerged notes"
+msgstr "Checkar in ej sammanslagna anteckningar"
+
+#: builtin/notes.c:872
+msgid "finalize notes merge by committing unmerged notes"
+msgstr ""
+"färdigställ sammanslagning av anteckningar genom att checka in ej "
+"sammanslagna anteckningar"
+
+#: builtin/notes.c:874
+msgid "Aborting notes merge resolution"
+msgstr "Avbryt lösning av sammanslagning av anteckningar"
+
+#: builtin/notes.c:876
+msgid "abort notes merge"
+msgstr "avbryt sammanslagning av anteckningar"
+
#: builtin/notes.c:971
#, c-format
msgid "Object %s has no note\n"
msgstr "Objektet %s har ingen anteckning\n"
+#: builtin/notes.c:983
+msgid "attempt to remove non-existent note is not an error"
+msgstr "försök att ta bort icke-existerande anteckningar är inte ett fel"
+
+#: builtin/notes.c:986
+msgid "read object names from the standard input"
+msgstr "läs objektnamn från standard in"
+
+#: builtin/notes.c:1067
+msgid "notes_ref"
+msgstr "anteckningar-ref"
+
+#: builtin/notes.c:1068
+msgid "use notes from <notes_ref>"
+msgstr "använd anteckningar från <anteckningsref>"
+
#: builtin/notes.c:1103 builtin/remote.c:1598
#, c-format
msgid "Unknown subcommand: %s"
msgstr "Okänt underkommando: %s"
-#: builtin/pack-objects.c:2337
+#: builtin/pack-objects.c:23
+msgid "git pack-objects --stdout [options...] [< ref-list | < object-list]"
+msgstr "git pack-objects --stdout [flaggor...] [< reflista | < objektlista]"
+
+#: builtin/pack-objects.c:24
+msgid "git pack-objects [options...] base-name [< ref-list | < object-list]"
+msgstr "git pack-objects [flaggor...] basnamn [< reflista | < objektlista]"
+
+#: builtin/pack-objects.c:183 builtin/pack-objects.c:186
+#, c-format
+msgid "deflate error (%d)"
+msgstr "fel i deflate (%d)"
+
+#: builtin/pack-objects.c:2398
#, c-format
msgid "unsupported index version %s"
msgstr "indexversionen %s stöds ej"
-#: builtin/pack-objects.c:2341
+#: builtin/pack-objects.c:2402
#, c-format
msgid "bad index version '%s'"
msgstr "felaktig indexversion \"%s\""
-#: builtin/pack-objects.c:2364
+#: builtin/pack-objects.c:2425
#, c-format
msgid "option %s does not accept negative form"
msgstr "flaggan %s godtar inte negativ form"
-#: builtin/pack-objects.c:2368
+#: builtin/pack-objects.c:2429
#, c-format
msgid "unable to parse value '%s' for option %s"
msgstr "kunde inte tolka värdet \"%s\" för flaggan %s"
+#: builtin/pack-objects.c:2448
+msgid "do not show progress meter"
+msgstr "visa inte förloppsindikator"
+
+#: builtin/pack-objects.c:2450
+msgid "show progress meter"
+msgstr "visa förloppsindikator"
+
+#: builtin/pack-objects.c:2452
+msgid "show progress meter during object writing phase"
+msgstr "visa förloppsindikator under objektskrivningsfasen"
+
+#: builtin/pack-objects.c:2455
+msgid "similar to --all-progress when progress meter is shown"
+msgstr "som --all-progress när förloppsmätaren visas"
+
+#: builtin/pack-objects.c:2456
+msgid "version[,offset]"
+msgstr "version[,offset]"
+
+#: builtin/pack-objects.c:2457
+msgid "write the pack index file in the specified idx format version"
+msgstr "skriv paketindexfilen i angiven indexformatversion"
+
+#: builtin/pack-objects.c:2460
+msgid "maximum size of each output pack file"
+msgstr "maximal storlek på varje utdatapaketfil"
+
+#: builtin/pack-objects.c:2462
+msgid "ignore borrowed objects from alternate object store"
+msgstr "ignorera lånade objekt från alternativa objektlager"
+
+#: builtin/pack-objects.c:2464
+msgid "ignore packed objects"
+msgstr "ignorera packade objekt"
+
+#: builtin/pack-objects.c:2466
+msgid "limit pack window by objects"
+msgstr "begränsa paketfönster efter objekt"
+
+#: builtin/pack-objects.c:2468
+msgid "limit pack window by memory in addition to object limit"
+msgstr "begränsa paketfönster efter minne förutom objektgräns"
+
+#: builtin/pack-objects.c:2470
+msgid "maximum length of delta chain allowed in the resulting pack"
+msgstr "maximal längd på deltakedja tillåten i slutligt paket"
+
+#: builtin/pack-objects.c:2472
+msgid "reuse existing deltas"
+msgstr "återanvänd befintliga delta"
+
+#: builtin/pack-objects.c:2474
+msgid "reuse existing objects"
+msgstr "återanvänd befintliga objekt"
+
+#: builtin/pack-objects.c:2476
+msgid "use OFS_DELTA objects"
+msgstr "använd OFS_DELTA-objekt"
+
+#: builtin/pack-objects.c:2478
+msgid "use threads when searching for best delta matches"
+msgstr "använd trådar vid sökning efter bästa deltaträffar"
+
+#: builtin/pack-objects.c:2480
+msgid "do not create an empty pack output"
+msgstr "försök inte skapa tom paketutdata"
+
+#: builtin/pack-objects.c:2482
+msgid "read revision arguments from standard input"
+msgstr "läs revisionsargument från standard in"
+
+#: builtin/pack-objects.c:2484
+msgid "limit the objects to those that are not yet packed"
+msgstr "begränsa objekt till de som ännu inte packats"
+
+#: builtin/pack-objects.c:2487
+msgid "include objects reachable from any reference"
+msgstr "inkludera objekt som kan nås från någon referens"
+
+#: builtin/pack-objects.c:2490
+msgid "include objects referred by reflog entries"
+msgstr "inkludera objekt som refereras från referensloggposter"
+
+#: builtin/pack-objects.c:2493
+msgid "output pack to stdout"
+msgstr "skriv paket på standard ut"
+
+#: builtin/pack-objects.c:2495
+msgid "include tag objects that refer to objects to be packed"
+msgstr "inkludera taggobjekt som refererar objekt som skall packas"
+
+#: builtin/pack-objects.c:2497
+msgid "keep unreachable objects"
+msgstr "behåll onåbara objekt"
+
+#: builtin/pack-objects.c:2498 parse-options.h:141
+msgid "time"
+msgstr "tid"
+
+#: builtin/pack-objects.c:2499
+msgid "unpack unreachable objects newer than <time>"
+msgstr "packa upp onåbara objekt nyare än <tid>"
+
+#: builtin/pack-objects.c:2502
+msgid "create thin packs"
+msgstr "skapa tunna paket"
+
+#: builtin/pack-objects.c:2504
+msgid "ignore packs that have companion .keep file"
+msgstr "ignorera paket som har tillhörande .keep-fil"
+
+#: builtin/pack-objects.c:2506
+msgid "pack compression level"
+msgstr "komprimeringsgrad för paket"
+
+#: builtin/pack-objects.c:2508
+msgid "do not hide commits by grafts"
+msgstr "göm inte incheckningar med ympningar (\"grafts\")"
+
+#: builtin/pack-refs.c:6
+msgid "git pack-refs [options]"
+msgstr "git pack-refs [flaggor]"
+
+#: builtin/pack-refs.c:14
+msgid "pack everything"
+msgstr "packa allt"
+
+#: builtin/pack-refs.c:15
+msgid "prune loose refs (default)"
+msgstr "ta bort lösa referenser (standard)"
+
+#: builtin/prune-packed.c:7
+msgid "git prune-packed [-n|--dry-run] [-q|--quiet]"
+msgstr "git prune-packed [-n|--dry-run] [-q|--quiet]"
+
+#: builtin/prune.c:12
+msgid "git prune [-n] [-v] [--expire <time>] [--] [<head>...]"
+msgstr "git prune [-n] [-v] [--expire <tid>] [--] [<huvud>...]"
+
+#: builtin/prune.c:132
+msgid "do not remove, show only"
+msgstr "ta inte bort, bara visa"
+
+#: builtin/prune.c:133
+msgid "report pruned objects"
+msgstr "rapportera borttagna objekt"
+
+#: builtin/prune.c:136
+msgid "expire objects older than <time>"
+msgstr "låt tid gå ut för objekt äldre än <tid>"
+
+#: builtin/push.c:14
+msgid "git push [<options>] [<repository> [<refspec>...]]"
+msgstr "git push [<flaggor>] [<arkiv> [<refspec>...]]"
+
#: builtin/push.c:45
msgid "tag shorthand without <tag>"
msgstr "taggförkortning utan <tagg>"
@@ -3952,14 +6809,48 @@ msgstr ""
"aktuella grenen \"%s\", utan att tala om för mig vad som\n"
"skall sändas för att uppdatera fjärrgrenen."
-#: builtin/push.c:174
+#: builtin/push.c:151
+msgid ""
+"push.default is unset; its implicit value is changing in\n"
+"Git 2.0 from 'matching' to 'simple'. To squelch this message\n"
+"and maintain the current behavior after the default changes, use:\n"
+"\n"
+" git config --global push.default matching\n"
+"\n"
+"To squelch this message and adopt the new behavior now, use:\n"
+"\n"
+" git config --global push.default simple\n"
+"\n"
+"See 'git help config' and search for 'push.default' for further "
+"information.\n"
+"(the 'simple' mode was introduced in Git 1.7.11. Use the similar mode\n"
+"'current' instead of 'simple' if you sometimes use older versions of Git)"
+msgstr ""
+"push.default har inte ställts in; dess underförstådda värde\n"
+"ändras i Git 2.0 från \"matching\" till \"simple\". För att\n"
+"undertrycka det här meddelandet och behålla nuvarande beteende\n"
+"efter att förvalet ändras,\n"
+"skriver du:\n"
+"\n"
+" git config --global push.default matching\n"
+"\n"
+"För att undertrycka meddelandet och välja det nya beteendet nu skriver du:\n"
+"\n"
+" git config --global push.default simple\n"
+"\n"
+"Se \"git help config\" och sök efter \"push.default\" för ytterligare \n"
+"information. (Läget \"simple\" introducerades i Git 1.7.11. Använd det\n"
+"liknande läget \"current\" istället för \"simple\" om du ibland använder\n"
+"äldre versioner av Git.)"
+
+#: builtin/push.c:199
msgid ""
"You didn't specify any refspecs to push, and push.default is \"nothing\"."
msgstr ""
"Du angav inga referensspecifikationer att sända, och push.default är "
"\"nothing\"."
-#: builtin/push.c:181
+#: builtin/push.c:206
msgid ""
"Updates were rejected because the tip of your current branch is behind\n"
"its remote counterpart. Merge the remote changes (e.g. 'git pull')\n"
@@ -3971,20 +6862,21 @@ msgstr ""
"innan du sänder igen.\n"
"Se avsnittet \"Note about fast-forward\" i \"git push --help\" för detaljer."
-#: builtin/push.c:187
+#: builtin/push.c:212
msgid ""
"Updates were rejected because a pushed branch tip is behind its remote\n"
"counterpart. If you did not intend to push that branch, you may want to\n"
-"specify branches to push or set the 'push.default' configuration\n"
-"variable to 'current' or 'upstream' to push only the current branch."
+"specify branches to push or set the 'push.default' configuration variable\n"
+"to 'simple', 'current' or 'upstream' to push only the current branch."
msgstr ""
"Uppdateringar avvisades då änden på en insänd gren är bakom dess\n"
"fjärrmotsvarighet. Om det inte var meningen att sända in grenen, bör\n"
"du specificera grenar att sända, eller ändra inställningsvariabeln\n"
-"\"push-default\" till \"current\" eller \"upstream\" för att endast sända\n"
-"aktuell gren."
+"\"push-default\" till \"simple\", \"current\" eller \"upstream\" för att "
+"endast\n"
+"sända aktuell gren."
-#: builtin/push.c:193
+#: builtin/push.c:218
msgid ""
"Updates were rejected because a pushed branch tip is behind its remote\n"
"counterpart. Check out this branch and merge the remote changes\n"
@@ -3996,22 +6888,22 @@ msgstr ""
"\"git pull\") innan du sänder igen.\n"
"Se avsnittet \"Note about fast-forward\" i \"git push --help\" för detaljer."
-#: builtin/push.c:233
+#: builtin/push.c:258
#, c-format
msgid "Pushing to %s\n"
msgstr "Sänder till %s\n"
-#: builtin/push.c:237
+#: builtin/push.c:262
#, c-format
msgid "failed to push some refs to '%s'"
msgstr "misslyckades sända vissa referenser till \"%s\""
-#: builtin/push.c:269
+#: builtin/push.c:294
#, c-format
msgid "bad repository '%s'"
msgstr "felaktigt arkiv \"%s\""
-#: builtin/push.c:270
+#: builtin/push.c:295
msgid ""
"No configured push destination.\n"
"Either specify the URL from the command-line or configure a remote "
@@ -4032,34 +6924,238 @@ msgstr ""
"\n"
" git push <namn>\n"
-#: builtin/push.c:285
+#: builtin/push.c:310
msgid "--all and --tags are incompatible"
msgstr "--all och --tags är inkompatibla"
-#: builtin/push.c:286
+#: builtin/push.c:311
msgid "--all can't be combined with refspecs"
msgstr "--all kan inte kombineras med referensspecifikationer"
-#: builtin/push.c:291
+#: builtin/push.c:316
msgid "--mirror and --tags are incompatible"
msgstr "--mirror och --tags är inkompatibla"
-#: builtin/push.c:292
+#: builtin/push.c:317
msgid "--mirror can't be combined with refspecs"
msgstr "--mirror kan inte kombineras med referensspecifikationer"
-#: builtin/push.c:297
+#: builtin/push.c:322
msgid "--all and --mirror are incompatible"
msgstr "--all och --mirror är inkompatibla"
-#: builtin/push.c:385
+#: builtin/push.c:382
+msgid "repository"
+msgstr "arkiv"
+
+#: builtin/push.c:383
+msgid "push all refs"
+msgstr "sänd alla referenser"
+
+#: builtin/push.c:384
+msgid "mirror all refs"
+msgstr "spegla alla referenser"
+
+#: builtin/push.c:386
+msgid "delete refs"
+msgstr "ta bort referenser"
+
+#: builtin/push.c:387
+msgid "push tags (can't be used with --all or --mirror)"
+msgstr "sänd taggar (kan inte användas med --all eller --mirror)"
+
+#: builtin/push.c:390
+msgid "force updates"
+msgstr "tvinga uppdateringar"
+
+#: builtin/push.c:391
+msgid "check"
+msgstr "kontrollera"
+
+#: builtin/push.c:392
+msgid "control recursive pushing of submodules"
+msgstr "styr rekursiv insändning av undermoduler"
+
+#: builtin/push.c:394
+msgid "use thin pack"
+msgstr "använd tunna paket"
+
+#: builtin/push.c:395 builtin/push.c:396
+msgid "receive pack program"
+msgstr "program för att ta emot paket"
+
+#: builtin/push.c:397
+msgid "set upstream for git pull/status"
+msgstr "ställ in uppström för git pull/status"
+
+#: builtin/push.c:400
+msgid "prune locally removed refs"
+msgstr "ta bort lokalt borttagna referenser"
+
+#: builtin/push.c:410
msgid "--delete is incompatible with --all, --mirror and --tags"
msgstr "--delete är imkompatibel med --all, --mirror och --tags"
-#: builtin/push.c:387
+#: builtin/push.c:412
msgid "--delete doesn't make sense without any refs"
msgstr "--delete kan inte användas utan referenser"
+#: builtin/read-tree.c:36
+msgid ""
+"git read-tree [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>] "
+"[-u [--exclude-per-directory=<gitignore>] | -i]] [--no-sparse-checkout] [--"
+"index-output=<file>] (--empty | <tree-ish1> [<tree-ish2> [<tree-ish3>]])"
+msgstr ""
+"git read-tree [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>] "
+"[-u [--exclude-per-directory=<gitignore>] | -i]] [--no-sparse-checkout] [--"
+"index-output=<fil>] (--empty | <träd-igt1> [<träd-igt2> [<träd-igt3>]])"
+
+#: builtin/read-tree.c:108
+msgid "write resulting index to <file>"
+msgstr "skriv resulterande index till <fil>"
+
+#: builtin/read-tree.c:111
+msgid "only empty the index"
+msgstr "töm bara indexet"
+
+#: builtin/read-tree.c:113
+msgid "Merging"
+msgstr "Sammanslagning"
+
+#: builtin/read-tree.c:115
+msgid "perform a merge in addition to a read"
+msgstr "utför en sammanslagning i tillägg till en läsning"
+
+#: builtin/read-tree.c:117
+msgid "3-way merge if no file level merging required"
+msgstr "3-vägssammanslagning om sammanslagning på filnivå ej krävs"
+
+#: builtin/read-tree.c:119
+msgid "3-way merge in presence of adds and removes"
+msgstr "3-vägssammanslagning när det finns tillägg och borttagningar"
+
+#: builtin/read-tree.c:121
+msgid "same as -m, but discard unmerged entries"
+msgstr "som -m, men kasta bort ej sammanslagna poster"
+
+#: builtin/read-tree.c:122
+msgid "<subdirectory>/"
+msgstr "<underkatalog>/"
+
+#: builtin/read-tree.c:123
+msgid "read the tree into the index under <subdirectory>/"
+msgstr "läs in trädet i indexet under <underkatalog>/"
+
+#: builtin/read-tree.c:126
+msgid "update working tree with merge result"
+msgstr "uppdatera arbetskatalogen med resultatet från sammanslagningen"
+
+#: builtin/read-tree.c:128
+msgid "gitignore"
+msgstr "gitignore"
+
+#: builtin/read-tree.c:129
+msgid "allow explicitly ignored files to be overwritten"
+msgstr "tillåt explicit ignorerade filer att skrivas över"
+
+#: builtin/read-tree.c:132
+msgid "don't check the working tree after merging"
+msgstr "kontrollera inte arbetskatalogen efter sammanslagning"
+
+#: builtin/read-tree.c:133
+msgid "don't update the index or the work tree"
+msgstr "uppdatera inte indexet eller arbetskatalogen"
+
+#: builtin/read-tree.c:135
+msgid "skip applying sparse checkout filter"
+msgstr "hoppa över att applicera filter för gles utcheckning"
+
+#: builtin/read-tree.c:137
+msgid "debug unpack-trees"
+msgstr "felsök unpack-trees"
+
+#: builtin/remote.c:11
+msgid "git remote [-v | --verbose]"
+msgstr "git remote [-v | --verbose]"
+
+#: builtin/remote.c:12
+msgid ""
+"git remote add [-t <branch>] [-m <master>] [-f] [--tags|--no-tags] [--"
+"mirror=<fetch|push>] <name> <url>"
+msgstr ""
+"git remote add [-t <gren>] [-m <master>] [-f] [--tags|--no-tags] [--"
+"mirror=<fetch|push>] <namn> <url>"
+
+#: builtin/remote.c:13 builtin/remote.c:32
+msgid "git remote rename <old> <new>"
+msgstr "git remote rename <gammal> <ny>"
+
+#: builtin/remote.c:14 builtin/remote.c:37
+msgid "git remote remove <name>"
+msgstr "git remote remove <namn>"
+
+#: builtin/remote.c:15
+msgid "git remote set-head <name> (-a | -d | <branch>)"
+msgstr "git remote set-head <namn> (-a | -d | <gren>)"
+
+#: builtin/remote.c:16
+msgid "git remote [-v | --verbose] show [-n] <name>"
+msgstr "git remote [-v | --verbose] show [-n] <namn>"
+
+#: builtin/remote.c:17
+msgid "git remote prune [-n | --dry-run] <name>"
+msgstr "git remote prune [-n | --dry-run] <namn>"
+
+#: builtin/remote.c:18
+msgid ""
+"git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]"
+msgstr ""
+"git remote [-v | --verbose] update [-p | --prune] [(<grupp> | <fjärr>)...]"
+
+#: builtin/remote.c:19
+msgid "git remote set-branches [--add] <name> <branch>..."
+msgstr "git remote set-branches [--add] <namn> <gren>..."
+
+#: builtin/remote.c:20 builtin/remote.c:68
+msgid "git remote set-url [--push] <name> <newurl> [<oldurl>]"
+msgstr "git remote set-url [--push] <namn> <nyurl> [<gammalurl>]"
+
+#: builtin/remote.c:21 builtin/remote.c:69
+msgid "git remote set-url --add <name> <newurl>"
+msgstr "git remote set-url --add <namn> <nyurl>"
+
+#: builtin/remote.c:22 builtin/remote.c:70
+msgid "git remote set-url --delete <name> <url>"
+msgstr "git remote set-url --delete <namn> <url>"
+
+#: builtin/remote.c:27
+msgid "git remote add [<options>] <name> <url>"
+msgstr "git remote add [<flaggor>] <namn> <url>"
+
+#: builtin/remote.c:42
+msgid "git remote set-head <name> (-a | -d | <branch>])"
+msgstr "git remote set-head <namn> (-a | -d | <gren>])"
+
+#: builtin/remote.c:47
+msgid "git remote set-branches <name> <branch>..."
+msgstr "git remote set-branches <namn> <gren>..."
+
+#: builtin/remote.c:48
+msgid "git remote set-branches --add <name> <branch>..."
+msgstr "git remote set-branches --add <namn> <gren>..."
+
+#: builtin/remote.c:53
+msgid "git remote show [<options>] <name>"
+msgstr "git remote show [<flaggor>] <namn>"
+
+#: builtin/remote.c:58
+msgid "git remote prune [<options>] <name>"
+msgstr "git remote prune [<flaggor>] <namn>"
+
+#: builtin/remote.c:63
+msgid "git remote update [<options>] [<group> | <remote>]..."
+msgstr "git remote update [<flaggor>] [<grupp> | <fjärr>]..."
+
#: builtin/remote.c:98
#, c-format
msgid "Updating %s"
@@ -4078,6 +7174,34 @@ msgstr ""
msgid "unknown mirror argument: %s"
msgstr "okänt argument till mirror: %s"
+#: builtin/remote.c:163
+msgid "fetch the remote branches"
+msgstr "hämta fjärrgrenarna"
+
+#: builtin/remote.c:165
+msgid "import all tags and associated objects when fetching"
+msgstr "importera alla taggar och associerade objekt vid hämtning"
+
+#: builtin/remote.c:168
+msgid "or do not fetch any tag at all (--no-tags)"
+msgstr "eller hämta inte några taggar alls (--no-tags)"
+
+#: builtin/remote.c:170
+msgid "branch(es) to track"
+msgstr "gren(ar) att spåra"
+
+#: builtin/remote.c:171
+msgid "master branch"
+msgstr "huvudgren"
+
+#: builtin/remote.c:172
+msgid "push|fetch"
+msgstr "push|fetch"
+
+#: builtin/remote.c:173
+msgid "set up remote as a mirror to push to or fetch from"
+msgstr "ställ in arkiv som spegel att sända eller ta emot från"
+
#: builtin/remote.c:185
msgid "specifying a master branch makes no sense with --mirror"
msgstr "att ange en master-gren ger ingen mening med --mirror"
@@ -4274,6 +7398,10 @@ msgstr " %-*s tvingar till %s"
msgid " %-*s pushes to %s"
msgstr " %-*s sänder till %s"
+#: builtin/remote.c:1091
+msgid "do not query remotes"
+msgstr "fråga inte fjärrar"
+
#: builtin/remote.c:1118
#, c-format
msgid "* remote %s"
@@ -4332,6 +7460,14 @@ msgid_plural " Local refs configured for 'git push'%s:"
msgstr[0] " Lokal referens konfigurerad för \"git push\"%s:"
msgstr[1] " Lokala referenser konfigurerade för \"git push\"%s:"
+#: builtin/remote.c:1199
+msgid "set refs/remotes/<name>/HEAD according to remote"
+msgstr "sätt refs/remotes/<namn>/HEAD enligt fjärren"
+
+#: builtin/remote.c:1201
+msgid "delete refs/remotes/<name>/HEAD"
+msgstr "ta bort refs/remotes/<namn>/HEAD"
+
#: builtin/remote.c:1216
msgid "Cannot determine remote HEAD"
msgstr "Kan inte bestämma HEAD på fjärren"
@@ -4385,15 +7521,35 @@ msgstr " * [skulle rensa] %s"
msgid " * [pruned] %s"
msgstr " * [rensad] %s"
+#: builtin/remote.c:1321
+msgid "prune remotes after fetching"
+msgstr "rensa fjärrar efter hämtning"
+
#: builtin/remote.c:1387 builtin/remote.c:1461
#, c-format
msgid "No such remote '%s'"
msgstr "Ingen sådan fjärr \"%s\""
+#: builtin/remote.c:1407
+msgid "add branch"
+msgstr "lägg till gren"
+
#: builtin/remote.c:1414
msgid "no remote specified"
msgstr "ingen fjärr angavs"
+#: builtin/remote.c:1436
+msgid "manipulate push URLs"
+msgstr "manipulera URL:ar för sändning"
+
+#: builtin/remote.c:1438
+msgid "add URL"
+msgstr "lägg till URL"
+
+#: builtin/remote.c:1440
+msgid "delete URLs"
+msgstr "ta bort URL:ar"
+
#: builtin/remote.c:1447
msgid "--add --delete doesn't make sense"
msgstr "--add --delete ger ingen mening"
@@ -4412,6 +7568,56 @@ msgstr "Ingen sådan URL hittades: %s"
msgid "Will not delete all non-push URLs"
msgstr "Kommer inte ta bort alla icke-sänd-URL:er"
+#: builtin/remote.c:1569
+msgid "be verbose; must be placed before a subcommand"
+msgstr "var pratsam; måste skrivas före ett underkommando"
+
+#: builtin/replace.c:17
+msgid "git replace [-f] <object> <replacement>"
+msgstr "git replace [-f] <objekt> <ersättning>"
+
+#: builtin/replace.c:18
+msgid "git replace -d <object>..."
+msgstr "git replace -d <objekt>..."
+
+#: builtin/replace.c:19
+msgid "git replace -l [<pattern>]"
+msgstr "git replace -l [<mönster>]"
+
+#: builtin/replace.c:118
+msgid "list replace refs"
+msgstr "visa ersättningsreferenser"
+
+#: builtin/replace.c:119
+msgid "delete replace refs"
+msgstr "ta bort ersättningsreferenser"
+
+#: builtin/replace.c:120
+msgid "replace the ref if it exists"
+msgstr "ersätt referensen om den finns"
+
+#: builtin/rerere.c:11
+msgid "git rerere [clear | forget path... | status | remaining | diff | gc]"
+msgstr "git rerere [clear | forget path... | status | remaining | diff | gc]"
+
+#: builtin/rerere.c:56
+msgid "register clean resolutions in index"
+msgstr "registrera rena lösningar i indexet"
+
+#: builtin/reset.c:25
+msgid ""
+"git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]"
+msgstr ""
+"git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<incheckning>]"
+
+#: builtin/reset.c:26
+msgid "git reset [-q] <commit> [--] <paths>..."
+msgstr "git reset [-q] <incheckning> [--] <sökvägar>..."
+
+#: builtin/reset.c:27
+msgid "git reset --patch [<commit>] [--] [<paths>...]"
+msgstr "git reset --patch [<incheckning>] [--] [<sökvägar>...]"
+
#: builtin/reset.c:33
msgid "mixed"
msgstr "blandad"
@@ -4467,52 +7673,175 @@ msgstr "Oköade ändringar efter återställning:"
msgid "Cannot do a %s reset in the middle of a merge."
msgstr "Kan inte utföra en %s återställning mitt i en sammanslagning."
-#: builtin/reset.c:297
+#: builtin/reset.c:238
+msgid "be quiet, only report errors"
+msgstr "var tyst, rapportera endast fel"
+
+#: builtin/reset.c:240
+msgid "reset HEAD and index"
+msgstr "återställ HEAD och index"
+
+#: builtin/reset.c:241
+msgid "reset only HEAD"
+msgstr "återställ endast HEAD"
+
+#: builtin/reset.c:243 builtin/reset.c:245
+msgid "reset HEAD, index and working tree"
+msgstr "återställ HEAD, index och arbetskatalog"
+
+#: builtin/reset.c:247
+msgid "reset HEAD but keep local changes"
+msgstr "återställ HEAD men behåll lokala ändringar"
+
+#: builtin/reset.c:303
#, c-format
msgid "Could not parse object '%s'."
msgstr "Kan inte tolka objektet \"%s\""
-#: builtin/reset.c:302
+#: builtin/reset.c:308
msgid "--patch is incompatible with --{hard,mixed,soft}"
msgstr "--patch är inkompatibel med --{hard,mixed,soft}"
-#: builtin/reset.c:311
+#: builtin/reset.c:317
msgid "--mixed with paths is deprecated; use 'git reset -- <paths>' instead."
msgstr ""
"--mixed rekommenderas inte med sökvägar; använd \"git reset -- <sökvägar>\"."
-#: builtin/reset.c:313
+#: builtin/reset.c:319
#, c-format
msgid "Cannot do %s reset with paths."
msgstr "Kan inte göra %s återställning med sökvägar."
-#: builtin/reset.c:325
+#: builtin/reset.c:331
#, c-format
msgid "%s reset is not allowed in a bare repository"
msgstr "%s återställning tillåts inte i ett naket arkiv"
-#: builtin/reset.c:341
+#: builtin/reset.c:347
#, c-format
msgid "Could not reset index file to revision '%s'."
msgstr "Kunde inte återställa indexfilen till versionen \"%s\"."
+#: builtin/rev-parse.c:339
+msgid "git rev-parse --parseopt [options] -- [<args>...]"
+msgstr "git rev-parse --parseopt [options] -- [<argument>...]"
+
+#: builtin/rev-parse.c:344
+msgid "keep the `--` passed as an arg"
+msgstr "behåll \"--\" sänt som argument"
+
+#: builtin/rev-parse.c:346
+msgid "stop parsing after the first non-option argument"
+msgstr "sluta tolka efter första argument som inte är flagga"
+
+#: builtin/rev-parse.c:464
+msgid ""
+"git rev-parse --parseopt [options] -- [<args>...]\n"
+" or: git rev-parse --sq-quote [<arg>...]\n"
+" or: git rev-parse [options] [<arg>...]\n"
+"\n"
+"Run \"git rev-parse --parseopt -h\" for more information on the first usage."
+msgstr ""
+"git rev-parse --parseopt [flaggor] -- [<argument>...]\n"
+" eller: git rev-parse --sq-quote [<argument>...]\n"
+" eller: git rev-parse [flaggor] [<argument>...]\n"
+"\n"
+"Kör \"git rev-parse --parseopt -h\" för mer information om den första "
+"varianten."
+
+#: builtin/revert.c:22
+msgid "git revert [options] <commit-ish>"
+msgstr "git revert [flaggor] <incheckning-igt>"
+
+#: builtin/revert.c:23
+msgid "git revert <subcommand>"
+msgstr "git revert <underkommando>"
+
+#: builtin/revert.c:28
+msgid "git cherry-pick [options] <commit-ish>"
+msgstr "git cherry-pick [flaggor] <incheckning-igt>"
+
+#: builtin/revert.c:29
+msgid "git cherry-pick <subcommand>"
+msgstr "git cherry-pick <underkommando>"
+
#: builtin/revert.c:70 builtin/revert.c:92
#, c-format
msgid "%s: %s cannot be used with %s"
msgstr "%s: %s kan inte användas med %s"
-#: builtin/revert.c:131
+#: builtin/revert.c:103
+msgid "end revert or cherry-pick sequence"
+msgstr "avsluta revert- eller cherry-pick-sekvens"
+
+#: builtin/revert.c:104
+msgid "resume revert or cherry-pick sequence"
+msgstr "Ã¥teruppta revert- eller cherry-pick-sekvens"
+
+#: builtin/revert.c:105
+msgid "cancel revert or cherry-pick sequence"
+msgstr "avbryt revert- eller cherry-pick-sekvens"
+
+#: builtin/revert.c:106
+msgid "don't automatically commit"
+msgstr "checka inte in automatiskt"
+
+#: builtin/revert.c:107
+msgid "edit the commit message"
+msgstr "redigera incheckningsmeddelandet"
+
+#: builtin/revert.c:110
+msgid "parent number"
+msgstr "nummer på förälder"
+
+#: builtin/revert.c:112
+msgid "merge strategy"
+msgstr "sammanslagninsstrategi"
+
+#: builtin/revert.c:113
+msgid "option"
+msgstr "alternativ"
+
+#: builtin/revert.c:114
+msgid "option for merge strategy"
+msgstr "alternativ för sammanslagningsstrategi"
+
+#: builtin/revert.c:125
+msgid "append commit name"
+msgstr "lägg till incheckningsnamn"
+
+#: builtin/revert.c:126
+msgid "allow fast-forward"
+msgstr "tillåt snabbspolning"
+
+#: builtin/revert.c:127
+msgid "preserve initially empty commits"
+msgstr "behåll incheckningar som börjar som tomma"
+
+#: builtin/revert.c:128
+msgid "allow commits with empty messages"
+msgstr "tillåt incheckningar med tomt meddelande"
+
+#: builtin/revert.c:129
+msgid "keep redundant, empty commits"
+msgstr "behåll redundanta, tomma incheckningar"
+
+#: builtin/revert.c:133
msgid "program error"
msgstr "programfel"
-#: builtin/revert.c:221
+#: builtin/revert.c:223
msgid "revert failed"
msgstr "\"revert\" misslyckades"
-#: builtin/revert.c:236
+#: builtin/revert.c:238
msgid "cherry-pick failed"
msgstr "\"cherry-pick\" misslyckades"
+#: builtin/rm.c:14
+msgid "git rm [options] [--] <file>..."
+msgstr "git rm [flaggor] [--] <fil>..."
+
#: builtin/rm.c:109
#, c-format
msgid ""
@@ -4540,6 +7869,26 @@ msgstr ""
"\"%s\" har lokala ändringar\n"
"(använd --cached för att behålla filen eller -f för att tvinga borttagning)"
+#: builtin/rm.c:134
+msgid "do not list removed files"
+msgstr "lista inte borttagna filer"
+
+#: builtin/rm.c:135
+msgid "only remove from the index"
+msgstr "ta bara bort från indexet"
+
+#: builtin/rm.c:136
+msgid "override the up-to-date check"
+msgstr "överstyr àjour-testet"
+
+#: builtin/rm.c:137
+msgid "allow recursive removal"
+msgstr "tillåt rekursiv borttagning"
+
+#: builtin/rm.c:139
+msgid "exit with a zero status even if nothing matched"
+msgstr "avsluta med nollstatus även om inget träffades"
+
#: builtin/rm.c:194
#, c-format
msgid "not removing '%s' recursively without -r"
@@ -4550,11 +7899,203 @@ msgstr "tar inte bort \"%s\" rekursivt utan -r"
msgid "git rm: unable to remove %s"
msgstr "git rm: kan inte ta bort %s"
+#: builtin/shortlog.c:13
+msgid "git shortlog [-n] [-s] [-e] [-w] [rev-opts] [--] [<commit-id>... ]"
+msgstr ""
+"git shortlog [-n] [-s] [-e] [-w] [rev-flaggor] [--] [<incheckning-id>... ]"
+
#: builtin/shortlog.c:157
#, c-format
msgid "Missing author: %s"
msgstr "Författare saknas: %s"
+#: builtin/shortlog.c:253
+msgid "sort output according to the number of commits per author"
+msgstr "sortera utdata enligt antal incheckningar per författare"
+
+#: builtin/shortlog.c:255
+msgid "Suppress commit descriptions, only provides commit count"
+msgstr "Undertryck beskrivningar, visa bara antal incheckningar"
+
+#: builtin/shortlog.c:257
+msgid "Show the email address of each author"
+msgstr "Visa e-postadress för varje författare"
+
+#: builtin/shortlog.c:258
+msgid "w[,i1[,i2]]"
+msgstr "w[,i1[,i2]]"
+
+#: builtin/shortlog.c:259
+msgid "Linewrap output"
+msgstr "Radbryt utdata"
+
+#: builtin/show-branch.c:9
+msgid ""
+"git show-branch [-a|--all] [-r|--remotes] [--topo-order | --date-order] [--"
+"current] [--color[=<when>] | --no-color] [--sparse] [--more=<n> | --list | --"
+"independent | --merge-base] [--no-name | --sha1-name] [--topics] [(<rev> | "
+"<glob>)...]"
+msgstr ""
+"git show-branch [-a|--all] [-r|--remotes] [--topo-order | --date-order] [--"
+"current] [--color[=<när>] | --no-color] [--sparse] [--more=<n> | --list | --"
+"independent | --merge-base] [--no-name | --sha1-name] [--topics] [(<rev> | "
+"<mönster>)...]"
+
+#: builtin/show-branch.c:10
+msgid "git show-branch (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]"
+msgstr "git show-branch (-g|--reflog)[=<n>[,<bas>]] [--list] [<ref>]"
+
+#: builtin/show-branch.c:651
+msgid "show remote-tracking and local branches"
+msgstr "visa fjärrspårande och lokala grenar"
+
+#: builtin/show-branch.c:653
+msgid "show remote-tracking branches"
+msgstr "visa fjärrspårande grenar"
+
+#: builtin/show-branch.c:655
+msgid "color '*!+-' corresponding to the branch"
+msgstr "färga \"*!+-\" enligt grenen"
+
+#: builtin/show-branch.c:657
+msgid "show <n> more commits after the common ancestor"
+msgstr "visa <n> ytterligare incheckningar efter gemensam anfader"
+
+#: builtin/show-branch.c:659
+msgid "synonym to more=-1"
+msgstr "synonym till more=-1"
+
+#: builtin/show-branch.c:660
+msgid "suppress naming strings"
+msgstr "undertyck namnsträngar"
+
+#: builtin/show-branch.c:662
+msgid "include the current branch"
+msgstr "inkludera aktuell gren"
+
+#: builtin/show-branch.c:664
+msgid "name commits with their object names"
+msgstr "namnge incheckningar med deras objektnamn"
+
+#: builtin/show-branch.c:666
+msgid "show possible merge bases"
+msgstr "visa möjliga sammanslaningsbaser"
+
+#: builtin/show-branch.c:668
+msgid "show refs unreachable from any other ref"
+msgstr "visa referenser som inte kan nås från någon annan referens"
+
+#: builtin/show-branch.c:670
+msgid "show commits in topological order"
+msgstr "visa incheckningar i topologisk ordning"
+
+#: builtin/show-branch.c:672
+msgid "show only commits not on the first branch"
+msgstr "visa endast incheckningar inte på den första grenen"
+
+#: builtin/show-branch.c:674
+msgid "show merges reachable from only one tip"
+msgstr "visa sammanslagningar som endast kan nås från en spets"
+
+#: builtin/show-branch.c:676
+msgid "show commits where no parent comes before its children"
+msgstr "visa incheckningar där ingen förälder kommer före dess barn"
+
+#: builtin/show-branch.c:678
+msgid "<n>[,<base>]"
+msgstr "<n>[,<bas>]"
+
+#: builtin/show-branch.c:679
+msgid "show <n> most recent ref-log entries starting at base"
+msgstr "visa <n> nyaste refloggposter med början på bas"
+
+#: builtin/show-ref.c:10
+msgid ""
+"git show-ref [-q|--quiet] [--verify] [--head] [-d|--dereference] [-s|--hash"
+"[=<n>]] [--abbrev[=<n>]] [--tags] [--heads] [--] [pattern*] "
+msgstr ""
+"git show-ref [-q|--quiet] [--verify] [--head] [-d|--dereference] [-s|--hash"
+"[=<n>]] [--abbrev[=<n>]] [--tags] [--heads] [--] [mönster*] "
+
+#: builtin/show-ref.c:11
+msgid "git show-ref --exclude-existing[=pattern] < ref-list"
+msgstr "git show-ref --exclude-existing[=mönster] < reflista"
+
+#: builtin/show-ref.c:182
+msgid "only show tags (can be combined with heads)"
+msgstr "visa endast taggar (kan kombineras med huvuden)"
+
+#: builtin/show-ref.c:183
+msgid "only show heads (can be combined with tags)"
+msgstr "visa endast huvuden (kan kombineras med taggar)"
+
+#: builtin/show-ref.c:184
+msgid "stricter reference checking, requires exact ref path"
+msgstr "striktare referenskontroll, kräver exakt referenssökväg"
+
+#: builtin/show-ref.c:187 builtin/show-ref.c:189
+msgid "show the HEAD reference"
+msgstr "visa HEAD-referensen"
+
+#: builtin/show-ref.c:191
+msgid "dereference tags into object IDs"
+msgstr "avreferera taggar till objekt-id"
+
+#: builtin/show-ref.c:193
+msgid "only show SHA1 hash using <n> digits"
+msgstr "visa SHA1-hash endast med <n> siffror"
+
+#: builtin/show-ref.c:197
+msgid "do not print results to stdout (useful with --verify)"
+msgstr "visa inte resultat på standard ut (användbart med --verify)"
+
+#: builtin/show-ref.c:199
+msgid "show refs from stdin that aren't in local repository"
+msgstr "visa referenser från standard in som inte finns i lokalt arkiv"
+
+#: builtin/symbolic-ref.c:7
+msgid "git symbolic-ref [options] name [ref]"
+msgstr "git symbolic-ref [flaggor] namn [ref]"
+
+#: builtin/symbolic-ref.c:38
+msgid "suppress error message for non-symbolic (detached) refs"
+msgstr ""
+"undertryck felmeddelanden för icke-symboliska (frånkopplade) referenser"
+
+#: builtin/symbolic-ref.c:39
+msgid "shorten ref output"
+msgstr "förkorta ref-utdata"
+
+#: builtin/symbolic-ref.c:40 builtin/update-ref.c:18
+msgid "reason"
+msgstr "skäl"
+
+#: builtin/symbolic-ref.c:40 builtin/update-ref.c:18
+msgid "reason of the update"
+msgstr "skäl till uppdateringen"
+
+#: builtin/tag.c:22
+msgid ""
+"git tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]"
+msgstr ""
+"git tag [-a|-s|-u <nyckel-id>] [-f] [-m <medd>|-F <fil>] <taggnamn> [<huvud>]"
+
+#: builtin/tag.c:23
+msgid "git tag -d <tagname>..."
+msgstr "git tag -d <taggnamn>..."
+
+#: builtin/tag.c:24
+msgid ""
+"git tag -l [-n[<num>]] [--contains <commit>] [--points-at <object>] \n"
+"\t\t[<pattern>...]"
+msgstr ""
+"git tag -l [-n[<antal>]] [--contains <incheckning>] [--points-at <objekt>] \n"
+"\t\t[<mönster>...]"
+
+#: builtin/tag.c:26
+msgid "git tag -v <tagname>..."
+msgstr "git tag -v <taggnamn>..."
+
#: builtin/tag.c:60
#, c-format
msgid "malformed object at '%s'"
@@ -4644,6 +8185,62 @@ msgstr "flaggan \"points-at\" behöver ett object"
msgid "malformed object name '%s'"
msgstr "felformat objektnamn \"%s\""
+#: builtin/tag.c:447
+msgid "list tag names"
+msgstr "lista taggnamn"
+
+#: builtin/tag.c:449
+msgid "print <n> lines of each tag message"
+msgstr "visa <n> rader från varje taggmeddelande"
+
+#: builtin/tag.c:451
+msgid "delete tags"
+msgstr "ta bort taggar"
+
+#: builtin/tag.c:452
+msgid "verify tags"
+msgstr "verifiera taggar"
+
+#: builtin/tag.c:454
+msgid "Tag creation options"
+msgstr "Alternativ för att skapa taggar"
+
+#: builtin/tag.c:456
+msgid "annotated tag, needs a message"
+msgstr "annoterad tagg, behöver meddelande"
+
+#: builtin/tag.c:458
+msgid "tag message"
+msgstr "taggmeddelande"
+
+#: builtin/tag.c:460
+msgid "annotated and GPG-signed tag"
+msgstr "annoterad och GPG-signerad tagg"
+
+#: builtin/tag.c:464
+msgid "use another key to sign the tag"
+msgstr "använd annan nyckel för att signera taggen"
+
+#: builtin/tag.c:465
+msgid "replace the tag if exists"
+msgstr "ersätt taggen om den finns"
+
+#: builtin/tag.c:466
+msgid "show tag list in columns"
+msgstr "lista taggar i spalter"
+
+#: builtin/tag.c:468
+msgid "Tag listing options"
+msgstr "Alternativ för listning av taggar"
+
+#: builtin/tag.c:471
+msgid "print only tags that contain the commit"
+msgstr "visa endast taggar som innehåller incheckningen"
+
+#: builtin/tag.c:477
+msgid "print only tags of the object"
+msgstr "visa endast taggar för objektet"
+
#: builtin/tag.c:506
msgid "--column and -n are incompatible"
msgstr "--column och -n är inkompatibla"
@@ -4693,27 +8290,182 @@ msgstr "%s: kan inte uppdatera referensen"
msgid "Updated tag '%s' (was %s)\n"
msgstr "Uppdaterad tagg \"%s\" (var %s)\n"
-#: git.c:16
-msgid "See 'git help <command>' for more information on a specific command."
-msgstr ""
-"Se \"git help <kommando>\" för mer information om ett specifikt kommando."
+#: builtin/update-index.c:401
+msgid "git update-index [options] [--] [<file>...]"
+msgstr "git update-index [flaggor] [--] [<fil>...]"
-#: parse-options.h:133 parse-options.h:235
-msgid "n"
-msgstr "n"
+#: builtin/update-index.c:717
+msgid "continue refresh even when index needs update"
+msgstr "fortsätt uppdatera även när index inte är àjour"
-#: parse-options.h:141
-msgid "time"
-msgstr "tid"
+#: builtin/update-index.c:720
+msgid "refresh: ignore submodules"
+msgstr "refresh: ignorera undermoduler"
-# %s är ett verb ("Untracked"/"Ignored"); lägg till ett -e.
-#: parse-options.h:149
-msgid "file"
-msgstr "fil"
+#: builtin/update-index.c:723
+msgid "do not ignore new files"
+msgstr "ignorera inte nya filer"
-#: parse-options.h:151
-msgid "when"
-msgstr "när"
+#: builtin/update-index.c:725
+msgid "let files replace directories and vice-versa"
+msgstr "låt filer ersätta kataloger och omvänt"
+
+#: builtin/update-index.c:727
+msgid "notice files missing from worktree"
+msgstr "lägg märke till filer som saknas i arbetskatalogen"
+
+#: builtin/update-index.c:729
+msgid "refresh even if index contains unmerged entries"
+msgstr "uppdatera även om indexet innehåller ej sammanslagna poster"
+
+#: builtin/update-index.c:732
+msgid "refresh stat information"
+msgstr "uppdatera statusinformation"
+
+#: builtin/update-index.c:736
+msgid "like --refresh, but ignore assume-unchanged setting"
+msgstr "som --refresh, men ignorera assume-unchanged-inställning"
+
+#: builtin/update-index.c:740
+msgid "<mode> <object> <path>"
+msgstr "<läge> <objekt> <sökväg>"
+
+#: builtin/update-index.c:741
+msgid "add the specified entry to the index"
+msgstr "lägg till angiven post i indexet"
+
+#: builtin/update-index.c:745
+msgid "(+/-)x"
+msgstr "(+/-)x"
+
+#: builtin/update-index.c:746
+msgid "override the executable bit of the listed files"
+msgstr "överstyr exekveringsbiten för angivna filer"
+
+#: builtin/update-index.c:750
+msgid "mark files as \"not changing\""
+msgstr "markera filer som \"ändras inte\""
+
+#: builtin/update-index.c:753
+msgid "clear assumed-unchanged bit"
+msgstr "rensa \"assume-unchanged\"-biten"
+
+#: builtin/update-index.c:756
+msgid "mark files as \"index-only\""
+msgstr "markera filer som \"endast index\""
+
+#: builtin/update-index.c:759
+msgid "clear skip-worktree bit"
+msgstr "töm \"skip-worktree\"-biten"
+
+#: builtin/update-index.c:762
+msgid "add to index only; do not add content to object database"
+msgstr "lägg endast till indexet; lägg inte till innehållet i objektdatabasen"
+
+#: builtin/update-index.c:764
+msgid "remove named paths even if present in worktree"
+msgstr "ta bort namngivna sökvägar även om de finns i arbetskatalogen"
+
+#: builtin/update-index.c:766
+msgid "with --stdin: input lines are terminated by null bytes"
+msgstr "med --stdin: indatarader termineras med null-byte"
+
+#: builtin/update-index.c:768
+msgid "read list of paths to be updated from standard input"
+msgstr "läs lista över sökvägar att uppdatera från standard in"
+
+#: builtin/update-index.c:772
+msgid "add entries from standard input to the index"
+msgstr "lägg poster från från standard in till indexet"
+
+#: builtin/update-index.c:776
+msgid "repopulate stages #2 and #3 for the listed paths"
+msgstr "återfyll etapp 2 och 3 från angivna sökvägar"
+
+#: builtin/update-index.c:780
+msgid "only update entries that differ from HEAD"
+msgstr "uppdatera endast poster som skiljer sig från HEAD"
+
+#: builtin/update-index.c:784
+msgid "ignore files missing from worktree"
+msgstr "ignorera filer som saknas i arbetskatalogen"
+
+#: builtin/update-index.c:787
+msgid "report actions to standard output"
+msgstr "raportera åtgärder på standard ut"
+
+#: builtin/update-index.c:789
+msgid "(for porcelains) forget saved unresolved conflicts"
+msgstr "(för porslin) glöm sparade olösta konflikter"
+
+#: builtin/update-index.c:793
+msgid "write index in this format"
+msgstr "skriv index i detta format"
+
+#: builtin/update-ref.c:7
+msgid "git update-ref [options] -d <refname> [<oldval>]"
+msgstr "git update-ref [flaggor] -d <refnamn> [<gammaltvärde>]"
+
+#: builtin/update-ref.c:8
+msgid "git update-ref [options] <refname> <newval> [<oldval>]"
+msgstr "git update-ref [flaggor] <refnamn> <gammaltvärde> [<nyttvärde>]"
+
+#: builtin/update-ref.c:19
+msgid "delete the reference"
+msgstr "ta bort referensen"
+
+#: builtin/update-ref.c:21
+msgid "update <refname> not the one it points to"
+msgstr "uppdatera <refnamn> inte det den pekar på"
+
+#: builtin/update-server-info.c:6
+msgid "git update-server-info [--force]"
+msgstr "git update-server-info [--force]"
+
+#: builtin/update-server-info.c:14
+msgid "update the info files from scratch"
+msgstr "uppdatera informationsfilerna från grunden"
+
+#: builtin/verify-pack.c:56
+msgid "git verify-pack [-v|--verbose] [-s|--stat-only] <pack>..."
+msgstr "git verify-pack [-v|--verbose] [-s|--stat-only] <paket>..."
+
+#: builtin/verify-pack.c:66
+msgid "verbose"
+msgstr "pratsam"
+
+#: builtin/verify-pack.c:68
+msgid "show statistics only"
+msgstr "visa endast statistik"
+
+#: builtin/verify-tag.c:17
+msgid "git verify-tag [-v|--verbose] <tag>..."
+msgstr "git verify-tag [-v|--verbose] <tagg>..."
+
+#: builtin/verify-tag.c:73
+msgid "print tag contents"
+msgstr "visa innehåll för tag"
+
+#: builtin/write-tree.c:13
+msgid "git write-tree [--missing-ok] [--prefix=<prefix>/]"
+msgstr "git write-tree [--missing-ok] [--prefix=<prefix>/]"
+
+#: builtin/write-tree.c:26
+msgid "<prefix>/"
+msgstr "<prefix>/"
+
+#: builtin/write-tree.c:27
+msgid "write tree object for a subdirectory <prefix>"
+msgstr "visa trädobjekt för underkatalogen <prefix>"
+
+#: builtin/write-tree.c:30
+msgid "only useful for debugging"
+msgstr "endast användbart vid felsökning"
+
+#: git.c:16
+msgid "See 'git help <command>' for more information on a specific command."
+msgstr ""
+"Se \"git help <kommando>\" för mer information om ett specifikt kommando."
#: parse-options.h:156
msgid "no-op (backward compatibility)"
@@ -4813,7 +8565,7 @@ msgstr "Visa status för arbetskatalogen"
#: common-cmds.h:28
msgid "Create, list, delete or verify a tag object signed with GPG"
-msgstr "Skapa, visa, ta bort eller verifiera ett taggobjekt signerat med GPG"
+msgstr "Skapa, visa, ta bort eller verifiera GPG-signerat taggobjekt"
#: git-am.sh:50
msgid "You need to set your committer info first"
@@ -4830,9 +8582,9 @@ msgstr ""
#: git-am.sh:105
#, sh-format
msgid ""
-"When you have resolved this problem run \"$cmdline --resolved\".\n"
-"If you would prefer to skip this patch, instead run \"$cmdline --skip\".\n"
-"To restore the original branch and stop patching run \"$cmdline --abort\"."
+"When you have resolved this problem, run \"$cmdline --resolved\".\n"
+"If you prefer to skip this patch, run \"$cmdline --skip\" instead.\n"
+"To restore the original branch and stop patching, run \"$cmdline --abort\"."
msgstr ""
"När du har löst problemet kör du \"$cmdline --resolved\".\n"
"Om du vill hoppa över patchen kör du istället \"$cmdline --skip\".\n"
@@ -4848,6 +8600,10 @@ msgstr ""
"Arkivet saknar objekt som behövs för att falla tillbaka på 3-"
"vägssammanslagning."
+#: git-am.sh:139
+msgid "Using index info to reconstruct a base tree..."
+msgstr "Använder indexinfo för att åteskapa ett basträd..."
+
#: git-am.sh:154
msgid ""
"Did you hand edit your patch?\n"
@@ -4861,42 +8617,50 @@ msgid "Falling back to patching base and 3-way merge..."
msgstr ""
"Faller tillbaka på att pacha grundversionen och trevägssammanslagning..."
-#: git-am.sh:275
+#: git-am.sh:179
+msgid "Failed to merge in the changes."
+msgstr "Misslyckads slå ihop ändringarna."
+
+#: git-am.sh:274
msgid "Only one StGIT patch series can be applied at once"
msgstr "Endast en StGIT-patchserie kan tillämpas åt gången"
-#: git-am.sh:362
+#: git-am.sh:361
#, sh-format
msgid "Patch format $patch_format is not supported."
msgstr "Patchformatet $patch_format stöds inte."
-#: git-am.sh:364
+#: git-am.sh:363
msgid "Patch format detection failed."
msgstr "Misslyckades detektera patchformat."
-#: git-am.sh:418
-msgid "-d option is no longer supported. Do not use."
-msgstr "Flaggan -d stöds inte lägre. Använd inte."
+#: git-am.sh:389
+msgid ""
+"The -b/--binary option has been a no-op for long time, and\n"
+"it will be removed. Please do not use it anymore."
+msgstr ""
+"Flaggan -b/--binary har varit utan funktion länge, och\n"
+"kommer tas bort. Vi ber dig att inte använda den längre."
-#: git-am.sh:481
+#: git-am.sh:477
#, sh-format
msgid "previous rebase directory $dotest still exists but mbox given."
msgstr "tidigare rebase-katalog $dotest finns fortfarande, men mbox angavs."
-#: git-am.sh:486
+#: git-am.sh:482
msgid "Please make up your mind. --skip or --abort?"
msgstr "Bestäm dig. --skip eller --abort?"
-#: git-am.sh:513
+#: git-am.sh:509
msgid "Resolve operation not in progress, we are not resuming."
msgstr "Lösningsoperation pågår inte, vi återupptar inte."
-#: git-am.sh:579
+#: git-am.sh:575
#, sh-format
msgid "Dirty index: cannot apply patches (dirty: $files)"
msgstr "Smutsigt index: kan inte tillämpa patchar (smutsiga: $files)"
-#: git-am.sh:671
+#: git-am.sh:679
#, sh-format
msgid ""
"Patch is empty. Was it split wrong?\n"
@@ -4907,32 +8671,32 @@ msgstr ""
"Om du vill hoppa över patchen kör du istället \"$cmdline --skip\".\n"
"För att återställa originalgrenen och avbryta kör du \"$cmdline --abort\"."
-#: git-am.sh:708
+#: git-am.sh:706
msgid "Patch does not have a valid e-mail address."
msgstr "Patchen har inte någon giltig e-postadress."
-#: git-am.sh:755
+#: git-am.sh:753
msgid "cannot be interactive without stdin connected to a terminal."
msgstr ""
"kan inte vara interaktiv om standard in inte är ansluten till en terminal."
-#: git-am.sh:759
+#: git-am.sh:757
msgid "Commit Body is:"
msgstr "Incheckningskroppen är:"
#. TRANSLATORS: Make sure to include [y], [n], [e], [v] and [a]
#. in your translation. The program will only accept English
#. input at this point.
-#: git-am.sh:766
+#: git-am.sh:764
msgid "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all "
msgstr "Tillämpa? Y=ja/N=nej/E=redigera/V=visa patch/A=godta alla "
-#: git-am.sh:802
+#: git-am.sh:800
#, sh-format
msgid "Applying: $FIRSTLINE"
msgstr "Tillämpar: $FIRSTLINE"
-#: git-am.sh:823
+#: git-am.sh:821
msgid ""
"No changes - did you forget to use 'git add'?\n"
"If there is nothing left to stage, chances are that something else\n"
@@ -4942,7 +8706,7 @@ msgstr ""
"Om det inte är något kvar att köa kan det hända att något annat redan\n"
"introducerat samma ändringar; kanske du bör hoppa över patchen."
-#: git-am.sh:831
+#: git-am.sh:829
msgid ""
"You still have unmerged paths in your index\n"
"did you forget to use 'git add'?"
@@ -4950,16 +8714,25 @@ msgstr ""
"Du har fortfarande sökvägar som inte slagits samman i ditt index\n"
"glömde du använda \"git add\"?"
-#: git-am.sh:847
+#: git-am.sh:845
msgid "No changes -- Patch already applied."
msgstr "Inga ändringar -- Patchen har redan tillämpats."
-#: git-am.sh:857
+#: git-am.sh:855
#, sh-format
msgid "Patch failed at $msgnum $FIRSTLINE"
msgstr "Patchen misslyckades vid $msgnum $FIRSTLINE"
-#: git-am.sh:873
+#: git-am.sh:858
+#, sh-format
+msgid ""
+"The copy of the patch that failed is found in:\n"
+" $dotest/patch"
+msgstr ""
+"En kopia av patchen som misslyckades finns i:\n"
+" $dotest/patch"
+
+#: git-am.sh:876
msgid "applying to an empty history"
msgstr "tillämpar på en tom historik"
@@ -5162,6 +8935,126 @@ msgstr "Kan inte slå ihop flera grenar i ett tomt huvud."
msgid "Cannot rebase onto multiple branches"
msgstr "Kan inte utföra en \"rebase\" ovanpå flera grenar"
+#: git-rebase.sh:52
+msgid ""
+"When you have resolved this problem, run \"git rebase --continue\".\n"
+"If you prefer to skip this patch, run \"git rebase --skip\" instead.\n"
+"To check out the original branch and stop rebasing, run \"git rebase --abort"
+"\"."
+msgstr ""
+"När du har löst problemet kör du \"git rebase --continue\".\n"
+"Om du vill hoppa över patchen kör du istället \"git rebase --skip\".\n"
+"För att återställa originalgrenen och avbryta kör du \"git rebase --abort\"."
+
+#: git-rebase.sh:159
+msgid "The pre-rebase hook refused to rebase."
+msgstr "Kroken pre-rebase vägrade ombaseringen."
+
+#: git-rebase.sh:164
+msgid "It looks like git-am is in progress. Cannot rebase."
+msgstr "Det verkar som en git-am körs. Kan inte ombasera."
+
+#: git-rebase.sh:295
+msgid "The --exec option must be used with the --interactive option"
+msgstr "Flaggan --exec måste användas tillsammans med flaggan --interactive"
+
+#: git-rebase.sh:300
+msgid "No rebase in progress?"
+msgstr "Ingen ombasering pågår?"
+
+#: git-rebase.sh:313
+msgid "Cannot read HEAD"
+msgstr "Kan inte läsa HEAD"
+
+#: git-rebase.sh:316
+msgid ""
+"You must edit all merge conflicts and then\n"
+"mark them as resolved using git add"
+msgstr ""
+"Du måste redigera alla sammanslagningskonflikter och\n"
+"därefter markera dem som lösta med git add"
+
+#: git-rebase.sh:334
+#, sh-format
+msgid "Could not move back to $head_name"
+msgstr "Kunde inte flytta tillbaka till $head_name"
+
+#: git-rebase.sh:350
+#, sh-format
+msgid ""
+"It seems that there is already a $state_dir_base directory, and\n"
+"I wonder if you are in the middle of another rebase. If that is the\n"
+"case, please try\n"
+"\t$cmd_live_rebase\n"
+"If that is not the case, please\n"
+"\t$cmd_clear_stale_rebase\n"
+"and run me again. I am stopping in case you still have something\n"
+"valuable there."
+msgstr ""
+"Det verkar som katalogen $state_dir_base redan existerar, och\n"
+"jag undrar om du redan är mitt i en annan ombasering. Om så är\n"
+"fallet, försök\n"
+"\t$cmd_live_rebase\n"
+"Om så inte är fallet, kör\n"
+"\t$cmd_clear_stale_rebase\n"
+"och kör programmet igen. Jag avslutar ifall du fortfarande har\n"
+"något av värde där."
+
+#: git-rebase.sh:395
+#, sh-format
+msgid "invalid upstream $upstream_name"
+msgstr "ogiltig uppström $upstream_name"
+
+#: git-rebase.sh:419
+#, sh-format
+msgid "$onto_name: there are more than one merge bases"
+msgstr "$onto_name: mer än en sammanslagningsbas finns"
+
+#: git-rebase.sh:422 git-rebase.sh:426
+#, sh-format
+msgid "$onto_name: there is no merge base"
+msgstr "$onto_name: ingen sammanslagningsbas finns"
+
+#: git-rebase.sh:431
+#, sh-format
+msgid "Does not point to a valid commit: $onto_name"
+msgstr "Peka på en giltig incheckning: $onto_name"
+
+#: git-rebase.sh:454
+#, sh-format
+msgid "fatal: no such branch: $branch_name"
+msgstr "ödesdigert: ingen sådan gren: $branch_name"
+
+#: git-rebase.sh:474
+msgid "Please commit or stash them."
+msgstr "Checka in eller använd \"stash\" på dem."
+
+#: git-rebase.sh:492
+#, sh-format
+msgid "Current branch $branch_name is up to date."
+msgstr "Aktuell gren $branch_name är à jour."
+
+#: git-rebase.sh:495
+#, sh-format
+msgid "Current branch $branch_name is up to date, rebase forced."
+msgstr "Aktuell gren $branch_name är à jour, ombasering framtvingad."
+
+#: git-rebase.sh:506
+#, sh-format
+msgid "Changes from $mb to $onto:"
+msgstr "Ändringar från $mb till $onto:"
+
+#. Detach HEAD and reset the tree
+#: git-rebase.sh:515
+msgid "First, rewinding head to replay your work on top of it..."
+msgstr ""
+"Först, spolar tillbaka huvudet för att spela av ditt arbete ovanpå det..."
+
+#: git-rebase.sh:523
+#, sh-format
+msgid "Fast-forwarded $branch_name to $onto_name."
+msgstr "Snabbspolade $branch_name till $onto_name."
+
#: git-stash.sh:51
msgid "git stash clear with parameters is unimplemented"
msgstr "\"git stash clear\" med parametrar har inte implementerats"
@@ -5269,60 +9162,60 @@ msgstr "Kunde inte spara indexträd"
msgid "Cannot unstage modified files"
msgstr "Kan inte ta bort ändrade filer ur kön"
-#: git-stash.sh:474
+#: git-stash.sh:475
msgid "Index was not unstashed."
msgstr "Indexet har inte tagits ur kön."
-#: git-stash.sh:491
+#: git-stash.sh:492
#, sh-format
msgid "Dropped ${REV} ($s)"
msgstr "Kastade ${REV} ($s)"
-#: git-stash.sh:492
+#: git-stash.sh:493
#, sh-format
msgid "${REV}: Could not drop stash entry"
msgstr "${REV}: Kunde inte kasta \"stash\"-post"
-#: git-stash.sh:499
+#: git-stash.sh:500
msgid "No branch name specified"
msgstr "Inget grennamn angavs"
-#: git-stash.sh:570
+#: git-stash.sh:571
msgid "(To restore them type \"git stash apply\")"
msgstr "(För att återställa dem, skriv \"git stash apply\")"
-#: git-submodule.sh:56
+#: git-submodule.sh:88
#, sh-format
msgid "cannot strip one component off url '$remoteurl'"
msgstr "kan inte ta bort en komponent från url:en \"$remoteurl\""
-#: git-submodule.sh:109
+#: git-submodule.sh:167
#, sh-format
msgid "No submodule mapping found in .gitmodules for path '$sm_path'"
msgstr ""
"Hittade ingen undermodulmappning i .gitmodules för sökvägen \"$sm_path\""
-#: git-submodule.sh:150
+#: git-submodule.sh:211
#, sh-format
msgid "Clone of '$url' into submodule path '$sm_path' failed"
msgstr "Misslyckades klona \"$url\" till undermodulsökvägen \"$sm_path\""
-#: git-submodule.sh:160
+#: git-submodule.sh:223
#, sh-format
msgid "Gitdir '$a' is part of the submodule path '$b' or vice versa"
msgstr "Gitkatalog \"$a\" ingår i underkatalogsökvägen \"$b\" eller omvänt"
-#: git-submodule.sh:249
+#: git-submodule.sh:312
#, sh-format
msgid "repo URL: '$repo' must be absolute or begin with ./|../"
msgstr "arkiv-URL: \"$repo\" måste vara absolut eller börja med ./|../"
-#: git-submodule.sh:266
+#: git-submodule.sh:329
#, sh-format
msgid "'$sm_path' already exists in the index"
msgstr "\"$sm_path\" finns redan i indexet"
-#: git-submodule.sh:270
+#: git-submodule.sh:333
#, sh-format
msgid ""
"The following path is ignored by one of your .gitignore files:\n"
@@ -5333,64 +9226,64 @@ msgstr ""
"$sm_path\n"
"Använd -f om du verkligen vill lägga till den"
-#: git-submodule.sh:281
+#: git-submodule.sh:344
#, sh-format
msgid "Adding existing repo at '$sm_path' to the index"
msgstr "Lägger till befintligt arkiv i \"$sm_path\" i indexet"
-#: git-submodule.sh:283
+#: git-submodule.sh:346
#, sh-format
msgid "'$sm_path' already exists and is not a valid git repo"
msgstr "\"$sm_path\" finns redan och är inte ett giltigt git-arkiv"
-#: git-submodule.sh:297
+#: git-submodule.sh:360
#, sh-format
msgid "Unable to checkout submodule '$sm_path'"
msgstr "Kan inte checka ut undermodulen \"$sm_path\""
-#: git-submodule.sh:302
+#: git-submodule.sh:365
#, sh-format
msgid "Failed to add submodule '$sm_path'"
msgstr "Misslyckades lägga till undermodulen \"$sm_path\""
-#: git-submodule.sh:307
+#: git-submodule.sh:370
#, sh-format
msgid "Failed to register submodule '$sm_path'"
msgstr "Misslyckades registrera undermodulen \"$sm_path\""
-#: git-submodule.sh:349
+#: git-submodule.sh:413
#, sh-format
msgid "Entering '$prefix$sm_path'"
msgstr "GÃ¥r in i \"$prefix$sm_path\""
-#: git-submodule.sh:363
+#: git-submodule.sh:427
#, sh-format
msgid "Stopping at '$sm_path'; script returned non-zero status."
msgstr ""
"Stoppar på \"$sm_path\"; skriptet returnerade en status skild från noll."
-#: git-submodule.sh:406
+#: git-submodule.sh:471
#, sh-format
msgid "No url found for submodule path '$sm_path' in .gitmodules"
msgstr "Hittade ingen url för undermodulsökvägen \"$sm_path\" i .gitmodules"
-#: git-submodule.sh:415
+#: git-submodule.sh:480
#, sh-format
msgid "Failed to register url for submodule path '$sm_path'"
msgstr "Misslyckades registrera url för underkatalogsökväg \"$sm_path\""
-#: git-submodule.sh:417
+#: git-submodule.sh:482
#, sh-format
msgid "Submodule '$name' ($url) registered for path '$sm_path'"
msgstr "Undermodulen \"$name\" ($url) registrerad för sökvägen \"$sm_path\""
-#: git-submodule.sh:425
+#: git-submodule.sh:490
#, sh-format
msgid "Failed to register update mode for submodule path '$sm_path'"
msgstr ""
"Misslyckades registrera uppdateringsläge för undermodulsökväg \"$sm_path\""
-#: git-submodule.sh:524
+#: git-submodule.sh:590
#, sh-format
msgid ""
"Submodule path '$sm_path' not initialized\n"
@@ -5399,97 +9292,140 @@ msgstr ""
"Undermodulen \"$sm_path\" har inte initierats\n"
"Kanske du vill köra \"update --init\"?"
-#: git-submodule.sh:537
+#: git-submodule.sh:603
#, sh-format
msgid "Unable to find current revision in submodule path '$sm_path'"
msgstr "Kan inte hitta aktuell revision i undermodulsökväg \"$sm_path\""
-#: git-submodule.sh:556
+#: git-submodule.sh:622
#, sh-format
msgid "Unable to fetch in submodule path '$sm_path'"
msgstr "Kan inte hämta i undermodulsökväg \"$sm_path\""
-#: git-submodule.sh:570
+#: git-submodule.sh:636
#, sh-format
msgid "Unable to rebase '$sha1' in submodule path '$sm_path'"
msgstr "Kan inte ombasera \"$sha1\" i undermodulsökväg \"$sm_path\""
-#: git-submodule.sh:571
+#: git-submodule.sh:637
#, sh-format
msgid "Submodule path '$sm_path': rebased into '$sha1'"
msgstr "Undermodulsökvägen \"$sm_path\": ombaserade in i \"$sha1\""
-#: git-submodule.sh:576
+#: git-submodule.sh:642
#, sh-format
msgid "Unable to merge '$sha1' in submodule path '$sm_path'"
msgstr "Kan inte slå ihop \"$sha1\" i undermodulsökvägen \"$sm_path\""
-#: git-submodule.sh:577
+#: git-submodule.sh:643
#, sh-format
msgid "Submodule path '$sm_path': merged in '$sha1'"
msgstr "Undermodulsökvägen \"$sm_path\": sammanslagen i \"$sha1\""
-#: git-submodule.sh:582
+#: git-submodule.sh:648
#, sh-format
msgid "Unable to checkout '$sha1' in submodule path '$sm_path'"
msgstr "Kan inte checka ut \"$sha1\" i undermodulsökvägen \"$sm_path\""
-#: git-submodule.sh:583
+#: git-submodule.sh:649
#, sh-format
msgid "Submodule path '$sm_path': checked out '$sha1'"
msgstr "Undermodulsökvägen \"$sm_path\": checkade ut \"$sha1\""
-#: git-submodule.sh:605 git-submodule.sh:928
+#: git-submodule.sh:671 git-submodule.sh:995
#, sh-format
msgid "Failed to recurse into submodule path '$sm_path'"
msgstr "Misslyckades rekursera in i undermodulsökvägen \"$sm_path\""
-#: git-submodule.sh:713
-msgid "--cached cannot be used with --files"
-msgstr "--cached kan inte användas med --files"
+#: git-submodule.sh:779
+msgid "The --cached option cannot be used with the --files option"
+msgstr "Flaggan --cached kan inte användas med flaggan --files"
#. unexpected type
-#: git-submodule.sh:753
+#: git-submodule.sh:819
#, sh-format
msgid "unexpected mode $mod_dst"
msgstr "oväntat läge $mod_dst"
-#: git-submodule.sh:771
+#: git-submodule.sh:837
#, sh-format
msgid " Warn: $name doesn't contain commit $sha1_src"
msgstr " Varning: $name innehåller inte incheckning $sha1_src"
-#: git-submodule.sh:774
+#: git-submodule.sh:840
#, sh-format
msgid " Warn: $name doesn't contain commit $sha1_dst"
msgstr " Varning: $name innehåller inte incheckning $sha1_dst"
-#: git-submodule.sh:777
+#: git-submodule.sh:843
#, sh-format
msgid " Warn: $name doesn't contain commits $sha1_src and $sha1_dst"
msgstr " Varning: $name innehåller inte incheckningar $sha1_src och $sha1_dst"
-#: git-submodule.sh:802
+#: git-submodule.sh:868
msgid "blob"
msgstr "blob"
-#: git-submodule.sh:803
-msgid "submodule"
-msgstr "undermodul"
-
-#: git-submodule.sh:840
+#: git-submodule.sh:906
msgid "# Submodules changed but not updated:"
msgstr "# Undermoduler ändrade men inte uppdaterade:"
-#: git-submodule.sh:842
+#: git-submodule.sh:908
msgid "# Submodule changes to be committed:"
msgstr "# Undermodulers ändringar att checka in:"
-#: git-submodule.sh:974
+#: git-submodule.sh:1054
#, sh-format
msgid "Synchronizing submodule url for '$name'"
msgstr "Synkroniserar undermodul-url för \"$name\""
+#~ msgid " (use \"git add\" to track)"
+#~ msgstr " (spåra med \"git add\")"
+
+#~ msgid "-B cannot be used with -b"
+#~ msgstr "-B kan inte användas med -b"
+
+#~ msgid "--patch is incompatible with all other options"
+#~ msgstr "--patch är inkompatibel med alla andra flaggor"
+
+#~ msgid "--detach cannot be used with -b/-B/--orphan"
+#~ msgstr "--detcah kan inte användas med -b/-B/--orphan"
+
+#~ msgid "--detach cannot be used with -t"
+#~ msgstr "--detach kan inte användas med -t"
+
+#~ msgid "--orphan and -b|-B are mutually exclusive"
+#~ msgstr "--orphan och -b|-B kan inte användas samtidigt"
+
+#~ msgid "--orphan cannot be used with -t"
+#~ msgstr "--orphan kan inte användas med -t"
+
+#~ msgid "git checkout: -f and -m are incompatible"
+#~ msgstr "git checkout: -f och -m är inkompatibla"
+
+#~ msgid ""
+#~ "git checkout: updating paths is incompatible with switching branches."
+#~ msgstr ""
+#~ "git checkout: uppdatera sökvägar är inkompatibelt med att växla gren."
+
+#~ msgid "diff setup failed"
+#~ msgstr "misslyckades sätta upp för diff"
+
+#~ msgid "merge-recursive: disk full?"
+#~ msgstr "merge-recursive: disk full?"
+
+#~ msgid "diff_setup_done failed"
+#~ msgstr "diff_setup_done misslyckades"
+
+#~ msgid "%s: has been deleted/renamed"
+#~ msgstr "%s: har tagits bort/ändrat namn"
+
+#~ msgid "'%s': not a documentation directory."
+#~ msgstr "\"%s\": inte en dokumentationskatalog."
+
+#~ msgid "-d option is no longer supported. Do not use."
+#~ msgstr "Flaggan -d stöds inte lägre. Använd inte."
+
#~ msgid "cherry-pick"
#~ msgstr "cherry-pick"
@@ -5502,9 +9438,6 @@ msgstr "Synkroniserar undermodul-url för \"$name\""
#~ msgid "--"
#~ msgstr "--"
-#~ msgid "Too many options specified"
-#~ msgstr "För många flaggor angavs"
-
#~ msgid "# Changed but not updated:"
#~ msgstr "# Ändrade men inte uppdaterade:"
@@ -5529,26 +9462,17 @@ msgstr "Synkroniserar undermodul-url för \"$name\""
#~ msgid "cannot mix --fixed-strings and regexp"
#~ msgstr "kan inte blanda --fixed-strings och reguljära uttryck"
-#~ msgid "invalid --decorate option: %s"
-#~ msgstr "felaktigt värde till --decorate: %s"
-
#~ msgid "%s; will overwrite!"
#~ msgstr "%s; kommer skriva över!"
#~ msgid "Failed to write current notes tree to database"
#~ msgstr "Kunde inte skriva aktuellt anteckningsträd till databasen"
-#~ msgid "Failed to commit notes tree to database"
-#~ msgstr "Kunde inte checka in anteckningsträd i databasen"
-
# FIXME: Untranslatable!
#
#~ msgid "Refusing to %s notes in %s (outside of refs/notes/)"
#~ msgstr "Vägrar %s anteckningar i %s (utanför refs/notes/)"
-#~ msgid "list"
-#~ msgstr "list"
-
#~ msgid "add"
#~ msgstr "add"
diff --git a/po/vi.po b/po/vi.po
index f0529f4..f858ce3 100644
--- a/po/vi.po
+++ b/po/vi.po
@@ -2,23 +2,22 @@
# Copyright (C) 2012, Trần Ngá»c Quân.
# This file is distributed under the same license as the git-core package.
# First translated by Trần Ngá»c Quân <vnwildman@gmail.com>, 2012.
+# Nguyá»…n Thái Ngá»c Duy <pclouds@gmail.com>, 2012.
#
msgid ""
msgstr ""
-"Project-Id-Version: git-1.7.11.rc2.2.gb694fbb\n"
+"Project-Id-Version: git-1.7.12-146-g16d26\n"
"Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2012-06-08 10:20+0800\n"
-"PO-Revision-Date: 2012-06-09 14:08+0700\n"
+"POT-Creation-Date: 2012-09-05 06:20+0800\n"
+"PO-Revision-Date: 2012-09-08 08:00+0700\n"
"Last-Translator: Trần Ngá»c Quân <vnwildman@gmail.com>\n"
"Language-Team: Vietnamese <translation-team-vi@lists.sourceforge.net>\n"
+"Language: vi\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"Language: \n"
"Plural-Forms: nplurals=2; plural=1;\n"
-"X-Poedit-Language: Vietnamese\n"
-"X-Poedit-Country: VIET NAM\n"
-"X-Poedit-SourceCharset: utf-8\n"
+"X-Poedit-SourceCharset: UTF-8\n"
"X-Poedit-Basepath: ../\n"
#: advice.c:40
@@ -38,9 +37,9 @@ msgid ""
"or use 'git commit -a'."
msgstr ""
"Sửa chúng trong cây làm việc,\n"
-"và sau đó sử dụng lệnh 'git add/rm <tập-tin>'\n"
+"và sau đó dùng lệnh 'git add/rm <tập-tin>'\n"
"dành riêng cho việc đánh dấu cần giải quyết và tạo lần chuyển giao,\n"
-"hoặc là sử dụng lệnh 'git commit -a'."
+"hoặc là dùng lệnh 'git commit -a'."
#: bundle.c:36
#, c-format
@@ -52,8 +51,7 @@ msgstr "'%s' không giống như tập tin v2 bundle (cụm)"
msgid "unrecognized header: %s%s (%d)"
msgstr "phần đầu (header) không được thừa nhận: %s%s (%d)"
-#: bundle.c:89
-#: builtin/commit.c:696
+#: bundle.c:89 builtin/commit.c:699
#, c-format
msgid "could not open '%s'"
msgstr "không thể mở '%s'"
@@ -62,14 +60,8 @@ msgstr "không thể mở '%s'"
msgid "Repository lacks these prerequisite commits:"
msgstr "Khó chứa thiếu những lần chuyển giao (commit) cần trước hết này:"
-#: bundle.c:164
-#: sequencer.c:550
-#: sequencer.c:982
-#: builtin/log.c:289
-#: builtin/log.c:720
-#: builtin/log.c:1309
-#: builtin/log.c:1528
-#: builtin/merge.c:347
+#: bundle.c:164 sequencer.c:550 sequencer.c:982 builtin/log.c:290
+#: builtin/log.c:727 builtin/log.c:1313 builtin/log.c:1529 builtin/merge.c:347
#: builtin/shortlog.c:181
msgid "revision walk setup failed"
msgstr "Cài đặt việc di chuyển qua các điểm xét lại gặp lỗi"
@@ -82,46 +74,48 @@ msgstr[0] "Bundle chứa %d tham chiếu (refs)"
msgstr[1] "Bundle chứa %d tham chiếu (refs)"
#: bundle.c:192
+msgid "The bundle records a complete history."
+msgstr "Lệnh bundle ghi lại toàn bộ lịch sử."
+
+#: bundle.c:195
#, c-format
msgid "The bundle requires this ref"
msgid_plural "The bundle requires these %d refs"
msgstr[0] "Lệnh bundle yêu cầu tham chiếu (refs) này"
msgstr[1] "Lệnh bundle yêu cầu %d tham chiếu (refs) này"
-#: bundle.c:290
+#: bundle.c:294
msgid "rev-list died"
msgstr "rev-list bị chết"
-#: bundle.c:296
-#: builtin/log.c:1205
-#: builtin/shortlog.c:284
+#: bundle.c:300 builtin/log.c:1209 builtin/shortlog.c:284
#, c-format
msgid "unrecognized argument: %s"
msgstr "đối số không được thừa nhận: %s"
-#: bundle.c:331
+#: bundle.c:335
#, c-format
msgid "ref '%s' is excluded by the rev-list options"
msgstr "tham chiếu '%s' bị loại trừ bởi các tùy chá»n rev-list"
-#: bundle.c:376
+#: bundle.c:380
msgid "Refusing to create empty bundle."
msgstr "Từ chối tạo một bundle trống rỗng."
-#: bundle.c:394
+#: bundle.c:398
msgid "Could not spawn pack-objects"
msgstr "Không thể sản sinh pack-objects"
-#: bundle.c:412
+#: bundle.c:416
msgid "pack-objects died"
msgstr "pack-objects đã chết"
-#: bundle.c:415
+#: bundle.c:419
#, c-format
msgid "cannot create '%s'"
msgstr "không thể tạo '%s'"
-#: bundle.c:437
+#: bundle.c:441
msgid "index-pack died"
msgstr "index-pack đã chết"
@@ -135,8 +129,7 @@ msgstr "không thể phân tích %s"
msgid "%s %s is not a commit!"
msgstr "%s %s không phải là một lần commit!"
-#: compat/obstack.c:406
-#: compat/obstack.c:408
+#: compat/obstack.c:406 compat/obstack.c:408
msgid "memory exhausted"
msgstr "cạn bộ nhớ"
@@ -214,8 +207,7 @@ msgid_plural "%s, %lu months ago"
msgstr[0] "%s, %lu tháng trước"
msgstr[1] "%s, %lu tháng trước"
-#: date.c:154
-#: date.c:159
+#: date.c:154 date.c:159
#, c-format
msgid "%lu year ago"
msgid_plural "%lu years ago"
@@ -241,32 +233,32 @@ msgstr ""
"Tìm thấy các lỗi trong biến cấu hình 'diff.dirstat':\n"
"%s"
-#: diff.c:1400
-msgid " 0 files changed\n"
-msgstr " 0 tập tin nào bị thay đổi\n"
+#: diff.c:1401
+msgid " 0 files changed"
+msgstr " 0 có tập tin nào thay đổi cả"
-#: diff.c:1404
+#: diff.c:1405
#, c-format
msgid " %d file changed"
msgid_plural " %d files changed"
-msgstr[0] " %d tập tin đã bị thay đổi"
-msgstr[1] " %d tập tin đã bị thay đổi"
+msgstr[0] " %d tập tin thay đổi"
+msgstr[1] " %d tập tin thay đổi"
-#: diff.c:1421
+#: diff.c:1422
#, c-format
msgid ", %d insertion(+)"
msgid_plural ", %d insertions(+)"
-msgstr[0] ", %d được thêm vào(+)"
-msgstr[1] ", %d được thêm vào(+)"
+msgstr[0] ", %d thêm(+)"
+msgstr[1] ", %d thêm(+)"
-#: diff.c:1432
+#: diff.c:1433
#, c-format
msgid ", %d deletion(-)"
msgid_plural ", %d deletions(-)"
-msgstr[0] ", %d bị xóa(-)"
-msgstr[1] ", %d bị xóa(-)"
+msgstr[0] ", %d xóa(-)"
+msgstr[1] ", %d xóa(-)"
-#: diff.c:3478
+#: diff.c:3460
#, c-format
msgid ""
"Failed to parse --dirstat/-X option parameter:\n"
@@ -302,16 +294,16 @@ msgstr "'%s': %s"
msgid "'%s': short read %s"
msgstr "'%s': Ä‘á»c ngắn %s"
-#: help.c:207
+#: help.c:212
#, c-format
msgid "available git commands in '%s'"
msgstr "các lệnh git sẵn sàng để dùng trong '%s'"
-#: help.c:214
+#: help.c:219
msgid "git commands available from elsewhere on your $PATH"
msgstr "các lệnh git sẵn sàng để dùng từ một nơi khác trong $PATH của bạn"
-#: help.c:270
+#: help.c:275
#, c-format
msgid ""
"'%s' appears to be a git command, but we were not\n"
@@ -320,30 +312,30 @@ msgstr ""
"'%s' trông như là một lệnh git, nhưng chúng tôi không\n"
"thể thá»±c thi nó. Có lẽ là lệnh git-%s đã bị há»ng?"
-#: help.c:327
+#: help.c:332
msgid "Uh oh. Your system reports no Git commands at all."
msgstr "á»i chà. Hệ thống của bạn báo rằng chẳng có lệnh Git nào cả."
-#: help.c:349
+#: help.c:354
#, c-format
msgid ""
"WARNING: You called a Git command named '%s', which does not exist.\n"
"Continuing under the assumption that you meant '%s'"
msgstr ""
-"CẢNH BÃO: Bạn đã gá»i lệnh Git có tên '%s', mà nó lại không sẵn có.\n"
+"CẢNH BÃO: Bạn đã gá»i lệnh Git có tên '%s', mà nó lại không có sẵn.\n"
"Giả định rằng ý bạn là '%s'"
-#: help.c:354
+#: help.c:359
#, c-format
msgid "in %0.1f seconds automatically..."
msgstr "trong %0.1f giây một cách tự động..."
-#: help.c:361
+#: help.c:366
#, c-format
msgid "git: '%s' is not a git command. See 'git --help'."
-msgstr "git: '%s' không phải là một lệnh của git. Xem thêm 'git --help'."
+msgstr "git: '%s' không phải là một lệnh của git. Xem 'git --help'."
-#: help.c:365
+#: help.c:370
msgid ""
"\n"
"Did you mean this?"
@@ -357,42 +349,303 @@ msgstr[1] ""
"\n"
"Có phải ý bạn là một trong số những cái này không?"
-#: parse-options.c:493
+#: merge-recursive.c:190
+#, c-format
+msgid "(bad commit)\n"
+msgstr "(commit sai)\n"
+
+#: merge-recursive.c:206
+#, c-format
+msgid "addinfo_cache failed for path '%s'"
+msgstr "addinfo_cache gặp lá»—i đối vá»›i Ä‘Æ°á»ng dẫn '%s'"
+
+#: merge-recursive.c:268
+msgid "error building trees"
+msgstr "gặp lỗi khi xây dựng cây"
+
+#: merge-recursive.c:672
+#, c-format
+msgid "failed to create path '%s'%s"
+msgstr "gặp lá»—i khi tạo Ä‘Æ°á»ng dẫn '%s'%s"
+
+#: merge-recursive.c:683
+#, c-format
+msgid "Removing %s to make room for subdirectory\n"
+msgstr "Gỡ bỠ%s để tạo chỗ (room) cho thư mục con\n"
+
+#. something else exists
+#. .. but not some other error (who really cares what?)
+#: merge-recursive.c:697 merge-recursive.c:718
+msgid ": perhaps a D/F conflict?"
+msgstr ": có lẽ là một xung đột D/F?"
+
+#: merge-recursive.c:708
+#, c-format
+msgid "refusing to lose untracked file at '%s'"
+msgstr "từ chối đóng tập tin không được theo vết tại '%s'"
+
+#: merge-recursive.c:748
+#, c-format
+msgid "cannot read object %s '%s'"
+msgstr "không thể Ä‘á»c đối tượng %s '%s'"
+
+#: merge-recursive.c:750
+#, c-format
+msgid "blob expected for %s '%s'"
+msgstr "đối tượng blob được mong đợi cho %s '%s'"
+
+#: merge-recursive.c:773 builtin/clone.c:302
+#, c-format
+msgid "failed to open '%s'"
+msgstr "gặp lỗi khi mở '%s'"
+
+#: merge-recursive.c:781
+#, c-format
+msgid "failed to symlink '%s'"
+msgstr "gặp lỗi khi tạo liên kết tượng trưng (symlink) '%s'"
+
+#: merge-recursive.c:784
+#, c-format
+msgid "do not know what to do with %06o %s '%s'"
+msgstr "không hiểu phải làm gì với %06o %s '%s'"
+
+#: merge-recursive.c:921
+msgid "Failed to execute internal merge"
+msgstr "Gặp lỗi khi thực hiện trộn nội bộ"
+
+#: merge-recursive.c:925
+#, c-format
+msgid "Unable to add %s to database"
+msgstr "Không thể thêm %s vào cơ sở dữ liệu"
+
+#: merge-recursive.c:941
+msgid "unsupported object type in the tree"
+msgstr "kiểu đối tượng không được hỗ trợ trong cây (tree)"
+
+#: merge-recursive.c:1020 merge-recursive.c:1034
+#, c-format
+msgid ""
+"CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left "
+"in tree."
+msgstr ""
+"XUNG ÄỘT (%s/xóa): %s bị xóa trong %s và %s trong %s. Phiên bản %s của %s "
+"còn lại trong cây (tree)."
+
+#: merge-recursive.c:1026 merge-recursive.c:1039
+#, c-format
+msgid ""
+"CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left "
+"in tree at %s."
+msgstr ""
+"XUNG ÄỘT (%s/xóa): %s bị xóa trong %s và %s trong %s. Phiên bản %s của %s "
+"còn lại trong cây (tree) tại %s."
+
+#: merge-recursive.c:1080
+msgid "rename"
+msgstr "đổi tên"
+
+#: merge-recursive.c:1080
+msgid "renamed"
+msgstr "đã đổi tên"
+
+#: merge-recursive.c:1136
+#, c-format
+msgid "%s is a directory in %s adding as %s instead"
+msgstr "%s là một thư mục trong %s thay vào đó thêm vào như là %s"
+
+#: merge-recursive.c:1158
+#, c-format
+msgid ""
+"CONFLICT (rename/rename): Rename \"%s\"->\"%s\" in branch \"%s\" rename \"%s"
+"\"->\"%s\" in \"%s\"%s"
+msgstr ""
+"XUNG ÄỘT (đổi-tên/đổi-tên): Äổi tên \"%s\"->\"%s\" trong nhánh \"%s\" đổi "
+"tên \"%s\"->\"%s\" trong \"%s\"%s"
+
+#: merge-recursive.c:1163
+msgid " (left unresolved)"
+msgstr " (cần giải quyết)"
+
+#: merge-recursive.c:1217
+#, c-format
+msgid "CONFLICT (rename/rename): Rename %s->%s in %s. Rename %s->%s in %s"
+msgstr ""
+"XUNG ÄỘT (đổi-tên/đổi-tên): Äổi tên %s->%s trong %s. Äổi tên %s->%s trong %s"
+
+#: merge-recursive.c:1247
+#, c-format
+msgid "Renaming %s to %s and %s to %s instead"
+msgstr "Äang đổi tên %s thành %s thay vì %s thành %s"
+
+#: merge-recursive.c:1446
+#, c-format
+msgid "CONFLICT (rename/add): Rename %s->%s in %s. %s added in %s"
+msgstr ""
+"XUNG ÄỘT (đổi-tên/thêm): Äổi tên %s->%s trong %s. %s được thêm vào trong %s"
+
+#: merge-recursive.c:1456
+#, c-format
+msgid "Adding merged %s"
+msgstr "Thêm hòa trộn %s"
+
+#: merge-recursive.c:1461 merge-recursive.c:1659
+#, c-format
+msgid "Adding as %s instead"
+msgstr "Thay vào đó thêm vào %s"
+
+#: merge-recursive.c:1512
+#, c-format
+msgid "cannot read object %s"
+msgstr "không thể Ä‘á»c đối tượng %s"
+
+#: merge-recursive.c:1515
+#, c-format
+msgid "object %s is not a blob"
+msgstr "đối tượng %s không phải là một blob"
+
+#: merge-recursive.c:1563
+msgid "modify"
+msgstr "sửa đổi"
+
+#: merge-recursive.c:1563
+msgid "modified"
+msgstr "đã bị sửa"
+
+#: merge-recursive.c:1573
+msgid "content"
+msgstr "ná»™i dung"
+
+#: merge-recursive.c:1580
+msgid "add/add"
+msgstr "thêm/thêm"
+
+#: merge-recursive.c:1614
+#, c-format
+msgid "Skipped %s (merged same as existing)"
+msgstr "Äã bá» qua %s (đã có sẵn lần hòa trá»™n này)"
+
+#: merge-recursive.c:1628
+#, c-format
+msgid "Auto-merging %s"
+msgstr "Tự-động-hòa-trộn %s"
+
+#: merge-recursive.c:1632 git-submodule.sh:869
+msgid "submodule"
+msgstr "mô-đun con"
+
+#: merge-recursive.c:1633
+#, c-format
+msgid "CONFLICT (%s): Merge conflict in %s"
+msgstr "XUNG ÄỘT (%s): Xung Ä‘á»™t hòa trá»™n trong %s"
+
+#: merge-recursive.c:1723
+#, c-format
+msgid "Removing %s"
+msgstr "Äang xóa %s"
+
+#: merge-recursive.c:1748
+msgid "file/directory"
+msgstr "tập-tin/thư-mục"
+
+#: merge-recursive.c:1754
+msgid "directory/file"
+msgstr "thư-mục/tập tin"
+
+#: merge-recursive.c:1759
+#, c-format
+msgid "CONFLICT (%s): There is a directory with name %s in %s. Adding %s as %s"
+msgstr ""
+"XUNG ÄỘT (%s): Ở đây không có thÆ° mục nào có tên %s trong %s. Thêm %s nhÆ° là "
+"%s"
+
+#: merge-recursive.c:1769
+#, c-format
+msgid "Adding %s"
+msgstr "Thêm \"%s\""
+
+#: merge-recursive.c:1786
+msgid "Fatal merge failure, shouldn't happen."
+msgstr "Việc hòa trá»™n há»ng nghiêm trá»ng, không nên để xảy ra."
+
+#: merge-recursive.c:1805
+msgid "Already up-to-date!"
+msgstr "Äã cập nhật rồi!"
+
+#: merge-recursive.c:1814
+#, c-format
+msgid "merging of trees %s and %s failed"
+msgstr "hòa trộn cây (tree) %s và %s gặp lỗi"
+
+#: merge-recursive.c:1844
+#, c-format
+msgid "Unprocessed path??? %s"
+msgstr "ÄÆ°á»ng dẫn chÆ°a được xá»­ lý??? %s"
+
+#: merge-recursive.c:1889
+msgid "Merging:"
+msgstr "Äang trá»™n:"
+
+#: merge-recursive.c:1902
+#, c-format
+msgid "found %u common ancestor:"
+msgid_plural "found %u common ancestors:"
+msgstr[0] "tìm thấy %u tổ tiên chung:"
+msgstr[1] "tìm thấy %u tổ tiên chung:"
+
+#: merge-recursive.c:1939
+msgid "merge returned no commit"
+msgstr "hòa trộn không trả vỠlần chuyển giao (commit) nào"
+
+#: merge-recursive.c:1996
+#, c-format
+msgid "Could not parse object '%s'"
+msgstr "Không thể phân tích đối tượng '%s'"
+
+#: merge-recursive.c:2008 builtin/merge.c:696
+msgid "Unable to write index."
+msgstr "Không thể ghi bảng mục lục"
+
+#: parse-options.c:494
msgid "..."
msgstr "..."
-#: parse-options.c:511
+#: parse-options.c:512
#, c-format
msgid "usage: %s"
-msgstr "cách sử dụng: %s"
+msgstr "cách dùng: %s"
#. TRANSLATORS: the colon here should align with the
#. one in "usage: %s" translation
-#: parse-options.c:515
+#: parse-options.c:516
#, c-format
msgid " or: %s"
-msgstr " hoặc: %s"
+msgstr " hoặc: %s"
-#: parse-options.c:518
+#: parse-options.c:519
#, c-format
msgid " %s"
msgstr " %s"
-#: remote.c:1629
+#: remote.c:1632
#, c-format
msgid "Your branch is ahead of '%s' by %d commit.\n"
msgid_plural "Your branch is ahead of '%s' by %d commits.\n"
msgstr[0] "Nhánh của bạn là đầu của '%s' bởi %d lần chuyển giao (commit).\n"
msgstr[1] "Nhánh của bạn là đầu của '%s' bởi %d lần chuyển giao (commit).\n"
-#: remote.c:1635
+#: remote.c:1638
#, c-format
msgid "Your branch is behind '%s' by %d commit, and can be fast-forwarded.\n"
-msgid_plural "Your branch is behind '%s' by %d commits, and can be fast-forwarded.\n"
-msgstr[0] "Nhánh của bạn thì ở đằng sau '%s' bởi %d lần chuyển giao (commit), và có thể được fast-forward.\n"
-msgstr[1] "Nhánh của bạn thì ở đằng sau '%s' bởi %d lần chuyển giao (commit), và có thể được fast-forward.\n"
+msgid_plural ""
+"Your branch is behind '%s' by %d commits, and can be fast-forwarded.\n"
+msgstr[0] ""
+"Nhánh của bạn thì ở đằng sau '%s' bởi %d lần chuyển giao (commit), và có thể "
+"được fast-forward.\n"
+msgstr[1] ""
+"Nhánh của bạn thì ở đằng sau '%s' bởi %d lần chuyển giao (commit), và có thể "
+"được fast-forward.\n"
-#: remote.c:1643
+#: remote.c:1646
#, c-format
msgid ""
"Your branch and '%s' have diverged,\n"
@@ -408,20 +661,14 @@ msgstr[1] ""
"Your branch and '%s' have diverged,\n"
"and have %d and %d different commit each, respectively.\n"
-#: sequencer.c:121
-#: builtin/merge.c:865
-#: builtin/merge.c:978
-#: builtin/merge.c:1088
-#: builtin/merge.c:1098
+#: sequencer.c:121 builtin/merge.c:864 builtin/merge.c:977
+#: builtin/merge.c:1087 builtin/merge.c:1097
#, c-format
msgid "Could not open '%s' for writing"
msgstr "Không thể mở %s' để ghi"
-#: sequencer.c:123
-#: builtin/merge.c:333
-#: builtin/merge.c:868
-#: builtin/merge.c:1090
-#: builtin/merge.c:1103
+#: sequencer.c:123 builtin/merge.c:333 builtin/merge.c:867
+#: builtin/merge.c:1089 builtin/merge.c:1102
#, c-format
msgid "Could not write to '%s'"
msgstr "Không thể ghi vào '%s'"
@@ -444,9 +691,7 @@ msgstr ""
"vá»›i lệnh 'git add <Ä‘Æ°á»ng_dẫn>' hoặc 'git rm <Ä‘Æ°á»ng_dẫn>'\n"
"và chuyển giao (commit) kết quả bằng lệnh 'git commit'"
-#: sequencer.c:160
-#: sequencer.c:758
-#: sequencer.c:841
+#: sequencer.c:160 sequencer.c:758 sequencer.c:841
#, c-format
msgid "Could not write to %s"
msgstr "Không thể ghi vào %s"
@@ -466,7 +711,7 @@ msgstr "Các thay đổi ná»™i bá»™ của bạn có thể bị ghi đè bởi lá
#: sequencer.c:183
msgid "Commit your changes or stash them to proceed."
-msgstr "Chuyển giao (commit) các thay đổi hay stash chúng để tiến hành."
+msgstr "Chuyển giao (commit) các thay đổi của bạn hay stash chúng để xử lý."
#. TRANSLATORS: %s will be "revert" or "cherry-pick"
#: sequencer.c:233
@@ -503,7 +748,9 @@ msgstr "Bạn không có HEAD nào hợp lệ"
#: sequencer.c:413
#, c-format
msgid "Commit %s is a merge but no -m option was given."
-msgstr "Lần chuyển giao (commit) %s là má»™t lần hòa trá»™n nhÆ°ng không Ä‘Æ°a ra tùy chá»n -m."
+msgstr ""
+"Lần chuyển giao (commit) %s là má»™t lần hòa trá»™n nhÆ°ng không Ä‘Æ°a ra tùy chá»n -"
+"m."
#: sequencer.c:421
#, c-format
@@ -513,7 +760,9 @@ msgstr "Lần chuyển giao (commit) %s không có cha mẹ %d"
#: sequencer.c:425
#, c-format
msgid "Mainline was specified but commit %s is not a merge."
-msgstr "Luồng chính được chỉ định nhưng lần chuyển giao (commit) %s không phải là một lần hòa trộn."
+msgstr ""
+"Luồng chính được chỉ ra nhưng lần chuyển giao (commit) %s không phải là một "
+"lần hòa trộn."
#. TRANSLATORS: The first %s will be "revert" or
#. "cherry-pick", the second %s a SHA1
@@ -608,14 +857,12 @@ msgstr "hãy thử \"git cherry-pick (--continue | --quit | --abort)\""
msgid "Could not create sequencer directory %s"
msgstr "Không thể tạo thư mục xếp dãy %s"
-#: sequencer.c:760
-#: sequencer.c:845
+#: sequencer.c:760 sequencer.c:845
#, c-format
msgid "Error wrapping up %s."
msgstr "Lá»—i bao bá»c %s."
-#: sequencer.c:779
-#: sequencer.c:913
+#: sequencer.c:779 sequencer.c:913
msgid "no cherry-pick or revert in progress"
msgstr "không cherry-pick hay revert trong tiến trình"
@@ -627,8 +874,7 @@ msgstr "không thể phân giải HEAD"
msgid "cannot abort from a branch yet to be born"
msgstr "không thể hủy bỠtừ một nhánh mà nó còn chưa được tạo ra"
-#: sequencer.c:805
-#: builtin/apply.c:3697
+#: sequencer.c:805 builtin/apply.c:3987
#, c-format
msgid "cannot open %s: %s"
msgstr "không thể mở %s: %s"
@@ -660,24 +906,26 @@ msgstr "Không thể revert một lần chuyển giao (commit) khởi tạo"
msgid "Can't cherry-pick into empty head"
msgstr "Không thể cherry-pick vào một đầu (head) trống rỗng"
-#: sha1_name.c:864
+#: sha1_name.c:1044
msgid "HEAD does not point to a branch"
msgstr "HEAD không chỉ đến một nhánh nào cả"
-#: sha1_name.c:867
+#: sha1_name.c:1047
#, c-format
msgid "No such branch: '%s'"
msgstr "Không có nhánh nào như thế: '%s'"
-#: sha1_name.c:869
+#: sha1_name.c:1049
#, c-format
msgid "No upstream configured for branch '%s'"
msgstr "Không có dòng ngược (upstream) được cấu hình cho nhánh '%s'"
-#: sha1_name.c:872
+#: sha1_name.c:1052
#, c-format
msgid "Upstream branch '%s' not stored as a remote-tracking branch"
-msgstr "Nhánh dòng ngược (upstream) '%s' không được lưu lại như là một nhánh 'remote-tracking'"
+msgstr ""
+"Nhánh dòng ngược (upstream) '%s' không được lưu lại như là một nhánh 'remote-"
+"tracking'"
#: wrapper.c:413
#, c-format
@@ -688,246 +936,370 @@ msgstr "không tìm thấy ngÆ°á»i dùng hiện tại trong tập tin passwd: %
msgid "no such user"
msgstr "không có ngÆ°á»i dùng nhÆ° vậy"
-#: wt-status.c:135
+#: wt-status.c:140
msgid "Unmerged paths:"
msgstr "Những Ä‘Æ°á»ng dẫn chÆ°a được hòa trá»™n:"
-#: wt-status.c:141
-#: wt-status.c:158
+#: wt-status.c:167 wt-status.c:194
#, c-format
msgid " (use \"git reset %s <file>...\" to unstage)"
-msgstr " (sử dụng \"git reset %s <tập-tin>...\" để bỠmột stage (trạng thái))"
+msgstr " (dùng \"git reset %s <tập-tin>...\" để bỠmột stage (trạng thái))"
-#: wt-status.c:143
-#: wt-status.c:160
+#: wt-status.c:169 wt-status.c:196
msgid " (use \"git rm --cached <file>...\" to unstage)"
-msgstr " (sử dụng \"git rm --cached <tập-tin>...\" để bỠtrạng thái (stage))"
+msgstr " (dùng \"git rm --cached <tập-tin>...\" để bỠtrạng thái (stage))"
+
+#: wt-status.c:173
+msgid " (use \"git add <file>...\" to mark resolution)"
+msgstr " (dùng \"git add <tập-tin>...\" để đánh dấu là cần giải quyết)"
-#: wt-status.c:144
+#: wt-status.c:175 wt-status.c:179
msgid " (use \"git add/rm <file>...\" as appropriate to mark resolution)"
-msgstr " (sử dụng \"git add/rm <tập-tin>...\" như là một cách thích hợp để đánh dấu là cần được giải quyết)"
+msgstr ""
+" (dùng \"git add/rm <tập-tin>...\" như là một cách thích hợp để đánh "
+"dấu là cần được giải quyết)"
-#: wt-status.c:152
+#: wt-status.c:177
+msgid " (use \"git rm <file>...\" to mark resolution)"
+msgstr " (dùng \"git rm <tập-tin>...\" để đánh dấu là cần giải quyết)"
+
+#: wt-status.c:188
msgid "Changes to be committed:"
msgstr "Những thay đổi sẽ được chuyển giao:"
-#: wt-status.c:170
+#: wt-status.c:206
msgid "Changes not staged for commit:"
-msgstr "Các thay đổi không được đặt trạng thái (stage) cho lần chuyển giao (commit):"
+msgstr ""
+"Các thay đổi không được đặt trạng thái (stage) cho lần chuyển giao (commit):"
-#: wt-status.c:174
+#: wt-status.c:210
msgid " (use \"git add <file>...\" to update what will be committed)"
-msgstr " (sử dụng \"git add <tập-tin>...\" để cập nhật những gì cần chuyển giao (commit))"
+msgstr ""
+" (dùng \"git add <tập-tin>...\" để cập nhật những gì cần chuyển giao "
+"(commit))"
-#: wt-status.c:176
+#: wt-status.c:212
msgid " (use \"git add/rm <file>...\" to update what will be committed)"
-msgstr " (sử dụng \"git add/rm <tập_tin>...\" để cập nhật những gì sẽ được chuyển giao)"
+msgstr ""
+" (dùng \"git add/rm <tập-tin>...\" để cập nhật những gì sẽ được chuyển "
+"giao)"
-#: wt-status.c:177
-msgid " (use \"git checkout -- <file>...\" to discard changes in working directory)"
-msgstr " (sử dụng \"git checkout -- <tập_tin>...\" để loại bỠnhững thay đổi trong thư mục làm việc)"
+#: wt-status.c:213
+msgid ""
+" (use \"git checkout -- <file>...\" to discard changes in working directory)"
+msgstr ""
+" (dùng \"git checkout -- <tập-tin>...\" để bỠthay đổi trong thư mục làm "
+"việc)"
-#: wt-status.c:179
+#: wt-status.c:215
msgid " (commit or discard the untracked or modified content in submodules)"
-msgstr " (chuyển giao (commit) hoặc là loại bỠcác nội dung không-bị-theo-vết hay đã bị chỉnh sửa trong mô-đun-con)"
+msgstr ""
+" (chuyển giao (commit) hoặc là loại bỠcác nội dung không-bị-theo-vết hay "
+"đã bị chỉnh sửa trong mô-đun-con)"
-#: wt-status.c:188
+#: wt-status.c:224
#, c-format
msgid "%s files:"
-msgstr "%s tệp tin:"
+msgstr "%s tập tin:"
-#: wt-status.c:191
+#: wt-status.c:227
#, c-format
msgid " (use \"git %s <file>...\" to include in what will be committed)"
-msgstr " (sử dụng \"git %s <tập-tin>...\" để bao gồm thêm vào những gì cần chuyển giao (commit))"
+msgstr ""
+" (dùng \"git %s <tập-tin>...\" để thêm vào những gì cần chuyển giao "
+"(commit))"
-#: wt-status.c:208
+#: wt-status.c:244
msgid "bug"
msgstr "lá»—i"
-#: wt-status.c:213
+#: wt-status.c:249
msgid "both deleted:"
msgstr "bị xóa bởi cả hai:"
-#: wt-status.c:214
+#: wt-status.c:250
msgid "added by us:"
msgstr "được thêm vào bởi chúng tôi:"
-#: wt-status.c:215
+#: wt-status.c:251
msgid "deleted by them:"
msgstr "bị xóa Ä‘i bởi há»:"
-#: wt-status.c:216
+#: wt-status.c:252
msgid "added by them:"
msgstr "được thêm vào bởi há»:"
-#: wt-status.c:217
+#: wt-status.c:253
msgid "deleted by us:"
msgstr "bị xóa bởi chúng tôi:"
-#: wt-status.c:218
+#: wt-status.c:254
msgid "both added:"
msgstr "được thêm vào bởi cả hai:"
-#: wt-status.c:219
+#: wt-status.c:255
msgid "both modified:"
msgstr "bị sửa bởi cả hai:"
-#: wt-status.c:249
+#: wt-status.c:285
msgid "new commits, "
-msgstr " lần chuyển giao (commit) mới, "
+msgstr "lần chuyển giao (commit) mới, "
-#: wt-status.c:251
+#: wt-status.c:287
msgid "modified content, "
-msgstr "nội dung được sửa đổi,"
+msgstr "nội dung được sửa đổi, "
-#: wt-status.c:253
+#: wt-status.c:289
msgid "untracked content, "
-msgstr "nội dung chưa được theo dõi"
+msgstr "nội dung chưa được theo dõi, "
-#: wt-status.c:267
+#: wt-status.c:303
#, c-format
msgid "new file: %s"
msgstr "tập tin mới: %s"
-#: wt-status.c:270
+#: wt-status.c:306
#, c-format
msgid "copied: %s -> %s"
msgstr "đã sao chép: %s -> %s"
-#: wt-status.c:273
+#: wt-status.c:309
#, c-format
msgid "deleted: %s"
-msgstr "bị xóa: %s"
+msgstr "đã xóa: %s"
-#: wt-status.c:276
+#: wt-status.c:312
#, c-format
msgid "modified: %s"
-msgstr "bị sửa đổi: %s"
+msgstr "đã sửa đổi: %s"
-#: wt-status.c:279
+#: wt-status.c:315
#, c-format
msgid "renamed: %s -> %s"
msgstr "đã đổi tên: %s -> %s"
-#: wt-status.c:282
+#: wt-status.c:318
#, c-format
msgid "typechange: %s"
msgstr "đổi-kiểu: %s"
-#: wt-status.c:285
+#: wt-status.c:321
#, c-format
msgid "unknown: %s"
-msgstr "không rõ: %s"
+msgstr "không hiểu: %s"
-#: wt-status.c:288
+#: wt-status.c:324
#, c-format
msgid "unmerged: %s"
msgstr "chưa hòa trộn: %s"
-#: wt-status.c:291
+#: wt-status.c:327
#, c-format
msgid "bug: unhandled diff status %c"
msgstr "lỗi: không lấy được trạng thái lệnh diff %c"
-#: wt-status.c:737
+#: wt-status.c:785
+msgid "You have unmerged paths."
+msgstr "Bạn có những Ä‘Æ°á»ng dẫn chÆ°a được hòa trá»™n."
+
+#: wt-status.c:788 wt-status.c:912
+msgid " (fix conflicts and run \"git commit\")"
+msgstr " (sửa các xung đột sau đó chạy \"git commit\")"
+
+#: wt-status.c:791
+msgid "All conflicts fixed but you are still merging."
+msgstr "Tất cả các xung đột đã được giải quyết nhưng bạn vẫn đang hòa trộn."
+
+#: wt-status.c:794
+msgid " (use \"git commit\" to conclude merge)"
+msgstr " (dùng \"git commit\" để hoàn tất việc hòa trộn)"
+
+#: wt-status.c:804
+msgid "You are in the middle of an am session."
+msgstr "Bạn đang ở giữa của một phiên 'am'."
+
+#: wt-status.c:807
+msgid "The current patch is empty."
+msgstr "Miếng vá hiện tại bị trống rỗng."
+
+#: wt-status.c:811
+msgid " (fix conflicts and then run \"git am --resolved\")"
+msgstr " (sửa các xung đột và sau đó chạy lệnh \"git am --resolved\")"
+
+#: wt-status.c:813
+msgid " (use \"git am --skip\" to skip this patch)"
+msgstr " (dùng \"git am --skip\" để bỠqua lần vá này)"
+
+#: wt-status.c:815
+msgid " (use \"git am --abort\" to restore the original branch)"
+msgstr " (dùng \"git am --abort\" để phục hồi lại nhánh nguyên thủy)"
+
+#: wt-status.c:873 wt-status.c:883
+msgid "You are currently rebasing."
+msgstr "Bạn hiện nay đang thực hiện việc rebase (tái cấu trúc)."
+
+#: wt-status.c:876
+msgid " (fix conflicts and then run \"git rebase --continue\")"
+msgstr " (sửa các xung đột và sau đó chạy lệnh \"git rebase --continue\")"
+
+#: wt-status.c:878
+msgid " (use \"git rebase --skip\" to skip this patch)"
+msgstr " (dùng \"git rebase --skip\" để bỠqua lần vá này)"
+
+#: wt-status.c:880
+msgid " (use \"git rebase --abort\" to check out the original branch)"
+msgstr " (dùng \"git rebase --abort\" để check-out nhánh nguyên thủy)"
+
+#: wt-status.c:886
+msgid " (all conflicts fixed: run \"git rebase --continue\")"
+msgstr ""
+" (khi tất cả các xung đột đã sửa xong: chạy lệnh \"git rebase --continue\")"
+
+#: wt-status.c:888
+msgid "You are currently splitting a commit during a rebase."
+msgstr ""
+"Bạn hiện tại đang cắt đôi một lần chuyển giao trong khi đang thực hiện việc "
+"rebase."
+
+#: wt-status.c:891
+msgid " (Once your working directory is clean, run \"git rebase --continue\")"
+msgstr ""
+" (Má»™t khi thÆ° mục làm việc của bạn đã gá»n gàng, chạy \"git rebase --continue"
+"\")"
+
+#: wt-status.c:893
+msgid "You are currently editing a commit during a rebase."
+msgstr "Bạn hiện đang sửa một lần chuyển giao trong khi bạn thực hiện rebase."
+
+#: wt-status.c:896
+msgid " (use \"git commit --amend\" to amend the current commit)"
+msgstr ""
+" (dùng \"git commit --amend\" để tu bổ lần chuyển giao (commit) hiện tại)"
+
+#: wt-status.c:898
+msgid ""
+" (use \"git rebase --continue\" once you are satisfied with your changes)"
+msgstr ""
+" (dùng \"git rebase --continue\" một khi bạn cảm thấy hài lòng vỠnhững "
+"thay đổi của mình)"
+
+#: wt-status.c:908
+msgid "You are currently cherry-picking."
+msgstr "Bạn hiện nay đang thực hiện việc cherry-pick."
+
+#: wt-status.c:915
+msgid " (all conflicts fixed: run \"git commit\")"
+msgstr " (khi tất cả các xung đột đã sửa xong: chạy lệnh \"git commit\")"
+
+#: wt-status.c:924
+msgid "You are currently bisecting."
+msgstr "Bạn hiện tại đang thực hiện việc bisect (chia đôi)."
+
+#: wt-status.c:927
+msgid " (use \"git bisect reset\" to get back to the original branch)"
+msgstr " (dùng \"git bisect reset\" để quay trở lại nhánh nguyên thủy)"
+
+#: wt-status.c:978
msgid "On branch "
-msgstr "Trên nhánh"
+msgstr "Trên nhánh "
-#: wt-status.c:744
+#: wt-status.c:985
msgid "Not currently on any branch."
msgstr "Hiện tại chẳng ở nhánh nào cả."
-#: wt-status.c:755
+#: wt-status.c:997
msgid "Initial commit"
msgstr "Lần chuyển giao (commit) khởi đầu"
-#: wt-status.c:769
+#: wt-status.c:1011
msgid "Untracked"
msgstr "Không được theo vết"
-#: wt-status.c:771
+#: wt-status.c:1013
msgid "Ignored"
msgstr "Bị bỠqua"
-#: wt-status.c:773
+#: wt-status.c:1015
#, c-format
msgid "Untracked files not listed%s"
msgstr "Những tập tin không bị theo vết không được liệt kê ra %s"
-#: wt-status.c:775
+#: wt-status.c:1017
msgid " (use -u option to show untracked files)"
-msgstr " (sá»­ dụng tùy chá»n -u để hiển thị các tập tin chÆ°a được theo dõi)"
+msgstr " (dùng tùy chá»n -u để hiển thị các tập tin chÆ°a được theo dõi)"
-#: wt-status.c:781
+#: wt-status.c:1023
msgid "No changes"
msgstr "Không có thay đổi nào"
-#: wt-status.c:785
+#: wt-status.c:1027
#, c-format
msgid "no changes added to commit%s\n"
msgstr "không có thay đổi nào được thêm vào lần chuyển giao (commit)%s\n"
-#: wt-status.c:787
+#: wt-status.c:1029
msgid " (use \"git add\" and/or \"git commit -a\")"
-msgstr " (sử dụng \"git add\" và/hoặc \"git commit -a\")"
+msgstr " (dùng \"git add\" và/hoặc \"git commit -a\")"
-#: wt-status.c:789
+#: wt-status.c:1031
#, c-format
msgid "nothing added to commit but untracked files present%s\n"
-msgstr "không có gì được thêm vào lần chuyển giao (commit) nhưng có những tập tin không được theo dấu vết hiện diện%s\n"
+msgstr ""
+"không có gì được thêm vào lần chuyển giao (commit) nhưng có những tập tin "
+"không được theo dấu vết hiện diện%s\n"
-#: wt-status.c:791
+#: wt-status.c:1033
msgid " (use \"git add\" to track)"
-msgstr " (sử dụng \"git add\" để theo dõi dấu vết)"
+msgstr " (dùng \"git add\" để theo dõi dấu vết)"
-#: wt-status.c:793
-#: wt-status.c:796
-#: wt-status.c:799
+#: wt-status.c:1035 wt-status.c:1038 wt-status.c:1041
#, c-format
msgid "nothing to commit%s\n"
msgstr "không có gì để chuyển giao (commit) %s\n"
-#: wt-status.c:794
+#: wt-status.c:1036
msgid " (create/copy files and use \"git add\" to track)"
-msgstr " (tạo/sao-chép các tập tin và sử dụng \"git add\" để theo dõi dấu vết)"
+msgstr " (tạo/sao-chép các tập tin và dùng \"git add\" để theo dõi dấu vết)"
-#: wt-status.c:797
+#: wt-status.c:1039
msgid " (use -u to show untracked files)"
-msgstr " (sá»­ dụng tùy chá»n -u để hiển thị các tập tin chÆ°a được theo dõi)"
+msgstr " (dùng tùy chá»n -u để hiển thị các tập tin chÆ°a được theo dõi)"
-#: wt-status.c:800
+#: wt-status.c:1042
msgid " (working directory clean)"
msgstr " (thư mục làm việc sạch sẽ)"
-#: wt-status.c:908
+#: wt-status.c:1150
msgid "HEAD (no branch)"
-msgstr "HEAD (chưa có nhánh nào)"
+msgstr "HEAD (không nhánh)"
-#: wt-status.c:914
+#: wt-status.c:1156
msgid "Initial commit on "
-msgstr "Lần chuyển giao (commit) khởi tạo trên"
+msgstr "Lần chuyển giao (commit) khởi tạo trên "
-#: wt-status.c:929
+#: wt-status.c:1171
msgid "behind "
-msgstr "đằng sau"
+msgstr "đằng sau "
-#: wt-status.c:932
-#: wt-status.c:935
+#: wt-status.c:1174 wt-status.c:1177
msgid "ahead "
-msgstr "phía trước"
+msgstr "phía trước "
-#: wt-status.c:937
+#: wt-status.c:1179
msgid ", behind "
-msgstr ", đằng sau"
+msgstr ", đằng sau "
+
+#: compat/precompose_utf8.c:58 builtin/clone.c:341
+#, c-format
+msgid "failed to unlink '%s'"
+msgstr "bỠliên kết (unlink) %s không thành công"
#: builtin/add.c:62
#, c-format
msgid "unexpected diff status %c"
msgstr "trạng thái lệnh diff không như mong đợi %c"
-#: builtin/add.c:67
-#: builtin/commit.c:226
+#: builtin/add.c:67 builtin/commit.c:229
msgid "updating files failed"
msgstr "Cập nhật tập tin gặp lỗi"
@@ -943,11 +1315,10 @@ msgstr "ÄÆ°á»ng dẫn '%s' thì ở trong mô-Ä‘un-con '%.*s'"
#: builtin/add.c:192
msgid "Unstaged changes after refreshing the index:"
-msgstr "Các thay đổi không được lưu trạng thái sau khi làm tươi mới lại bảng mục lục:"
+msgstr ""
+"Các thay đổi không được lưu trạng thái sau khi làm tươi mới lại bảng mục lục:"
-#: builtin/add.c:195
-#: builtin/add.c:456
-#: builtin/rm.c:186
+#: builtin/add.c:195 builtin/add.c:459 builtin/rm.c:186
#, c-format
msgid "pathspec '%s' did not match any files"
msgstr "pathspec '%s' không khớp với bất kỳ tập tin nào"
@@ -986,7 +1357,9 @@ msgstr "Không thể apply (áp dụng miếng vá) '%s'"
#: builtin/add.c:312
msgid "The following paths are ignored by one of your .gitignore files:\n"
-msgstr "Các Ä‘Æ°á»ng dẫn theo sau đây sẽ bị lá» Ä‘i bởi má»™t trong các tập tin .gitignore của bạn:\n"
+msgstr ""
+"Các Ä‘Æ°á»ng dẫn theo sau đây sẽ bị lá» Ä‘i bởi má»™t trong các tập tin .gitignore "
+"của bạn:\n"
#: builtin/add.c:352
#, c-format
@@ -1007,7 +1380,7 @@ msgstr "-A và -u xung khắc nhau"
#: builtin/add.c:393
msgid "Option --ignore-missing can only be used together with --dry-run"
-msgstr "Tùy chá»n --ignore-missing chỉ có thể được sá»­ dụng cùng vá»›i --dry-run"
+msgstr "Tùy chá»n --ignore-missing chỉ có thể được dùng cùng vá»›i --dry-run"
#: builtin/add.c:413
#, c-format
@@ -1019,163 +1392,167 @@ msgstr "Không có gì được chỉ ra, không có gì được thêm vào.\n"
msgid "Maybe you wanted to say 'git add .'?\n"
msgstr "Có lẽ bạn muốn nói là 'git add .' phải không?\n"
-#: builtin/add.c:420
-#: builtin/clean.c:95
-#: builtin/commit.c:286
-#: builtin/mv.c:82
+#: builtin/add.c:420 builtin/clean.c:95 builtin/commit.c:289 builtin/mv.c:82
#: builtin/rm.c:162
msgid "index file corrupt"
msgstr "tập tin ghi bảng mục lục bị há»ng"
-#: builtin/add.c:476
-#: builtin/apply.c:4108
-#: builtin/mv.c:229
-#: builtin/rm.c:260
+#: builtin/add.c:480 builtin/apply.c:4432 builtin/mv.c:229 builtin/rm.c:260
msgid "Unable to write new index file"
msgstr "Không thể ghi tập tin lưu bảng mục lục mới"
-#: builtin/apply.c:53
+#: builtin/apply.c:57
msgid "git apply [options] [<patch>...]"
msgstr "git apply [các-tùy-chá»n] [<miếng-vá>...]"
-#: builtin/apply.c:106
+#: builtin/apply.c:110
#, c-format
msgid "unrecognized whitespace option '%s'"
msgstr "không nhận ra tùy chá»n vá» khoảng trắng '%s'"
-#: builtin/apply.c:121
+#: builtin/apply.c:125
#, c-format
msgid "unrecognized whitespace ignore option '%s'"
msgstr "không nhận ra tùy chá»n bá» qua khoảng trắng '%s'"
-#: builtin/apply.c:815
+#: builtin/apply.c:823
#, c-format
msgid "Cannot prepare timestamp regexp %s"
-msgstr "Không thể chuẩn bị biểu thức chính qui dấu vết thá»i gian (timestamp regexp) %s"
+msgstr ""
+"Không thể chuẩn bị biểu thức chính qui dấu vết thá»i gian (timestamp regexp) "
+"%s"
-#: builtin/apply.c:824
+#: builtin/apply.c:832
#, c-format
msgid "regexec returned %d for input: %s"
msgstr "thi hành biểu thức chính quy trả vỠ%d cho kết xuất: %s"
-#: builtin/apply.c:905
+#: builtin/apply.c:913
#, c-format
msgid "unable to find filename in patch at line %d"
msgstr "không thể tìm thấy tên tập tin trong miếng vá tại dòng %d"
-#: builtin/apply.c:937
+#: builtin/apply.c:945
#, c-format
msgid "git apply: bad git-diff - expected /dev/null, got %s on line %d"
msgstr "git apply: git-diff sai - mong đợi /dev/null, đã nhận %s trên dòng %d"
-#: builtin/apply.c:941
+#: builtin/apply.c:949
#, c-format
msgid "git apply: bad git-diff - inconsistent new filename on line %d"
msgstr "git apply: git-diff sai - tên tập tin mới mâu thuấn trên dòng %d"
-#: builtin/apply.c:942
+#: builtin/apply.c:950
#, c-format
msgid "git apply: bad git-diff - inconsistent old filename on line %d"
msgstr "git apply: git-diff sai - tên tập tin cũ mâu thuấn trên dòng %d"
-#: builtin/apply.c:949
+#: builtin/apply.c:957
#, c-format
msgid "git apply: bad git-diff - expected /dev/null on line %d"
msgstr "git apply: git-diff sai - mong đợi /dev/null trên dòng %d"
-#: builtin/apply.c:1394
+#: builtin/apply.c:1402
#, c-format
msgid "recount: unexpected line: %.*s"
msgstr "chi tiết: dòng không được mong đợi: %.*s"
-#: builtin/apply.c:1451
+#: builtin/apply.c:1459
#, c-format
msgid "patch fragment without header at line %d: %.*s"
msgstr "miếng vá phân mảnh mà không có phần đầu tại dòng %d: %.*s"
-#: builtin/apply.c:1468
+#: builtin/apply.c:1476
#, c-format
-msgid "git diff header lacks filename information when removing %d leading pathname component (line %d)"
-msgid_plural "git diff header lacks filename information when removing %d leading pathname components (line %d)"
-msgstr[0] "phần đầu diff cho git thiếu thông tin tên tập tin khi gỡ bá» Ä‘i %d trong thành phần dẫn đầu tên của Ä‘Æ°á»ng dẫn (dòng %d)"
-msgstr[1] "phần đầu diff cho git thiếu thông tin tên tập tin khi gỡ bá» Ä‘i %d trong thành phần dẫn đầu tên của Ä‘Æ°á»ng dẫn (dòng %d)"
+msgid ""
+"git diff header lacks filename information when removing %d leading pathname "
+"component (line %d)"
+msgid_plural ""
+"git diff header lacks filename information when removing %d leading pathname "
+"components (line %d)"
+msgstr[0] ""
+"phần đầu diff cho git thiếu thông tin tên tập tin khi gỡ bỠđi %d trong "
+"thành phần dẫn đầu tên của Ä‘Æ°á»ng dẫn (dòng %d)"
+msgstr[1] ""
+"phần đầu diff cho git thiếu thông tin tên tập tin khi gỡ bỠđi %d trong "
+"thành phần dẫn đầu tên của Ä‘Æ°á»ng dẫn (dòng %d)"
-#: builtin/apply.c:1628
+#: builtin/apply.c:1636
msgid "new file depends on old contents"
msgstr "tập tin mới phụ thuộc vào nội dung cũ"
-#: builtin/apply.c:1630
+#: builtin/apply.c:1638
msgid "deleted file still has contents"
msgstr "tập tin đã xóa vẫn còn nội dung"
-#: builtin/apply.c:1656
+#: builtin/apply.c:1664
#, c-format
msgid "corrupt patch at line %d"
msgstr "miếng vá há»ng tại dòng %d"
-#: builtin/apply.c:1692
+#: builtin/apply.c:1700
#, c-format
msgid "new file %s depends on old contents"
msgstr "tập tin mới %s phụ thuộc vào nội dung cũ"
-#: builtin/apply.c:1694
+#: builtin/apply.c:1702
#, c-format
msgid "deleted file %s still has contents"
msgstr "tập tin đã xóa %s vẫn còn nội dung"
-#: builtin/apply.c:1697
+#: builtin/apply.c:1705
#, c-format
msgid "** warning: file %s becomes empty but is not deleted"
msgstr "** cảnh báo: tập tin %s trở nên trống rỗng nhưng không bị xóa"
-#: builtin/apply.c:1843
+#: builtin/apply.c:1851
#, c-format
msgid "corrupt binary patch at line %d: %.*s"
msgstr "miếng vá định dạng nhị phân sai há»ng tại dòng %d: %.*s"
#. there has to be one hunk (forward hunk)
-#: builtin/apply.c:1872
+#: builtin/apply.c:1880
#, c-format
msgid "unrecognized binary patch at line %d"
msgstr "miếng vá định dạng nhị phân không được nhận ra tại dòng %d"
-#: builtin/apply.c:1958
+#: builtin/apply.c:1966
#, c-format
msgid "patch with only garbage at line %d"
msgstr "vá chỉ với 'garbage' tại dòng %d"
-#: builtin/apply.c:2048
+#: builtin/apply.c:2056
#, c-format
msgid "unable to read symlink %s"
msgstr "không thể Ä‘á»c liên kết tượng trÆ°ng %s"
-#: builtin/apply.c:2052
+#: builtin/apply.c:2060
#, c-format
msgid "unable to open or read %s"
msgstr "không thể mở để Ä‘á»c hay ghi %s"
-#: builtin/apply.c:2123
+#: builtin/apply.c:2131
msgid "oops"
msgstr "ôi?"
-#: builtin/apply.c:2645
+#: builtin/apply.c:2653
#, c-format
msgid "invalid start of line: '%c'"
msgstr "sai khởi đầu dòng: '%c'"
-#: builtin/apply.c:2763
+#: builtin/apply.c:2771
#, c-format
msgid "Hunk #%d succeeded at %d (offset %d line)."
msgid_plural "Hunk #%d succeeded at %d (offset %d lines)."
msgstr[0] "Khối dữ liệu #%d thành công tại %d (offset %d dòng)."
msgstr[1] "Khối dữ liệu #%d thành công tại %d (offset %d dòng)."
-#: builtin/apply.c:2775
+#: builtin/apply.c:2783
#, c-format
msgid "Context reduced to (%ld/%ld) to apply fragment at %d"
-msgstr "Nội dung được giảm xuống (%ld/%ld) để áp dụng mảnh dữ liệu tại %d"
+msgstr "Nội dung bị giảm xuống (%ld/%ld) để áp dụng mảnh dữ liệu tại %d"
-#: builtin/apply.c:2781
+#: builtin/apply.c:2789
#, c-format
msgid ""
"while searching for:\n"
@@ -1184,320 +1561,327 @@ msgstr ""
"Trong khi đang tìm kiếm cho:\n"
"%.*s"
-#: builtin/apply.c:2800
+#: builtin/apply.c:2808
#, c-format
msgid "missing binary patch data for '%s'"
msgstr "thiếu dữ liệu của miếng vá định dạng nhị phân cho '%s'"
-#: builtin/apply.c:2903
+#: builtin/apply.c:2911
#, c-format
msgid "binary patch does not apply to '%s'"
msgstr "miếng vá định dạng nhị phân không được áp dụng cho '%s'"
-#: builtin/apply.c:2909
+#: builtin/apply.c:2917
#, c-format
msgid "binary patch to '%s' creates incorrect result (expecting %s, got %s)"
-msgstr "vá nhị phân cho '%s' tạo ra kết quả không chính xác (đang chỠ%s, đã nhận %s)"
+msgstr ""
+"vá nhị phân cho '%s' tạo ra kết quả không chính xác (mong chỠ%s, lại nhận %s)"
-#: builtin/apply.c:2930
+#: builtin/apply.c:2938
#, c-format
msgid "patch failed: %s:%ld"
msgstr "vá gặp lỗi: %s:%ld"
-#: builtin/apply.c:3045
+#: builtin/apply.c:3060
#, c-format
-msgid "patch %s has been renamed/deleted"
-msgstr "miếng vá %s đã bị xóa/đổi tên"
+msgid "cannot checkout %s"
+msgstr "không thể \"checkout\" %s"
-#: builtin/apply.c:3052
-#: builtin/apply.c:3069
+#: builtin/apply.c:3105 builtin/apply.c:3114 builtin/apply.c:3158
#, c-format
msgid "read of %s failed"
msgstr "Ä‘á»c %s gặp lá»—i"
-#: builtin/apply.c:3084
-msgid "removal patch leaves file contents"
-msgstr "loại bỠmiếng vá để lại nội dung tập tin"
-
-#: builtin/apply.c:3105
+#: builtin/apply.c:3138 builtin/apply.c:3360
#, c-format
-msgid "%s: already exists in working directory"
-msgstr "%s: đã sẵn có trong thư mục đang làm việc"
+msgid "path %s has been renamed/deleted"
+msgstr "Ä‘Æ°á»ng dẫn %s đã bị xóa/đổi tên"
-#: builtin/apply.c:3143
+#: builtin/apply.c:3219 builtin/apply.c:3374
#, c-format
-msgid "%s: has been deleted/renamed"
-msgstr "%s: đã được xóa/thay-tên"
+msgid "%s: does not exist in index"
+msgstr "%s: không tồn tại trong bảng mục lục"
-#: builtin/apply.c:3148
-#: builtin/apply.c:3179
+#: builtin/apply.c:3223 builtin/apply.c:3366 builtin/apply.c:3388
#, c-format
msgid "%s: %s"
msgstr "%s: %s"
-#: builtin/apply.c:3159
-#, c-format
-msgid "%s: does not exist in index"
-msgstr "%s: không tồn tại trong bảng mục lục"
-
-#: builtin/apply.c:3173
+#: builtin/apply.c:3228 builtin/apply.c:3382
#, c-format
msgid "%s: does not match index"
msgstr "%s: không khớp trong mục lục"
-#: builtin/apply.c:3190
+#: builtin/apply.c:3330
+msgid "removal patch leaves file contents"
+msgstr "loại bỠmiếng vá để lại nội dung tập tin"
+
+#: builtin/apply.c:3399
#, c-format
msgid "%s: wrong type"
msgstr "%s: sai kiểu"
-#: builtin/apply.c:3192
+#: builtin/apply.c:3401
#, c-format
msgid "%s has type %o, expected %o"
msgstr "%s có kiểu %o, mong chỠ%o"
-#: builtin/apply.c:3247
+#: builtin/apply.c:3502
#, c-format
msgid "%s: already exists in index"
msgstr "%s: đã có từ trước trong bảng mục lục"
-#: builtin/apply.c:3267
+#: builtin/apply.c:3505
+#, c-format
+msgid "%s: already exists in working directory"
+msgstr "%s: đã sẵn có trong thư mục đang làm việc"
+
+#: builtin/apply.c:3525
#, c-format
msgid "new mode (%o) of %s does not match old mode (%o)"
msgstr "chế độ mới (%o) của %s không khớp với chế độ cũ (%o)"
-#: builtin/apply.c:3272
+#: builtin/apply.c:3530
#, c-format
msgid "new mode (%o) of %s does not match old mode (%o) of %s"
msgstr "chế độ mới (%o) của %s không khớp với chế độ cũ (%o) của %s"
-#: builtin/apply.c:3280
+#: builtin/apply.c:3538
#, c-format
msgid "%s: patch does not apply"
msgstr "%s: miếng vá không được áp dụng"
-#: builtin/apply.c:3293
+#: builtin/apply.c:3551
#, c-format
msgid "Checking patch %s..."
msgstr "Äang kiểm tra miếng vá %s..."
-#: builtin/apply.c:3348
-#: builtin/checkout.c:212
-#: builtin/reset.c:158
+#: builtin/apply.c:3606 builtin/checkout.c:213 builtin/reset.c:158
#, c-format
msgid "make_cache_entry failed for path '%s'"
msgstr "make_cache_entry gặp lá»—i đối vá»›i Ä‘Æ°á»ng dẫn '%s'"
-#: builtin/apply.c:3491
+#: builtin/apply.c:3749
#, c-format
msgid "unable to remove %s from index"
msgstr "không thể gỡ bỠ%s từ mục lục"
-#: builtin/apply.c:3518
+#: builtin/apply.c:3777
#, c-format
msgid "corrupt patch for subproject %s"
msgstr "miếng vá sai há»ng cho dá»± án con (subproject) %s"
-#: builtin/apply.c:3522
+#: builtin/apply.c:3781
#, c-format
msgid "unable to stat newly created file '%s'"
msgstr "không thể lấy trạng thái vỠtập tin %s mới hơn đã được tạo"
-#: builtin/apply.c:3527
+#: builtin/apply.c:3786
#, c-format
msgid "unable to create backing store for newly created file %s"
msgstr "không thể tạo 'backing store' cho tập tin được tạo mới hơn %s"
-#: builtin/apply.c:3530
+#: builtin/apply.c:3789 builtin/apply.c:3897
#, c-format
msgid "unable to add cache entry for %s"
msgstr "không thể thêm mục nhớ tạm cho %s"
-#: builtin/apply.c:3563
+#: builtin/apply.c:3822
#, c-format
msgid "closing file '%s'"
msgstr "đang đóng tập tin '%s'"
-#: builtin/apply.c:3612
+#: builtin/apply.c:3871
#, c-format
msgid "unable to write file '%s' mode %o"
msgstr "không thể ghi vào tập tin '%s' chế độ (mode) %o"
-#: builtin/apply.c:3668
+#: builtin/apply.c:3958
#, c-format
msgid "Applied patch %s cleanly."
msgstr "Äã áp dụng miếng và %s má»™t cách sạch sẽ."
-#: builtin/apply.c:3676
+#: builtin/apply.c:3966
msgid "internal error"
msgstr "lá»—i ná»™i bá»™"
#. Say this even without --verbose
-#: builtin/apply.c:3679
+#: builtin/apply.c:3969
#, c-format
msgid "Applying patch %%s with %d reject..."
msgid_plural "Applying patch %%s with %d rejects..."
msgstr[0] "Äang áp dụng miếng vá %%s vá»›i %d lần từ chối..."
msgstr[1] "Äang áp dụng miếng vá %%s vá»›i %d lần từ chối..."
-#: builtin/apply.c:3689
+#: builtin/apply.c:3979
#, c-format
msgid "truncating .rej filename to %.*s.rej"
msgstr "đang cắt cụt tên tập tin .rej thành %.*s.rej"
-#: builtin/apply.c:3710
+#: builtin/apply.c:4000
#, c-format
msgid "Hunk #%d applied cleanly."
msgstr "Khối nhá»› #%d được áp dụng gá»n gàng."
-#: builtin/apply.c:3713
+#: builtin/apply.c:4003
#, c-format
msgid "Rejected hunk #%d."
msgstr "hunk #%d bị từ chối."
-#: builtin/apply.c:3844
+#: builtin/apply.c:4153
msgid "unrecognized input"
msgstr "không thừa nhận đầu vào"
-#: builtin/apply.c:3855
+#: builtin/apply.c:4164
msgid "unable to read index file"
msgstr "không thể Ä‘á»c tập tin lÆ°u bảng mục lục"
-#: builtin/apply.c:3970
-#: builtin/apply.c:3973
+#: builtin/apply.c:4283 builtin/apply.c:4286
msgid "path"
msgstr "Ä‘Æ°á»ng-dẫn"
-#: builtin/apply.c:3971
+#: builtin/apply.c:4284
msgid "don't apply changes matching the given path"
msgstr "không áp dụng các thay đổi khá»›p vá»›i Ä‘Æ°á»ng dẫn đã cho"
-#: builtin/apply.c:3974
+#: builtin/apply.c:4287
msgid "apply changes matching the given path"
msgstr "áp dụng các thay đổi khá»›p vá»›i Ä‘Æ°á»ng dẫn đã cho"
-#: builtin/apply.c:3976
+#: builtin/apply.c:4289
msgid "num"
msgstr "số"
-#: builtin/apply.c:3977
+#: builtin/apply.c:4290
msgid "remove <num> leading slashes from traditional diff paths"
msgstr "gỡ bá» <số> phần dẫn đầu (slashe) từ Ä‘Æ°á»ng dẫn diff cổ Ä‘iển"
-#: builtin/apply.c:3980
+#: builtin/apply.c:4293
msgid "ignore additions made by the patch"
msgstr "lỠđi phần phụ thêm tạo ra bởi miếng vá"
-#: builtin/apply.c:3982
+#: builtin/apply.c:4295
msgid "instead of applying the patch, output diffstat for the input"
-msgstr "thay vì áp dụng một miếng vá, kết xuất kết quả từ lệnh diffstat cho đầu ra"
+msgstr ""
+"thay vì áp dụng một miếng vá, kết xuất kết quả từ lệnh diffstat cho đầu ra"
-#: builtin/apply.c:3986
+#: builtin/apply.c:4299
msgid "shows number of added and deleted lines in decimal notation"
-msgstr "hiển thị số lượng các dòng được thêm vào và xóa đi theo ký hiệu thập phân"
+msgstr ""
+"hiển thị số lượng các dòng được thêm vào và xóa đi theo ký hiệu thập phân"
-#: builtin/apply.c:3988
+#: builtin/apply.c:4301
msgid "instead of applying the patch, output a summary for the input"
msgstr "thay vì áp dụng một miếng vá, kết xuất kết quả cho đầu vào"
-#: builtin/apply.c:3990
+#: builtin/apply.c:4303
msgid "instead of applying the patch, see if the patch is applicable"
msgstr "thay vì áp dụng miếng vá, hãy xem xem miếng vá có thích hợp không"
-#: builtin/apply.c:3992
+#: builtin/apply.c:4305
msgid "make sure the patch is applicable to the current index"
msgstr "hãy chắc chắn là miếng vá thích hợp với bảng mục lục hiện hành"
-#: builtin/apply.c:3994
+#: builtin/apply.c:4307
msgid "apply a patch without touching the working tree"
msgstr "áp dụng một miếng vá mà không động chạm đến cây làm việc"
-#: builtin/apply.c:3996
+#: builtin/apply.c:4309
msgid "also apply the patch (use with --stat/--summary/--check)"
-msgstr "đồng thá»i áp dụng miếng vá (sá»­ dụng vá»›i tùy chá»n --stat/--summary/--check)"
+msgstr ""
+"đồng thá»i áp dụng miếng vá (dùng vá»›i tùy chá»n --stat/--summary/--check)"
-#: builtin/apply.c:3998
+#: builtin/apply.c:4311
+msgid "attempt three-way merge if a patch does not apply"
+msgstr "thử hòa trộn kiểu three-way nếu việc vá không thể thực hiện được"
+
+#: builtin/apply.c:4313
msgid "build a temporary index based on embedded index information"
-msgstr "xây dá»±ng bảng mục lục tạm thá»i trên cÆ¡ sở thông tin bảng mục lục được nhúng"
+msgstr ""
+"xây dá»±ng bảng mục lục tạm thá»i trên cÆ¡ sở thông tin bảng mục lục được nhúng"
-#: builtin/apply.c:4000
+#: builtin/apply.c:4315
msgid "paths are separated with NUL character"
msgstr "các Ä‘Æ°á»ng dẫn bị ngăn cách bởi ký tá»± NULL"
-#: builtin/apply.c:4003
+#: builtin/apply.c:4318
msgid "ensure at least <n> lines of context match"
msgstr "đảm bảo rằng có ít nhất <n> dòng nội dung khớp"
-#: builtin/apply.c:4004
+#: builtin/apply.c:4319
msgid "action"
msgstr "hành động"
-#: builtin/apply.c:4005
+#: builtin/apply.c:4320
msgid "detect new or modified lines that have whitespace errors"
msgstr "tìm thấy một dòng mới hoặc bị sửa đổi mà nó có lỗi do khoảng trắng"
-#: builtin/apply.c:4008
-#: builtin/apply.c:4011
+#: builtin/apply.c:4323 builtin/apply.c:4326
msgid "ignore changes in whitespace when finding context"
msgstr "lỠđi sự thay đổi do khoảng trắng khi quét nội dung"
-#: builtin/apply.c:4014
+#: builtin/apply.c:4329
msgid "apply the patch in reverse"
msgstr "áp dụng miếng vá theo chiá»u ngược"
-#: builtin/apply.c:4016
+#: builtin/apply.c:4331
msgid "don't expect at least one line of context"
msgstr "đừng hy vá»ng có ít nhất má»™t dòng ná»™i dung"
-#: builtin/apply.c:4018
+#: builtin/apply.c:4333
msgid "leave the rejected hunks in corresponding *.rej files"
msgstr "để lại khối dữ liệu bị từ chối trong các tập tin *.rej tương ứng"
-#: builtin/apply.c:4020
+#: builtin/apply.c:4335
msgid "allow overlapping hunks"
msgstr "cho phép chồng khối nhớ"
-#: builtin/apply.c:4021
+#: builtin/apply.c:4336
msgid "be verbose"
msgstr "chi tiết"
-#: builtin/apply.c:4023
+#: builtin/apply.c:4338
msgid "tolerate incorrectly detected missing new-line at the end of file"
-msgstr "dung sai không chính xác đã tìm thấy thiếu dòng mới tại cuối tập tin"
+msgstr ""
+"đã dò tìm thấy dung sai không chính xác thiếu dòng mới tại cuối tập tin"
-#: builtin/apply.c:4026
+#: builtin/apply.c:4341
msgid "do not trust the line counts in the hunk headers"
msgstr "không tin số lượng dòng trong phần đầu khối dữ liệu"
-#: builtin/apply.c:4028
+#: builtin/apply.c:4343
msgid "root"
msgstr "root"
-#: builtin/apply.c:4029
+#: builtin/apply.c:4344
msgid "prepend <root> to all filenames"
msgstr "treo thêm <root> vào tất cả các tên tập tin"
-#: builtin/apply.c:4050
+#: builtin/apply.c:4366
+msgid "--3way outside a repository"
+msgstr "--3way ở ngoài một kho chứa"
+
+#: builtin/apply.c:4374
msgid "--index outside a repository"
msgstr "--index ở ngoài một kho chứa"
-#: builtin/apply.c:4053
+#: builtin/apply.c:4377
msgid "--cached outside a repository"
msgstr "--cached ở ngoài một kho chứa"
-#: builtin/apply.c:4069
+#: builtin/apply.c:4393
#, c-format
msgid "can't open patch '%s'"
msgstr "không thể mở miếng vá '%s'"
-#: builtin/apply.c:4083
+#: builtin/apply.c:4407
#, c-format
msgid "squelched %d whitespace error"
msgid_plural "squelched %d whitespace errors"
msgstr[0] "đã chấm dứt %d lỗi khoảng trắng"
msgstr[1] "đã chấm dứt %d lỗi khoảng trắng"
-#: builtin/apply.c:4089
-#: builtin/apply.c:4099
+#: builtin/apply.c:4413 builtin/apply.c:4423
#, c-format
msgid "%d line adds whitespace errors."
msgid_plural "%d lines add whitespace errors."
@@ -1559,7 +1943,7 @@ msgstr ""
#: builtin/branch.c:180
msgid "cannot use -a with -d"
-msgstr "không thể sử dụng -a với -d"
+msgstr "không thể dùng tùy chá»n -a vá»›i -d"
#: builtin/branch.c:186
msgid "Couldn't look up commit object for HEAD"
@@ -1573,7 +1957,7 @@ msgstr "Không thể xóa nhánh '%s' cái mà bạn hiện nay đang ở."
#: builtin/branch.c:202
#, c-format
msgid "remote branch '%s' not found."
-msgstr "nhánh máy chủ '%s' không tìm thấy."
+msgstr "không tìm thấy nhánh máy chủ '%s'."
#: builtin/branch.c:203
#, c-format
@@ -1607,16 +1991,16 @@ msgstr "Lỗi khi xoá bỠnhánh '%s'"
#: builtin/branch.c:233
#, c-format
msgid "Deleted remote branch %s (was %s).\n"
-msgstr "Nhánh máy chủ đã xóa %s (trước là %s).\n"
+msgstr "Nhánh máy chủ \"%s\" đã bị xóa (từng là %s).\n"
#: builtin/branch.c:234
#, c-format
msgid "Deleted branch %s (was %s).\n"
-msgstr "Nhánh đã bị xóa '%s' (trước là %s)\n"
+msgstr "Nhánh '%s' đã bị xóa (từng là %s)\n"
#: builtin/branch.c:239
msgid "Update of config-file failed"
-msgstr "Cập nhật tệp tin cấu hình gặp lỗi"
+msgstr "Cập nhật tập tin cấu hình gặp lỗi"
#: builtin/branch.c:337
#, c-format
@@ -1655,7 +2039,7 @@ msgstr "[phía trước %d, phía sau %d]"
#: builtin/branch.c:535
msgid "(no branch)"
-msgstr "(không có nhánh nào)"
+msgstr "(không nhánh)"
#: builtin/branch.c:600
msgid "some refs could not be read"
@@ -1668,7 +2052,7 @@ msgstr "không thể đổi tên nhánh hiện hành trong khi nó chẳng ở Ä
#: builtin/branch.c:623
#, c-format
msgid "Invalid branch name: '%s'"
-msgstr "tên nhánh sai: '%s'"
+msgstr "Sai tên nhánh: '%s'"
#: builtin/branch.c:638
msgid "Branch rename failed"
@@ -1702,10 +2086,9 @@ msgstr "không thể ghi vào mẫu mô tả nhánh: %s"
msgid "Failed to resolve HEAD as a valid ref."
msgstr "Gặp lỗi khi giải quyết HEAD như là một tham chiếu (ref) hợp lệ."
-#: builtin/branch.c:788
-#: builtin/clone.c:558
+#: builtin/branch.c:788 builtin/clone.c:561
msgid "HEAD not found below refs/heads!"
-msgstr "HEAD không tìm thấy ở dưới refs/heads!"
+msgstr "không tìm thấy HEAD ở dưới refs/heads!"
#: builtin/branch.c:808
msgid "--column and --verbose are incompatible"
@@ -1713,7 +2096,9 @@ msgstr "--column và --verbose xung khắc nhau"
#: builtin/branch.c:857
msgid "-a and -r options to 'git branch' do not make sense with a branch name"
-msgstr "hai tùy chá»n -a và -r áp dụng cho lệnh 'git branch' không hợp lý đối vá»›i tên nhánh"
+msgstr ""
+"hai tùy chá»n -a và -r áp dụng cho lệnh 'git branch' không hợp lý đối vá»›i tên "
+"nhánh"
#: builtin/bundle.c:47
#, c-format
@@ -1728,62 +2113,50 @@ msgstr "Cần một kho chứa để mà tạo một bundle."
msgid "Need a repository to unbundle."
msgstr "Cần một kho chứa để mà bung một bundle."
-#: builtin/checkout.c:113
-#: builtin/checkout.c:146
+#: builtin/checkout.c:114 builtin/checkout.c:147
#, c-format
msgid "path '%s' does not have our version"
msgstr "Ä‘Æ°á»ng dẫn '%s' không có các phiên bản của chúng ta"
-#: builtin/checkout.c:115
-#: builtin/checkout.c:148
+#: builtin/checkout.c:116 builtin/checkout.c:149
#, c-format
msgid "path '%s' does not have their version"
msgstr "Ä‘Æ°á»ng dẫn '%s' không có các phiên bản của chúng"
-#: builtin/checkout.c:131
+#: builtin/checkout.c:132
#, c-format
msgid "path '%s' does not have all necessary versions"
msgstr "Ä‘Æ°á»ng dẫn '%s' không có tất cả các phiên bản cần thiết"
-#: builtin/checkout.c:175
+#: builtin/checkout.c:176
#, c-format
msgid "path '%s' does not have necessary versions"
msgstr "Ä‘Æ°á»ng dẫn '%s' không có các phiên bản cần thiết"
-#: builtin/checkout.c:192
+#: builtin/checkout.c:193
#, c-format
msgid "path '%s': cannot merge"
msgstr "Ä‘Æ°á»ng dẫn '%s': không thể hòa trá»™n"
-#: builtin/checkout.c:209
+#: builtin/checkout.c:210
#, c-format
msgid "Unable to add merge result for '%s'"
msgstr "Không thể thêm kết quả hòa trộn cho '%s'"
-#: builtin/checkout.c:234
-#: builtin/checkout.c:392
+#: builtin/checkout.c:235 builtin/checkout.c:392
msgid "corrupt index file"
msgstr "tập tin ghi bảng mục lục bị há»ng"
-#: builtin/checkout.c:264
-#: builtin/checkout.c:271
+#: builtin/checkout.c:265 builtin/checkout.c:272
#, c-format
msgid "path '%s' is unmerged"
msgstr "Ä‘Æ°á»ng dẫn '%s' không được hòa trá»™n"
-#: builtin/checkout.c:302
-#: builtin/checkout.c:498
-#: builtin/clone.c:583
-#: builtin/merge.c:812
+#: builtin/checkout.c:303 builtin/checkout.c:498 builtin/clone.c:586
+#: builtin/merge.c:811
msgid "unable to write new index file"
msgstr "không thể ghi tập tin lưu bảng mục lục mới"
-#: builtin/checkout.c:319
-#: builtin/diff.c:302
-#: builtin/merge.c:408
-msgid "diff_setup_done failed"
-msgstr "diff_setup_done gặp lỗi"
-
#: builtin/checkout.c:414
msgid "you need to resolve your current index first"
msgstr "bạn cần phải giải quyết bảng mục lục hiện tại của bạn trước đã!"
@@ -1841,12 +2214,14 @@ msgid_plural ""
"\n"
"%s\n"
msgstr[0] ""
-"Cảnh báo: bạn đã rá»i bở %d lần chuyển giao (commit) lại đằng sau, không được kết nối đến\n"
+"Cảnh báo: bạn đã rá»i bá» %d lần chuyển giao (commit) lại đằng sau, không được "
+"kết nối đến\n"
"bất kỳ nhánh nào của bạn:\n"
"\n"
"%s\n"
msgstr[1] ""
-"Cảnh báo: bạn đã rá»i bở %d lần chuyển giao (commit) lại đằng sau, không được kết nối đến\n"
+"Cảnh báo: bạn đã rá»i bá» %d lần chuyển giao (commit) lại đằng sau, không được "
+"kết nối đến\n"
"bất kỳ nhánh nào của bạn:\n"
"\n"
"%s\n"
@@ -1860,7 +2235,8 @@ msgid ""
" git branch new_branch_name %s\n"
"\n"
msgstr ""
-"Nếu bạn muốn giữ chúng bằng cách tạo ra má»™t nhánh má»›i, đây có lẽ là má»™t thá»i Ä‘iểm thích hợp\n"
+"Nếu bạn muốn giữ chúng bằng cách tạo ra má»™t nhánh má»›i, đây có lẽ là má»™t thá»i "
+"điểm thích hợp\n"
"để làm thế bằng lệnh:\n"
"\n"
" git branch tên_nhánh_mới %s\n"
@@ -1874,7 +2250,7 @@ msgstr "lỗi nội bộ trong khi di chuyển qua các điểm xét lại"
msgid "Previous HEAD position was"
msgstr "Vị trí kế trước của HEAD là"
-#: builtin/checkout.c:724
+#: builtin/checkout.c:724 builtin/checkout.c:919
msgid "You are on a branch yet to be born"
msgstr "Bạn tại nhánh mà nó chưa hỠđược sinh ra"
@@ -1888,78 +2264,82 @@ msgstr "tham chiếu sai: %s"
#: builtin/checkout.c:894
#, c-format
msgid "reference is not a tree: %s"
-msgstr "tham chiếu không phải là cây:%s"
+msgstr "tham chiếu không phải là một cây (tree):%s"
-#: builtin/checkout.c:974
+#: builtin/checkout.c:976
msgid "-B cannot be used with -b"
-msgstr "-B không thể được sử dụng với -b"
+msgstr "tùy chá»n -B không thể dùng -b"
-#: builtin/checkout.c:983
+#: builtin/checkout.c:985
msgid "--patch is incompatible with all other options"
msgstr "--patch xung khắc vá»›i tất cả các tùy chá»n khác"
-#: builtin/checkout.c:986
+#: builtin/checkout.c:988
msgid "--detach cannot be used with -b/-B/--orphan"
-msgstr "--detach không thể được sử dụng với -b/-B/--orphan"
+msgstr "--detach không thể được sá»­ dụng vá»›i tùy chá»n -b/-B/--orphan"
-#: builtin/checkout.c:988
+#: builtin/checkout.c:990
msgid "--detach cannot be used with -t"
msgstr "--detach không thể được sá»­ dụng vá»›i tùy chá»n -t"
-#: builtin/checkout.c:994
+#: builtin/checkout.c:996
msgid "--track needs a branch name"
msgstr "--track cần tên một nhánh"
-#: builtin/checkout.c:1001
+#: builtin/checkout.c:1003
msgid "Missing branch name; try -b"
msgstr "Thiếu tên nhánh; hãy thử -b"
-#: builtin/checkout.c:1007
+#: builtin/checkout.c:1009
msgid "--orphan and -b|-B are mutually exclusive"
msgstr "Tùy chá»n --orphan và -b|-B loại từ lẫn nhau"
-#: builtin/checkout.c:1009
+#: builtin/checkout.c:1011
msgid "--orphan cannot be used with -t"
msgstr "--orphan không thể được sá»­ dụng vá»›i tùy chá»n -t"
-#: builtin/checkout.c:1019
+#: builtin/checkout.c:1021
msgid "git checkout: -f and -m are incompatible"
-msgstr "git checkout: -f và -m xung khắc nhau"
+msgstr "git checkout: hai tùy chá»n -f và -m xung khắc nhau"
-#: builtin/checkout.c:1053
+#: builtin/checkout.c:1055
msgid "invalid path specification"
msgstr "Ä‘Æ°á»ng dẫn đã cho không hợp lệ"
-#: builtin/checkout.c:1061
+#: builtin/checkout.c:1063
#, 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: việc cập nhật các Ä‘Æ°á»ng dẫn là xung khắc vá»›i việc chuyển đổi các nhánh..\n"
-"Bạn đã có ý định checkout '%s' cái mà không thể được phân giải như là lần chuyển giao (commit)?"
+"git checkout: việc cập nhật các Ä‘Æ°á»ng dẫn là xung khắc vá»›i việc chuyển đổi "
+"các nhánh..\n"
+"Bạn đã có ý định checkout '%s' cái mà không thể được phân giải như là lần "
+"chuyển giao (commit)?"
-#: builtin/checkout.c:1063
+#: builtin/checkout.c:1065
msgid "git checkout: updating paths is incompatible with switching branches."
-msgstr "git checkout: việc cập nhật các Ä‘Æ°á»ng dẫn là xung khắc vá»›i việc chuyển đổi các nhánh."
+msgstr ""
+"git checkout: việc cập nhật các Ä‘Æ°á»ng dẫn là xung khắc vá»›i việc chuyển đổi "
+"các nhánh."
-#: builtin/checkout.c:1068
+#: builtin/checkout.c:1070
msgid "git checkout: --detach does not take a path argument"
-msgstr "git checkout: --detach không nhận má»™t đối số Ä‘Æ°á»ng dẫn"
+msgstr "git checkout: --detach không nhận má»™t đối số là Ä‘Æ°á»ng dẫn"
-#: builtin/checkout.c:1071
+#: builtin/checkout.c:1073
msgid ""
"git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
"checking out of the index."
msgstr ""
"git checkout: --ours/--theirs, --force và --merge là xung khắc với nhau khi\n"
-"checkout."
+"checkout bảng mục lục (index)."
-#: builtin/checkout.c:1090
+#: builtin/checkout.c:1092
msgid "Cannot switch branch to a non-commit."
msgstr "Không thể chuyển đến một non-commit."
-#: builtin/checkout.c:1093
+#: builtin/checkout.c:1095
msgid "--ours/--theirs is incompatible with switching branches."
msgstr "--ours/--theirs là xung khắc nhau khi chuyển đổi các nhánh."
@@ -1968,27 +2348,31 @@ msgid "-x and -X cannot be used together"
msgstr "-x và -X không thể dùng cùng một lúc với nhau"
#: builtin/clean.c:82
-msgid "clean.requireForce set to true and neither -n nor -f given; refusing to clean"
-msgstr "clean.requireForce được đặt thành true và không Ä‘Æ°a ra tùy chá»n -n mà cÅ©ng không -f; từ chối lệnh dá»n dẹp (clean)"
+msgid ""
+"clean.requireForce set to true and neither -n nor -f given; refusing to clean"
+msgstr ""
+"clean.requireForce được đặt thành true và không Ä‘Æ°a ra tùy chá»n -n mà cÅ©ng "
+"không -f; từ chối lệnh dá»n dẹp (clean)"
#: builtin/clean.c:85
-msgid "clean.requireForce defaults to true and neither -n nor -f given; refusing to clean"
-msgstr "clean.requireForce mặc định được đặt thành true và không Ä‘Æ°a ra tùy chá»n -n mà cÅ©ng không -f; từ chối lệnh dá»n dẹp (clean)"
+msgid ""
+"clean.requireForce defaults to true and neither -n nor -f given; refusing to "
+"clean"
+msgstr ""
+"clean.requireForce mặc định được đặt thành true và không Ä‘Æ°a ra tùy chá»n -n "
+"mà cÅ©ng không -f; từ chối lệnh dá»n dẹp (clean)"
-#: builtin/clean.c:155
-#: builtin/clean.c:176
+#: builtin/clean.c:155 builtin/clean.c:176
#, c-format
msgid "Would remove %s\n"
msgstr "Có thể gỡ bỠ%s\n"
-#: builtin/clean.c:159
-#: builtin/clean.c:179
+#: builtin/clean.c:159 builtin/clean.c:179
#, c-format
msgid "Removing %s\n"
msgstr "Äang gỡ bá» %s\n"
-#: builtin/clean.c:162
-#: builtin/clean.c:182
+#: builtin/clean.c:162 builtin/clean.c:182
#, c-format
msgid "failed to remove %s"
msgstr "gặp lỗi khi gỡ bỠ%s"
@@ -2008,18 +2392,12 @@ msgstr "Không xóa %s\n"
msgid "reference repository '%s' is not a local directory."
msgstr "kho tham chiếu '%s' không phải là một thư mục nội bộ."
-#: builtin/clone.c:302
-#, c-format
-msgid "failed to open '%s'"
-msgstr "gặp lỗi khi mở '%s'"
-
#: builtin/clone.c:306
#, c-format
msgid "failed to create directory '%s'"
msgstr "tạo thư mục \"%s\" gặp lỗi"
-#: builtin/clone.c:308
-#: builtin/diff.c:75
+#: builtin/clone.c:308 builtin/diff.c:77
#, c-format
msgid "failed to stat '%s'"
msgstr "gặp lá»—i stat (lấy trạng thái vá») '%s'"
@@ -2034,99 +2412,93 @@ msgstr "%s tồn tại nhưng không phải là một thư mục"
msgid "failed to stat %s\n"
msgstr "lá»—i stat (lấy trạng thái vá») %s\n"
-#: builtin/clone.c:341
-#, c-format
-msgid "failed to unlink '%s'"
-msgstr "bỠliên kết (unlink) %s không thành công"
-
#: builtin/clone.c:346
#, c-format
msgid "failed to create link '%s'"
-msgstr "tạo được liên kết má»m tá»›i %s gặp lá»—i"
+msgstr "gặp lá»—i khi tạo được liên kết má»m %s"
#: builtin/clone.c:350
#, c-format
msgid "failed to copy file to '%s'"
-msgstr "sao chép tệp tin tới '%s' gặp lỗi"
+msgstr "gặp lỗi khi chép tập tin tới '%s'"
#: builtin/clone.c:373
#, c-format
msgid "done.\n"
msgstr "hoàn tất.\n"
-#: builtin/clone.c:440
+#: builtin/clone.c:443
#, c-format
msgid "Could not find remote branch %s to clone."
msgstr "Không tìm thấy nhánh máy chủ %s để nhân bản (clone)."
-#: builtin/clone.c:549
+#: builtin/clone.c:552
msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n"
msgstr "refers HEAD máy chủ chỉ đến ref không tồn tại, không thể checkout.\n"
-#: builtin/clone.c:639
+#: builtin/clone.c:642
msgid "Too many arguments."
msgstr "Có quá nhiá»u đối số."
-#: builtin/clone.c:643
+#: builtin/clone.c:646
msgid "You must specify a repository to clone."
msgstr "Bạn phải chỉ định một kho để mà nhân bản (clone)."
-#: builtin/clone.c:654
+#: builtin/clone.c:657
#, c-format
msgid "--bare and --origin %s options are incompatible."
msgstr "tùy chá»n --bare và --origin %s xung khắc nhau."
-#: builtin/clone.c:668
+#: builtin/clone.c:671
#, c-format
msgid "repository '%s' does not exist"
msgstr "kho chứa '%s' chưa tồn tại"
-#: builtin/clone.c:673
+#: builtin/clone.c:676
msgid "--depth is ignored in local clones; use file:// instead."
msgstr "--depth bị lỠđi khi nhân bản nội bộ; hãy sử dụng file:// để thay thế."
-#: builtin/clone.c:683
+#: builtin/clone.c:686
#, c-format
msgid "destination path '%s' already exists and is not an empty directory."
msgstr "Ä‘Æ°á»ng dẫn đích '%s' đã có từ trÆ°á»›c và không phải là má»™t thÆ° mục rá»—ng."
-#: builtin/clone.c:693
+#: builtin/clone.c:696
#, c-format
msgid "working tree '%s' already exists."
msgstr "cây làm việc '%s' đã sẵn tồn tại rồi."
-#: builtin/clone.c:706
-#: builtin/clone.c:720
+#: builtin/clone.c:709 builtin/clone.c:723
#, c-format
msgid "could not create leading directories of '%s'"
msgstr "không thể tạo các thư mục dẫn đầu của '%s'"
-#: builtin/clone.c:709
+#: builtin/clone.c:712
#, c-format
msgid "could not create work tree dir '%s'."
msgstr "không thể tạo cây thư mục làm việc dir '%s'."
-#: builtin/clone.c:728
+#: builtin/clone.c:731
#, c-format
msgid "Cloning into bare repository '%s'...\n"
msgstr "Äang nhân bản thành kho chứa bare '%s'...\n"
-#: builtin/clone.c:730
+#: builtin/clone.c:733
#, c-format
msgid "Cloning into '%s'...\n"
msgstr "Äang nhân bản thành '%s'...\n"
-#: builtin/clone.c:786
+#: builtin/clone.c:789
#, c-format
msgid "Don't know how to clone %s"
msgstr "Không biết làm cách nào để nhân bản (clone) %s"
-#: builtin/clone.c:835
+#: builtin/clone.c:838
#, c-format
msgid "Remote branch %s not found in upstream %s"
msgstr "Nhánh máy chủ %s không tìm thấy trong dòng ngược (upstream) %s"
-#: builtin/clone.c:842
+#: builtin/clone.c:845
msgid "You appear to have cloned an empty repository."
msgstr "Bạn hình như là đã nhân bản một kho trống rỗng."
@@ -2147,14 +2519,18 @@ msgid ""
"\n"
" git commit --amend --reset-author\n"
msgstr ""
-"Tên và địa chỉ thư điện tử của bạn được cấu hình một cách tự động trên cơ sở\n"
-"tài khoản và địa chỉ máy chủ của bạn. Xin hãy kiểm tra xem chúng có chính xác không.\n"
-"Bạn có thể chặn những thông báo kiểu này bằng cách cài đặt các thông tin trên một cách rõ ràng:\n"
+"Tên và địa chỉ thư điện tử của bạn được cấu hình một cách tự động trên cơ "
+"sở\n"
+"tài khoản và địa chỉ máy chủ của bạn. Xin hãy kiểm tra xem chúng có chính "
+"xác không.\n"
+"Bạn có thể chặn những thông báo kiểu này bằng cách cài đặt các thông tin "
+"trên một cách rõ ràng:\n"
"\n"
" git config --global user.name \"Tên của bạn\"\n"
" git config --global user.email you@example.com\n"
"\n"
-"Sau khi thực hiện xong, bạn có thể sửa chữa định danh được sử dụng cho lần chuyển giao (commit) này với lệnh:\n"
+"Sau khi thực hiện xong, bạn có thể sửa chữa định danh được sử dụng cho lần "
+"chuyển giao (commit) này với lệnh:\n"
"\n"
" git commit --amend --reset-author\n"
@@ -2164,8 +2540,10 @@ msgid ""
"it empty. You can repeat your command with --allow-empty, or you can\n"
"remove the commit entirely with \"git reset HEAD^\".\n"
msgstr ""
-"Bạn đã yêu cầu amend (tu bổ) phần lớn các lần chuyển giao (commit) gần đây, nhưng làm như thế\n"
-"có thể làm cho nó trở nên trống rỗng. Bạn có thể lặp lại lệnh của mình bằng --allow-empty,\n"
+"Bạn đã yêu cầu amend (tu bổ) phần lớn các lần chuyển giao (commit) gần đây, "
+"nhưng làm như thế\n"
+"có thể làm cho nó trở nên trống rỗng. Bạn có thể lặp lại lệnh của mình bằng "
+"--allow-empty,\n"
"hoặc là bạn gỡ bỠcác lần chuyển giao một cách hoàn toàn bằng lệnh:\n"
"\"git reset HEAD^\".\n"
@@ -2178,106 +2556,105 @@ msgid ""
"\n"
"Otherwise, please use 'git reset'\n"
msgstr ""
-"Lần cherry-pick trước hiện nay trống rỗng, có lẽ là bởi vì sự phân giải xung đột.\n"
+"Lần cherry-pick trước hiện nay trống rỗng, có lẽ là bởi vì sự phân giải xung "
+"Ä‘á»™t.\n"
"Nếu bạn muốn chuyển giao nó cho dù thế nào đi nữa, sử dụng:\n"
"\n"
" git commit --allow-empty\n"
"\n"
-"Nếu không, hãy thử sử dụng 'git reset'\n"
+"Nếu không, hãy thử dùng 'git reset'\n"
-#: builtin/commit.c:253
+#: builtin/commit.c:256
msgid "failed to unpack HEAD tree object"
msgstr "gặp lỗi khi tháo dỡ HEAD đối tượng cây"
-#: builtin/commit.c:295
+#: builtin/commit.c:298
msgid "unable to create temporary index"
msgstr "không thể tạo bảng mục lục tạm thá»i"
-#: builtin/commit.c:301
+#: builtin/commit.c:304
msgid "interactive add failed"
msgstr "việc thêm tương tác gặp lỗi"
-#: builtin/commit.c:334
-#: builtin/commit.c:355
-#: builtin/commit.c:405
+#: builtin/commit.c:337 builtin/commit.c:358 builtin/commit.c:408
msgid "unable to write new_index file"
msgstr "không thể ghi tập tin lưu bảng mục lục mới (new_index)"
-#: builtin/commit.c:386
+#: builtin/commit.c:389
msgid "cannot do a partial commit during a merge."
-msgstr "không thể thực hiện việc chuyển giao (commit) cục bộ trong khi đang được hòa trộn."
+msgstr ""
+"không thể thực hiện việc chuyển giao (commit) cục bộ trong khi đang được hòa "
+"trá»™n."
-#: builtin/commit.c:388
+#: builtin/commit.c:391
msgid "cannot do a partial commit during a cherry-pick."
-msgstr "không thể thực hiện việc chuyển giao (commit) bộ phận trong khi đang cherry-pick."
+msgstr ""
+"không thể thực hiện việc chuyển giao (commit) bộ phận trong khi đang cherry-"
+"pick."
-#: builtin/commit.c:398
+#: builtin/commit.c:401
msgid "cannot read the index"
msgstr "không Ä‘á»c được bảng mục lục"
-#: builtin/commit.c:418
+#: builtin/commit.c:421
msgid "unable to write temporary index file"
msgstr "không thể ghi tập tin lÆ°u bảng mục lục tạm thá»i"
-#: builtin/commit.c:493
-#: builtin/commit.c:499
+#: builtin/commit.c:496 builtin/commit.c:502
#, c-format
msgid "invalid commit: %s"
msgstr "lần chuyển giao (commit) không hợp lệ: %s"
-#: builtin/commit.c:522
+#: builtin/commit.c:525
msgid "malformed --author parameter"
msgstr "đối số --author bị dị hình"
-#: builtin/commit.c:582
+#: builtin/commit.c:585
#, c-format
msgid "Malformed ident string: '%s'"
msgstr "Chuỗi thụt lỠđầu dòng dị hình: '%s'"
-#: builtin/commit.c:620
-#: builtin/commit.c:653
-#: builtin/commit.c:967
+#: builtin/commit.c:623 builtin/commit.c:656 builtin/commit.c:970
#, c-format
msgid "could not lookup commit %s"
msgstr "không thể tìm kiếm commit (lần chuyển giao) %s"
-#: builtin/commit.c:632
-#: builtin/shortlog.c:296
+#: builtin/commit.c:635 builtin/shortlog.c:296
#, c-format
msgid "(reading log message from standard input)\n"
msgstr "(Ä‘ang Ä‘á»c thông Ä‘iệp nhật ký từ đầu vào tiêu chuẩn)\n"
-#: builtin/commit.c:634
+#: builtin/commit.c:637
msgid "could not read log from standard input"
msgstr "không thể Ä‘á»c nhật ký từ đầu vào tiêu chuẩn"
-#: builtin/commit.c:638
+#: builtin/commit.c:641
#, c-format
msgid "could not read log file '%s'"
msgstr "không Ä‘á»c được tệp nhật ký '%s'"
-#: builtin/commit.c:644
+#: builtin/commit.c:647
msgid "commit has empty message"
msgstr "lần chuyển giao (commit) có ghi chú trống rỗng"
-#: builtin/commit.c:660
+#: builtin/commit.c:663
msgid "could not read MERGE_MSG"
msgstr "không thể Ä‘á»c MERGE_MSG"
-#: builtin/commit.c:664
+#: builtin/commit.c:667
msgid "could not read SQUASH_MSG"
msgstr "không thể Ä‘á»c SQUASH_MSG"
-#: builtin/commit.c:668
+#: builtin/commit.c:671
#, c-format
msgid "could not read '%s'"
msgstr "Không thể Ä‘á»c '%s'."
-#: builtin/commit.c:720
+#: builtin/commit.c:723
msgid "could not write commit template"
msgstr "không thể ghi mẫu commit"
-#: builtin/commit.c:731
+#: builtin/commit.c:734
#, c-format
msgid ""
"\n"
@@ -2292,7 +2669,7 @@ msgstr ""
"\t%s\n"
"và thử lại.\n"
-#: builtin/commit.c:736
+#: builtin/commit.c:739
#, c-format
msgid ""
"\n"
@@ -2307,182 +2684,191 @@ msgstr ""
"\t%s\n"
"và thử lại.\n"
-#: builtin/commit.c:748
+#: builtin/commit.c:751
msgid ""
"Please enter the commit message for your changes. Lines starting\n"
"with '#' will be ignored, and an empty message aborts the commit.\n"
msgstr ""
-"Hãy nhập vào các thông tin để giải thích các thay đổi của bạn. Những dòng được\n"
-"bắt đầu bằng '#' sẽ được bỠqua, phần chú thích này nếu rỗng sẽ làm hủy bỠlần chuyển giao (commit).\n"
+"Hãy nhập vào các thông tin để giải thích các thay đổi của bạn. Những dòng "
+"được\n"
+"bắt đầu bằng '#' sẽ được bỠqua, phần chú thích này nếu rỗng sẽ làm hủy bỠ"
+"lần chuyển giao (commit).\n"
-#: builtin/commit.c:753
+#: builtin/commit.c:756
msgid ""
"Please enter the commit message for your changes. Lines starting\n"
"with '#' will be kept; you may remove them yourself if you want to.\n"
"An empty message aborts the commit.\n"
msgstr ""
-"Hãy nhập vào các thông tin để giải thích các thay đổi của bạn.Những dòng được\n"
+"Hãy nhập vào các thông tin để giải thích các thay đổi của bạn.Những dòng "
+"được\n"
"bắt đầu bằng '#' sẽ được bỠqua; bạn có thể xóa chúng đi nếu muốn.\n"
"Phần chú thích này nếu rỗng sẽ làm hủy bỠlần chuyển giao (commit).\n"
-#: builtin/commit.c:766
+#: builtin/commit.c:769
#, c-format
msgid "%sAuthor: %s"
msgstr "%sTác giả: %s"
-#: builtin/commit.c:773
+#: builtin/commit.c:776
#, c-format
msgid "%sCommitter: %s"
msgstr "%sNgÆ°á»i chuyển giao (commit): %s"
-#: builtin/commit.c:793
+#: builtin/commit.c:796
msgid "Cannot read index"
msgstr "không Ä‘á»c được bảng mục lục"
-#: builtin/commit.c:830
+#: builtin/commit.c:833
msgid "Error building trees"
msgstr "Gặp lỗi khi xây dựng cây"
-#: builtin/commit.c:845
-#: builtin/tag.c:361
+#: builtin/commit.c:848 builtin/tag.c:361
#, c-format
msgid "Please supply the message using either -m or -F option.\n"
msgstr "Xin hãy áp dụng thông Ä‘iệp sá»­ dụng hoặc là tùy chá»n -m hoặc là -F.\n"
-#: builtin/commit.c:942
+#: builtin/commit.c:945
#, c-format
msgid "No existing author found with '%s'"
-msgstr "Không tìm thấy tác giả đã sẵn có với '%s'"
+msgstr "Không tìm thấy tác giả có sẵn với '%s'"
-#: builtin/commit.c:957
-#: builtin/commit.c:1157
+#: builtin/commit.c:960 builtin/commit.c:1160
#, c-format
msgid "Invalid untracked files mode '%s'"
msgstr "Chế độ cho các tập tin không bị theo vết không hợp lệ '%s'"
-#: builtin/commit.c:997
+#: builtin/commit.c:1000
msgid "Using both --reset-author and --author does not make sense"
msgstr "Sá»­ dụng cả hai tùy chá»n --reset-author và --author không hợp lý"
-#: builtin/commit.c:1008
+#: builtin/commit.c:1011
msgid "You have nothing to amend."
msgstr "Không có gì để amend (tu bổ) cả."
-#: builtin/commit.c:1011
+#: builtin/commit.c:1014
msgid "You are in the middle of a merge -- cannot amend."
-msgstr "Bạn đang ở giữa của quá trình hòa trộn -- không thể thực hiện amend (tu bổ)."
+msgstr ""
+"Bạn đang ở giữa của quá trình hòa trộn -- không thể thực hiện amend (tu bổ)."
-#: builtin/commit.c:1013
+#: builtin/commit.c:1016
msgid "You are in the middle of a cherry-pick -- cannot amend."
-msgstr "Bạn đang ở giữa của quá trình cherry-pick -- không thể thực hiện amend (tu bổ)."
+msgstr ""
+"Bạn đang ở giữa của quá trình cherry-pick -- không thể thực hiện amend (tu "
+"bổ)."
-#: builtin/commit.c:1016
+#: builtin/commit.c:1019
msgid "Options --squash and --fixup cannot be used together"
msgstr "Các tùy chá»n --squash và --fixup không thể sá»­ dụng cùng vá»›i nhau"
-#: builtin/commit.c:1026
+#: builtin/commit.c:1029
msgid "Only one of -c/-C/-F/--fixup can be used."
msgstr "Chỉ má»™t tùy chá»n trong số -c/-C/-F/--fixup được sá»­ dụng"
-#: builtin/commit.c:1028
+#: builtin/commit.c:1031
msgid "Option -m cannot be combined with -c/-C/-F/--fixup."
msgstr "Tùy chá»n -m không thể được tổ hợp cùng vá»›i -c/-C/-F/--fixup."
-#: builtin/commit.c:1036
+#: builtin/commit.c:1039
msgid "--reset-author can be used only with -C, -c or --amend."
-msgstr "--reset-author chỉ có thể được sá»­ dụng vá»›i tùy chá»n -C, -c hay --amend."
+msgstr ""
+"--reset-author chỉ có thể được sá»­ dụng vá»›i tùy chá»n -C, -c hay --amend."
-#: builtin/commit.c:1053
+#: builtin/commit.c:1056
msgid "Only one of --include/--only/--all/--interactive/--patch can be used."
-msgstr "Chỉ má»™t trong các tùy chá»n --include/--only/--all/--interactive/--patch được sá»­ dụng."
+msgstr ""
+"Chỉ má»™t trong các tùy chá»n --include/--only/--all/--interactive/--patch được "
+"sử dụng."
-#: builtin/commit.c:1055
+#: builtin/commit.c:1058
msgid "No paths with --include/--only does not make sense."
msgstr "Không Ä‘Æ°á»ng dẫn vá»›i các tùy chá»n --include/--only không hợp lý."
-#: builtin/commit.c:1057
+#: builtin/commit.c:1060
msgid "Clever... amending the last one with dirty index."
-msgstr "Giá»i... Ä‘ang tu bổ cái cuối vá»›i bảng mục lục phi nghÄ©a."
+msgstr "Giá»i... tu bổ cái cuối vá»›i bảng mục lục phi nghÄ©a."
-#: builtin/commit.c:1059
+#: builtin/commit.c:1062
msgid "Explicit paths specified without -i nor -o; assuming --only paths..."
-msgstr "Những Ä‘Æ°á»ng dẫn rõ ràng được chỉ ra không có tùy chá»n -i cÅ©ng không -o; Ä‘ang giả định --only những-Ä‘Æ°á»ng-dẫn..."
+msgstr ""
+"Những Ä‘Æ°á»ng dẫn rõ ràng được chỉ ra không có tùy chá»n -i cÅ©ng không -o; Ä‘ang "
+"giả định --only những-Ä‘Æ°á»ng-dẫn..."
-#: builtin/commit.c:1069
-#: builtin/tag.c:577
+#: builtin/commit.c:1072 builtin/tag.c:577
#, c-format
msgid "Invalid cleanup mode %s"
msgstr "Chế Ä‘á»™ dá»n dẹp không hợp lệ %s"
-#: builtin/commit.c:1074
+#: builtin/commit.c:1077
msgid "Paths with -a does not make sense."
msgstr "Các Ä‘Æ°á»ng dẫn vá»›i tùy chá»n -a không hợp lý."
-#: builtin/commit.c:1257
+#: builtin/commit.c:1260
msgid "couldn't look up newly created commit"
msgstr "không thể tìm thấy lần chuyển giao (commit) mới hơn đã được tạo"
-#: builtin/commit.c:1259
+#: builtin/commit.c:1262
msgid "could not parse newly created commit"
-msgstr "không thể phân tích cú pháp của đối tượng chuyển giao mới hơn đã được tạo"
+msgstr ""
+"không thể phân tích cú pháp của đối tượng chuyển giao mới hơn đã được tạo"
-#: builtin/commit.c:1300
+#: builtin/commit.c:1303
msgid "detached HEAD"
msgstr "đã rá»i khá»i HEAD"
-#: builtin/commit.c:1302
+#: builtin/commit.c:1305
msgid " (root-commit)"
msgstr " (root-commit)"
-#: builtin/commit.c:1446
+#: builtin/commit.c:1449
msgid "could not parse HEAD commit"
msgstr "không thể phân tích commit (lần chuyển giao) HEAD"
-#: builtin/commit.c:1484
-#: builtin/merge.c:509
+#: builtin/commit.c:1487 builtin/merge.c:508
#, c-format
msgid "could not open '%s' for reading"
msgstr "không thể mở %s' để Ä‘á»c"
-#: builtin/commit.c:1491
+#: builtin/commit.c:1494
#, c-format
msgid "Corrupt MERGE_HEAD file (%s)"
msgstr "Tập tin MERGE_HEAD sai há»ng (%s)"
-#: builtin/commit.c:1498
+#: builtin/commit.c:1501
msgid "could not read MERGE_MODE"
msgstr "không thể Ä‘á»c MERGE_MODE"
-#: builtin/commit.c:1517
+#: builtin/commit.c:1520
#, c-format
msgid "could not read commit message: %s"
msgstr "không thể Ä‘á»c thông Ä‘iệp (message) commit (lần chuyển giao): %s"
-#: builtin/commit.c:1531
+#: builtin/commit.c:1534
#, c-format
msgid "Aborting commit; you did not edit the message.\n"
-msgstr "Äang bá» qua việc chuyển giao (commit); bạn đã không biên soạn thông Ä‘iệp (message).\n"
+msgstr ""
+"Äang bá» qua việc chuyển giao (commit); bạn đã không biên soạn thông Ä‘iệp "
+"(message).\n"
-#: builtin/commit.c:1536
+#: builtin/commit.c:1539
#, c-format
msgid "Aborting commit due to empty commit message.\n"
-msgstr "Äang bá» qua lần chuyển giao (commit) bởi vì thông Ä‘iệp của nó trống rá»—ng.\n"
+msgstr ""
+"Äang bá» qua lần chuyển giao (commit) bởi vì thông Ä‘iệp của nó trống rá»—ng.\n"
-#: builtin/commit.c:1551
-#: builtin/merge.c:936
-#: builtin/merge.c:961
+#: builtin/commit.c:1554 builtin/merge.c:935 builtin/merge.c:960
msgid "failed to write commit object"
msgstr "gặp lỗi khi ghi đối tượng chuyển giao (commit)"
-#: builtin/commit.c:1572
+#: builtin/commit.c:1575
msgid "cannot lock HEAD ref"
msgstr "không thể khóa HEAD ref (tham chiếu)"
-#: builtin/commit.c:1576
+#: builtin/commit.c:1579
msgid "cannot update HEAD ref"
-msgstr "không thể cập nhật HEAD ref (tham chiếu)"
+msgstr "không thể cập nhật ref (tham chiếu) HEAD"
-#: builtin/commit.c:1587
+#: builtin/commit.c:1590
msgid ""
"Repository has been updated, but unable to write\n"
"new_index file. Check that disk is not full or quota is\n"
@@ -2490,7 +2876,8 @@ msgid ""
msgstr ""
"Kho chứa đã hoàn tất việc cập nhật, nhưng không thể ghi vào\n"
"tập tin new_index (bảng mục lục mới). Hãy kiểm tra xem đĩa có bị đầy quá\n"
-"hay quota (hạn nghạch đĩa cứng) bị vượt quá, và sau đó \"git reset HEAD\" để khắc phục."
+"hay quota (hạn nghạch đĩa cứng) bị vượt quá, và sau đó \"git reset HEAD\" để "
+"khắc phục."
#: builtin/describe.c:234
#, c-format
@@ -2576,36 +2963,36 @@ msgstr "Không tìm thấy các tên, không thể mô tả gì cả."
msgid "--dirty is incompatible with committishes"
msgstr "--dirty là xung khắc vá»›i các tùy chá»n dành cho chuyển giao (commit)"
-#: builtin/diff.c:77
+#: builtin/diff.c:79
#, c-format
msgid "'%s': not a regular file or symlink"
msgstr "'%s': không phải tập tin bình thÆ°á»ng hay liên kết tượng trÆ°ng"
-#: builtin/diff.c:220
+#: builtin/diff.c:224
#, c-format
msgid "invalid option: %s"
msgstr "tùy chá»n sai: %s"
-#: builtin/diff.c:297
+#: builtin/diff.c:301
msgid "Not a git repository"
msgstr "Không phải là kho git"
-#: builtin/diff.c:347
+#: builtin/diff.c:344
#, c-format
msgid "invalid object '%s' given."
msgstr "đối tượng đã cho '%s' không hợp lệ."
-#: builtin/diff.c:352
+#: builtin/diff.c:349
#, c-format
msgid "more than %d trees given: '%s'"
msgstr "đã chỉ ra nhiá»u hÆ¡n %d cây (tree): '%s'"
-#: builtin/diff.c:362
+#: builtin/diff.c:359
#, c-format
msgid "more than two blobs given: '%s'"
msgstr "đã cho nhiá»u hÆ¡n hai đối tượng blob: '%s'"
-#: builtin/diff.c:370
+#: builtin/diff.c:367
#, c-format
msgid "unhandled object '%s' given."
msgstr "đã cho đối tượng không thể nắm giữ '%s'."
@@ -2626,10 +3013,9 @@ msgstr "[đã cập nhật]"
#: builtin/fetch.c:273
#, c-format
msgid "! %-*s %-*s -> %s (can't fetch in current branch)"
-msgstr "! %-*s %-*s -> %s (không thể fetch (lấy vá») trong nhánh hiện hành)"
+msgstr "! %-*s %-*s -> %s (không thể fetch (lấy) vỠnhánh hiện hành)"
-#: builtin/fetch.c:274
-#: builtin/fetch.c:360
+#: builtin/fetch.c:274 builtin/fetch.c:360
msgid "[rejected]"
msgstr "[Bị từ chối]"
@@ -2637,9 +3023,7 @@ msgstr "[Bị từ chối]"
msgid "[tag update]"
msgstr "[cập nhật thẻ]"
-#: builtin/fetch.c:287
-#: builtin/fetch.c:322
-#: builtin/fetch.c:340
+#: builtin/fetch.c:287 builtin/fetch.c:322 builtin/fetch.c:340
msgid " (unable to update local ref)"
msgstr " (không thể cập nhật tham chiếu (ref) nội bộ)"
@@ -2667,8 +3051,7 @@ msgstr "cưỡng bức cập nhật"
msgid "(non-fast-forward)"
msgstr "(non-fast-forward)"
-#: builtin/fetch.c:393
-#: builtin/fetch.c:685
+#: builtin/fetch.c:393 builtin/fetch.c:685
#, c-format
msgid "cannot open %s: %s\n"
msgstr "không thể mở %s: %s\n"
@@ -2695,26 +3078,27 @@ msgstr ""
#: builtin/fetch.c:549
#, c-format
msgid " (%s will become dangling)"
-msgstr " (%s sẽ trở thành lủng lẳng (không được quản lý))"
+msgstr " (%s sẽ trở thành không đầu (không được quản lý))"
#: builtin/fetch.c:550
#, c-format
msgid " (%s has become dangling)"
-msgstr " (%s phải trở thành lủng lẳng (không được quản lý))"
+msgstr " (%s đã trở thành không đầu (không được quản lý))"
#: builtin/fetch.c:557
msgid "[deleted]"
msgstr "[đã xóa]"
-#: builtin/fetch.c:558
-#: builtin/remote.c:1055
+#: builtin/fetch.c:558 builtin/remote.c:1055
msgid "(none)"
msgstr "(không)"
#: builtin/fetch.c:675
#, c-format
msgid "Refusing to fetch into current branch %s of non-bare repository"
-msgstr "Từ chối việc lấy (fetch) vào trong nhánh hiện tại %s của một kho chứa không phải kho trần (bare)"
+msgstr ""
+"Từ chối việc lấy (fetch) vào trong nhánh hiện tại %s của một kho chứa không "
+"phải kho trần (bare)"
#: builtin/fetch.c:709
#, c-format
@@ -2736,8 +3120,7 @@ msgstr "Tùy chá»n \"%s\" bị bá» qua vá»›i %s\n"
msgid "Fetching %s\n"
msgstr "Äang lấy (fetch) %s\n"
-#: builtin/fetch.c:890
-#: builtin/remote.c:100
+#: builtin/fetch.c:890 builtin/remote.c:100
#, c-format
msgid "Could not fetch %s"
msgstr "không thể fetch (lấy) %s"
@@ -2756,11 +3139,11 @@ msgstr "Bạn phải định rõ tên thẻ."
#: builtin/fetch.c:979
msgid "fetch --all does not take a repository argument"
-msgstr "lệnh lấy vá» sá»­ dụng tùy chá»n --all sẽ không lấy đối số kho chứa"
+msgstr "lệnh lấy vỠ\"fetch --all\" không lấy đối số kho chứa"
#: builtin/fetch.c:981
msgid "fetch --all does not make sense with refspecs"
-msgstr "lệnh lấy vá» fetch sá»­ dụng tùy chá»n --all không hợp lý vá»›i refspecs"
+msgstr "lệnh lấy vỠ\"fetch --all\" không hợp lý với refspecs"
#: builtin/fetch.c:992
#, c-format
@@ -2793,99 +3176,101 @@ msgid ""
"run \"git gc\" manually. See \"git help gc\" for more information.\n"
msgstr ""
"Tự động đóng gói kho chứa để tối ưu hóa hiệu suất làm việc.\n"
-"chạy lệnh \"git gc\" một cách thủ công. Hãy xem \"git help gc\" để biết thêm chi tiết.\n"
+"chạy lệnh \"git gc\" một cách thủ công. Hãy xem \"git help gc\" để biết thêm "
+"chi tiết.\n"
#: builtin/gc.c:251
-msgid "There are too many unreachable loose objects; run 'git prune' to remove them."
-msgstr "Có quá nhiá»u đối tượng tá»± do không được dùng đến; hãy chạy lệnh 'git prune' để xóa bá» chúng Ä‘i."
+msgid ""
+"There are too many unreachable loose objects; run 'git prune' to remove them."
+msgstr ""
+"Có quá nhiá»u đối tượng tá»± do không được dùng đến; hãy chạy lệnh 'git prune' "
+"để xóa bỠchúng đi."
#: builtin/grep.c:216
#, c-format
msgid "grep: failed to create thread: %s"
msgstr "grep: gặp lỗi tạo tuyến (thread): %s"
-#: builtin/grep.c:402
+#: builtin/grep.c:454
#, c-format
msgid "Failed to chdir: %s"
msgstr "Gặp lỗi với lệnh chdir: %s"
-#: builtin/grep.c:478
-#: builtin/grep.c:512
+#: builtin/grep.c:530 builtin/grep.c:564
#, c-format
msgid "unable to read tree (%s)"
msgstr "không thể Ä‘á»c cây (%s)"
-#: builtin/grep.c:526
+#: builtin/grep.c:578
#, c-format
msgid "unable to grep from object of type %s"
msgstr "không thể thá»±c hiện lệnh grep (lá»c tìm) từ đối tượng thuá»™c kiểu %s"
-#: builtin/grep.c:584
+#: builtin/grep.c:636
#, c-format
msgid "switch `%c' expects a numerical value"
msgstr "chuyển đến `%c' mong chỠmột giá trị bằng số"
-#: builtin/grep.c:601
+#: builtin/grep.c:653
#, c-format
msgid "cannot open '%s'"
msgstr "không mở được '%s'"
-#: builtin/grep.c:885
+#: builtin/grep.c:917
msgid "no pattern given."
msgstr "chưa chỉ ra mẫu."
-#: builtin/grep.c:899
+#: builtin/grep.c:931
#, c-format
msgid "bad object %s"
msgstr "đối tượng sai %s"
-#: builtin/grep.c:940
+#: builtin/grep.c:972
msgid "--open-files-in-pager only works on the worktree"
msgstr "--open-files-in-pager chỉ làm việc trên cây-làm-việc"
-#: builtin/grep.c:963
+#: builtin/grep.c:995
msgid "--cached or --untracked cannot be used with --no-index."
msgstr "--cached hay --untracked không được sử dụng với --no-index."
-#: builtin/grep.c:968
+#: builtin/grep.c:1000
msgid "--no-index or --untracked cannot be used with revs."
-msgstr "--no-index hay --untracked không được sá»­ dụng cùng vá»›i các tùy chá»n liên quan đến revs."
+msgstr ""
+"--no-index hay --untracked không được sá»­ dụng cùng vá»›i các tùy chá»n liên "
+"quan đến revs."
-#: builtin/grep.c:971
+#: builtin/grep.c:1003
msgid "--[no-]exclude-standard cannot be used for tracked contents."
msgstr "--[no-]exclude-standard không thể sử dụng cho nội dung lưu dấu vết."
-#: builtin/grep.c:979
+#: builtin/grep.c:1011
msgid "both --cached and trees are given."
msgstr "cả hai --cached và các cây phải được chỉ ra."
-#: builtin/help.c:59
+#: builtin/help.c:65
#, c-format
msgid "unrecognized help format '%s'"
msgstr "không nhận ra định dạng trợ giúp '%s'"
-#: builtin/help.c:87
+#: builtin/help.c:93
msgid "Failed to start emacsclient."
msgstr "Lỗi khởi chạy emacsclient."
-#: builtin/help.c:100
+#: builtin/help.c:106
msgid "Failed to parse emacsclient version."
msgstr "Gặp lỗi khi phân tích phiên bản emacsclient."
-#: builtin/help.c:108
+#: builtin/help.c:114
#, c-format
msgid "emacsclient version '%d' too old (< 22)."
msgstr "phiên bản của emacsclient '%d' quá cũ (< 22)."
-#: builtin/help.c:126
-#: builtin/help.c:154
-#: builtin/help.c:163
-#: builtin/help.c:171
+#: builtin/help.c:132 builtin/help.c:160 builtin/help.c:169 builtin/help.c:177
#, c-format
msgid "failed to exec '%s': %s"
msgstr "gặp lỗi khi thực thi '%s': %s"
-#: builtin/help.c:211
+#: builtin/help.c:217
#, c-format
msgid ""
"'%s': path for unsupported man viewer.\n"
@@ -2894,7 +3279,7 @@ msgstr ""
"'%s': Ä‘Æ°á»ng dẫn không há»— trợ bá»™ trình chiếu man.\n"
"Hãy cân nhắc đến việc sử dụng 'man.<tool>.cmd' để thay thế."
-#: builtin/help.c:223
+#: builtin/help.c:229
#, c-format
msgid ""
"'%s': cmd for supported man viewer.\n"
@@ -2903,271 +3288,272 @@ msgstr ""
"'%s': cmd (lệnh) hỗ trợ bộ trình chiếu man.\n"
"Hãy cân nhắc đến việc sử dụng 'man.<tool>.path' để thay thế."
-#: builtin/help.c:287
+#: builtin/help.c:299
msgid "The most commonly used git commands are:"
msgstr "Những lệnh git hay được sử dụng nhất là:"
-#: builtin/help.c:355
+#: builtin/help.c:367
#, c-format
msgid "'%s': unknown man viewer."
msgstr "'%s': không rõ chương trình xem man."
-#: builtin/help.c:372
+#: builtin/help.c:384
msgid "no man viewer handled the request"
msgstr "không có trình xem trợ giúp dạng manpage tiếp hợp với yêu cầu"
-#: builtin/help.c:380
+#: builtin/help.c:392
msgid "no info viewer handled the request"
msgstr "không có trình xem trợ giúp dạng info tiếp hợp với yêu cầu"
-#: builtin/help.c:391
-#, c-format
-msgid "'%s': not a documentation directory."
-msgstr "'%s': không phải là một thư mục tài liệu."
-
-#: builtin/help.c:432
-#: builtin/help.c:439
+#: builtin/help.c:447 builtin/help.c:454
#, c-format
msgid "usage: %s%s"
msgstr "cách sử dụng: %s%s"
-#: builtin/help.c:453
+#: builtin/help.c:470
#, c-format
msgid "`git %s' is aliased to `%s'"
msgstr "`git %s' được đặt bí danh thành `%s'"
-#: builtin/index-pack.c:169
+#: builtin/index-pack.c:170
#, c-format
msgid "object type mismatch at %s"
msgstr "kiểu đối tượng không khớp tại %s"
-#: builtin/index-pack.c:189
+#: builtin/index-pack.c:190
msgid "object of unexpected type"
msgstr "đối tượng của kiểu không mong đợi"
-#: builtin/index-pack.c:226
+#: builtin/index-pack.c:227
#, c-format
msgid "cannot fill %d byte"
msgid_plural "cannot fill %d bytes"
msgstr[0] "không thể Ä‘iá»n vào %d byte"
msgstr[1] "không thể Ä‘iá»n vào %d byte"
-#: builtin/index-pack.c:236
+#: builtin/index-pack.c:237
msgid "early EOF"
msgstr "vừa đúng lúc EOF"
-#: builtin/index-pack.c:237
+#: builtin/index-pack.c:238
msgid "read error on input"
msgstr "lá»—i Ä‘á»c ở đầu vào"
-#: builtin/index-pack.c:249
+#: builtin/index-pack.c:250
msgid "used more bytes than were available"
msgstr "sá»­ dụng nhiá»u hÆ¡n số lượng byte mà nó sẵn có"
-#: builtin/index-pack.c:256
+#: builtin/index-pack.c:257
msgid "pack too large for current definition of off_t"
msgstr "pack quá lớn so với định nghĩa hiện tại của kiểu off_t"
-#: builtin/index-pack.c:272
+#: builtin/index-pack.c:273
#, c-format
msgid "unable to create '%s'"
msgstr "không thể tạo '%s'"
-#: builtin/index-pack.c:277
+#: builtin/index-pack.c:278
#, c-format
msgid "cannot open packfile '%s'"
msgstr "không thể mở packfile '%s'"
-#: builtin/index-pack.c:291
+#: builtin/index-pack.c:292
msgid "pack signature mismatch"
msgstr "chữ ký cho pack không khớp"
-#: builtin/index-pack.c:311
+#: builtin/index-pack.c:312
#, c-format
msgid "pack has bad object at offset %lu: %s"
msgstr "pack có đối tượng sai khoảng bù (offset) %lu: %s"
-#: builtin/index-pack.c:405
+#: builtin/index-pack.c:434
#, c-format
msgid "inflate returned %d"
msgstr "xả nén trả vỠ%d"
-#: builtin/index-pack.c:450
+#: builtin/index-pack.c:483
msgid "offset value overflow for delta base object"
msgstr "tràn giá trị khoảng bù cho đối tượng delta cơ sở"
-#: builtin/index-pack.c:458
+#: builtin/index-pack.c:491
msgid "delta base offset is out of bound"
msgstr "khoảng bù cơ sở cho delta nằm ngoài phạm vi"
-#: builtin/index-pack.c:466
+#: builtin/index-pack.c:499
#, c-format
msgid "unknown object type %d"
msgstr "không hiểu kiểu đối tượng %d"
-#: builtin/index-pack.c:495
+#: builtin/index-pack.c:530
msgid "cannot pread pack file"
msgstr "không thể chạy hàm pread cho tập tin pack"
-#: builtin/index-pack.c:497
+#: builtin/index-pack.c:532
#, c-format
msgid "premature end of pack file, %lu byte missing"
msgid_plural "premature end of pack file, %lu bytes missing"
msgstr[0] "tập tin pack bị kết thúc sớm, %lu byte bị thiếu"
msgstr[1] "tập tin pack bị kết thúc sớm, %lu byte bị thiếu"
-#: builtin/index-pack.c:510
+#: builtin/index-pack.c:558
msgid "serious inflate inconsistency"
msgstr "sá»± mâu thuẫn xả nén nghiêm trá»ng"
-#: builtin/index-pack.c:583
-#, c-format
-msgid "cannot read existing object %s"
-msgstr "không thể Ä‘á»c đối tượng đã tồn tại %s"
-
-#: builtin/index-pack.c:586
+#: builtin/index-pack.c:649 builtin/index-pack.c:655 builtin/index-pack.c:678
+#: builtin/index-pack.c:712 builtin/index-pack.c:721
#, c-format
msgid "SHA1 COLLISION FOUND WITH %s !"
msgstr "Sá»° VA CHẠM SHA1 ÄÃ XẢY RA VỚI %s!"
-#: builtin/index-pack.c:598
+#: builtin/index-pack.c:652 builtin/pack-objects.c:170
+#: builtin/pack-objects.c:262
+#, c-format
+msgid "unable to read %s"
+msgstr "không thể Ä‘á»c %s"
+
+#: builtin/index-pack.c:718
+#, c-format
+msgid "cannot read existing object %s"
+msgstr "không thể Ä‘á»c đối tượng đã tồn tại %s"
+
+#: builtin/index-pack.c:732
#, c-format
msgid "invalid blob object %s"
msgstr "đối tượng blob không hợp lệ %s"
-#: builtin/index-pack.c:610
+#: builtin/index-pack.c:747
#, c-format
msgid "invalid %s"
msgstr "%s không hợp lệ"
-#: builtin/index-pack.c:612
+#: builtin/index-pack.c:749
msgid "Error in object"
msgstr "Lỗi trong đối tượng"
-#: builtin/index-pack.c:614
+#: builtin/index-pack.c:751
#, c-format
msgid "Not all child objects of %s are reachable"
msgstr "Không phải tất cả các đối tượng con của %s là có thể với tới được"
-#: builtin/index-pack.c:687
-#: builtin/index-pack.c:713
+#: builtin/index-pack.c:821 builtin/index-pack.c:847
msgid "failed to apply delta"
msgstr "gặp lỗi khi áp dụng delta"
-#: builtin/index-pack.c:850
+#: builtin/index-pack.c:986
msgid "Receiving objects"
msgstr "Äang nhận vá» các đối tượng"
-#: builtin/index-pack.c:850
+#: builtin/index-pack.c:986
msgid "Indexing objects"
msgstr "Các đối tượng bảng mục lục"
-#: builtin/index-pack.c:872
+#: builtin/index-pack.c:1012
msgid "pack is corrupted (SHA1 mismatch)"
msgstr "pack bị sai há»ng (SHA1 không khá»›p)"
-#: builtin/index-pack.c:877
+#: builtin/index-pack.c:1017
msgid "cannot fstat packfile"
msgstr "không thể fstat packfile"
-#: builtin/index-pack.c:880
+#: builtin/index-pack.c:1020
msgid "pack has junk at the end"
msgstr "pack có phần thừa ở cuối"
-#: builtin/index-pack.c:903
+#: builtin/index-pack.c:1031
+msgid "confusion beyond insanity in parse_pack_objects()"
+msgstr "lộn xộn hơn cả điên rồ khi chạy hàm parse_pack_objects()"
+
+#: builtin/index-pack.c:1054
msgid "Resolving deltas"
msgstr "Äang phân giải các delta"
-#: builtin/index-pack.c:954
+#: builtin/index-pack.c:1105
msgid "confusion beyond insanity"
msgstr "lộn xộn hơn cả điên rồ"
-#: builtin/index-pack.c:973
+#: builtin/index-pack.c:1124
#, c-format
msgid "pack has %d unresolved delta"
msgid_plural "pack has %d unresolved deltas"
msgstr[0] "pack có %d delta chưa được giải quyết"
msgstr[1] "pack có %d delta chưa được giải quyết"
-#: builtin/index-pack.c:998
+#: builtin/index-pack.c:1149
#, c-format
msgid "unable to deflate appended object (%d)"
msgstr "không thể xả đối tượng nối thêm (%d)"
-#: builtin/index-pack.c:1077
+#: builtin/index-pack.c:1228
#, c-format
msgid "local object %s is corrupt"
msgstr "đối tượng ná»™i bá»™ %s bị há»ng"
-#: builtin/index-pack.c:1101
+#: builtin/index-pack.c:1252
msgid "error while closing pack file"
msgstr "gặp lỗi trong khi đóng tập tin pack"
-#: builtin/index-pack.c:1114
+#: builtin/index-pack.c:1265
#, c-format
msgid "cannot write keep file '%s'"
msgstr "không thể ghi tập tin giữ lại '%s'"
-#: builtin/index-pack.c:1122
+#: builtin/index-pack.c:1273
#, c-format
msgid "cannot close written keep file '%s'"
msgstr "không thể đóng tập tin giữ lại đã được ghi '%s'"
-#: builtin/index-pack.c:1135
+#: builtin/index-pack.c:1286
msgid "cannot store pack file"
msgstr "không thể lưu tập tin pack"
-#: builtin/index-pack.c:1146
+#: builtin/index-pack.c:1297
msgid "cannot store index file"
msgstr "không thể lưu trữ tập tin ghi mục lục"
-#: builtin/index-pack.c:1247
+#: builtin/index-pack.c:1398
#, c-format
msgid "Cannot open existing pack file '%s'"
-msgstr "Không thể mở tập tin pack đã sẵn có '%s' "
+msgstr "Không thể mở tập tin pack đã sẵn có '%s'"
-#: builtin/index-pack.c:1249
+#: builtin/index-pack.c:1400
#, c-format
msgid "Cannot open existing pack idx file for '%s'"
msgstr "Không thể mở tập tin 'pack idx' cho '%s'"
-#: builtin/index-pack.c:1296
+#: builtin/index-pack.c:1447
#, c-format
msgid "non delta: %d object"
msgid_plural "non delta: %d objects"
msgstr[0] "không delta: %d đối tượng"
msgstr[1] "không delta: %d đối tượng"
-#: builtin/index-pack.c:1303
+#: builtin/index-pack.c:1454
#, c-format
msgid "chain length = %d: %lu object"
msgid_plural "chain length = %d: %lu objects"
msgstr[0] "chiá»u dài xích = %d: %lu đối tượng"
msgstr[1] "chiá»u dài xích = %d: %lu đối tượng"
-#: builtin/index-pack.c:1330
+#: builtin/index-pack.c:1481
msgid "Cannot come back to cwd"
msgstr "Không thể quay lại cwd"
-#: builtin/index-pack.c:1374
-#: builtin/index-pack.c:1377
-#: builtin/index-pack.c:1389
-#: builtin/index-pack.c:1393
+#: builtin/index-pack.c:1525 builtin/index-pack.c:1528
+#: builtin/index-pack.c:1540 builtin/index-pack.c:1544
#, c-format
msgid "bad %s"
msgstr "%s sai"
-#: builtin/index-pack.c:1407
+#: builtin/index-pack.c:1558
msgid "--fix-thin cannot be used without --stdin"
msgstr "--fix-thin không thể được dùng mà không có --stdin"
-#: builtin/index-pack.c:1411
-#: builtin/index-pack.c:1421
+#: builtin/index-pack.c:1562 builtin/index-pack.c:1572
#, c-format
msgid "packfile name '%s' does not end with '.pack'"
msgstr "tên tập tin packfile '%s' không được kết thúc bằng đuôi '.pack'"
-#: builtin/index-pack.c:1430
+#: builtin/index-pack.c:1581
msgid "--verify with no packfile name given"
msgstr "dùng tùy chá»n --verify mà không Ä‘Æ°a ra tên packfile"
@@ -3241,23 +3627,22 @@ msgstr "không sao chép các mẫu của phiên bản sai định dạng %d tá»
msgid "insane git directory %s"
msgstr "thư mục git điên rồ %s"
-#: builtin/init-db.c:322
-#: builtin/init-db.c:325
+#: builtin/init-db.c:323 builtin/init-db.c:326
#, c-format
msgid "%s already exists"
-msgstr "%s đã tồn tại rồi"
+msgstr "%s đã có từ trước rồi"
-#: builtin/init-db.c:354
+#: builtin/init-db.c:355
#, c-format
msgid "unable to handle file type %d"
-msgstr "không thể handle tệp tin kiểu %d"
+msgstr "không thể nắm (handle) tập tin kiểu %d"
-#: builtin/init-db.c:357
+#: builtin/init-db.c:358
#, c-format
msgid "unable to move %s to %s"
msgstr "không di chuyển được %s vào %s"
-#: builtin/init-db.c:362
+#: builtin/init-db.c:363
#, c-format
msgid "Could not create git link %s"
msgstr "Không thể tạo liên kết git '%s'"
@@ -3267,148 +3652,151 @@ msgstr "Không thể tạo liên kết git '%s'"
#. * existing" or "Initialized empty", the second " shared" or
#. * "", and the last '%s%s' is the verbatim directory name.
#.
-#: builtin/init-db.c:419
+#: builtin/init-db.c:420
#, c-format
msgid "%s%s Git repository in %s%s\n"
msgstr "%s%s kho Git trong %s%s\n"
-#: builtin/init-db.c:420
+#: builtin/init-db.c:421
msgid "Reinitialized existing"
msgstr "Khởi tạo lại đã sẵn có rồi"
-#: builtin/init-db.c:420
+#: builtin/init-db.c:421
msgid "Initialized empty"
msgstr "Khởi tạo trống rỗng"
-#: builtin/init-db.c:421
+#: builtin/init-db.c:422
msgid " shared"
msgstr " đã chia sẻ"
-#: builtin/init-db.c:440
+#: builtin/init-db.c:441
msgid "cannot tell cwd"
msgstr "không nói chuyện được với lệnh cwd"
-#: builtin/init-db.c:521
-#: builtin/init-db.c:528
+#: builtin/init-db.c:522 builtin/init-db.c:529
#, c-format
msgid "cannot mkdir %s"
msgstr "không thể mkdir (tạo thư mục): %s"
-#: builtin/init-db.c:532
+#: builtin/init-db.c:533
#, c-format
msgid "cannot chdir to %s"
msgstr "không thể chdir (chuyển đổi thư mục) sang %s"
-#: builtin/init-db.c:554
+#: builtin/init-db.c:555
#, c-format
-msgid "%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-dir=<directory>)"
-msgstr "%s (hoặc --work-tree=<thư-mục>) không cho phép không chỉ định %s (hoặc --git-dir=<thư-mục>)"
+msgid ""
+"%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-"
+"dir=<directory>)"
+msgstr ""
+"%s (hoặc --work-tree=<thư-mục>) không cho phép không chỉ định %s (hoặc --git-"
+"dir=<thư-mục>)"
-#: builtin/init-db.c:578
+#: builtin/init-db.c:579
msgid "Cannot access current working directory"
msgstr "Không thể truy cập thư mục làm việc hiện hành"
-#: builtin/init-db.c:585
+#: builtin/init-db.c:586
#, c-format
msgid "Cannot access work tree '%s'"
msgstr "không thể truy cập cây (tree) làm việc '%s'"
-#: builtin/log.c:188
+#: builtin/log.c:189
#, c-format
msgid "Final output: %d %s\n"
msgstr "Kết xuất cuối cùng: %d %s\n"
-#: builtin/log.c:401
-#: builtin/log.c:489
+#: builtin/log.c:403 builtin/log.c:494
#, c-format
msgid "Could not read object %s"
msgstr "Không thể Ä‘á»c đối tượng %s"
-#: builtin/log.c:513
+#: builtin/log.c:518
#, c-format
msgid "Unknown type: %d"
msgstr "Không nhận ra kiểu: %d"
-#: builtin/log.c:602
+#: builtin/log.c:608
msgid "format.headers without value"
msgstr "format.headers không có giá trị cụ thể"
-#: builtin/log.c:676
+#: builtin/log.c:682
msgid "name of output directory is too long"
msgstr "tên của thư mục kết xuất quá dài"
-#: builtin/log.c:687
+#: builtin/log.c:693
#, c-format
msgid "Cannot open patch file %s"
msgstr "Không thể mở tập tin miếng vá: %s"
-#: builtin/log.c:701
+#: builtin/log.c:707
msgid "Need exactly one range."
msgstr "Cần chính xác một vùng."
-#: builtin/log.c:709
+#: builtin/log.c:715
msgid "Not a range."
msgstr "Không phải là một vùng."
-#: builtin/log.c:786
+#: builtin/log.c:789
msgid "Cover letter needs email format"
msgstr "'Cover letter' cần cho định dạng thư"
-#: builtin/log.c:859
+#: builtin/log.c:862
#, c-format
msgid "insane in-reply-to: %s"
msgstr "in-reply-to điên rồ: %s"
-#: builtin/log.c:932
+#: builtin/log.c:935
msgid "Two output directories?"
msgstr "Hai thư mục kết xuất?"
-#: builtin/log.c:1153
+#: builtin/log.c:1157
#, c-format
msgid "bogus committer info %s"
msgstr "thông tin ngÆ°á»i chuyển giao không có thá»±c %s"
-#: builtin/log.c:1198
+#: builtin/log.c:1202
msgid "-n and -k are mutually exclusive."
msgstr "-n và -k loại từ lẫn nhau."
-#: builtin/log.c:1200
+#: builtin/log.c:1204
msgid "--subject-prefix and -k are mutually exclusive."
msgstr "--subject-prefix và -k xung khắc nhau."
-#: builtin/log.c:1208
+#: builtin/log.c:1212
msgid "--name-only does not make sense"
msgstr "--name-only không hợp lý"
-#: builtin/log.c:1210
+#: builtin/log.c:1214
msgid "--name-status does not make sense"
msgstr "--name-status không hợp lý"
-#: builtin/log.c:1212
+#: builtin/log.c:1216
msgid "--check does not make sense"
msgstr "--check không hợp lý"
-#: builtin/log.c:1235
+#: builtin/log.c:1239
msgid "standard output, or directory, which one?"
msgstr "đầu ra chuẩn, hay thÆ° mục, chá»n cái nào?"
-#: builtin/log.c:1237
+#: builtin/log.c:1241
#, c-format
msgid "Could not create directory '%s'"
msgstr "Không thể tạo thư mục '%s'"
-#: builtin/log.c:1390
+#: builtin/log.c:1394
msgid "Failed to create output files"
msgstr "Gặp lỗi khi tạo các tập tin kết xuất"
-#: builtin/log.c:1494
+#: builtin/log.c:1498
#, c-format
-msgid "Could not find a tracked remote branch, please specify <upstream> manually.\n"
-msgstr "Không tìm thấy nhánh mạng bị theo vết, hãy chỉ định <dòng-ngược> một cách thủ công.\n"
+msgid ""
+"Could not find a tracked remote branch, please specify <upstream> manually.\n"
+msgstr ""
+"Không tìm thấy nhánh mạng bị theo vết, hãy chỉ định <dòng-ngược> một cách "
+"thủ công.\n"
-#: builtin/log.c:1510
-#: builtin/log.c:1512
-#: builtin/log.c:1524
+#: builtin/log.c:1511 builtin/log.c:1513 builtin/log.c:1525
#, c-format
msgid "Unknown commit %s"
msgstr "Không hiểu lần chuyển giao (commit) %s"
@@ -3445,14 +3833,13 @@ msgstr "stash gặp lỗi"
msgid "not a valid object: %s"
msgstr "không phải là một đối tượng hợp lệ: %s"
-#: builtin/merge.c:269
-#: builtin/merge.c:286
+#: builtin/merge.c:269 builtin/merge.c:286
msgid "read-tree failed"
msgstr "read-tree gặp lỗi"
#: builtin/merge.c:316
msgid " (nothing to squash)"
-msgstr " (không có ghì để squash)"
+msgstr " (không có gì để squash)"
#: builtin/merge.c:329
#, c-format
@@ -3472,53 +3859,51 @@ msgstr "Hoàn thành SQUASH_MSG"
msgid "No merge message -- not updating HEAD\n"
msgstr "Không thông điệp hòa trộn -- không cập nhật HEAD\n"
-#: builtin/merge.c:437
+#: builtin/merge.c:436
#, c-format
msgid "'%s' does not point to a commit"
msgstr "'%s' không chỉ đến một lần chuyển giao (commit) nào cả"
-#: builtin/merge.c:536
+#: builtin/merge.c:535
#, c-format
msgid "Bad branch.%s.mergeoptions string: %s"
msgstr "Chuá»—i branch.%s.mergeoptions sai: %s"
-#: builtin/merge.c:629
+#: builtin/merge.c:628
msgid "git write-tree failed to write a tree"
msgstr "lệnh git write-tree gặp lỗi khi ghi một cây"
-#: builtin/merge.c:679
+#: builtin/merge.c:678
msgid "failed to read the cache"
msgstr "gặp lá»—i khi Ä‘á»c bá»™ nhá»› tạm"
-#: builtin/merge.c:697
-msgid "Unable to write index."
-msgstr "Không thể ghi bảng mục lục"
-
-#: builtin/merge.c:710
+#: builtin/merge.c:709
msgid "Not handling anything other than two heads merge."
msgstr "Không cầm nắm gì ngoài hai head hòa trộn"
-#: builtin/merge.c:724
+#: builtin/merge.c:723
#, c-format
msgid "Unknown option for merge-recursive: -X%s"
msgstr "Không hiểu tùy chá»n cho merge-recursive: -X%s"
-#: builtin/merge.c:738
+#: builtin/merge.c:737
#, c-format
msgid "unable to write %s"
-msgstr "không ghi được %s"
+msgstr "không thể ghi %s"
-#: builtin/merge.c:877
+#: builtin/merge.c:876
#, c-format
msgid "Could not read from '%s'"
msgstr "Không thể Ä‘á»c từ '%s'"
-#: builtin/merge.c:886
+#: builtin/merge.c:885
#, c-format
msgid "Not committing merge; use 'git commit' to complete the merge.\n"
-msgstr "Vẫn chưa hòa trộn các lần chuyển giao (commit); sử dụng lệnh 'git commit' để hoàn tất việc hòa trộn.\n"
+msgstr ""
+"Vẫn chưa hòa trộn các lần chuyển giao (commit); sử dụng lệnh 'git commit' để "
+"hoàn tất việc hòa trộn.\n"
-#: builtin/merge.c:892
+#: builtin/merge.c:891
msgid ""
"Please enter a commit message to explain why this merge is necessary,\n"
"especially if it merges an updated upstream into a topic branch.\n"
@@ -3526,60 +3911,64 @@ msgid ""
"Lines starting with '#' will be ignored, and an empty message aborts\n"
"the commit.\n"
msgstr ""
-"Hãy nhập vào các thông tin để giải thích tại sao sự hòa trộn này là cần thiết,\n"
-"đặc biệt là khi nó hòa trộn dòng ngược đã cập nhật vào trong một nhánh topic.\n"
+"Hãy nhập vào các thông tin để giải thích tại sao sự hòa trộn này là cần "
+"thiết,\n"
+"đặc biệt là khi nó hòa trộn dòng ngược đã cập nhật vào trong một nhánh "
+"topic.\n"
"\n"
-"Những dòng được bắt đầu bằng '#' sẽ được bỠqua, và phần chú thích này nếu rỗng\n"
+"Những dòng được bắt đầu bằng '#' sẽ được bỠqua, và phần chú thích này nếu "
+"rá»—ng\n"
"sẽ làm hủy bỠlần chuyển giao (commit).\n"
-#: builtin/merge.c:916
+#: builtin/merge.c:915
msgid "Empty commit message."
msgstr "Chú thích của lần commit (chuyển giao) bị trống rỗng."
-#: builtin/merge.c:928
+#: builtin/merge.c:927
#, c-format
msgid "Wonderful.\n"
msgstr "Thần kỳ.\n"
-#: builtin/merge.c:993
+#: builtin/merge.c:992
#, c-format
msgid "Automatic merge failed; fix conflicts and then commit the result.\n"
-msgstr "Việc tự động hòa trộn gặp lỗi; hãy sửa các xung đột sau đó chuyển giao (commit) kết quả.\n"
+msgstr ""
+"Việc tự động hòa trộn gặp lỗi; hãy sửa các xung đột sau đó chuyển giao "
+"(commit) kết quả.\n"
-#: builtin/merge.c:1009
+#: builtin/merge.c:1008
#, c-format
msgid "'%s' is not a commit"
msgstr "%s không phải là một lần commit (chuyển giao)"
-#: builtin/merge.c:1050
+#: builtin/merge.c:1049
msgid "No current branch."
msgstr "không phải nhánh hiện hành"
-#: builtin/merge.c:1052
+#: builtin/merge.c:1051
msgid "No remote for the current branch."
msgstr "Không có máy chủ cho nhánh hiện hành."
-#: builtin/merge.c:1054
+#: builtin/merge.c:1053
msgid "No default upstream defined for the current branch."
msgstr "Không có dòng ngược mặc định được định nghĩa cho nhánh hiện hành."
-#: builtin/merge.c:1059
+#: builtin/merge.c:1058
#, c-format
msgid "No remote tracking branch for %s from %s"
msgstr "Không nhánh mạng theo vết cho %s từ %s"
-#: builtin/merge.c:1146
-#: builtin/merge.c:1303
+#: builtin/merge.c:1145 builtin/merge.c:1302
#, c-format
msgid "%s - not something we can merge"
msgstr "%s - không phải là một số thứ chúng tôi có thể hòa trộn"
-#: builtin/merge.c:1214
+#: builtin/merge.c:1213
msgid "There is no merge to abort (MERGE_HEAD missing)."
-msgstr "Ở đây không có lần hòa trộn nào được hủy bỠgiữa chừng cả (không thấy MERGE_HEAD)."
+msgstr ""
+"Ở đây không có lần hòa trộn nào được hủy bỠgiữa chừng cả (thiếu MERGE_HEAD)."
-#: builtin/merge.c:1230
-#: git-pull.sh:31
+#: builtin/merge.c:1229 git-pull.sh:31
msgid ""
"You have not concluded your merge (MERGE_HEAD exists).\n"
"Please, commit your changes before you can merge."
@@ -3587,12 +3976,11 @@ msgstr ""
"Bạn chưa kết thúc việc hòa trộng (MERGE_HEAD vẫn tồn tại).\n"
"Hãy chuyển giao (commit) các thay đổi trước khi bạn có thể hòa trộn."
-#: builtin/merge.c:1233
-#: git-pull.sh:34
+#: builtin/merge.c:1232 git-pull.sh:34
msgid "You have not concluded your merge (MERGE_HEAD exists)."
msgstr "Bạn chưa kết thúc việc hòa trộng (MERGE_HEAD vẫn tồn tại)."
-#: builtin/merge.c:1237
+#: builtin/merge.c:1236
msgid ""
"You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
"Please, commit your changes before you can merge."
@@ -3600,83 +3988,90 @@ msgstr ""
"Bạn chưa kết thúc việc cherry-pick (CHERRY_PICK_HEAD vẫn tồn tại).\n"
"Hãy chuyển giao (commit) các thay đổi trước khi bạn có thể hòa trộn."
-#: builtin/merge.c:1240
+#: builtin/merge.c:1239
msgid "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)."
msgstr "Bạn chưa kết thúc việc cherry-pick (CHERRY_PICK_HEAD vẫn tồn tại)."
-#: builtin/merge.c:1249
+#: builtin/merge.c:1248
msgid "You cannot combine --squash with --no-ff."
-msgstr "Bạn không thể tổ hợp --squash với --no-ff."
+msgstr "Bạn không thể kết hợp --squash với --no-ff."
-#: builtin/merge.c:1254
+#: builtin/merge.c:1253
msgid "You cannot combine --no-ff with --ff-only."
-msgstr "Bạn không thể tổ hợp --no-ff với --ff-only."
+msgstr "Bạn không thể kết hợp --no-ff với --ff-only."
-#: builtin/merge.c:1261
+#: builtin/merge.c:1260
msgid "No commit specified and merge.defaultToUpstream not set."
-msgstr "Không chỉ ra lần chuyển giao (commit) và merge.defaultToUpstream chưa được đặt."
+msgstr ""
+"Không chỉ ra lần chuyển giao (commit) và merge.defaultToUpstream chưa được "
+"đặt."
-#: builtin/merge.c:1293
+#: builtin/merge.c:1292
msgid "Can merge only exactly one commit into empty head"
-msgstr "Không thể hòa trộn một cách đúng đắn một lần chuyển giao (commit) vào một head rỗng"
+msgstr ""
+"Không thể hòa trộn một cách đúng đắn một lần chuyển giao (commit) vào một "
+"head rá»—ng"
-#: builtin/merge.c:1296
+#: builtin/merge.c:1295
msgid "Squash commit into empty head not supported yet"
msgstr "Squash commit vào một head trống rỗng vẫn chưa được hỗ trợ"
-#: builtin/merge.c:1298
+#: builtin/merge.c:1297
msgid "Non-fast-forward commit does not make sense into an empty head"
-msgstr "Chuyển giao (commit) không-fast-forward không hợp lý ở trong một head trống rỗng"
+msgstr ""
+"Chuyển giao (commit) không-fast-forward không hợp lý ở trong một head trống "
+"rá»—ng"
-#: builtin/merge.c:1413
+#: builtin/merge.c:1412
#, c-format
msgid "Updating %s..%s\n"
msgstr "Äang cập nhật %s..%s\n"
-#: builtin/merge.c:1451
+#: builtin/merge.c:1450
#, c-format
msgid "Trying really trivial in-index merge...\n"
msgstr "Äang thá»­ hòa trá»™n kiểu 'trivial in-index'...\n"
-#: builtin/merge.c:1458
+#: builtin/merge.c:1457
#, c-format
msgid "Nope.\n"
msgstr "Không.\n"
-#: builtin/merge.c:1490
+#: builtin/merge.c:1489
msgid "Not possible to fast-forward, aborting."
msgstr "Thực hiện lệnh fast-forward là không thể được, đang bỠqua."
-#: builtin/merge.c:1513
-#: builtin/merge.c:1592
+#: builtin/merge.c:1512 builtin/merge.c:1591
#, c-format
msgid "Rewinding the tree to pristine...\n"
msgstr "Äang tua lại cây thành thá»i xa xÆ°a...\n"
-#: builtin/merge.c:1517
+#: builtin/merge.c:1516
#, c-format
msgid "Trying merge strategy %s...\n"
msgstr "Äang thá»­ chiến lược hòa trá»™n %s...\n"
-#: builtin/merge.c:1583
+#: builtin/merge.c:1582
#, c-format
msgid "No merge strategy handled the merge.\n"
msgstr "Không có chiến lược hòa trộn nào được nắm giữ (handle) sự hòa trộn.\n"
-#: builtin/merge.c:1585
+#: builtin/merge.c:1584
#, c-format
msgid "Merge with strategy %s failed.\n"
msgstr "Hòa trộn với chiến lược %s gặp lỗi.\n"
-#: builtin/merge.c:1594
+#: builtin/merge.c:1593
#, c-format
msgid "Using the %s to prepare resolving by hand.\n"
msgstr "Sử dụng %s để chuẩn bị giải quyết bằng tay.\n"
-#: builtin/merge.c:1606
+#: builtin/merge.c:1605
#, c-format
msgid "Automatic merge went well; stopped before committing as requested\n"
-msgstr "Hòa trộn tự động đã trở nên tốt; bị dừng trước khi việc chuyển giao được yêu cầu\n"
+msgstr ""
+"Hòa trộn tự động đã trở nên tốt; bị dừng trước khi việc chuyển giao được yêu "
+"cầu\n"
#: builtin/mv.c:108
#, c-format
@@ -3719,7 +4114,7 @@ msgstr "đang ghi đè lên '%s'"
#: builtin/mv.c:184
msgid "Cannot overwrite"
-msgstr "Không thể ghi chèn"
+msgstr "Không thể ghi đè"
#: builtin/mv.c:187
msgid "multiple sources for the same target"
@@ -3733,10 +4128,9 @@ msgstr "%s, nguồn=%s, đích=%s"
#: builtin/mv.c:212
#, c-format
msgid "Renaming %s to %s\n"
-msgstr "Äang thay đổi tên %s thành %s\n"
+msgstr "Äổi tên %s thành %s\n"
-#: builtin/mv.c:215
-#: builtin/remote.c:731
+#: builtin/mv.c:215 builtin/remote.c:731
#, c-format
msgid "renaming '%s' failed"
msgstr "đổi tên %s gặp lỗi"
@@ -3760,18 +4154,17 @@ msgstr "gặp lá»—i khi đóng Ä‘Æ°á»ng ống cho lệnh 'show' cho đối tÆ°á
msgid "failed to finish 'show' for object '%s'"
msgstr "gặp lỗi khi hoàn thành 'show' cho đối tượng '%s'"
-#: builtin/notes.c:175
-#: builtin/tag.c:347
+#: builtin/notes.c:175 builtin/tag.c:347
#, c-format
msgid "could not create file '%s'"
msgstr "không thể tạo tập tin '%s'"
#: builtin/notes.c:189
msgid "Please supply the note contents using either -m or -F option"
-msgstr "Xin hãy áp dụng ná»™i dung của ghi chú sá»­ dụng hoặc là tùy chá»n -m hoặc là -F"
+msgstr ""
+"Xin hãy áp dụng ná»™i dung của ghi chú sá»­ dụng hoặc là tùy chá»n -m hoặc là -F"
-#: builtin/notes.c:210
-#: builtin/notes.c:973
+#: builtin/notes.c:210 builtin/notes.c:973
#, c-format
msgid "Removing note for object %s\n"
msgstr "Äang gỡ bá» ghi chú (note) cho đối tượng %s\n"
@@ -3785,30 +4178,20 @@ msgstr "không thể ghi đối tượng ghi chú (note)"
msgid "The note contents has been left in %s"
msgstr "Nội dung ghi chú còn lại %s"
-#: builtin/notes.c:251
-#: builtin/tag.c:542
+#: builtin/notes.c:251 builtin/tag.c:542
#, c-format
msgid "cannot read '%s'"
msgstr "không thể Ä‘á»c '%s'"
-#: builtin/notes.c:253
-#: builtin/tag.c:545
+#: builtin/notes.c:253 builtin/tag.c:545
#, c-format
msgid "could not open or read '%s'"
msgstr "không thể mở để Ä‘á»c hay ghi '%s'"
-#: builtin/notes.c:272
-#: builtin/notes.c:445
-#: builtin/notes.c:447
-#: builtin/notes.c:507
-#: builtin/notes.c:561
-#: builtin/notes.c:644
-#: builtin/notes.c:649
-#: builtin/notes.c:724
-#: builtin/notes.c:766
-#: builtin/notes.c:968
-#: builtin/reset.c:293
-#: builtin/tag.c:558
+#: builtin/notes.c:272 builtin/notes.c:445 builtin/notes.c:447
+#: builtin/notes.c:507 builtin/notes.c:561 builtin/notes.c:644
+#: builtin/notes.c:649 builtin/notes.c:724 builtin/notes.c:766
+#: builtin/notes.c:968 builtin/reset.c:293 builtin/tag.c:558
#, c-format
msgid "Failed to resolve '%s' as a valid ref."
msgstr "Gặp lỗi khi giải quyết '%s' như là một tham chiếu (ref) hợp lệ."
@@ -3820,7 +4203,9 @@ msgstr "Gặp lá»—i khi Ä‘á»c đối tượng '%s'."
#: builtin/notes.c:299
msgid "Cannot commit uninitialized/unreferenced notes tree"
-msgstr "Không thể chuyển giao (commit) chưa được khởi tạo hoặc không được tham chiếu cây ghi chú"
+msgstr ""
+"Không thể chuyển giao (commit) chưa được khởi tạo hoặc không được tham chiếu "
+"cây ghi chú"
#: builtin/notes.c:340
#, c-format
@@ -3849,29 +4234,27 @@ msgstr "Dòng nhập vào dị hình: '%s'."
msgid "Failed to copy notes from '%s' to '%s'"
msgstr "Gặp lỗi khi sao chép ghi chú (note) từ '%s' tới '%s'"
-#: builtin/notes.c:500
-#: builtin/notes.c:554
-#: builtin/notes.c:627
-#: builtin/notes.c:639
-#: builtin/notes.c:712
-#: builtin/notes.c:759
+#: builtin/notes.c: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 "quá nhiá»u đối số"
-#: builtin/notes.c:513
-#: builtin/notes.c:772
+#: builtin/notes.c:513 builtin/notes.c:772
#, c-format
msgid "No note found for object %s."
-msgstr "không ghi chú được tìm thấy cho đối tượng %s."
+msgstr "không tìm thấy ghi chú cho đối tượng %s."
#: builtin/notes.c:580
#, c-format
-msgid "Cannot add notes. Found existing notes for object %s. Use '-f' to overwrite existing notes"
-msgstr "Không thể thêm các ghi chú. Äã tìm thấy các ghi chú đã sẵn có cho đối tượng %s. Sá»­ dụng tùy chá»n '-f' để ghi đè lên các ghi chú cÅ©"
+msgid ""
+"Cannot add notes. Found existing notes for object %s. Use '-f' to overwrite "
+"existing notes"
+msgstr ""
+"Không thể thêm các ghi chú. Äã tìm thấy các ghi chú đã có sẵn cho đối tượng "
+"%s. Sá»­ dụng tùy chá»n '-f' để ghi đè lên các ghi chú cÅ©"
-#: builtin/notes.c:585
-#: builtin/notes.c:662
+#: builtin/notes.c:585 builtin/notes.c:662
#, c-format
msgid "Overwriting existing notes for object %s\n"
msgstr "Äang ghi đè lên ghi chú cÅ© cho đối tượng %s\n"
@@ -3882,8 +4265,12 @@ msgstr "quá ít đối số"
#: builtin/notes.c:656
#, c-format
-msgid "Cannot copy notes. Found existing notes for object %s. Use '-f' to overwrite existing notes"
-msgstr "Không thể sao chép các ghi chú. Äã tìm thấy các ghi chú đã sẵn có cho đối tượng %s. Sá»­ dụng tùy chá»n '-f' để ghi đè lên các ghi chú cÅ©"
+msgid ""
+"Cannot copy notes. Found existing notes for object %s. Use '-f' to overwrite "
+"existing notes"
+msgstr ""
+"Không thể sao chép các ghi chú. Äã tìm thấy các ghi chú đã có sẵn cho đối "
+"tượng %s. Sá»­ dụng tùy chá»n '-f' để ghi đè lên các ghi chú cÅ©"
#: builtin/notes.c:668
#, c-format
@@ -3904,28 +4291,32 @@ msgstr ""
msgid "Object %s has no note\n"
msgstr "Äối tượng %s không có ghi chú (note)\n"
-#: builtin/notes.c:1103
-#: builtin/remote.c:1598
+#: builtin/notes.c:1103 builtin/remote.c:1598
#, c-format
msgid "Unknown subcommand: %s"
msgstr "Không hiểu câu lệnh con: %s"
-#: builtin/pack-objects.c:2337
+#: builtin/pack-objects.c:183 builtin/pack-objects.c:186
+#, c-format
+msgid "deflate error (%d)"
+msgstr "lỗi giải nén (%d)"
+
+#: builtin/pack-objects.c:2398
#, c-format
msgid "unsupported index version %s"
msgstr "phiên bản mục lục không được hỗ trợ %s"
-#: builtin/pack-objects.c:2341
+#: builtin/pack-objects.c:2402
#, c-format
msgid "bad index version '%s'"
msgstr "phiên bản mục lục sai '%s'"
-#: builtin/pack-objects.c:2364
+#: builtin/pack-objects.c:2425
#, c-format
msgid "option %s does not accept negative form"
msgstr "tùy chá»n %s không chấp nhận dạng thức âm"
-#: builtin/pack-objects.c:2368
+#: builtin/pack-objects.c:2429
#, c-format
msgid "unable to parse value '%s' for option %s"
msgstr "không thể phân tích giá trị '%s' cho tùy chá»n %s"
@@ -3944,7 +4335,8 @@ msgid ""
"To choose either option permanently, see push.default in 'git help config'."
msgstr ""
"\n"
-"Äể chá»n má»—i tùy chá»n má»™t cách cố định, xem push.default trong 'git help config'."
+"Äể chá»n má»—i tùy chá»n má»™t cách cố định, xem push.default trong 'git help "
+"config'."
#: builtin/push.c:102
#, c-format
@@ -3995,7 +4387,8 @@ msgid ""
" git push --set-upstream %s %s\n"
msgstr ""
"Nhánh hiện tại %s không có nhánh dòng ngược (upstream) nào.\n"
-"Äể push (đẩy lên) nhánh hiện tại và đặt máy chủ nhÆ° là dòng ngược (upstream), sá»­ dụng\n"
+"Äể push (đẩy lên) nhánh hiện tại và đặt máy chủ nhÆ° là dòng ngược "
+"(upstream), sử dụng\n"
"\n"
" git push --set-upstream %s %s\n"
@@ -4011,15 +4404,51 @@ msgid ""
"your current branch '%s', without telling me what to push\n"
"to update which remote branch."
msgstr ""
-"Bạn đang push (đẩy lên) máy chủ '%s', mà nó không phải là dòng ngược (upstream) của\n"
+"Bạn đang push (đẩy lên) máy chủ '%s', mà nó không phải là dòng ngược "
+"(upstream) của\n"
"nhánh hiện tại '%s' của bạn, mà không báo cho tôi biết là cái gì được push\n"
"để cập nhật nhánh máy chủ nào."
-#: builtin/push.c:174
-msgid "You didn't specify any refspecs to push, and push.default is \"nothing\"."
-msgstr "Bạn đã không chỉ ra một refspecs nào để push, và push.default là \"không là gì cả\"."
+#: builtin/push.c:151
+msgid ""
+"push.default is unset; its implicit value is changing in\n"
+"Git 2.0 from 'matching' to 'simple'. To squelch this message\n"
+"and maintain the current behavior after the default changes, use:\n"
+"\n"
+" git config --global push.default matching\n"
+"\n"
+"To squelch this message and adopt the new behavior now, use:\n"
+"\n"
+" git config --global push.default simple\n"
+"\n"
+"See 'git help config' and search for 'push.default' for further "
+"information.\n"
+"(the 'simple' mode was introduced in Git 1.7.11. Use the similar mode\n"
+"'current' instead of 'simple' if you sometimes use older versions of Git)"
+msgstr ""
+"push.default chưa được đặt; giá trị ngầm định của nó đã được thay đổi trong\n"
+"Git 2.0 từ 'matching' thành 'simple'. Äể chấm dứt lá»i nhắc nhở này\n"
+"và duy trì cách xử lý sau những thay đổi mặc định này, hãy chạy lệnh:\n"
+"\n"
+" git config --global push.default matching\n"
+"\n"
+"Äể chấm dứt lá»i nhắc nhở này và sá»­ dụng cách xá»­ lý má»›i, hãy chạy lệnh:\n"
+"\n"
+" git config --global push.default simple\n"
+"\n"
+"Xem 'git help config' và tìm đến 'push.default' để có thêm thông tin.\n"
+"(chế độ 'simple' được bắt đầu sử dụng từ Git 1.7.11. Sử dụng chế độ tương "
+"tá»±\n"
+"'current' thay vì 'simple' nếu bạn thỉnh thoảng phải sử dụng bản Git cũ)"
-#: builtin/push.c:181
+#: builtin/push.c:199
+msgid ""
+"You didn't specify any refspecs to push, and push.default is \"nothing\"."
+msgstr ""
+"Bạn đã không chỉ ra một refspecs nào để push, và push.default là \"không là "
+"gì cả\"."
+
+#: builtin/push.c:206
msgid ""
"Updates were rejected because the tip of your current branch is behind\n"
"its remote counterpart. Merge the remote changes (e.g. 'git pull')\n"
@@ -4027,23 +4456,28 @@ msgid ""
"See the 'Note about fast-forwards' in 'git push --help' for details."
msgstr ""
"Việc cập nhật bị từ chối bởi vì đầu mút của nhánh được push nằm đằng sau bộ\n"
-"phận tương ứng của máy chủ. Hòa trộn với các thay đổi từ máy chủ (v.d. 'git pull')\n"
+"phận tương ứng của máy chủ. Hòa trộn với các thay đổi từ máy chủ (v.d. 'git "
+"pull')\n"
"trước khi lại push lần nữa.\n"
-"Xem trong phần 'Note about fast-forwards' trong nội dung từ lệnh 'git push --help'."
+"Xem trong phần 'Note about fast-forwards' từ lệnh 'git push --help' để có "
+"thông tin chi tiết."
-#: builtin/push.c:187
+#: builtin/push.c:212
msgid ""
"Updates were rejected because a pushed branch tip is behind its remote\n"
"counterpart. If you did not intend to push that branch, you may want to\n"
-"specify branches to push or set the 'push.default' configuration\n"
-"variable to 'current' or 'upstream' to push only the current branch."
+"specify branches to push or set the 'push.default' configuration variable\n"
+"to 'simple', 'current' or 'upstream' to push only the current branch."
msgstr ""
"Việc cập nhật bị từ chối bởi vì đầu mút của nhánh được push nằm đằng sau bộ\n"
-"phận tương ứng của máy chủ. Nếu bạn không có ý định push nhánh đó, bạn có lẽ muốn\n"
-"chỉ định các nhánh để push hoặt là đặt nội dung cho biến cấu hình 'push.default'\n"
-"thành 'current' hoặc 'upstream' để push chỉ nhánh hiện hành mà thôi."
-
-#: builtin/push.c:193
+"phận tương ứng của máy chủ. Nếu bạn không có ý định push nhánh đó, bạn có lẽ "
+"muốn\n"
+"chỉ định các nhánh để push hoặt là đặt nội dung cho biến cấu hình 'push."
+"default'\n"
+"thành 'simple', 'current' hoặc 'upstream' để chỉ push nhánh hiện hành mà "
+"thôi."
+
+#: builtin/push.c:218
msgid ""
"Updates were rejected because a pushed branch tip is behind its remote\n"
"counterpart. Check out this branch and merge the remote changes\n"
@@ -4051,29 +4485,32 @@ msgid ""
"See the 'Note about fast-forwards' in 'git push --help' for details."
msgstr ""
"Việc cập nhật bị từ chối bởi vì đầu mút của nhánh được push nằm đằng sau bộ\n"
-"phận tương ứng của máy chủ. Checkou nhánh này và hòa trộn với các thay đổi từ máy chủ\n"
+"phận tương ứng của máy chủ. Checkou nhánh này và hòa trộn với các thay đổi "
+"từ máy chủ\n"
"(v.d. 'git pull') trước khi lại push lần nữa.\n"
-"Xem trong phần 'Note about fast-forwards' trong nội dung từ lệnh 'git push --help'."
+"Xem trong phần 'Note about fast-forwards' từ lệnh 'git push --help' để có "
+"thông tin chi tiết."
-#: builtin/push.c:233
+#: builtin/push.c:258
#, c-format
msgid "Pushing to %s\n"
msgstr "Äang push (đẩy) lên %s\n"
-#: builtin/push.c:237
+#: builtin/push.c:262
#, c-format
msgid "failed to push some refs to '%s'"
msgstr "gặp lỗi khi push (đẩy lên) một số tham chiếu (ref) đến '%s'"
-#: builtin/push.c:269
+#: builtin/push.c:294
#, c-format
msgid "bad repository '%s'"
msgstr "repository (kho) sai '%s'"
-#: builtin/push.c:270
+#: builtin/push.c:295
msgid ""
"No configured push destination.\n"
-"Either specify the URL from the command-line or configure a remote repository using\n"
+"Either specify the URL from the command-line or configure a remote "
+"repository using\n"
"\n"
" git remote add <name> <url>\n"
"\n"
@@ -4090,31 +4527,31 @@ msgstr ""
"\n"
" git push <tên>\n"
-#: builtin/push.c:285
+#: builtin/push.c:310
msgid "--all and --tags are incompatible"
msgstr "--all và --tags xung khắc nhau"
-#: builtin/push.c:286
+#: builtin/push.c:311
msgid "--all can't be combined with refspecs"
msgstr "--all không thể được tổ hợp cùng với refspecs"
-#: builtin/push.c:291
+#: builtin/push.c:316
msgid "--mirror and --tags are incompatible"
msgstr "--mirror và --tags xung khắc nhau"
-#: builtin/push.c:292
+#: builtin/push.c:317
msgid "--mirror can't be combined with refspecs"
msgstr "--mirror không thể được tổ hợp cùng với refspecs"
-#: builtin/push.c:297
+#: builtin/push.c:322
msgid "--all and --mirror are incompatible"
msgstr "--all và --mirror xung khắc nhau"
-#: builtin/push.c:385
+#: builtin/push.c:410
msgid "--delete is incompatible with --all, --mirror and --tags"
msgstr "--delete là xung khắc vá»›i các tùy chá»n --all, --mirror và --tags"
-#: builtin/push.c:387
+#: builtin/push.c:412
msgid "--delete doesn't make sense without any refs"
msgstr "--delete không hợp lý nếu không có bất kỳ tham chiếu (refs) nào"
@@ -4138,20 +4575,18 @@ msgstr "không hiểu tham số máy bản sao (mirror): %s"
#: builtin/remote.c:185
msgid "specifying a master branch makes no sense with --mirror"
-msgstr "Ä‘ang chỉ định má»™t nhánh master không phân biệt HOA/thÆ°á»ng vá»›i tùy chá»n --mirror"
+msgstr "Ä‘ang chỉ định má»™t nhánh master không hợp lý vá»›i tùy chá»n --mirror"
#: builtin/remote.c:187
msgid "specifying branches to track makes sense only with fetch mirrors"
msgstr "chỉ định những nhánh để theo vết chỉ hợp lý với các 'fetch mirror'"
-#: builtin/remote.c:195
-#: builtin/remote.c:646
+#: builtin/remote.c:195 builtin/remote.c:646
#, c-format
msgid "remote %s already exists."
msgstr "máy chủ %s đã tồn tại rồi."
-#: builtin/remote.c:199
-#: builtin/remote.c:650
+#: builtin/remote.c:199 builtin/remote.c:650
#, c-format
msgid "'%s' is not a valid remote name"
msgstr "'%s' không phải tên máy chủ hợp lệ"
@@ -4171,8 +4606,7 @@ msgstr "nhiá»u hÆ¡n má»™t %s"
msgid "Could not get fetch map for refspec %s"
msgstr "Không thể lấy ánh xạ (map) fetch cho refspec %s"
-#: builtin/remote.c:440
-#: builtin/remote.c:448
+#: builtin/remote.c:440 builtin/remote.c:448
msgid "(matching)"
msgstr "(mẫu)"
@@ -4180,16 +4614,12 @@ msgstr "(mẫu)"
msgid "(delete)"
msgstr "(xoá)"
-#: builtin/remote.c:595
-#: builtin/remote.c:601
-#: builtin/remote.c:607
+#: builtin/remote.c:595 builtin/remote.c:601 builtin/remote.c:607
#, c-format
msgid "Could not append '%s' to '%s'"
msgstr "Không thể nối thêm '%s' vào '%s'"
-#: builtin/remote.c:639
-#: builtin/remote.c:792
-#: builtin/remote.c:890
+#: builtin/remote.c:639 builtin/remote.c:792 builtin/remote.c:890
#, c-format
msgid "No such remote: %s"
msgstr "Không có máy chủ nào như thế: %s"
@@ -4199,8 +4629,7 @@ msgstr "Không có máy chủ nào như thế: %s"
msgid "Could not rename config section '%s' to '%s'"
msgstr "Không thể đổi tên chương (section) cấu hình từ '%s' thành '%s'"
-#: builtin/remote.c:662
-#: builtin/remote.c:799
+#: builtin/remote.c:662 builtin/remote.c:799
#, c-format
msgid "Could not remove config section '%s'"
msgstr "Không thể gỡ bỠchương (section) cấu hình '%s'"
@@ -4239,7 +4668,7 @@ msgstr "tạo %s gặp lỗi"
#: builtin/remote.c:764
#, c-format
msgid "Could not remove branch %s"
-msgstr "Không thể gỡ nhánh %s"
+msgstr "Không thể gỡ bỠnhánh %s"
#: builtin/remote.c:834
msgid ""
@@ -4252,7 +4681,8 @@ msgstr[0] ""
"Chú ý: Một nhánh nằm ngoài hệ thống refs/remotes/ đã không được gỡ bỠđi;\n"
"để xóa đi, sử dụng:"
msgstr[1] ""
-"Chú ý: Một số nhánh nằm ngoài hệ thống refs/remotes/ đã không được gỡ bỠđi;\n"
+"Chú ý: Một số nhánh nằm ngoài hệ thống refs/remotes/ đã không được gỡ bỠ"
+"Ä‘i;\n"
"để xóa đi, sử dụng:"
#: builtin/remote.c:943
@@ -4266,7 +4696,7 @@ msgstr " bị theo vết"
#: builtin/remote.c:948
msgid " stale (use 'git remote prune' to remove)"
-msgstr " cÅ© (sá»­ dụng 'git remote prune' để gỡ bá»)"
+msgstr " cÅ© (dùng 'git remote prune' để gỡ bá»)"
#: builtin/remote.c:950
msgid " ???"
@@ -4294,7 +4724,7 @@ msgstr " và với máy chủ"
#: builtin/remote.c:1004
#, c-format
msgid "merges with remote %s"
-msgstr "hòa trộn với máy chủ %s"
+msgstr "hòa trộn với máy chủ %s"
#: builtin/remote.c:1005
msgid " and with remote"
@@ -4350,28 +4780,25 @@ msgstr "* máy chủ %s"
msgid " Fetch URL: %s"
msgstr " URL để lấy vỠ(fetch): %s"
-#: builtin/remote.c:1120
-#: builtin/remote.c:1285
+#: builtin/remote.c:1120 builtin/remote.c:1285
msgid "(no URL)"
-msgstr "(không có URL nào)"
+msgstr "(không có URL)"
-#: builtin/remote.c:1129
-#: builtin/remote.c:1131
+#: builtin/remote.c:1129 builtin/remote.c:1131
#, c-format
msgid " Push URL: %s"
-msgstr " URL để đẩy lên (push) : %s"
+msgstr " URL để đẩy lên (push): %s"
-#: builtin/remote.c:1133
-#: builtin/remote.c:1135
-#: builtin/remote.c:1137
+#: builtin/remote.c:1133 builtin/remote.c:1135 builtin/remote.c:1137
#, c-format
msgid " HEAD branch: %s"
msgstr " Nhánh HEAD: %s"
#: builtin/remote.c:1139
#, c-format
-msgid " HEAD branch (remote HEAD is ambiguous, may be one of the following):\n"
-msgstr " nhánh HEAD (HEAD máy chủ là không rõ ràng, có lẽ là một trong số sau):\n"
+msgid ""
+" HEAD branch (remote HEAD is ambiguous, may be one of the following):\n"
+msgstr " nhánh HEAD (HEAD máy chủ chưa rõ ràng, có lẽ là một trong số sau):\n"
#: builtin/remote.c:1151
#, c-format
@@ -4380,8 +4807,7 @@ msgid_plural " Remote branches:%s"
msgstr[0] " Nhánh trên máy chủ:%s"
msgstr[1] " Những nhánh trên máy chủ:%s"
-#: builtin/remote.c:1154
-#: builtin/remote.c:1181
+#: builtin/remote.c:1154 builtin/remote.c:1181
msgid " (status not queried)"
msgstr " (trạng thái không được yêu cầu)"
@@ -4428,12 +4854,12 @@ msgstr "Không thể cài đặt %s"
#: builtin/remote.c:1274
#, c-format
msgid " %s will become dangling!"
-msgstr " %s sẽ trở thành lủng lẳng (không được quản lý)!"
+msgstr " %s sẽ trở thành không đầu (không được quản lý)!"
#: builtin/remote.c:1275
#, c-format
msgid " %s has become dangling!"
-msgstr " %s phải trở thành lủng lẳng (không được quản lý)!"
+msgstr " %s đã trở thành không đầu (không được quản lý)!"
#: builtin/remote.c:1281
#, c-format
@@ -4455,8 +4881,7 @@ msgstr " * [nên xén bớt] %s"
msgid " * [pruned] %s"
msgstr " *[đã xén bớ] %s"
-#: builtin/remote.c:1387
-#: builtin/remote.c:1461
+#: builtin/remote.c:1387 builtin/remote.c:1461
#, c-format
msgid "No such remote '%s'"
msgstr "Không có máy chủ nào có tên '%s'"
@@ -4538,36 +4963,37 @@ msgstr "Những thay đổi bị bỠtrạng thái (stage) sau khi reset:"
msgid "Cannot do a %s reset in the middle of a merge."
msgstr "Không thể thực hiện một %s reset ở giữa của quá trình hòa trộn."
-#: builtin/reset.c:297
+#: builtin/reset.c:303
#, c-format
msgid "Could not parse object '%s'."
msgstr "không thể phân tích đối tượng '%s'."
-#: builtin/reset.c:302
+#: builtin/reset.c:308
msgid "--patch is incompatible with --{hard,mixed,soft}"
msgstr "--patch xung khắc với --{hard,mixed,soft}"
-#: builtin/reset.c:311
+#: builtin/reset.c:317
msgid "--mixed with paths is deprecated; use 'git reset -- <paths>' instead."
-msgstr "--mixed vá»›i các Ä‘Æ°á»ng dẫn không còn dùng nữa; hãy thay thế bằng lệnh 'git reset -- <Ä‘Æ°á»ng_dẫn>'."
+msgstr ""
+"--mixed vá»›i các Ä‘Æ°á»ng dẫn không còn dùng nữa; hãy thay thế bằng lệnh 'git "
+"reset -- <Ä‘Æ°á»ng_dẫn>'."
-#: builtin/reset.c:313
+#: builtin/reset.c:319
#, c-format
msgid "Cannot do %s reset with paths."
msgstr "Không thể thá»±c hiện lệnh %s reset vá»›i các Ä‘Æ°á»ng dẫn."
-#: builtin/reset.c:325
+#: builtin/reset.c:331
#, c-format
msgid "%s reset is not allowed in a bare repository"
msgstr "%s reset không được phép trên kho bare (trên máy chủ)"
-#: builtin/reset.c:341
+#: builtin/reset.c:347
#, c-format
msgid "Could not reset index file to revision '%s'."
msgstr "Không thể đặt lại (reset) bảng mục lục thành điểm xét lại '%s'."
-#: builtin/revert.c:70
-#: builtin/revert.c:92
+#: builtin/revert.c:70 builtin/revert.c:92
#, c-format
msgid "%s: %s cannot be used with %s"
msgstr "%s: %s không thể được sử dụng với %s"
@@ -4591,7 +5017,7 @@ msgid ""
"(use -f to force removal)"
msgstr ""
"'%s' có nội dung được lưu trạng thái khác biệt từ cả tập tin và cả HEAD\n"
-"(sá»­ dụng -f để ép buá»™c gỡ bá»)"
+"(dùng tùy chá»n -f để ép buá»™c gỡ bá»)"
#: builtin/rm.c:115
#, c-format
@@ -4600,7 +5026,7 @@ msgid ""
"(use --cached to keep the file, or -f to force removal)"
msgstr ""
"'%s' có các thay đổi được lưu trạng thái trong bảng mục lục\n"
-"(sá»­ dụng --cached để giữ tập tin, hoặc -f để ép buá»™c gỡ bá»)"
+"(dùng tùy chá»n --cached để giữ tập tin, hoặc -f để ép buá»™c gỡ bá»)"
#: builtin/rm.c:119
#, c-format
@@ -4609,7 +5035,7 @@ msgid ""
"(use --cached to keep the file, or -f to force removal)"
msgstr ""
"'%s' có các thay đổi nội bộ\n"
-"(sá»­ dụng --cached để giữ tập tin, hoặc -f để ép buá»™c gỡ bá»)"
+"(dùng tùy chá»n --cached để giữ tập tin, hoặc -f để ép buá»™c gỡ bá»)"
#: builtin/rm.c:194
#, c-format
@@ -4670,13 +5096,15 @@ msgid ""
"\n"
"#\n"
"# Write a tag message\n"
-"# Lines starting with '#' will be kept; you may remove them yourself if you want to.\n"
+"# Lines starting with '#' will be kept; you may remove them yourself if you "
+"want to.\n"
"#\n"
msgstr ""
"\n"
"#\n"
"# Viết các ghi chú cho (thẻ) tag\n"
-"# Những dòng được bắt đầu bằng '#' sẽ được bỠqua; bạn có thể xóa chúng đi nếu muốn.\n"
+"# Những dòng được bắt đầu bằng '#' sẽ được bỠqua; bạn có thể xóa chúng đi "
+"nếu muốn.\n"
"#\n"
#: builtin/tag.c:298
@@ -4764,10 +5192,10 @@ msgstr "Thẻ đã cập nhật '%s' (cũ là %s)\n"
#: git.c:16
msgid "See 'git help <command>' for more information on a specific command."
-msgstr "Chạy lệnh 'git help <tên-lệnh>' để có thêm thông tin vỠlệnh được chỉ ra."
+msgstr ""
+"Chạy lệnh 'git help <tên-lệnh>' để có thêm thông tin vỠlệnh được chỉ ra."
-#: parse-options.h:133
-#: parse-options.h:235
+#: parse-options.h:133 parse-options.h:235
msgid "n"
msgstr "n"
@@ -4813,7 +5241,7 @@ msgstr "Liệt kê, tạo hay là xóa các nhánh"
#: common-cmds.h:11
msgid "Checkout a branch or paths to the working tree"
-msgstr "Checkout má»™t nhánh hay các Ä‘Æ°á»ng dẫn tá»i cây làm việc"
+msgstr "Checkout má»™t nhánh hay các Ä‘Æ°á»ng dẫn tá»›i cây làm việc"
#: common-cmds.h:12
msgid "Clone a repository into a new directory"
@@ -4825,7 +5253,9 @@ msgstr "Ghi các thay đổi vào kho chứa"
#: common-cmds.h:14
msgid "Show changes between commits, commit and working tree, etc"
-msgstr "Hiển thị các thay đổi giữa những lần chuyển giao (commit), commit và cây làm việc, v.v.."
+msgstr ""
+"Hiển thị các thay đổi giữa những lần chuyển giao (commit), commit và cây làm "
+"việc, v.v.."
#: common-cmds.h:15
msgid "Download objects and refs from another repository"
@@ -4837,7 +5267,8 @@ msgstr "In ra những dòng khớp với một mẫu"
#: common-cmds.h:17
msgid "Create an empty git repository or reinitialize an existing one"
-msgstr "Tạo một kho git trống rỗng hay khởi tạo lại một kho đã tồn tại từ trước"
+msgstr ""
+"Tạo một kho git trống rỗng hay khởi tạo lại một kho đã tồn tại từ trước"
#: common-cmds.h:18
msgid "Show commit logs"
@@ -4845,7 +5276,9 @@ msgstr "hiển thị nhật ký các lần commit (chuyển giao)"
#: common-cmds.h:19
msgid "Join two or more development histories together"
-msgstr "Hợp nhất hai hay nhiá»u hÆ¡n lịch sá»­ của các nhà phát triển phần má»m lại vá»›i nhau"
+msgstr ""
+"Hợp nhất hai hay nhiá»u hÆ¡n lịch sá»­ của các nhà phát triển phần má»m lại vá»›i "
+"nhau"
#: common-cmds.h:20
msgid "Move or rename a file, a directory, or a symlink"
@@ -4857,11 +5290,13 @@ msgstr "Fetch (lấy vá») và hòa trá»™ng vá»›i kho khác hay nhánh ná»™i bá»
#: common-cmds.h:22
msgid "Update remote refs along with associated objects"
-msgstr "Cập nhật tham chiếu (refs) máy chủ cùng với các đối tượng liên quan đến nó"
+msgstr ""
+"Cập nhật tham chiếu (refs) máy chủ cùng với các đối tượng liên quan đến nó"
#: common-cmds.h:23
msgid "Forward-port local commits to the updated upstream head"
-msgstr "Forward-port những lần chuyển giao nội bộ tới head dòng ngược đã cập nhật"
+msgstr ""
+"Forward-port những lần chuyển giao nội bộ tới head dòng ngược đã cập nhật"
#: common-cmds.h:24
msgid "Reset current HEAD to the specified state"
@@ -4881,7 +5316,9 @@ msgstr "Hiển thị trạng thái cây làm việc"
#: common-cmds.h:28
msgid "Create, list, delete or verify a tag object signed with GPG"
-msgstr "Tạo, liệt kê, xóa hay xác thực một đối tượng thẻ (tag) mà nó được ký sử dụng GPG"
+msgstr ""
+"Tạo, liệt kê, xóa hay xác thực một đối tượng thẻ (tag) mà nó được ký sử dụng "
+"GPG"
#: git-am.sh:50
msgid "You need to set your committer info first"
@@ -4898,13 +5335,15 @@ msgstr ""
#: git-am.sh:105
#, sh-format
msgid ""
-"When you have resolved this problem run \"$cmdline --resolved\".\n"
-"If you would prefer to skip this patch, instead run \"$cmdline --skip\".\n"
-"To restore the original branch and stop patching run \"$cmdline --abort\"."
+"When you have resolved this problem, run \"$cmdline --resolved\".\n"
+"If you prefer to skip this patch, run \"$cmdline --skip\" instead.\n"
+"To restore the original branch and stop patching, run \"$cmdline --abort\"."
msgstr ""
"Khi bạn cần giải quyết vấn đỠnày hãy chạy lệnh \"$cmdline --resolved\".\n"
-"Nếu bạn có ý định bỠqua miếng vá, thay vào đó bạn chạy \"$cmdline --skip\".\n"
-"Äể phục hồi lại thành nhánh nguyên bản và dừng việc vá lại thì chạy \"$cmdline --abort\"."
+"Nếu bạn có ý định bỠqua miếng vá, thay vào đó bạn chạy \"$cmdline --skip"
+"\".\n"
+"Äể phục hồi lại thành nhánh nguyên thủy và dừng việc vá lại thì chạy "
+"\"$cmdline --abort\"."
#: git-am.sh:121
msgid "Cannot fall back to three-way merge."
@@ -4914,6 +5353,11 @@ msgstr "Äang trở lại để hòa trá»™n kiểu 'three-way'."
msgid "Repository lacks necessary blobs to fall back on 3-way merge."
msgstr "Kho thiếu đối tượng blob cần thiết để trở vỠtrên '3-way merge'."
+#: git-am.sh:139
+msgid "Using index info to reconstruct a base tree..."
+msgstr ""
+"Sử dụng thông tin trong bảng mục lục để cấu trúc lại một cây (tree) cơ sở..."
+
#: git-am.sh:154
msgid ""
"Did you hand edit your patch?\n"
@@ -4926,42 +5370,51 @@ msgstr ""
msgid "Falling back to patching base and 3-way merge..."
msgstr "Äang trở lại để vá cÆ¡ sở và '3-way merge'..."
-#: git-am.sh:275
+#: git-am.sh:179
+msgid "Failed to merge in the changes."
+msgstr "Gặp lỗi khi trộn vào các thay đổi."
+
+#: git-am.sh:274
msgid "Only one StGIT patch series can be applied at once"
msgstr "Chỉ có một sê-ri miếng vá StGIT được áp dụng một lúc"
-#: git-am.sh:362
+#: git-am.sh:361
#, sh-format
msgid "Patch format $patch_format is not supported."
msgstr "Äịnh dạng miếng vá $patch_format không được há»— trợ."
-#: git-am.sh:364
+#: git-am.sh:363
msgid "Patch format detection failed."
msgstr "Dò tìm định dạng miếng vá gặp lỗi."
-#: git-am.sh:418
-msgid "-d option is no longer supported. Do not use."
-msgstr "Tùy chá»n -d không còn được há»— trợ nữa. Xin đừng sá»­ dụng."
+#: git-am.sh:389
+msgid ""
+"The -b/--binary option has been a no-op for long time, and\n"
+"it will be removed. Please do not use it anymore."
+msgstr ""
+"Tùy chá»n -b/--binary đã không dùng từ lâu rồi, và\n"
+"nó sẽ được bỠđi. Xin đừng sử dụng nó thêm nữa."
-#: git-am.sh:481
+#: git-am.sh:477
#, sh-format
msgid "previous rebase directory $dotest still exists but mbox given."
msgstr "thư mục rebase trước $dotest vẫn chưa sẵn sàng nhưng mbox được đưa ra."
-#: git-am.sh:486
+#: git-am.sh:482
msgid "Please make up your mind. --skip or --abort?"
msgstr "Xin hãy rõ ràng. --skip hay --abort?"
-#: git-am.sh:513
+#: git-am.sh:509
msgid "Resolve operation not in progress, we are not resuming."
-msgstr "Thao tác phân giải không đang được tiến hành, chúng ta không phục hồi lại."
+msgstr ""
+"Thao tác phân giải không đang được tiến hành, chúng ta không phục hồi lại."
-#: git-am.sh:579
+#: git-am.sh:575
#, sh-format
msgid "Dirty index: cannot apply patches (dirty: $files)"
msgstr "Bảng mục lục sai: không thể áp dụng các miếng vá (sai: $files)"
-#: git-am.sh:671
+#: git-am.sh:679
#, sh-format
msgid ""
"Patch is empty. Was it split wrong?\n"
@@ -4969,34 +5422,39 @@ msgid ""
"To restore the original branch and stop patching run \"$cmdline --abort\"."
msgstr ""
"Miếng vá trống rỗng. Nó đã bị chia cắt sai phải không?\n"
-"Nếu bạn thích bỠqua miếng vá này, hãy chạy lệnh sau để thay thế \"$cmdline --skip\".\n"
-"Äể phục hồi lại nhánh nguyên bản và dừng vá lại hãy chạy lệnh \"$cmdline --abort\"."
+"Nếu bạn thích bỠqua miếng vá này, hãy chạy lệnh sau để thay thế \"$cmdline "
+"--skip\".\n"
+"Äể phục hồi lại nhánh nguyên thủy và dừng vá lại hãy chạy lệnh \"$cmdline --"
+"abort\"."
-#: git-am.sh:708
+#: git-am.sh:706
msgid "Patch does not have a valid e-mail address."
msgstr "Miếng vá không có địa chỉ e-mail hợp lệ."
-#: git-am.sh:755
+#: git-am.sh:753
msgid "cannot be interactive without stdin connected to a terminal."
-msgstr "không thể được tương tác mà không có stdin kết nối với một thiết bị cuối"
+msgstr ""
+"không thể được tương tác mà không có stdin kết nối với một thiết bị cuối"
-#: git-am.sh:759
+#: git-am.sh:757
msgid "Commit Body is:"
msgstr "Thân của lần chuyển giao (commit) là:"
#. TRANSLATORS: Make sure to include [y], [n], [e], [v] and [a]
#. in your translation. The program will only accept English
#. input at this point.
-#: git-am.sh:766
+#: git-am.sh:764
msgid "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all "
-msgstr "Ãp dụng? đồng ý [y]/không [n]/chỉnh sá»­a [e]/hiển thị miếng [v]á/đồng ý tất cả [a]"
+msgstr ""
+"Ãp dụng? đồng ý [y]/không [n]/chỉnh sá»­a [e]/hiển thị miếng [v]á/đồng ý tất "
+"cả [a] "
-#: git-am.sh:802
+#: git-am.sh:800
#, sh-format
msgid "Applying: $FIRSTLINE"
msgstr "Äang áp dụng (miếng vá): $FIRSTLINE"
-#: git-am.sh:823
+#: git-am.sh:821
msgid ""
"No changes - did you forget to use 'git add'?\n"
"If there is nothing left to stage, chances are that something else\n"
@@ -5004,9 +5462,10 @@ msgid ""
msgstr ""
"Không có thay đổi nào - bạn đã quên sử dụng lệnh 'git add' à?\n"
"Nếu ở đây không có gì còn lại stage, tình cỠlà có một số thứ khác\n"
-"đã sẵn được đưa vào với cùng nội dung thay đổi; bạn có lẽ muốn bỠqua miếng vá này."
+"đã sẵn được đưa vào với cùng nội dung thay đổi; bạn có lẽ muốn bỠqua miếng "
+"vá này."
-#: git-am.sh:831
+#: git-am.sh:829
msgid ""
"You still have unmerged paths in your index\n"
"did you forget to use 'git add'?"
@@ -5014,16 +5473,16 @@ msgstr ""
"Bạn vẫn có những Ä‘Æ°á»ng dẫn chÆ°a được hòa trá»™n trong bảng mục lục của mình\n"
"bạn đã quên sử dụng lệnh 'git add' à?"
-#: git-am.sh:847
+#: git-am.sh:845
msgid "No changes -- Patch already applied."
msgstr "Không thay đổi gì cả -- Miếng vá đã được áp dụng rồi."
-#: git-am.sh:857
+#: git-am.sh:855
#, sh-format
msgid "Patch failed at $msgnum $FIRSTLINE"
msgstr "Vá gặp lỗi tại $msgnum $FIRSTLINE"
-#: git-am.sh:873
+#: git-am.sh:876
msgid "applying to an empty history"
msgstr "áp dụng vào một lịch sử trống rỗng"
@@ -5054,8 +5513,11 @@ msgstr "HEAD sai - Tôi cần một HEAD"
#: git-bisect.sh:130
#, sh-format
-msgid "Checking out '$start_head' failed. Try 'git bisect reset <validbranch>'."
-msgstr "Việc checkout '$start_head' gặp lỗi. Hãy thử 'git bisect reset <nhánh_hợp_lệ>'."
+msgid ""
+"Checking out '$start_head' failed. Try 'git bisect reset <validbranch>'."
+msgstr ""
+"Việc checkout '$start_head' gặp lỗi. Hãy thử 'git bisect reset "
+"<nhánh_hợp_lệ>'."
#: git-bisect.sh:140
msgid "won't bisect on seeked tree"
@@ -5092,14 +5554,15 @@ msgstr "'git bisect bad' có thể lấy chỉ một đối số."
#. this is less optimum.
#: git-bisect.sh:273
msgid "Warning: bisecting only with a bad commit."
-msgstr "Cảnh báo: chỉ thực hiện việc bisect với một lần chuyển giao (commit) sai."
+msgstr ""
+"Cảnh báo: chỉ thực hiện việc bisect với một lần chuyển giao (commit) sai."
#. TRANSLATORS: Make sure to include [Y] and [n] in your
#. translation. The program will only accept English input
#. at this point.
#: git-bisect.sh:279
msgid "Are you sure [Y/n]? "
-msgstr "Bạn có chắc chắn chưa [Y/n]?"
+msgstr "Bạn có chắc chắn chưa [Y/n]? "
#: git-bisect.sh:289
msgid ""
@@ -5116,11 +5579,11 @@ msgid ""
"(You can use \"git bisect bad\" and \"git bisect good\" for that.)"
msgstr ""
"Bạn cần bắt đầu bằng lệnh \"git bisect start\".\n"
-"Bạn sau đó cần phải chỉ cho tôi ít nhất một điểm xét duyệt đúng và một điểm sai.\n"
+"Bạn sau đó cần phải chỉ cho tôi ít nhất một điểm xét duyệt đúng và một điểm "
+"sai.\n"
"(Bạn có thể sử dụng \"git bisect bad\" và \"git bisect good\" cho chúng.)"
-#: git-bisect.sh:347
-#: git-bisect.sh:474
+#: git-bisect.sh:347 git-bisect.sh:474
msgid "We are not bisecting."
msgstr "Chúng tôi không bisect."
@@ -5135,8 +5598,8 @@ msgid ""
"Could not check out original HEAD '$branch'.\n"
"Try 'git bisect reset <commit>'."
msgstr ""
-"Không thể check out original HEAD '$branch'.\n"
-"Hãy thử 'git bisect reset <commit>'."
+"Không thể check-out HEAD nguyên thủy của '$branch'.\n"
+"Hãy thử 'git bisect reset <lần-chuyển-giao>'."
#: git-bisect.sh:390
msgid "No logfile given"
@@ -5190,15 +5653,19 @@ msgid ""
msgstr ""
"Pull là không thể được bởi vì bạn có những tập tin chưa được hòa trộn.\n"
"Xin hãy sửa chữa chúng trước, và sau đó sử dụng lệnh 'git add/rm <tập-tin>'\n"
-"để phê chuẩn việc đánh dấu đây cần được giải quyết, hoặc là sử dụng 'git commit -a'."
+"để phê chuẩn việc đánh dấu đây cần được giải quyết, hoặc là sử dụng 'git "
+"commit -a'."
#: git-pull.sh:25
msgid "Pull is not possible because you have unmerged files."
-msgstr "Full là không thể thực hiện bởi vì bạn có những tập tin chưa được hòa trộn."
+msgstr ""
+"Full là không thể thực hiện bởi vì bạn có những tập tin chưa được hòa trộn."
#: git-pull.sh:197
msgid "updating an unborn branch with changes added to the index"
-msgstr "đang cập nhật một nhánh chưa được sinh ra với các thay đổi được thêm vào bảng mục lục"
+msgstr ""
+"đang cập nhật một nhánh chưa được sinh ra với các thay đổi được thêm vào "
+"bảng mục lục"
#. The fetch involved updating the current branch.
#. The working tree and the index file is still based on the
@@ -5223,9 +5690,136 @@ msgstr "Không thể hòa trá»™n nhiá»u nhánh và trong má»™t head trống rá»
msgid "Cannot rebase onto multiple branches"
msgstr "Không thể thá»±c hiện lệnh rebase (cÆ¡ cấu lại) trên nhiá»u nhánh"
+#: git-rebase.sh:52
+msgid ""
+"When you have resolved this problem, run \"git rebase --continue\".\n"
+"If you prefer to skip this patch, run \"git rebase --skip\" instead.\n"
+"To check out the original branch and stop rebasing, run \"git rebase --abort"
+"\"."
+msgstr ""
+"Khi bạn cần giải quyết vấn đỠnày hãy chạy lệnh \"git rebase --continue\".\n"
+"Nếu bạn có ý định bỠqua miếng vá, thay vào đó bạn chạy \"git rebase --skip"
+"\".\n"
+"Äể phục hồi lại thành nhánh nguyên thủy và dừng việc vá lại thì chạy \"git "
+"rebase --abort\"."
+
+#: git-rebase.sh:159
+msgid "The pre-rebase hook refused to rebase."
+msgstr "hook (chương trình móc vào git) pre-rebase từ chối rebase."
+
+#: git-rebase.sh:164
+msgid "It looks like git-am is in progress. Cannot rebase."
+msgstr ""
+"Hình như đang trong quá trình thực hiện lệnh git-am. Không thể chạy lệnh "
+"rebase."
+
+#: git-rebase.sh:295
+msgid "The --exec option must be used with the --interactive option"
+msgstr "Tùy chá»n --exec phải được sá»­ dụng cùng vá»›i tùy chá»n --interactive"
+
+#: git-rebase.sh:300
+msgid "No rebase in progress?"
+msgstr "Không có tiến trình rebase nào phải không?"
+
+#: git-rebase.sh:313
+msgid "Cannot read HEAD"
+msgstr "Không thể Ä‘á»c HEAD"
+
+#: git-rebase.sh:316
+msgid ""
+"You must edit all merge conflicts and then\n"
+"mark them as resolved using git add"
+msgstr ""
+"Bạn phải sửa tất cả các lần hòa trộn xung đột và sau\n"
+"đó đánh dấu chúng là cần xử lý sử dụng lệnh git add"
+
+#: git-rebase.sh:334
+#, sh-format
+msgid "Could not move back to $head_name"
+msgstr "Không thể quay trở lại $head_name"
+
+#: git-rebase.sh:350
+#, sh-format
+msgid ""
+"It seems that there is already a $state_dir_base directory, and\n"
+"I wonder if you are in the middle of another rebase. If that is the\n"
+"case, please try\n"
+"\t$cmd_live_rebase\n"
+"If that is not the case, please\n"
+"\t$cmd_clear_stale_rebase\n"
+"and run me again. I am stopping in case you still have something\n"
+"valuable there."
+msgstr ""
+"Hình như là ở đây sẵn có một thư mục $state_dir_base directory, và\n"
+"Tôi tá»± há»i có phải bạn Ä‘ang ở giữa má»™t lệnh rebase khác. Nếu đúng là\n"
+"như vậy, xin hãy thử\n"
+"\t$cmd_live_rebase\n"
+"Nếu không phải thế, hãy thử\n"
+"\t$cmd_clear_stale_rebase\n"
+"và chạy TÔI lần nữa. TÔI dừng lại trong trÆ°á»ng hợp bạn vẫn\n"
+"có một số thứ quý giá ở đây.\n"
+"\n"
+"TÔI: là lệnh bạn vừa gá»i!"
+
+#: git-rebase.sh:395
+#, sh-format
+msgid "invalid upstream $upstream_name"
+msgstr "dòng ngược không hợp lệ $upstream_name"
+
+#: git-rebase.sh:419
+#, sh-format
+msgid "$onto_name: there are more than one merge bases"
+msgstr "$onto_name: ở đây có nhiá»u hÆ¡n má»™t"
+
+#: git-rebase.sh:422 git-rebase.sh:426
+#, sh-format
+msgid "$onto_name: there is no merge base"
+msgstr "$onto_name: ở đây không có gì để hòa trộn"
+
+#: git-rebase.sh:431
+#, sh-format
+msgid "Does not point to a valid commit: $onto_name"
+msgstr "Không chỉ đến một lần chuyển giao (commit) không hợp lệ: $onto_name"
+
+#: git-rebase.sh:454
+#, sh-format
+msgid "fatal: no such branch: $branch_name"
+msgstr "nghiêm trá»ng: không có nhánh nhÆ° thế: $branch_name"
+
+#: git-rebase.sh:474
+msgid "Please commit or stash them."
+msgstr "Xin hãy commit hoặc stash chúng."
+
+#: git-rebase.sh:492
+#, sh-format
+msgid "Current branch $branch_name is up to date."
+msgstr "Nhánh hiện tại $branch_name đã được cập nhật rồi."
+
+#: git-rebase.sh:495
+#, sh-format
+msgid "Current branch $branch_name is up to date, rebase forced."
+msgstr "Nhánh hiện tại $branch_name đã được cập nhật rồi, lệnh rebase ép buộc."
+
+#: git-rebase.sh:506
+#, sh-format
+msgid "Changes from $mb to $onto:"
+msgstr "Thay đổi từ $mb thành $onto:"
+
+#. Detach HEAD and reset the tree
+#: git-rebase.sh:515
+msgid "First, rewinding head to replay your work on top of it..."
+msgstr ""
+"Trước tiên, di chuyển head để xem lại các công việc trên đỉnh của nó..."
+
+#: git-rebase.sh:523
+#, sh-format
+msgid "Fast-forwarded $branch_name to $onto_name."
+msgstr "Fast-forward $branch_name thành $onto_name."
+
#: git-stash.sh:51
msgid "git stash clear with parameters is unimplemented"
-msgstr "git stash clear với các tham số là chưa được thực hiện (không nhận đối số)"
+msgstr ""
+"git stash clear với các tham số là chưa được thực hiện (không nhận đối số)"
#: git-stash.sh:74
msgid "You do not have the initial commit yet"
@@ -5235,8 +5829,7 @@ msgstr "Bạn chưa còn có lần chuyển giao (commit) khởi tạo"
msgid "Cannot save the current index state"
msgstr "Không thể ghi lại trạng thái bảng mục lục hiện hành"
-#: git-stash.sh:123
-#: git-stash.sh:136
+#: git-stash.sh:123 git-stash.sh:136
msgid "Cannot save the current worktree state"
msgstr "Không thể ghi lại trạng thái cây-làm-việc hiện hành"
@@ -5289,7 +5882,7 @@ msgstr "Không thể gỡ bỠcác thay đổi cây-làm-việc"
#: git-stash.sh:352
msgid "No stash found."
-msgstr "Không tìm thấy stast nào."
+msgstr "Không tìm thấy stash nào."
#: git-stash.sh:359
#, sh-format
@@ -5353,103 +5946,110 @@ msgstr "Chưa chỉ ra tên của nhánh"
msgid "(To restore them type \"git stash apply\")"
msgstr "(Äể phục hồi lại chúng hãy gõ \"git stash apply\")"
-#: git-submodule.sh:56
+#: git-submodule.sh:88
#, sh-format
msgid "cannot strip one component off url '$remoteurl'"
msgstr "không thể tháo bá» má»™t thành phần ra khá»i url '$remoteurl'"
-#: git-submodule.sh:109
+#: git-submodule.sh:167
#, sh-format
msgid "No submodule mapping found in .gitmodules for path '$sm_path'"
-msgstr "Không tìm thấy ánh xạ (mapping) mô-Ä‘un-con trong .gitmodules cho Ä‘Æ°á»ng dẫn '$sm_path'"
+msgstr ""
+"Không tìm thấy ánh xạ (mapping) mô-Ä‘un-con trong .gitmodules cho Ä‘Æ°á»ng dẫn "
+"'$sm_path'"
-#: git-submodule.sh:150
+#: git-submodule.sh:211
#, sh-format
msgid "Clone of '$url' into submodule path '$sm_path' failed"
msgstr "Nhân bản '$url' vào Ä‘Æ°á»ng dẫn mô-Ä‘un-con '$sm_path' gặp lá»—i"
-#: git-submodule.sh:160
+#: git-submodule.sh:223
#, sh-format
msgid "Gitdir '$a' is part of the submodule path '$b' or vice versa"
-msgstr "Gitdir '$a' là bá»™ phận của Ä‘Æ°á»ng dẫn mô-Ä‘un-con '$b' hoặc \"vice versa\""
+msgstr ""
+"Gitdir '$a' là bá»™ phận của Ä‘Æ°á»ng dẫn mô-Ä‘un-con '$b' hoặc \"vice versa\""
-#: git-submodule.sh:249
+#: git-submodule.sh:312
#, sh-format
msgid "repo URL: '$repo' must be absolute or begin with ./|../"
-msgstr "repo URL: '$repo' phải là Ä‘Æ°á»ng dẫn tuyệt đối hoặc là bắt đầu bằng ./|../"
+msgstr ""
+"repo URL: '$repo' phải là Ä‘Æ°á»ng dẫn tuyệt đối hoặc là bắt đầu bằng ./|../"
-#: git-submodule.sh:266
+#: git-submodule.sh:329
#, sh-format
msgid "'$sm_path' already exists in the index"
msgstr "'$sm_path' thực sự đã tồn tại ở bảng mục lục rồi"
-#: git-submodule.sh:270
+#: git-submodule.sh:333
#, sh-format
msgid ""
"The following path is ignored by one of your .gitignore files:\n"
"$sm_path\n"
"Use -f if you really want to add it."
msgstr ""
-"Các Ä‘Æ°á»ng dẫn theo sau đây sẽ bị lá» Ä‘i bởi má»™t trong các tập tin .gitignore của bạn:\n"
+"Các Ä‘Æ°á»ng dẫn theo sau đây sẽ bị lá» Ä‘i bởi má»™t trong các tập tin .gitignore "
+"của bạn:\n"
"$sm_path\n"
"Sử dụng -f nếu bạn thực sự muốn thêm nó vào."
-#: git-submodule.sh:281
+#: git-submodule.sh:344
#, sh-format
msgid "Adding existing repo at '$sm_path' to the index"
msgstr "Äang thêm repo có sẵn tại '$sm_path' vào bảng mục lục"
-#: git-submodule.sh:283
+#: git-submodule.sh:346
#, sh-format
msgid "'$sm_path' already exists and is not a valid git repo"
msgstr "'$sm_path' đã tồn tại từ trước và không phải là một kho git hợp lệ"
-#: git-submodule.sh:297
+#: git-submodule.sh:360
#, sh-format
msgid "Unable to checkout submodule '$sm_path'"
msgstr "Không thể checkout mô-đun con '$sm_path'"
-#: git-submodule.sh:302
+#: git-submodule.sh:365
#, sh-format
msgid "Failed to add submodule '$sm_path'"
msgstr "Gặp lỗi khi thêm mô-đun con '$sm_path'"
-#: git-submodule.sh:307
+#: git-submodule.sh:370
#, sh-format
msgid "Failed to register submodule '$sm_path'"
msgstr "Gặp lỗi khi đăng ký với hệ thống mô-đun con '$sm_path'"
-#: git-submodule.sh:349
+#: git-submodule.sh:413
#, sh-format
msgid "Entering '$prefix$sm_path'"
msgstr "Äang nhập '$prefix$sm_path'"
-#: git-submodule.sh:363
+#: git-submodule.sh:427
#, sh-format
msgid "Stopping at '$sm_path'; script returned non-zero status."
msgstr "Dừng lại tại '$sm_path'; script trả vỠtrạng thái khác không."
-#: git-submodule.sh:406
+#: git-submodule.sh:471
#, sh-format
msgid "No url found for submodule path '$sm_path' in .gitmodules"
-msgstr "Không tìm thấy url cho Ä‘Æ°á»ng dẫn mô-Ä‘un-con '$sm_path' trong .gitmodules"
+msgstr ""
+"Không tìm thấy url cho Ä‘Æ°á»ng dẫn mô-Ä‘un-con '$sm_path' trong .gitmodules"
-#: git-submodule.sh:415
+#: git-submodule.sh:480
#, sh-format
msgid "Failed to register url for submodule path '$sm_path'"
msgstr "Gặp lá»—i khi đăng ký url cho Ä‘Æ°á»ng dẫn mô-Ä‘un-con '$sm_path'"
-#: git-submodule.sh:417
+#: git-submodule.sh:482
#, sh-format
msgid "Submodule '$name' ($url) registered for path '$sm_path'"
msgstr "Mô-Ä‘un-con '$name' ($url) được đăng ký cho Ä‘Æ°á»ng dẫn '$sm_path'"
-#: git-submodule.sh:425
+#: git-submodule.sh:490
#, sh-format
msgid "Failed to register update mode for submodule path '$sm_path'"
-msgstr "Gặp lá»—i khi đăng ký chế Ä‘á»™ cập nhật cho Ä‘Æ°á»ng dẫn mô-Ä‘un-con '$sm_path'"
+msgstr ""
+"Gặp lá»—i khi đăng ký chế Ä‘á»™ cập nhật cho Ä‘Æ°á»ng dẫn mô-Ä‘un-con '$sm_path'"
-#: git-submodule.sh:524
+#: git-submodule.sh:590
#, sh-format
msgid ""
"Submodule path '$sm_path' not initialized\n"
@@ -5458,98 +6058,115 @@ msgstr ""
"ÄÆ°á»ng dẫn mô-Ä‘un-con '$sm_path' chÆ°a được khởi tạo\n"
"Có lẽ bạn muốn sử dụng lệnh 'update --init'?"
-#: git-submodule.sh:537
+#: git-submodule.sh:603
#, sh-format
msgid "Unable to find current revision in submodule path '$sm_path'"
-msgstr "Không tìm thấy Ä‘iểm xét lại hiện hành trong Ä‘Æ°á»ng dẫn mô-Ä‘un-con '$sm_path'"
+msgstr ""
+"Không tìm thấy Ä‘iểm xét lại hiện hành trong Ä‘Æ°á»ng dẫn mô-Ä‘un-con '$sm_path'"
-#: git-submodule.sh:556
+#: git-submodule.sh:622
#, sh-format
msgid "Unable to fetch in submodule path '$sm_path'"
msgstr "Không thể lấy vá» (fetch) trong Ä‘Æ°á»ng dẫn mô-Ä‘un-con '$sm_path'"
-#: git-submodule.sh:570
+#: git-submodule.sh:636
#, sh-format
msgid "Unable to rebase '$sha1' in submodule path '$sm_path'"
msgstr "Không thể rebase '$sha1' trong Ä‘Æ°á»ng dẫn mô-Ä‘un-con '$sm_path'"
-#: git-submodule.sh:571
+#: git-submodule.sh:637
#, sh-format
msgid "Submodule path '$sm_path': rebased into '$sha1'"
msgstr "ÄÆ°á»ng dẫn mô-Ä‘un-con '$sm_path': được rebase vào trong '$sha1'"
-#: git-submodule.sh:576
+#: git-submodule.sh:642
#, sh-format
msgid "Unable to merge '$sha1' in submodule path '$sm_path'"
-msgstr "Không thể hòa trá»™n (merge) '$sha1' trong Ä‘Æ°á»ng dẫn mô-Ä‘un-con '$sm_path'"
+msgstr ""
+"Không thể hòa trá»™n (merge) '$sha1' trong Ä‘Æ°á»ng dẫn mô-Ä‘un-con '$sm_path'"
-#: git-submodule.sh:577
+#: git-submodule.sh:643
#, sh-format
msgid "Submodule path '$sm_path': merged in '$sha1'"
msgstr "ÄÆ°á»ng dẫn mô-Ä‘un-con '$sm_path': được hòa trá»™n vào '$sha1'"
-#: git-submodule.sh:582
+#: git-submodule.sh:648
#, sh-format
msgid "Unable to checkout '$sha1' in submodule path '$sm_path'"
msgstr "Không thể checkout '$sha1' trong Ä‘Æ°á»ng dẫn mô-Ä‘un-con '$sm_path'"
-#: git-submodule.sh:583
+#: git-submodule.sh:649
#, sh-format
msgid "Submodule path '$sm_path': checked out '$sha1'"
msgstr "ÄÆ°á»ng dẫn mô-Ä‘un-con '$sm_path': được checkout '$sha1'"
-#: git-submodule.sh:605
-#: git-submodule.sh:928
+#: git-submodule.sh:671 git-submodule.sh:995
#, sh-format
msgid "Failed to recurse into submodule path '$sm_path'"
msgstr "Gặp lá»—i khi đệ quy vào trong Ä‘Æ°á»ng dẫn mô-Ä‘un-con '$sm_path'"
-#: git-submodule.sh:713
-msgid "--cached cannot be used with --files"
-msgstr "--cached không thể được sử dụng cùng với --files"
+#: git-submodule.sh:779
+msgid "The --cached option cannot be used with the --files option"
+msgstr "Tùy chá»n --cached không thể dùng cùng vá»›i tùy chá»n --files"
#. unexpected type
-#: git-submodule.sh:753
+#: git-submodule.sh:819
#, sh-format
msgid "unexpected mode $mod_dst"
msgstr "chế độ không như mong chỠ$mod_dst"
-#: git-submodule.sh:771
+#: git-submodule.sh:837
#, sh-format
msgid " Warn: $name doesn't contain commit $sha1_src"
msgstr " Cảnh báo: $name không chứa lần chuyển giao (commit) $sha1_src"
-#: git-submodule.sh:774
+#: git-submodule.sh:840
#, sh-format
msgid " Warn: $name doesn't contain commit $sha1_dst"
msgstr " Cảnh báo: $name không chứa lần chuyển giao (commit) $sha1_dst"
-#: git-submodule.sh:777
+#: git-submodule.sh:843
#, sh-format
msgid " Warn: $name doesn't contain commits $sha1_src and $sha1_dst"
-msgstr " Cảnh báo: $name không chứa những lần chuyển giao (commit) $sha1_src và $sha1_dst"
+msgstr ""
+" Cảnh báo: $name không chứa những lần chuyển giao (commit) $sha1_src và "
+"$sha1_dst"
-#: git-submodule.sh:802
+#: git-submodule.sh:868
msgid "blob"
msgstr "blob"
-#: git-submodule.sh:803
-msgid "submodule"
-msgstr "mô-đun con"
-
-#: git-submodule.sh:840
+#: git-submodule.sh:906
msgid "# Submodules changed but not updated:"
msgstr "# Những mô-đun-con đã bị thay đổi nhưng chưa được cập nhật:"
-#: git-submodule.sh:842
+#: git-submodule.sh:908
msgid "# Submodule changes to be committed:"
msgstr "# Những thay đổi mô-đun-con được chuyển giao (commit):"
-#: git-submodule.sh:974
+#: git-submodule.sh:1054
#, sh-format
msgid "Synchronizing submodule url for '$name'"
msgstr "Äang đồng bá»™ hóa url mô-Ä‘un-con cho '$name'"
+#~ msgid "diff setup failed"
+#~ msgstr "cài đặt diff gặp lỗi"
+
+#~ msgid "merge-recursive: disk full?"
+#~ msgstr "merge-recursive: đĩa bị đầy?"
+
+#~ msgid "diff_setup_done failed"
+#~ msgstr "diff_setup_done gặp lỗi"
+
+#~ msgid "-d option is no longer supported. Do not use."
+#~ msgstr "Tùy chá»n -d không còn được há»— trợ nữa. Xin đừng sá»­ dụng."
+
+#~ msgid "%s: has been deleted/renamed"
+#~ msgstr "%s: đã được xóa/thay-tên"
+
+#~ msgid "'%s': not a documentation directory."
+#~ msgstr "'%s': không phải là một thư mục tài liệu."
+
#~ msgid "--"
#~ msgstr "--"
diff --git a/po/zh_CN.po b/po/zh_CN.po
index b46b53e..46d158f 100644
--- a/po/zh_CN.po
+++ b/po/zh_CN.po
@@ -12,8 +12,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Git\n"
"Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2012-06-08 10:20+0800\n"
-"PO-Revision-Date: 2012-06-08 12:24+0800\n"
+"POT-Creation-Date: 2012-09-15 10:21+0800\n"
+"PO-Revision-Date: 2012-09-07 17:56+0800\n"
"Last-Translator: Jiang Xin <worldhello.net@gmail.com>\n"
"Language-Team: GitHub <https://github.com/gotgit/git/>\n"
"Language: zh_CN\n"
@@ -42,6 +42,95 @@ msgstr ""
"'git add/rm <file>' 标记解决方案,\n"
"或使用 'git commit -a'。"
+#: archive.c:10
+#, fuzzy
+msgid "git archive [options] <tree-ish> [<path>...]"
+msgstr "git apply [选项] [<è¡¥ä¸>...]"
+
+#: archive.c:11
+#, fuzzy
+msgid "git archive --list"
+msgstr "git archive:NACK %s"
+
+#: archive.c:12
+msgid ""
+"git archive --remote <repo> [--exec <cmd>] [options] <tree-ish> [<path>...]"
+msgstr ""
+
+#: archive.c:13
+msgid "git archive --remote <repo> [--exec <cmd>] --list"
+msgstr ""
+
+#: archive.c:322
+msgid "fmt"
+msgstr ""
+
+#: archive.c:322
+msgid "archive format"
+msgstr ""
+
+#: archive.c:323 builtin/log.c:1079
+msgid "prefix"
+msgstr ""
+
+#: archive.c:324
+msgid "prepend prefix to each pathname in the archive"
+msgstr ""
+
+#: archive.c:325 builtin/archive.c:91 builtin/blame.c:2332
+#: builtin/blame.c:2333 builtin/config.c:56 builtin/fast-export.c:642
+#: builtin/fast-export.c:644 builtin/grep.c:800 builtin/hash-object.c:77
+#: builtin/ls-files.c:494 builtin/ls-files.c:497 builtin/notes.c:537
+#: builtin/notes.c:694 builtin/read-tree.c:107 parse-options.h:149
+msgid "file"
+msgstr "文件"
+
+#: archive.c:326 builtin/archive.c:92
+msgid "write the archive to this file"
+msgstr ""
+
+#: archive.c:328
+#, fuzzy
+msgid "read .gitattributes in working directory"
+msgstr "%s:已ç»å­˜åœ¨äºŽå·¥ä½œåŒºä¸­"
+
+#: archive.c:329
+msgid "report archived files on stderr"
+msgstr ""
+
+#: archive.c:330
+msgid "store only"
+msgstr ""
+
+#: archive.c:331
+msgid "compress faster"
+msgstr ""
+
+#: archive.c:339
+msgid "compress better"
+msgstr ""
+
+#: archive.c:342
+msgid "list supported archive formats"
+msgstr ""
+
+#: archive.c:344 builtin/archive.c:93 builtin/clone.c:85
+msgid "repo"
+msgstr ""
+
+#: archive.c:345 builtin/archive.c:94
+msgid "retrieve the archive from remote repository <repo>"
+msgstr ""
+
+#: archive.c:346 builtin/archive.c:95 builtin/notes.c:616
+#, fuzzy
+msgid "command"
+msgstr "è¿è¡Œ $command"
+
+#: archive.c:347 builtin/archive.c:96
+msgid "path to the remote git-upload-archive command"
+msgstr ""
+
#: bundle.c:36
#, c-format
msgid "'%s' does not look like a v2 bundle file"
@@ -52,7 +141,7 @@ msgstr "'%s' ä¸åƒæ˜¯ä¸€ä¸ª v2 版本的包文件"
msgid "unrecognized header: %s%s (%d)"
msgstr "未能识别的包头:%s%s (%d)"
-#: bundle.c:89 builtin/commit.c:696
+#: bundle.c:89 builtin/commit.c:714
#, c-format
msgid "could not open '%s'"
msgstr "ä¸èƒ½æ‰“å¼€ '%s'"
@@ -61,8 +150,8 @@ msgstr "ä¸èƒ½æ‰“å¼€ '%s'"
msgid "Repository lacks these prerequisite commits:"
msgstr "版本库缺少这些必备的æ交:"
-#: bundle.c:164 sequencer.c:550 sequencer.c:982 builtin/log.c:289
-#: builtin/log.c:720 builtin/log.c:1309 builtin/log.c:1528 builtin/merge.c:347
+#: bundle.c:164 sequencer.c:557 sequencer.c:989 builtin/log.c:290
+#: builtin/log.c:727 builtin/log.c:1313 builtin/log.c:1529 builtin/merge.c:347
#: builtin/shortlog.c:181
msgid "revision walk setup failed"
msgstr "版本é历设置失败"
@@ -75,44 +164,48 @@ msgstr[0] "这个包中å«æœ‰ %d 个引用"
msgstr[1] "这个包中å«æœ‰ %d 个引用"
#: bundle.c:192
+msgid "The bundle records a complete history."
+msgstr "这个包记录一个完整历å²ã€‚"
+
+#: bundle.c:195
#, c-format
msgid "The bundle requires this ref"
msgid_plural "The bundle requires these %d refs"
msgstr[0] "这个包需è¦è¿™ä¸ªå¼•ç”¨"
msgstr[1] "è¿™ä¸ªåŒ…éœ€è¦ %d 个这些引用"
-#: bundle.c:290
+#: bundle.c:294
msgid "rev-list died"
msgstr "rev-list 终止"
-#: bundle.c:296 builtin/log.c:1205 builtin/shortlog.c:284
+#: bundle.c:300 builtin/log.c:1209 builtin/shortlog.c:284
#, c-format
msgid "unrecognized argument: %s"
msgstr "未能识别的å‚数:%s"
-#: bundle.c:331
+#: bundle.c:335
#, c-format
msgid "ref '%s' is excluded by the rev-list options"
msgstr "引用 '%s' 被 rev-list 选项排除"
-#: bundle.c:376
+#: bundle.c:380
msgid "Refusing to create empty bundle."
msgstr "ä¸èƒ½åˆ›å»ºç©ºåŒ…。"
-#: bundle.c:394
+#: bundle.c:398
msgid "Could not spawn pack-objects"
msgstr "ä¸èƒ½ç”Ÿæˆ pack-objects 进程"
-#: bundle.c:412
+#: bundle.c:416
msgid "pack-objects died"
msgstr "pack-objects 终止"
-#: bundle.c:415
+#: bundle.c:419
#, c-format
msgid "cannot create '%s'"
msgstr "ä¸èƒ½åˆ›å»º '%s'"
-#: bundle.c:437
+#: bundle.c:441
msgid "index-pack died"
msgstr "index-pack 终止"
@@ -232,32 +325,32 @@ msgstr ""
"å‘现é…ç½®å˜é‡ 'diff.dirstat' 中的错误:\n"
"%s"
-#: diff.c:1400
-msgid " 0 files changed\n"
-msgstr " 0 个文件被修改\n"
+#: diff.c:1401
+msgid " 0 files changed"
+msgstr " 0 个文件被修改"
-#: diff.c:1404
+#: diff.c:1405
#, c-format
msgid " %d file changed"
msgid_plural " %d files changed"
msgstr[0] " %d 个文件被修改"
msgstr[1] " %d 个文件被修改"
-#: diff.c:1421
+#: diff.c:1422
#, c-format
msgid ", %d insertion(+)"
msgid_plural ", %d insertions(+)"
msgstr[0] ",æ’å…¥ %d è¡Œ(+)"
msgstr[1] ",æ’å…¥ %d è¡Œ(+)"
-#: diff.c:1432
+#: diff.c:1433
#, c-format
msgid ", %d deletion(-)"
msgid_plural ", %d deletions(-)"
msgstr[0] ",删除 %d 行(-)"
msgstr[1] ",删除 %d 行(-)"
-#: diff.c:3478
+#: diff.c:3460
#, c-format
msgid ""
"Failed to parse --dirstat/-X option parameter:\n"
@@ -293,16 +386,16 @@ msgstr "'%s':%s"
msgid "'%s': short read %s"
msgstr "'%s':读å–ä¸å®Œæ•´ %s"
-#: help.c:207
+#: help.c:212
#, c-format
msgid "available git commands in '%s'"
msgstr "在 '%s' 下å¯ç”¨çš„ git 命令"
-#: help.c:214
+#: help.c:219
msgid "git commands available from elsewhere on your $PATH"
msgstr "在 $PATH 路径中的其他地方å¯ç”¨çš„ git 命令"
-#: help.c:270
+#: help.c:275
#, c-format
msgid ""
"'%s' appears to be a git command, but we were not\n"
@@ -311,11 +404,11 @@ msgstr ""
"'%s' åƒæ˜¯ä¸€ä¸ª git 命令,但å´æ— æ³•è¿è¡Œã€‚\n"
"å¯èƒ½æ˜¯ git-%s å—æŸï¼Ÿ"
-#: help.c:327
+#: help.c:332
msgid "Uh oh. Your system reports no Git commands at all."
msgstr "唉呀,您的系统中未å‘现 Git 命令。"
-#: help.c:349
+#: help.c:354
#, c-format
msgid ""
"WARNING: You called a Git command named '%s', which does not exist.\n"
@@ -324,17 +417,17 @@ msgstr ""
"警告:您è¿è¡Œä¸€ä¸ªä¸å­˜åœ¨çš„ Git 命令 '%s'。继续执行å‡å®šæ‚¨è¦è¦è¿è¡Œçš„\n"
"是 '%s'"
-#: help.c:354
+#: help.c:359
#, c-format
msgid "in %0.1f seconds automatically..."
msgstr "在 %0.1f 秒钟åŽè‡ªåŠ¨è¿è¡Œ..."
-#: help.c:361
+#: help.c:366
#, c-format
msgid "git: '%s' is not a git command. See 'git --help'."
msgstr "git:'%s' ä¸æ˜¯ä¸€ä¸ª git 命令。å‚è§ 'git --help'。"
-#: help.c:365
+#: help.c:370
msgid ""
"\n"
"Did you mean this?"
@@ -346,38 +439,292 @@ msgstr[0] ""
"您指的是这个么?"
msgstr[1] ""
"\n"
-"您指的是这些其中一个么?"
+"您指的是这其中的æŸä¸€ä¸ªä¹ˆï¼Ÿ"
+
+#: merge-recursive.c:190
+#, c-format
+msgid "(bad commit)\n"
+msgstr "(åæ交)\n"
+
+#: merge-recursive.c:206
+#, c-format
+msgid "addinfo_cache failed for path '%s'"
+msgstr "为路径 '%s' addinfo_cache 失败"
+
+#: merge-recursive.c:268
+msgid "error building trees"
+msgstr "无法创建树"
+
+#: merge-recursive.c:672
+#, c-format
+msgid "failed to create path '%s'%s"
+msgstr "无法创建路径 '%s'%s"
+
+#: merge-recursive.c:683
+#, c-format
+msgid "Removing %s to make room for subdirectory\n"
+msgstr "删除 %s 以便为å­ç›®å½•ç•™å‡ºç©ºé—´\n"
+
+#. something else exists
+#. .. but not some other error (who really cares what?)
+#: merge-recursive.c:697 merge-recursive.c:718
+msgid ": perhaps a D/F conflict?"
+msgstr ":å¯èƒ½æ˜¯ä¸€ä¸ªç›®å½•/文件冲çªï¼Ÿ"
+
+#: merge-recursive.c:708
+#, c-format
+msgid "refusing to lose untracked file at '%s'"
+msgstr "æ‹’ç»ä¸¢å¼ƒ '%s' 中的未跟踪文件"
+
+#: merge-recursive.c:748
+#, c-format
+msgid "cannot read object %s '%s'"
+msgstr "ä¸èƒ½è¯»å–对象 %s '%s'"
+
+#: merge-recursive.c:750
+#, c-format
+msgid "blob expected for %s '%s'"
+msgstr "%s '%s' 应为二进制对象(blob)"
+
+#: merge-recursive.c:773 builtin/clone.c:302
+#, c-format
+msgid "failed to open '%s'"
+msgstr "无法打开 '%s'"
+
+#: merge-recursive.c:781
+#, c-format
+msgid "failed to symlink '%s'"
+msgstr "无法创建符å·é“¾æŽ¥ '%s'"
+
+#: merge-recursive.c:784
+#, c-format
+msgid "do not know what to do with %06o %s '%s'"
+msgstr "ä¸çŸ¥é“å¦‚ä½•å¤„ç† %06o %s '%s'"
+
+#: merge-recursive.c:922
+msgid "Failed to execute internal merge"
+msgstr "无法执行内部åˆå¹¶"
+
+#: merge-recursive.c:926
+#, c-format
+msgid "Unable to add %s to database"
+msgstr "ä¸èƒ½æ·»åŠ  %s 至对象库"
+
+#: merge-recursive.c:942
+msgid "unsupported object type in the tree"
+msgstr "在树中有ä¸æ”¯æŒçš„对象类型"
+
+#: merge-recursive.c:1021 merge-recursive.c:1035
+#, c-format
+msgid ""
+"CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left "
+"in tree."
+msgstr ""
+"冲çªï¼ˆ%1$s/删除):%2$s 在 %3$s 中被删除,在 %5$s 中被 %4$s。%7$s 在 %6$s 中"
+"的版本被ä¿ç•™ã€‚"
+
+#: merge-recursive.c:1027 merge-recursive.c:1040
+#, c-format
+msgid ""
+"CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left "
+"in tree at %s."
+msgstr ""
+"冲çªï¼ˆ%1$s/删除):%2$s 在 %3$s 中被删除,在 %5$s 中被 %4$s。%7$s 在 %6$s 中"
+"的版本ä¿ç•™äºŽ %8$s 中。"
+
+#: merge-recursive.c:1081
+msgid "rename"
+msgstr "é‡å‘½å"
+
+#: merge-recursive.c:1081
+msgid "renamed"
+msgstr "é‡å‘½å"
+
+#: merge-recursive.c:1137
+#, c-format
+msgid "%s is a directory in %s adding as %s instead"
+msgstr "%s 是 %s 中的一个目录而以 %s 为å被添加"
+
+#: merge-recursive.c:1159
+#, c-format
+msgid ""
+"CONFLICT (rename/rename): Rename \"%s\"->\"%s\" in branch \"%s\" rename \"%s"
+"\"->\"%s\" in \"%s\"%s"
+msgstr ""
+"冲çªï¼ˆé‡å‘½å/é‡å‘½å):在分支 \"%3$s\" 中é‡å‘½å \"%1$s\"->\"%2$s\",在分支 "
+"\"%6$s\" 中é‡å‘½å \"%4$s\"->\"%5$s\"%7$s"
+
+#: merge-recursive.c:1164
+msgid " (left unresolved)"
+msgstr "(留下未解决)"
+
+#: merge-recursive.c:1218
+#, c-format
+msgid "CONFLICT (rename/rename): Rename %s->%s in %s. Rename %s->%s in %s"
+msgstr ""
+"冲çªï¼ˆé‡å‘½å/é‡å‘½å):在 %3$s 中é‡å‘½å %1$s->%2$s,在 %6$s 中é‡å‘½å %4$s->"
+"%5$s"
+
+#: merge-recursive.c:1248
+#, c-format
+msgid "Renaming %s to %s and %s to %s instead"
+msgstr "而是é‡å‘½å %s 至 %s ä»¥åŠ %s 至 %s"
+
+#: merge-recursive.c:1447
+#, c-format
+msgid "CONFLICT (rename/add): Rename %s->%s in %s. %s added in %s"
+msgstr "冲çªï¼ˆé‡å‘½å/添加):在 %3$s 中é‡å‘½å %1$s->%2$s。在 %5$s 中添加 %4$s"
+
+#: merge-recursive.c:1457
+#, c-format
+msgid "Adding merged %s"
+msgstr "添加åˆå¹¶åŽçš„ %s"
+
+#: merge-recursive.c:1462 merge-recursive.c:1660
+#, c-format
+msgid "Adding as %s instead"
+msgstr "而是以 %s 为å添加"
+
+#: merge-recursive.c:1513
+#, c-format
+msgid "cannot read object %s"
+msgstr "ä¸èƒ½è¯»å–对象 %s"
+
+#: merge-recursive.c:1516
+#, c-format
+msgid "object %s is not a blob"
+msgstr "对象 %s ä¸æ˜¯ä¸€ä¸ªäºŒè¿›åˆ¶å¯¹è±¡ï¼ˆblob)"
+
+#: merge-recursive.c:1564
+msgid "modify"
+msgstr "修改"
+
+#: merge-recursive.c:1564
+msgid "modified"
+msgstr "修改"
+
+#: merge-recursive.c:1574
+msgid "content"
+msgstr "内容"
+
+#: merge-recursive.c:1581
+msgid "add/add"
+msgstr "添加/添加"
+
+#: merge-recursive.c:1615
+#, c-format
+msgid "Skipped %s (merged same as existing)"
+msgstr "略过 %s(已ç»åšè¿‡ç›¸åŒåˆå¹¶ï¼‰"
+
+#: merge-recursive.c:1629
+#, c-format
+msgid "Auto-merging %s"
+msgstr "自动åˆå¹¶ %s"
+
+#: merge-recursive.c:1633 git-submodule.sh:869
+msgid "submodule"
+msgstr "å­æ¨¡ç»„"
+
+#: merge-recursive.c:1634
+#, c-format
+msgid "CONFLICT (%s): Merge conflict in %s"
+msgstr "冲çªï¼ˆ%s):åˆå¹¶å†²çªäºŽ %s"
+
+#: merge-recursive.c:1724
+#, c-format
+msgid "Removing %s"
+msgstr "删除 %s"
+
+#: merge-recursive.c:1749
+msgid "file/directory"
+msgstr "文件/目录"
+
+#: merge-recursive.c:1755
+msgid "directory/file"
+msgstr "目录/文件"
+
+#: merge-recursive.c:1760
+#, c-format
+msgid "CONFLICT (%s): There is a directory with name %s in %s. Adding %s as %s"
+msgstr "冲çªï¼ˆ%1$s):在 %3$s 中有一个å为 %2$s 的目录。以 %5$s 为å添加 %4$s"
+
+#: merge-recursive.c:1770
+#, c-format
+msgid "Adding %s"
+msgstr "添加 %s"
-#: parse-options.c:493
+#: merge-recursive.c:1787
+msgid "Fatal merge failure, shouldn't happen."
+msgstr "严é‡çš„åˆå¹¶é”™è¯¯ï¼Œä¸åº”å‘生。"
+
+#: merge-recursive.c:1806
+msgid "Already up-to-date!"
+msgstr "å·²ç»æ˜¯æœ€æ–°çš„ï¼"
+
+#: merge-recursive.c:1815
+#, c-format
+msgid "merging of trees %s and %s failed"
+msgstr "无法åˆå¹¶æ ‘ %s å’Œ %s"
+
+#: merge-recursive.c:1845
+#, c-format
+msgid "Unprocessed path??? %s"
+msgstr "未处ç†çš„路径??? %s"
+
+#: merge-recursive.c:1890
+msgid "Merging:"
+msgstr "åˆå¹¶ï¼š"
+
+#: merge-recursive.c:1903
+#, c-format
+msgid "found %u common ancestor:"
+msgid_plural "found %u common ancestors:"
+msgstr[0] "å‘现 %u 个共åŒç¥–先:"
+msgstr[1] "å‘现 %u 个共åŒç¥–先:"
+
+#: merge-recursive.c:1940
+msgid "merge returned no commit"
+msgstr "åˆå¹¶æœªè¿”回æ交"
+
+#: merge-recursive.c:1997
+#, c-format
+msgid "Could not parse object '%s'"
+msgstr "ä¸èƒ½è§£æžå¯¹è±¡ '%s'"
+
+#: merge-recursive.c:2009 builtin/merge.c:696
+msgid "Unable to write index."
+msgstr "ä¸èƒ½å†™å…¥ç´¢å¼•ã€‚"
+
+#: parse-options.c:494
msgid "..."
msgstr "..."
-#: parse-options.c:511
+#: parse-options.c:512
#, c-format
msgid "usage: %s"
msgstr "用法:%s"
#. TRANSLATORS: the colon here should align with the
#. one in "usage: %s" translation
-#: parse-options.c:515
+#: parse-options.c:516
#, c-format
msgid " or: %s"
msgstr " 或:%s"
# 译者:为ä¿è¯åœ¨è¾“出中对é½ï¼Œæ³¨æ„调整å¥ä¸­ç©ºæ ¼ï¼
-#: parse-options.c:518
+#: parse-options.c:519
#, c-format
msgid " %s"
msgstr " %s"
-#: remote.c:1629
+#: remote.c:1632
#, c-format
msgid "Your branch is ahead of '%s' by %d commit.\n"
msgid_plural "Your branch is ahead of '%s' by %d commits.\n"
msgstr[0] "您的分支领先 '%s' å…± %d 个æ交。\n"
msgstr[1] "您的分支领先 '%s' å…± %d 个æ交。\n"
-#: remote.c:1635
+#: remote.c:1638
#, c-format
msgid "Your branch is behind '%s' by %d commit, and can be fast-forwarded.\n"
msgid_plural ""
@@ -385,7 +732,7 @@ msgid_plural ""
msgstr[0] "您的分支è½åŽ '%s' å…± %d 个æ交,并且å¯ä»¥å¿«è¿›ã€‚\n"
msgstr[1] "您的分支è½åŽ '%s' å…± %d 个æ交,并且å¯ä»¥å¿«è¿›ã€‚\n"
-#: remote.c:1643
+#: remote.c:1646
#, c-format
msgid ""
"Your branch and '%s' have diverged,\n"
@@ -395,19 +742,19 @@ msgid_plural ""
"and have %d and %d different commits each, respectively.\n"
msgstr[0] ""
"您的分支和 '%s' 出现了å离,\n"
-"并且å„自分别有 %d å’Œ %d 处ä¸åŒçš„æ交。\n"
+"并且分别有 %d å’Œ %d 处ä¸åŒçš„æ交。\n"
msgstr[1] ""
"您的分支和 '%s' 出现了å离,\n"
-"并且å„自分别有 %d å’Œ %d 处ä¸åŒçš„æ交。\n"
+"并且分别有 %d å’Œ %d 处ä¸åŒçš„æ交。\n"
-#: sequencer.c:121 builtin/merge.c:865 builtin/merge.c:978
-#: builtin/merge.c:1088 builtin/merge.c:1098
+#: sequencer.c:121 builtin/merge.c:864 builtin/merge.c:977
+#: builtin/merge.c:1087 builtin/merge.c:1097
#, c-format
msgid "Could not open '%s' for writing"
msgstr "ä¸èƒ½ä¸ºå†™å…¥æ‰“å¼€ '%s'"
-#: sequencer.c:123 builtin/merge.c:333 builtin/merge.c:868
-#: builtin/merge.c:1090 builtin/merge.c:1103
+#: sequencer.c:123 builtin/merge.c:333 builtin/merge.c:867
+#: builtin/merge.c:1089 builtin/merge.c:1102
#, c-format
msgid "Could not write to '%s'"
msgstr "ä¸èƒ½å†™å…¥ '%s'"
@@ -429,7 +776,7 @@ msgstr ""
"冲çªè§£å†³å®Œæ¯•åŽï¼Œç”¨ 'git add <paths>' 或 'git rm <paths>'\n"
"对修正åŽçš„文件åšæ ‡è®°ï¼Œç„¶åŽç”¨ 'git commit' æ交"
-#: sequencer.c:160 sequencer.c:758 sequencer.c:841
+#: sequencer.c:160 sequencer.c:765 sequencer.c:848
#, c-format
msgid "Could not write to %s"
msgstr "ä¸èƒ½å†™å…¥ %s"
@@ -465,473 +812,608 @@ msgstr "ä¸èƒ½è§£æž HEAD æ交\n"
msgid "Unable to update cache tree\n"
msgstr "ä¸èƒ½æ›´æ–°ç¼“å­˜\n"
-#: sequencer.c:324
+#: sequencer.c:327
#, c-format
msgid "Could not parse commit %s\n"
msgstr "ä¸èƒ½è§£æžæ交 %s\n"
-#: sequencer.c:329
+#: sequencer.c:332
#, c-format
msgid "Could not parse parent commit %s\n"
msgstr "ä¸èƒ½è§£æžçˆ¶æ交 %s\n"
-#: sequencer.c:395
+#: sequencer.c:398
msgid "Your index file is unmerged."
msgstr "您的索引文件未完æˆåˆå¹¶ã€‚"
-#: sequencer.c:398
+#: sequencer.c:401
msgid "You do not have a valid HEAD"
msgstr "您没有一个有效的 HEAD"
-#: sequencer.c:413
+#: sequencer.c:416
#, c-format
msgid "Commit %s is a merge but no -m option was given."
msgstr "æ交 %s 是一个åˆå¹¶æ交但未æä¾› -m 选项。"
-#: sequencer.c:421
+#: sequencer.c:424
#, c-format
msgid "Commit %s does not have parent %d"
msgstr "æ交 %s 没有父æ交 %d"
-#: sequencer.c:425
+#: sequencer.c:428
#, c-format
msgid "Mainline was specified but commit %s is not a merge."
msgstr "指定了主线但æ交 %s ä¸æ˜¯ä¸€ä¸ªåˆå¹¶ã€‚"
#. TRANSLATORS: The first %s will be "revert" or
#. "cherry-pick", the second %s a SHA1
-#: sequencer.c:436
+#: sequencer.c:439
#, c-format
msgid "%s: cannot parse parent commit %s"
msgstr "%s:ä¸èƒ½è§£æžçˆ¶æ交 %s"
-#: sequencer.c:440
+#: sequencer.c:443
#, c-format
msgid "Cannot get commit message for %s"
msgstr "ä¸èƒ½å¾—到 %s çš„æ交说明"
-#: sequencer.c:524
+#: sequencer.c:527
#, c-format
msgid "could not revert %s... %s"
msgstr "ä¸èƒ½è¿˜åŽŸ %s... %s"
-#: sequencer.c:525
+#: sequencer.c:528
#, c-format
msgid "could not apply %s... %s"
msgstr "ä¸èƒ½åº”用 %s... %s"
-#: sequencer.c:553
+#: sequencer.c:560
msgid "empty commit set passed"
msgstr "æ供了空的æ交集"
-#: sequencer.c:561
+#: sequencer.c:568
#, c-format
msgid "git %s: failed to read the index"
msgstr "git %s:无法读å–索引"
-#: sequencer.c:566
+#: sequencer.c:573
#, c-format
msgid "git %s: failed to refresh the index"
msgstr "git %s:无法刷新索引"
-#: sequencer.c:624
+#: sequencer.c:631
#, c-format
msgid "Cannot %s during a %s"
msgstr "无法 %s 在一个 %s 过程中"
-#: sequencer.c:646
+#: sequencer.c:653
#, c-format
msgid "Could not parse line %d."
msgstr "ä¸èƒ½è§£æžç¬¬ %d 行。"
-#: sequencer.c:651
+#: sequencer.c:658
msgid "No commits parsed."
msgstr "没有æ交被解æžã€‚"
-#: sequencer.c:664
+#: sequencer.c:671
#, c-format
msgid "Could not open %s"
msgstr "ä¸èƒ½æ‰“å¼€ %s"
-#: sequencer.c:668
+#: sequencer.c:675
#, c-format
msgid "Could not read %s."
msgstr "ä¸èƒ½è¯»å– %s。"
-#: sequencer.c:675
+#: sequencer.c:682
#, c-format
msgid "Unusable instruction sheet: %s"
msgstr "无用的指令表å•ï¼š%s"
-#: sequencer.c:703
+#: sequencer.c:710
#, c-format
msgid "Invalid key: %s"
msgstr "无效键å:%s"
-#: sequencer.c:706
+#: sequencer.c:713
#, c-format
msgid "Invalid value for %s: %s"
msgstr "%s 的值无效:%s"
-#: sequencer.c:718
+#: sequencer.c:725
#, c-format
msgid "Malformed options sheet: %s"
msgstr "éžæ³•çš„选项表å•ï¼š%s"
-#: sequencer.c:739
+#: sequencer.c:746
msgid "a cherry-pick or revert is already in progress"
msgstr "一个拣选或还原æ“作已在进行"
-#: sequencer.c:740
+#: sequencer.c:747
msgid "try \"git cherry-pick (--continue | --quit | --abort)\""
msgstr "å°è¯• \"git cherry-pick (--continue | --quit | --abort)\""
-#: sequencer.c:744
+#: sequencer.c:751
#, c-format
msgid "Could not create sequencer directory %s"
msgstr "ä¸èƒ½åˆ›å»ºåºåˆ—目录 %s"
-#: sequencer.c:760 sequencer.c:845
+#: sequencer.c:767 sequencer.c:852
#, c-format
msgid "Error wrapping up %s."
msgstr "错误收尾 %s。"
-#: sequencer.c:779 sequencer.c:913
+#: sequencer.c:786 sequencer.c:920
msgid "no cherry-pick or revert in progress"
-msgstr "没有拣选或还原æ“作在进行"
+msgstr "拣选或还原æ“作并未进行"
-#: sequencer.c:781
+#: sequencer.c:788
msgid "cannot resolve HEAD"
msgstr "ä¸èƒ½è§£æž HEAD"
-#: sequencer.c:783
+#: sequencer.c:790
msgid "cannot abort from a branch yet to be born"
msgstr "ä¸èƒ½ä»Žå°šæœªå»ºç«‹çš„分支终止"
-#: sequencer.c:805 builtin/apply.c:3697
+#: sequencer.c:812 builtin/apply.c:4005
#, c-format
msgid "cannot open %s: %s"
msgstr "ä¸èƒ½æ‰“å¼€ %s:%s"
-#: sequencer.c:808
+#: sequencer.c:815
#, c-format
msgid "cannot read %s: %s"
msgstr "ä¸èƒ½è¯»å– %s:%s"
-#: sequencer.c:809
+#: sequencer.c:816
msgid "unexpected end of file"
-msgstr "未预期的文件结æŸ"
+msgstr "æ„外的文件结æŸ"
-#: sequencer.c:815
+#: sequencer.c:822
#, c-format
msgid "stored pre-cherry-pick HEAD file '%s' is corrupt"
msgstr "ä¿å­˜æ‹£é€‰æ交å‰çš„ HEAD 文件 '%s' æŸå"
-#: sequencer.c:838
+#: sequencer.c:845
#, c-format
msgid "Could not format %s."
msgstr "ä¸èƒ½æ ¼å¼åŒ– %s。"
-#: sequencer.c:1000
+#: sequencer.c:1007
msgid "Can't revert as initial commit"
msgstr "ä¸èƒ½ä½œä¸ºåˆå§‹æ交还原"
-#: sequencer.c:1001
+#: sequencer.c:1008
msgid "Can't cherry-pick into empty head"
msgstr "ä¸èƒ½æ‹£é€‰åˆ°ç©ºåˆ†æ”¯"
-#: sha1_name.c:864
+#: sha1_name.c:1044
msgid "HEAD does not point to a branch"
msgstr "HEAD 没有指å‘一个分支"
-#: sha1_name.c:867
+#: sha1_name.c:1047
#, c-format
msgid "No such branch: '%s'"
msgstr "没有此分支:'%s'"
-#: sha1_name.c:869
+#: sha1_name.c:1049
#, c-format
msgid "No upstream configured for branch '%s'"
msgstr "尚未给分支 '%s' 设置上游"
-#: sha1_name.c:872
+#: sha1_name.c:1052
#, c-format
msgid "Upstream branch '%s' not stored as a remote-tracking branch"
msgstr "上游分支 '%s' 没有存储为一个远程跟踪分支"
-#: wrapper.c:413
+#: wrapper.c:408
+#, fuzzy, c-format
+msgid "unable to access '%s': %s"
+msgstr "ä¸èƒ½åˆ›å»º '%s'"
+
+#: wrapper.c:426
#, c-format
msgid "unable to look up current user in the passwd file: %s"
-msgstr "无法在 passwd 文件中查询到当å‰ç”¨æˆ·ï¼š%s"
+msgstr "无法在 passwd 文件中查询到该用户:%s"
-#: wrapper.c:414
+#: wrapper.c:427
msgid "no such user"
msgstr "无此用户"
-#: wt-status.c:135
+#: wt-status.c:140
msgid "Unmerged paths:"
msgstr "未åˆå¹¶çš„路径:"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: wt-status.c:141 wt-status.c:158
+#: wt-status.c:167 wt-status.c:194
#, c-format
msgid " (use \"git reset %s <file>...\" to unstage)"
msgstr " (使用 \"git reset %s <file>...\" 撤出暂存区)"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: wt-status.c:143 wt-status.c:160
+#: wt-status.c:169 wt-status.c:196
msgid " (use \"git rm --cached <file>...\" to unstage)"
msgstr " (使用 \"git rm --cached <file>...\" 撤出暂存区)"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: wt-status.c:144
+#: wt-status.c:173
+msgid " (use \"git add <file>...\" to mark resolution)"
+msgstr " (使用 \"git add <file>...\" 标记解决方案)"
+
+# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
+#: wt-status.c:175 wt-status.c:179
msgid " (use \"git add/rm <file>...\" as appropriate to mark resolution)"
msgstr " (酌情使用 \"git add/rm <file>...\" 标记解决方案)"
-#: wt-status.c:152
+# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
+#: wt-status.c:177
+msgid " (use \"git rm <file>...\" to mark resolution)"
+msgstr " (使用 \"git rm <file>...\" 标记解决方案)"
+
+#: wt-status.c:188
msgid "Changes to be committed:"
msgstr "è¦æ交的å˜æ›´ï¼š"
-#: wt-status.c:170
+#: wt-status.c:206
msgid "Changes not staged for commit:"
msgstr "尚未暂存以备æ交的å˜æ›´ï¼š"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: wt-status.c:174
+#: wt-status.c:210
msgid " (use \"git add <file>...\" to update what will be committed)"
msgstr " (使用 \"git add <file>...\" æ›´æ–°è¦æ交的内容)"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: wt-status.c:176
+#: wt-status.c:212
msgid " (use \"git add/rm <file>...\" to update what will be committed)"
msgstr " (使用 \"git add/rm <file>...\" æ›´æ–°è¦æ交的内容)"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: wt-status.c:177
+#: wt-status.c:213
msgid ""
" (use \"git checkout -- <file>...\" to discard changes in working directory)"
msgstr " (使用 \"git checkout -- <file>...\" 丢弃工作区的改动)"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: wt-status.c:179
+#: wt-status.c:215
msgid " (commit or discard the untracked or modified content in submodules)"
msgstr " (æ交或丢弃å­æ¨¡ç»„中未跟踪或修改的内容)"
-#: wt-status.c:188
-#, c-format
-msgid "%s files:"
-msgstr "%s文件:"
-
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: wt-status.c:191
+#: wt-status.c:227
#, c-format
msgid " (use \"git %s <file>...\" to include in what will be committed)"
msgstr " (使用 \"git %s <file>...\" 以包å«è¦æ交的内容)"
-#: wt-status.c:208
+#: wt-status.c:244
msgid "bug"
msgstr "bug"
-#: wt-status.c:213
+#: wt-status.c:249
msgid "both deleted:"
msgstr "åŒæ–¹åˆ é™¤ï¼š"
-#: wt-status.c:214
+#: wt-status.c:250
msgid "added by us:"
msgstr "由我们添加:"
-#: wt-status.c:215
+#: wt-status.c:251
msgid "deleted by them:"
msgstr "由他们删除:"
-#: wt-status.c:216
+#: wt-status.c:252
msgid "added by them:"
msgstr "由他们添加:"
-#: wt-status.c:217
+#: wt-status.c:253
msgid "deleted by us:"
msgstr "由我们删除:"
-#: wt-status.c:218
+#: wt-status.c:254
msgid "both added:"
msgstr "åŒæ–¹æ·»åŠ ï¼š"
-#: wt-status.c:219
+#: wt-status.c:255
msgid "both modified:"
msgstr "åŒæ–¹ä¿®æ”¹ï¼š"
# 译者:末尾两个字节å¯èƒ½è¢«åˆ å‡ï¼Œå¦‚果翻译为中文标点会出现åŠä¸ªæ±‰å­—
-#: wt-status.c:249
+#: wt-status.c:285
msgid "new commits, "
msgstr "æ–°æ交, "
# 译者:末尾两个字节å¯èƒ½è¢«åˆ å‡ï¼Œå¦‚果翻译为中文标点会出现åŠä¸ªæ±‰å­—
-#: wt-status.c:251
+#: wt-status.c:287
msgid "modified content, "
msgstr "修改的内容, "
# 译者:末尾两个字节å¯èƒ½è¢«åˆ å‡ï¼Œå¦‚果翻译为中文标点会出现åŠä¸ªæ±‰å­—
-#: wt-status.c:253
+#: wt-status.c:289
msgid "untracked content, "
msgstr "未跟踪的内容, "
# 译者:为ä¿è¯åœ¨è¾“出中对é½ï¼Œæ³¨æ„调整å¥ä¸­ç©ºæ ¼ï¼
-#: wt-status.c:267
+#: wt-status.c:303
#, c-format
msgid "new file: %s"
msgstr "新文件: %s"
# 译者:为ä¿è¯åœ¨è¾“出中对é½ï¼Œæ³¨æ„调整å¥ä¸­ç©ºæ ¼ï¼
-#: wt-status.c:270
+#: wt-status.c:306
#, c-format
msgid "copied: %s -> %s"
msgstr "æ‹·è´ï¼š %s -> %s"
# 译者:为ä¿è¯åœ¨è¾“出中对é½ï¼Œæ³¨æ„调整å¥ä¸­ç©ºæ ¼ï¼
-#: wt-status.c:273
+#: wt-status.c:309
#, c-format
msgid "deleted: %s"
msgstr "删除: %s"
# 译者:为ä¿è¯åœ¨è¾“出中对é½ï¼Œæ³¨æ„调整å¥ä¸­ç©ºæ ¼ï¼
-#: wt-status.c:276
+#: wt-status.c:312
#, c-format
msgid "modified: %s"
msgstr "修改: %s"
# 译者:为ä¿è¯åœ¨è¾“出中对é½ï¼Œæ³¨æ„调整å¥ä¸­ç©ºæ ¼ï¼
-#: wt-status.c:279
+#: wt-status.c:315
#, c-format
msgid "renamed: %s -> %s"
msgstr "é‡å‘½å: %s -> %s"
# 译者:为ä¿è¯åœ¨è¾“出中对é½ï¼Œæ³¨æ„调整å¥ä¸­ç©ºæ ¼ï¼
-#: wt-status.c:282
+#: wt-status.c:318
#, c-format
msgid "typechange: %s"
msgstr "类型å˜æ›´ï¼š %s"
# 译者:为ä¿è¯åœ¨è¾“出中对é½ï¼Œæ³¨æ„调整å¥ä¸­ç©ºæ ¼ï¼
-#: wt-status.c:285
+#: wt-status.c:321
#, c-format
msgid "unknown: %s"
msgstr "未知: %s"
# 译者:为ä¿è¯åœ¨è¾“出中对é½ï¼Œæ³¨æ„调整å¥ä¸­ç©ºæ ¼ï¼
-#: wt-status.c:288
+#: wt-status.c:324
#, c-format
msgid "unmerged: %s"
msgstr "未åˆå¹¶ï¼š %s"
-#: wt-status.c:291
+#: wt-status.c:327
#, c-format
msgid "bug: unhandled diff status %c"
msgstr "bug:未处ç†çš„å·®å¼‚çŠ¶æ€ %c"
-#: wt-status.c:737
+#: wt-status.c:785
+msgid "You have unmerged paths."
+msgstr "您有尚未åˆå¹¶çš„路径。"
+
+# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
+#: wt-status.c:788 wt-status.c:912
+msgid " (fix conflicts and run \"git commit\")"
+msgstr " (解决冲çªå¹¶è¿è¡Œ \"git commit\")"
+
+#: wt-status.c:791
+msgid "All conflicts fixed but you are still merging."
+msgstr "所有冲çªå·²è§£å†³ä½†æ‚¨ä»å¤„于åˆå¹¶ä¸­ã€‚"
+
+# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
+#: wt-status.c:794
+msgid " (use \"git commit\" to conclude merge)"
+msgstr " (使用 \"git commit\" 结æŸåˆå¹¶ï¼‰"
+
+#: wt-status.c:804
+msgid "You are in the middle of an am session."
+msgstr "您正处于一个 am 过程中。"
+
+#: wt-status.c:807
+msgid "The current patch is empty."
+msgstr "当å‰çš„è¡¥ä¸ä¸ºç©ºã€‚"
+
+# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
+#: wt-status.c:811
+msgid " (fix conflicts and then run \"git am --resolved\")"
+msgstr " (解决冲çªï¼Œç„¶åŽè¿è¡Œ \"git am --resolved\")"
+
+# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
+#: wt-status.c:813
+msgid " (use \"git am --skip\" to skip this patch)"
+msgstr " (使用 \"git am --skip\" 跳过此补ä¸ï¼‰"
+
+# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
+#: wt-status.c:815
+msgid " (use \"git am --abort\" to restore the original branch)"
+msgstr " (使用 \"git am --abort\" æ¢å¤åŽŸæœ‰åˆ†æ”¯ï¼‰"
+
+#: wt-status.c:873 wt-status.c:883
+msgid "You are currently rebasing."
+msgstr "您正在å˜åŸºã€‚"
+
+# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
+#: wt-status.c:876
+msgid " (fix conflicts and then run \"git rebase --continue\")"
+msgstr " (解决冲çªï¼Œç„¶åŽè¿è¡Œ \"git rebase --continue\")"
+
+# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
+#: wt-status.c:878
+msgid " (use \"git rebase --skip\" to skip this patch)"
+msgstr " (使用 \"git rebase --skip\" 跳过此补ä¸ï¼‰"
+
+# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
+#: wt-status.c:880
+msgid " (use \"git rebase --abort\" to check out the original branch)"
+msgstr " (使用 \"git rebase --abort\" 以检出原有分支)"
+
+# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
+#: wt-status.c:886
+msgid " (all conflicts fixed: run \"git rebase --continue\")"
+msgstr " (所有冲çªå·²è§£å†³ï¼šè¿è¡Œ \"git rebase --continue\")"
+
+#: wt-status.c:888
+msgid "You are currently splitting a commit during a rebase."
+msgstr "您正在å˜åŸºè¿‡ç¨‹ä¸­æ‹†åˆ†ä¸€ä¸ªæ交。"
+
+# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
+#: wt-status.c:891
+msgid " (Once your working directory is clean, run \"git rebase --continue\")"
+msgstr " (一旦您工作目录æ交干净åŽï¼Œè¿è¡Œ \"git rebase --continue\")"
+
+#: wt-status.c:893
+msgid "You are currently editing a commit during a rebase."
+msgstr "您正在å˜åŸºè¿‡ç¨‹ä¸­ç¼–辑一个æ交。"
+
+# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
+#: wt-status.c:896
+msgid " (use \"git commit --amend\" to amend the current commit)"
+msgstr " (使用 \"git commit --amend\" 修补当å‰æ交)"
+
+# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
+#: wt-status.c:898
+msgid ""
+" (use \"git rebase --continue\" once you are satisfied with your changes)"
+msgstr " (当您对您的修改满æ„åŽæ‰§è¡Œ \"git rebase --continue\")"
+
+#: wt-status.c:908
+msgid "You are currently cherry-picking."
+msgstr "您正在åšæ‹£é€‰æ“作。"
+
+# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
+#: wt-status.c:915
+msgid " (all conflicts fixed: run \"git commit\")"
+msgstr " (解决所有冲çªåŽï¼Œæ‰§è¡Œ \"git commit\")"
+
+#: wt-status.c:924
+msgid "You are currently bisecting."
+msgstr "您正在åšäºŒåˆ†æŸ¥æ‰¾ã€‚"
+
+# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
+#: wt-status.c:927
+msgid " (use \"git bisect reset\" to get back to the original branch)"
+msgstr " (使用 \"git bisect reset\" 以回到原有分支)"
+
+#: wt-status.c:978
msgid "On branch "
msgstr "ä½äºŽåˆ†æ”¯ "
-#: wt-status.c:744
+#: wt-status.c:985
msgid "Not currently on any branch."
msgstr "当å‰ä¸åœ¨ä»»ä½•åˆ†æ”¯ä¸Šã€‚"
-#: wt-status.c:755
+#: wt-status.c:997
msgid "Initial commit"
msgstr "åˆå§‹æ交"
-#: wt-status.c:769
-msgid "Untracked"
+#: wt-status.c:1011
+#, fuzzy
+msgid "Untracked files"
msgstr "未跟踪的"
-#: wt-status.c:771
-msgid "Ignored"
+#: wt-status.c:1013
+#, fuzzy
+msgid "Ignored files"
msgstr "忽略的"
-#: wt-status.c:773
+#: wt-status.c:1015
#, c-format
msgid "Untracked files not listed%s"
msgstr "未跟踪的文件没有列出%s"
# 译者:中文字符串拼接,å¯åˆ é™¤å‰å¯¼ç©ºæ ¼
-#: wt-status.c:775
+#: wt-status.c:1017
msgid " (use -u option to show untracked files)"
msgstr "(使用 -u å‚数显示未跟踪的文件)"
-#: wt-status.c:781
+#: wt-status.c:1023
msgid "No changes"
msgstr "没有修改"
-#: wt-status.c:785
-#, c-format
-msgid "no changes added to commit%s\n"
-msgstr "修改尚未加入æ交%s\n"
-
# 译者:中文字符串拼接,å¯åˆ é™¤å‰å¯¼ç©ºæ ¼
-#: wt-status.c:787
-msgid " (use \"git add\" and/or \"git commit -a\")"
+#: wt-status.c:1028
+#, fuzzy, c-format
+msgid "no changes added to commit (use \"git add\" and/or \"git commit -a\")\n"
msgstr "(使用 \"git add\" 和/或 \"git commit -a\")"
-#: wt-status.c:789
-#, c-format
-msgid "nothing added to commit but untracked files present%s\n"
-msgstr "空æ交但存在未跟踪文件%s\n"
+#: wt-status.c:1031
+#, fuzzy, c-format
+msgid "no changes added to commit\n"
+msgstr "修改尚未加入æ交%s\n"
-# 译者:中文字符串拼接,å¯åˆ é™¤å‰å¯¼ç©ºæ ¼
-#: wt-status.c:791
-msgid " (use \"git add\" to track)"
-msgstr "(使用 \"git add\" 建立跟踪)"
+#: wt-status.c:1034
+#, fuzzy, c-format
+msgid ""
+"nothing added to commit but untracked files present (use \"git add\" to "
+"track)\n"
+msgstr "空æ交但存在未跟踪文件%s\n"
-#: wt-status.c:793 wt-status.c:796 wt-status.c:799
-#, c-format
-msgid "nothing to commit%s\n"
-msgstr "æ— é¡»æ交%s\n"
+#: wt-status.c:1037
+#, fuzzy, c-format
+msgid "nothing added to commit but untracked files present\n"
+msgstr "空æ交但存在未跟踪文件%s\n"
# 译者:中文字符串拼接,å¯åˆ é™¤å‰å¯¼ç©ºæ ¼
-#: wt-status.c:794
-msgid " (create/copy files and use \"git add\" to track)"
+#: wt-status.c:1040
+#, fuzzy, c-format
+msgid "nothing to commit (create/copy files and use \"git add\" to track)\n"
msgstr "(新建/æ‹·è´çš„文件使用 \"git add\" 建立跟踪)"
+#: wt-status.c:1043 wt-status.c:1048
+#, fuzzy, c-format
+msgid "nothing to commit\n"
+msgstr "æ— é¡»æ交%s\n"
+
# 译者:中文字符串拼接,å¯åˆ é™¤å‰å¯¼ç©ºæ ¼
-#: wt-status.c:797
-msgid " (use -u to show untracked files)"
+#: wt-status.c:1046
+#, fuzzy, c-format
+msgid "nothing to commit (use -u to show untracked files)\n"
msgstr "(使用 -u 显示未跟踪文件)"
# 译者:中文字符串拼接,å¯åˆ é™¤å‰å¯¼ç©ºæ ¼
-#: wt-status.c:800
-msgid " (working directory clean)"
+#: wt-status.c:1050
+#, fuzzy, c-format
+msgid "nothing to commit, working directory clean\n"
msgstr "(干净的工作区)"
-#: wt-status.c:908
+#: wt-status.c:1158
msgid "HEAD (no branch)"
msgstr "HEAD(éžåˆ†æ”¯ï¼‰"
# 译者:注æ„ä¿æŒå¥å°¾ç©ºæ ¼
-#: wt-status.c:914
+#: wt-status.c:1164
msgid "Initial commit on "
msgstr "åˆå§‹æ交于 "
# 译者:注æ„ä¿æŒå¥å°¾ç©ºæ ¼
-#: wt-status.c:929
+#: wt-status.c:1179
msgid "behind "
msgstr "è½åŽ "
# 译者:注æ„ä¿æŒå¥å°¾ç©ºæ ¼
-#: wt-status.c:932 wt-status.c:935
+#: wt-status.c:1182 wt-status.c:1185
msgid "ahead "
msgstr "领先 "
# 译者:注æ„ä¿æŒå¥å°¾ç©ºæ ¼
-#: wt-status.c:937
+#: wt-status.c:1187
msgid ", behind "
msgstr ",è½åŽ "
+#: compat/precompose_utf8.c:58 builtin/clone.c:341
+#, c-format
+msgid "failed to unlink '%s'"
+msgstr "无法删除 '%s'"
+
+#: builtin/add.c:19
+#, fuzzy
+msgid "git add [options] [--] <filepattern>..."
+msgstr "git apply [选项] [<è¡¥ä¸>...]"
+
#: builtin/add.c:62
#, c-format
msgid "unexpected diff status %c"
msgstr "æ„å¤–çš„å·®å¼‚çŠ¶æ€ %c"
-#: builtin/add.c:67 builtin/commit.c:226
+#: builtin/add.c:67 builtin/commit.c:229
msgid "updating files failed"
msgstr "更新文件失败"
@@ -949,7 +1431,7 @@ msgstr "路径 '%s' 属于模组 '%.*s'"
msgid "Unstaged changes after refreshing the index:"
msgstr "刷新索引之åŽå°šæœªè¢«æš‚存的å˜æ›´ï¼š"
-#: builtin/add.c:195 builtin/add.c:456 builtin/rm.c:186
+#: builtin/add.c:195 builtin/add.c:460 builtin/rm.c:186
#, c-format
msgid "pathspec '%s' did not match any files"
msgstr "路径 '%s' 未匹é…任何文件"
@@ -966,11 +1448,11 @@ msgstr "ä¸èƒ½è¯»å–索引"
#: builtin/add.c:286
#, c-format
msgid "Could not open '%s' for writing."
-msgstr "ä¸èƒ½ä¸ºå†™å…¥æ‰“å¼€ '%s'。"
+msgstr "ä¸èƒ½æ‰“å¼€ '%s' 以写入。"
#: builtin/add.c:290
msgid "Could not write patch"
-msgstr "ä¸èƒ½å†™è¡¥ä¸"
+msgstr "ä¸èƒ½ç”Ÿæˆè¡¥ä¸"
#: builtin/add.c:295
#, c-format
@@ -986,110 +1468,165 @@ msgstr "空补ä¸ã€‚异常终止。"
msgid "Could not apply '%s'"
msgstr "ä¸èƒ½åº”用 '%s'"
-#: builtin/add.c:312
+#: builtin/add.c:313
msgid "The following paths are ignored by one of your .gitignore files:\n"
-msgstr "下列路径被您的一个 .gitignore 文件所忽略:\n"
+msgstr "下列路径根æ®æ‚¨çš„一个 .gitignore 文件而被忽略:\n"
+
+#: builtin/add.c:319 builtin/clean.c:52 builtin/fetch.c:78 builtin/mv.c:63
+#: builtin/prune-packed.c:76 builtin/push.c:388 builtin/remote.c:1253
+#: builtin/rm.c:133
+msgid "dry run"
+msgstr ""
+
+#: builtin/add.c:320 builtin/apply.c:4354 builtin/commit.c:1187
+#: builtin/count-objects.c:82 builtin/fsck.c:613 builtin/log.c:1477
+#: builtin/mv.c:62 builtin/read-tree.c:112
+msgid "be verbose"
+msgstr "冗长输出"
+
+#: builtin/add.c:322
+#, fuzzy
+msgid "interactive picking"
+msgstr "交互å¼æ·»åŠ å¤±è´¥"
+
+#: builtin/add.c:323 builtin/checkout.c:1028 builtin/reset.c:248
+msgid "select hunks interactively"
+msgstr ""
+
+#: builtin/add.c:324
+msgid "edit current diff and apply"
+msgstr ""
+
+#: builtin/add.c:325
+msgid "allow adding otherwise ignored files"
+msgstr ""
+
+#: builtin/add.c:326
+#, fuzzy
+msgid "update tracked files"
+msgstr "无法存储包文件"
-#: builtin/add.c:352
+#: builtin/add.c:327
+msgid "record only the fact that the path will be added later"
+msgstr ""
+
+#: builtin/add.c:328
+msgid "add changes from all tracked and untracked files"
+msgstr ""
+
+#: builtin/add.c:329
+#, fuzzy
+msgid "don't add, only refresh the index"
+msgstr "git %s:无法刷新索引"
+
+#: builtin/add.c:330
+msgid "just skip files which cannot be added because of errors"
+msgstr ""
+
+#: builtin/add.c:331
+msgid "check if - even missing - files are ignored in dry run"
+msgstr ""
+
+#: builtin/add.c:353
#, c-format
msgid "Use -f if you really want to add them.\n"
msgstr "使用 -f å‚数如果您确实è¦æ·»åŠ å®ƒä»¬ã€‚\n"
-#: builtin/add.c:353
+#: builtin/add.c:354
msgid "no files added"
msgstr "没有文件被添加"
-#: builtin/add.c:359
+#: builtin/add.c:360
msgid "adding files failed"
msgstr "添加文件失败"
-#: builtin/add.c:391
+#: builtin/add.c:392
msgid "-A and -u are mutually incompatible"
msgstr "-A 和 -u 选项互斥"
-#: builtin/add.c:393
+#: builtin/add.c:394
msgid "Option --ignore-missing can only be used together with --dry-run"
-msgstr "选项 --ignore-missing åªèƒ½å’Œ --dry-run 共用"
+msgstr "选项 --ignore-missing åªèƒ½å’Œ --dry-run åŒæ—¶ä½¿ç”¨"
-#: builtin/add.c:413
+#: builtin/add.c:414
#, c-format
msgid "Nothing specified, nothing added.\n"
msgstr "没有指定文件,也没有文件被添加。\n"
-#: builtin/add.c:414
+#: builtin/add.c:415
#, c-format
msgid "Maybe you wanted to say 'git add .'?\n"
msgstr "也许您想è¦æ‰§è¡Œ 'git add .'?\n"
-#: builtin/add.c:420 builtin/clean.c:95 builtin/commit.c:286 builtin/mv.c:82
+#: builtin/add.c:421 builtin/clean.c:95 builtin/commit.c:289 builtin/mv.c:82
#: builtin/rm.c:162
msgid "index file corrupt"
msgstr "索引文件æŸå"
-#: builtin/add.c:476 builtin/apply.c:4108 builtin/mv.c:229 builtin/rm.c:260
+#: builtin/add.c:481 builtin/apply.c:4450 builtin/mv.c:229 builtin/rm.c:260
msgid "Unable to write new index file"
msgstr "无法写入新索引文件"
-#: builtin/apply.c:53
+#: builtin/apply.c:57
msgid "git apply [options] [<patch>...]"
msgstr "git apply [选项] [<è¡¥ä¸>...]"
-#: builtin/apply.c:106
+#: builtin/apply.c:110
#, c-format
msgid "unrecognized whitespace option '%s'"
msgstr "未能识别的空白字符选项 '%s'"
-#: builtin/apply.c:121
+#: builtin/apply.c:125
#, c-format
msgid "unrecognized whitespace ignore option '%s'"
msgstr "未能识别的空白字符忽略选项 '%s'"
-#: builtin/apply.c:815
+#: builtin/apply.c:823
#, c-format
msgid "Cannot prepare timestamp regexp %s"
msgstr "æ— æ³•å‡†å¤‡æ—¶é—´æˆ³æ­£åˆ™è¡¨è¾¾å¼ %s"
-#: builtin/apply.c:824
+#: builtin/apply.c:832
#, c-format
msgid "regexec returned %d for input: %s"
msgstr "regexec 返回 %d,输入为:%s"
-#: builtin/apply.c:905
+#: builtin/apply.c:913
#, c-format
msgid "unable to find filename in patch at line %d"
msgstr "ä¸èƒ½åœ¨è¡¥ä¸çš„第 %d 行找到文件å"
-#: builtin/apply.c:937
+#: builtin/apply.c:945
#, c-format
msgid "git apply: bad git-diff - expected /dev/null, got %s on line %d"
-msgstr "git apply:错误的 git-diff - 期望 /dev/null,但在第 %2$d 行得到 %1$s"
+msgstr "git apply:错误的 git-diff - 应为 /dev/null,但在第 %2$d 行得到 %1$s"
-#: builtin/apply.c:941
+#: builtin/apply.c:949
#, c-format
msgid "git apply: bad git-diff - inconsistent new filename on line %d"
msgstr "git apply:错误的 git-diff - 第 %d 行上新文件åä¸ä¸€è‡´"
-#: builtin/apply.c:942
+#: builtin/apply.c:950
#, c-format
msgid "git apply: bad git-diff - inconsistent old filename on line %d"
msgstr "git apply:错误的 git-diff - 第 %d 行上旧文件åä¸ä¸€è‡´"
-#: builtin/apply.c:949
+#: builtin/apply.c:957
#, c-format
msgid "git apply: bad git-diff - expected /dev/null on line %d"
-msgstr "git apply:错误的 git-diff - 期望 /dev/null 于第 %d 行"
+msgstr "git apply:错误的 git-diff - 第 %d 行处应为 /dev/null"
-#: builtin/apply.c:1394
+#: builtin/apply.c:1420
#, c-format
msgid "recount: unexpected line: %.*s"
msgstr "recount:æ„外的行:%.*s"
-#: builtin/apply.c:1451
+#: builtin/apply.c:1477
#, c-format
msgid "patch fragment without header at line %d: %.*s"
msgstr "第 %d 行的补ä¸ç‰‡æ®µæ²¡æœ‰å¤´ä¿¡æ¯ï¼š%.*s"
-#: builtin/apply.c:1468
+#: builtin/apply.c:1494
#, c-format
msgid ""
"git diff header lacks filename information when removing %d leading pathname "
@@ -1100,82 +1637,82 @@ msgid_plural ""
msgstr[0] "当移除 %d 个å‰å¯¼è·¯å¾„åŽ git diff 头缺ä¹æ–‡ä»¶åä¿¡æ¯ï¼ˆç¬¬ %d 行)"
msgstr[1] "当移除 %d 个å‰å¯¼è·¯å¾„åŽ git diff 头缺ä¹æ–‡ä»¶åä¿¡æ¯ï¼ˆç¬¬ %d 行)"
-#: builtin/apply.c:1628
+#: builtin/apply.c:1654
msgid "new file depends on old contents"
msgstr "新文件ä¾èµ–旧内容"
-#: builtin/apply.c:1630
+#: builtin/apply.c:1656
msgid "deleted file still has contents"
msgstr "删除的文件ä»æœ‰å†…容"
-#: builtin/apply.c:1656
+#: builtin/apply.c:1682
#, c-format
msgid "corrupt patch at line %d"
-msgstr "è¡¥ä¸æŸåä½äºŽç¬¬ %d è¡Œ"
+msgstr "è¡¥ä¸åœ¨ç¬¬ %d è¡ŒæŸå"
-#: builtin/apply.c:1692
+#: builtin/apply.c:1718
#, c-format
msgid "new file %s depends on old contents"
msgstr "新文件 %s ä¾èµ–旧内容"
-#: builtin/apply.c:1694
+#: builtin/apply.c:1720
#, c-format
msgid "deleted file %s still has contents"
msgstr "删除的文件 %s ä»æœ‰å†…容"
-#: builtin/apply.c:1697
+#: builtin/apply.c:1723
#, c-format
msgid "** warning: file %s becomes empty but is not deleted"
msgstr "** 警告:文件 %s æˆä¸ºç©ºæ–‡ä»¶ä½†å¹¶æœªåˆ é™¤"
-#: builtin/apply.c:1843
+#: builtin/apply.c:1869
#, c-format
msgid "corrupt binary patch at line %d: %.*s"
msgstr "二进制补ä¸åœ¨ç¬¬ %d è¡ŒæŸå:%.*s"
#. there has to be one hunk (forward hunk)
-#: builtin/apply.c:1872
+#: builtin/apply.c:1898
#, c-format
msgid "unrecognized binary patch at line %d"
msgstr "未能识别的二进制补ä¸ä½äºŽç¬¬ %d è¡Œ"
-#: builtin/apply.c:1958
+#: builtin/apply.c:1984
#, c-format
msgid "patch with only garbage at line %d"
msgstr "è¡¥ä¸æ–‡ä»¶çš„第 %d è¡Œåªæœ‰åžƒåœ¾æ•°æ®"
-#: builtin/apply.c:2048
+#: builtin/apply.c:2074
#, c-format
msgid "unable to read symlink %s"
msgstr "无法读å–符å·é“¾æŽ¥ %s"
-#: builtin/apply.c:2052
+#: builtin/apply.c:2078
#, c-format
msgid "unable to open or read %s"
msgstr "ä¸èƒ½æ‰“å¼€æˆ–è¯»å– %s"
-#: builtin/apply.c:2123
+#: builtin/apply.c:2149
msgid "oops"
msgstr "å“Žå“Ÿ"
-#: builtin/apply.c:2645
+#: builtin/apply.c:2671
#, c-format
msgid "invalid start of line: '%c'"
msgstr "无效的行首字符:'%c'"
-#: builtin/apply.c:2763
+#: builtin/apply.c:2789
#, c-format
msgid "Hunk #%d succeeded at %d (offset %d line)."
msgid_plural "Hunk #%d succeeded at %d (offset %d lines)."
msgstr[0] "å— #%d æˆåŠŸåº”用于 %d (å移 %d 行)"
msgstr[1] "å— #%d æˆåŠŸåº”用于 %d (å移 %d 行)"
-#: builtin/apply.c:2775
+#: builtin/apply.c:2801
#, c-format
msgid "Context reduced to (%ld/%ld) to apply fragment at %d"
msgstr "上下文å‡å°‘到(%ld/%ld)以在第 %d 行应用补ä¸ç‰‡æ®µ"
-#: builtin/apply.c:2781
+#: builtin/apply.c:2807
#, c-format
msgid ""
"while searching for:\n"
@@ -1184,313 +1721,319 @@ msgstr ""
"当查询:\n"
"%.*s"
-#: builtin/apply.c:2800
+#: builtin/apply.c:2826
#, c-format
msgid "missing binary patch data for '%s'"
msgstr "缺失 '%s' 的二进制补ä¸æ•°æ®"
-#: builtin/apply.c:2903
+#: builtin/apply.c:2929
#, c-format
msgid "binary patch does not apply to '%s'"
msgstr "二进制补ä¸æœªåº”用到 '%s'"
-#: builtin/apply.c:2909
+#: builtin/apply.c:2935
#, c-format
msgid "binary patch to '%s' creates incorrect result (expecting %s, got %s)"
-msgstr "到 '%s' 的二进制补ä¸äº§ç”Ÿäº†ä¸æ­£ç¡®çš„结果(预期 %s,得到 %s)"
+msgstr "到 '%s' 的二进制补ä¸äº§ç”Ÿäº†ä¸æ­£ç¡®çš„结果(应为 %s,å´ä¸º %s)"
-#: builtin/apply.c:2930
+#: builtin/apply.c:2956
#, c-format
msgid "patch failed: %s:%ld"
msgstr "打补ä¸å¤±è´¥ï¼š%s:%ld"
-#: builtin/apply.c:3045
+#: builtin/apply.c:3078
#, c-format
-msgid "patch %s has been renamed/deleted"
-msgstr "è¡¥ä¸ %s å·²ç»è¢«é‡å‘½å/删除"
+msgid "cannot checkout %s"
+msgstr "ä¸èƒ½æ£€å‡º %s"
-#: builtin/apply.c:3052 builtin/apply.c:3069
+#: builtin/apply.c:3123 builtin/apply.c:3132 builtin/apply.c:3176
#, c-format
msgid "read of %s failed"
msgstr "è¯»å– %s 失败"
-#: builtin/apply.c:3084
-msgid "removal patch leaves file contents"
-msgstr "移除补ä¸ä»ç•™ä¸‹äº†æ–‡ä»¶å†…容"
-
-#: builtin/apply.c:3105
+#: builtin/apply.c:3156 builtin/apply.c:3378
#, c-format
-msgid "%s: already exists in working directory"
-msgstr "%s:已ç»å­˜åœ¨äºŽå·¥ä½œåŒºä¸­"
+msgid "path %s has been renamed/deleted"
+msgstr "路径 %s å·²ç»è¢«é‡å‘½å/删除"
-#: builtin/apply.c:3143
+#: builtin/apply.c:3237 builtin/apply.c:3392
#, c-format
-msgid "%s: has been deleted/renamed"
-msgstr "%s:已ç»è¢«åˆ é™¤/é‡å‘½å"
+msgid "%s: does not exist in index"
+msgstr "%s:ä¸å­˜åœ¨äºŽç´¢å¼•ä¸­"
-#: builtin/apply.c:3148 builtin/apply.c:3179
+#: builtin/apply.c:3241 builtin/apply.c:3384 builtin/apply.c:3406
#, c-format
msgid "%s: %s"
msgstr "%s:%s"
-#: builtin/apply.c:3159
-#, c-format
-msgid "%s: does not exist in index"
-msgstr "%s:ä¸å­˜åœ¨äºŽç´¢å¼•ä¸­"
-
-#: builtin/apply.c:3173
+#: builtin/apply.c:3246 builtin/apply.c:3400
#, c-format
msgid "%s: does not match index"
msgstr "%s:和索引ä¸åŒ¹é…"
-#: builtin/apply.c:3190
+#: builtin/apply.c:3348
+msgid "removal patch leaves file contents"
+msgstr "移除补ä¸ä»ç•™ä¸‹äº†æ–‡ä»¶å†…容"
+
+#: builtin/apply.c:3417
#, c-format
msgid "%s: wrong type"
msgstr "%s:错误类型"
-#: builtin/apply.c:3192
+#: builtin/apply.c:3419
#, c-format
msgid "%s has type %o, expected %o"
-msgstr "%s 的类型是 %o,预期是 %o"
+msgstr "%s 的类型是 %o,应为 %o"
-#: builtin/apply.c:3247
+#: builtin/apply.c:3520
#, c-format
msgid "%s: already exists in index"
msgstr "%s:已ç»å­˜åœ¨äºŽç´¢å¼•ä¸­"
-#: builtin/apply.c:3267
+#: builtin/apply.c:3523
+#, c-format
+msgid "%s: already exists in working directory"
+msgstr "%s:已ç»å­˜åœ¨äºŽå·¥ä½œåŒºä¸­"
+
+#: builtin/apply.c:3543
#, c-format
msgid "new mode (%o) of %s does not match old mode (%o)"
msgstr "%2$s 的新模å¼ï¼ˆ%1$o)和旧模å¼ï¼ˆ%3$o)ä¸åŒ¹é…"
-#: builtin/apply.c:3272
+#: builtin/apply.c:3548
#, c-format
msgid "new mode (%o) of %s does not match old mode (%o) of %s"
msgstr "%2$s 的新模å¼ï¼ˆ%1$o)和 %4$s 的旧模å¼ï¼ˆ%3$o)ä¸åŒ¹é…"
-#: builtin/apply.c:3280
+#: builtin/apply.c:3556
#, c-format
msgid "%s: patch does not apply"
msgstr "%s:补ä¸æœªåº”用"
-#: builtin/apply.c:3293
+#: builtin/apply.c:3569
#, c-format
msgid "Checking patch %s..."
msgstr "æ£€æŸ¥è¡¥ä¸ %s..."
-#: builtin/apply.c:3348 builtin/checkout.c:212 builtin/reset.c:158
+#: builtin/apply.c:3624 builtin/checkout.c:215 builtin/reset.c:158
#, c-format
msgid "make_cache_entry failed for path '%s'"
msgstr "对路径 '%s' çš„ make_cache_entry æ“作失败"
-#: builtin/apply.c:3491
+#: builtin/apply.c:3767
#, c-format
msgid "unable to remove %s from index"
msgstr "ä¸èƒ½ä»Žç´¢å¼•ä¸­ç§»é™¤ %s"
-#: builtin/apply.c:3518
+#: builtin/apply.c:3795
#, c-format
msgid "corrupt patch for subproject %s"
msgstr "å­é¡¹ç›® %s æŸåçš„è¡¥ä¸"
-#: builtin/apply.c:3522
+#: builtin/apply.c:3799
#, c-format
msgid "unable to stat newly created file '%s'"
msgstr "ä¸èƒ½æžšä¸¾æ–°å»ºæ–‡ä»¶ '%s' 的状æ€"
-#: builtin/apply.c:3527
+#: builtin/apply.c:3804
#, c-format
msgid "unable to create backing store for newly created file %s"
msgstr "ä¸èƒ½ä¸ºæ–°å»ºæ–‡ä»¶ %s 创建åŽç«¯å­˜å‚¨"
-#: builtin/apply.c:3530
+#: builtin/apply.c:3807 builtin/apply.c:3915
#, c-format
msgid "unable to add cache entry for %s"
msgstr "无法为 %s 添加缓存æ¡ç›®"
-#: builtin/apply.c:3563
+#: builtin/apply.c:3840
#, c-format
msgid "closing file '%s'"
msgstr "关闭文件 '%s'"
-#: builtin/apply.c:3612
+#: builtin/apply.c:3889
#, c-format
msgid "unable to write file '%s' mode %o"
msgstr "ä¸èƒ½å†™æ–‡ä»¶ '%s' æƒé™ %o"
-#: builtin/apply.c:3668
+#: builtin/apply.c:3976
#, c-format
msgid "Applied patch %s cleanly."
msgstr "æˆåŠŸåº”ç”¨è¡¥ä¸ %s。"
-#: builtin/apply.c:3676
+#: builtin/apply.c:3984
msgid "internal error"
msgstr "内部错误"
#. Say this even without --verbose
-#: builtin/apply.c:3679
+#: builtin/apply.c:3987
#, c-format
msgid "Applying patch %%s with %d reject..."
msgid_plural "Applying patch %%s with %d rejects..."
-msgstr[0] "åº”ç”¨è¡¥ä¸ %%s æ—¶ %d 个被拒ç»..."
-msgstr[1] "åº”ç”¨è¡¥ä¸ %%s æ—¶ %d 个被拒ç»..."
+msgstr[0] "应用 %%s 个补ä¸ï¼Œå…¶ä¸­ %d 个被拒ç»..."
+msgstr[1] "应用 %%s 个补ä¸ï¼Œå…¶ä¸­ %d 个被拒ç»..."
-#: builtin/apply.c:3689
+#: builtin/apply.c:3997
#, c-format
msgid "truncating .rej filename to %.*s.rej"
msgstr "截短 .rej 文件å为 %.*s.rej"
-#: builtin/apply.c:3710
+#: builtin/apply.c:4018
#, c-format
msgid "Hunk #%d applied cleanly."
msgstr "第 #%d 个片段æˆåŠŸåº”用。"
-#: builtin/apply.c:3713
+#: builtin/apply.c:4021
#, c-format
msgid "Rejected hunk #%d."
msgstr "æ‹’ç»ç¬¬ #%d 个片段。"
-#: builtin/apply.c:3844
+#: builtin/apply.c:4171
msgid "unrecognized input"
msgstr "未能识别的输入"
-#: builtin/apply.c:3855
+#: builtin/apply.c:4182
msgid "unable to read index file"
msgstr "无法读å–索引文件"
-#: builtin/apply.c:3970 builtin/apply.c:3973
+#: builtin/apply.c:4301 builtin/apply.c:4304 builtin/clone.c:91
+#: builtin/fetch.c:63
msgid "path"
msgstr "路径"
-#: builtin/apply.c:3971
+#: builtin/apply.c:4302
msgid "don't apply changes matching the given path"
msgstr "ä¸è¦åº”用与给出路径å‘匹é…çš„å˜æ›´"
-#: builtin/apply.c:3974
+#: builtin/apply.c:4305
msgid "apply changes matching the given path"
msgstr "应用与给出路径å‘匹é…çš„å˜æ›´"
-#: builtin/apply.c:3976
+#: builtin/apply.c:4307
msgid "num"
msgstr "æ•°å­—"
-#: builtin/apply.c:3977
+#: builtin/apply.c:4308
msgid "remove <num> leading slashes from traditional diff paths"
msgstr "从传统的 diff 路径中移除 <æ•°å­—> 个å‰å¯¼è·¯å¾„"
-#: builtin/apply.c:3980
+#: builtin/apply.c:4311
msgid "ignore additions made by the patch"
msgstr "忽略补ä¸ä¸­çš„添加的文件"
-#: builtin/apply.c:3982
+#: builtin/apply.c:4313
msgid "instead of applying the patch, output diffstat for the input"
msgstr "ä¸åº”用补ä¸ï¼Œè€Œæ˜¯æ˜¾ç¤ºè¾“入的差异统计(diffstat)"
-#: builtin/apply.c:3986
-msgid "shows number of added and deleted lines in decimal notation"
+#: builtin/apply.c:4317
+#, fuzzy
+msgid "show number of added and deleted lines in decimal notation"
msgstr "以数字方å¼æ˜¾ç¤ºæ·»åŠ æˆ–删除行的数é‡"
-#: builtin/apply.c:3988
+#: builtin/apply.c:4319
msgid "instead of applying the patch, output a summary for the input"
msgstr "ä¸åº”用补ä¸ï¼Œè€Œæ˜¯æ˜¾ç¤ºè¾“入的概è¦"
-#: builtin/apply.c:3990
+#: builtin/apply.c:4321
msgid "instead of applying the patch, see if the patch is applicable"
msgstr "ä¸åº”用补ä¸ï¼Œè€Œæ˜¯æŸ¥çœ‹è¡¥ä¸æ˜¯å¦å¯åº”用"
-#: builtin/apply.c:3992
+#: builtin/apply.c:4323
msgid "make sure the patch is applicable to the current index"
msgstr "确认补ä¸å¯ä»¥åº”用到当å‰ç´¢å¼•"
-#: builtin/apply.c:3994
+#: builtin/apply.c:4325
msgid "apply a patch without touching the working tree"
msgstr "应用补ä¸è€Œä¸ä¿®æ”¹å·¥ä½œåŒº"
-#: builtin/apply.c:3996
+#: builtin/apply.c:4327
msgid "also apply the patch (use with --stat/--summary/--check)"
-msgstr "åŒæ—¶åº”用此补ä¸ï¼ˆå’Œ --stat/--summary/--check 共用)"
+msgstr "还应用此补ä¸ï¼ˆä¸Ž --stat/--summary/--check 选项åŒæ—¶ä½¿ç”¨ï¼‰"
-#: builtin/apply.c:3998
+#: builtin/apply.c:4329
+msgid "attempt three-way merge if a patch does not apply"
+msgstr "如果一个补ä¸ä¸èƒ½åº”用则å°è¯•ä¸‰è·¯åˆå¹¶"
+
+#: builtin/apply.c:4331
msgid "build a temporary index based on embedded index information"
msgstr "创建一个临时索引基于嵌入的索引信æ¯"
-#: builtin/apply.c:4000
+#: builtin/apply.c:4333 builtin/checkout-index.c:197 builtin/ls-files.c:460
msgid "paths are separated with NUL character"
msgstr "路径以 NUL 字符分隔"
-#: builtin/apply.c:4003
+#: builtin/apply.c:4336
msgid "ensure at least <n> lines of context match"
msgstr "ç¡®ä¿è‡³å°‘åŒ¹é… <n> 行上下文"
-#: builtin/apply.c:4004
+#: builtin/apply.c:4337
msgid "action"
msgstr "动作"
-#: builtin/apply.c:4005
+#: builtin/apply.c:4338
msgid "detect new or modified lines that have whitespace errors"
msgstr "检查新增和修改的行中间的空白字符滥用"
-#: builtin/apply.c:4008 builtin/apply.c:4011
+#: builtin/apply.c:4341 builtin/apply.c:4344
msgid "ignore changes in whitespace when finding context"
msgstr "查找上下文时忽略空白字符的å˜æ›´"
-#: builtin/apply.c:4014
+#: builtin/apply.c:4347
msgid "apply the patch in reverse"
msgstr "åå‘应用补ä¸"
-#: builtin/apply.c:4016
+#: builtin/apply.c:4349
msgid "don't expect at least one line of context"
msgstr "无需至少一行上下文"
-#: builtin/apply.c:4018
+#: builtin/apply.c:4351
msgid "leave the rejected hunks in corresponding *.rej files"
msgstr "将拒ç»çš„è¡¥ä¸ç‰‡æ®µä¿å­˜åœ¨å¯¹åº”çš„ *.rej 文件中"
-#: builtin/apply.c:4020
+#: builtin/apply.c:4353
msgid "allow overlapping hunks"
msgstr "å…许é‡å çš„è¡¥ä¸ç‰‡æ®µ"
-#: builtin/apply.c:4021
-msgid "be verbose"
-msgstr "冗长输出"
-
-#: builtin/apply.c:4023
+#: builtin/apply.c:4356
msgid "tolerate incorrectly detected missing new-line at the end of file"
-msgstr "宽容ä¸æ­£ç¡®çš„文件末尾æ¢è¡Œç¬¦"
+msgstr "å…许ä¸æ­£ç¡®çš„文件末尾æ¢è¡Œç¬¦"
-#: builtin/apply.c:4026
+#: builtin/apply.c:4359
msgid "do not trust the line counts in the hunk headers"
msgstr "ä¸ä¿¡ä»»è¡¥ä¸ç‰‡æ®µçš„头信æ¯ä¸­çš„è¡Œå·"
-#: builtin/apply.c:4028
+#: builtin/apply.c:4361
msgid "root"
msgstr "根目录"
-#: builtin/apply.c:4029
+#: builtin/apply.c:4362
msgid "prepend <root> to all filenames"
msgstr "为所有文件åå‰æ·»åŠ  <根目录>"
-#: builtin/apply.c:4050
+#: builtin/apply.c:4384
+msgid "--3way outside a repository"
+msgstr "--3way 在一个版本库之外"
+
+#: builtin/apply.c:4392
msgid "--index outside a repository"
msgstr "--index 在一个版本库之外"
-#: builtin/apply.c:4053
+#: builtin/apply.c:4395
msgid "--cached outside a repository"
msgstr "--cached 在一个版本库之外"
-#: builtin/apply.c:4069
+#: builtin/apply.c:4411
#, c-format
msgid "can't open patch '%s'"
msgstr "ä¸èƒ½æ‰“å¼€è¡¥ä¸ '%s'"
-#: builtin/apply.c:4083
+#: builtin/apply.c:4425
#, c-format
msgid "squelched %d whitespace error"
msgid_plural "squelched %d whitespace errors"
msgstr[0] "抑制下ä»æœ‰ %d 个空白字符误用"
msgstr[1] "抑制下ä»æœ‰ %d 个空白字符误用"
-#: builtin/apply.c:4089 builtin/apply.c:4099
+#: builtin/apply.c:4431 builtin/apply.c:4441
#, c-format
msgid "%d line adds whitespace errors."
msgid_plural "%d lines add whitespace errors."
@@ -1504,7 +2047,7 @@ msgstr "ä¸èƒ½åˆ›å»ºå½’档文件 '%s'"
#: builtin/archive.c:20
msgid "could not redirect output"
-msgstr "ä¸èƒ½è¾“出é‡å®šå‘"
+msgstr "ä¸èƒ½é‡å®šå‘输出"
#: builtin/archive.c:37
msgid "git archive: Remote with no URL"
@@ -1512,7 +2055,7 @@ msgstr "git archive:未æ供远程URL"
#: builtin/archive.c:58
msgid "git archive: expected ACK/NAK, got EOF"
-msgstr "git archive:期待ACK/NACK,å´å¾—到EOF"
+msgstr "git archive:应为ACK/NACK,å´å¾—到EOF"
#: builtin/archive.c:63
#, c-format
@@ -1530,10 +2073,142 @@ msgstr "git archive:å议错误"
#: builtin/archive.c:71
msgid "git archive: expected a flush"
-msgstr "git archive:预期一个刷新"
+msgstr "git archive:应为刷新"
+
+#: builtin/bisect--helper.c:7
+msgid "git bisect--helper --next-all [--no-checkout]"
+msgstr ""
+
+#: builtin/bisect--helper.c:17
+msgid "perform 'git bisect next'"
+msgstr ""
+
+#: builtin/bisect--helper.c:19
+msgid "update BISECT_HEAD instead of checking out the current commit"
+msgstr ""
+
+#: builtin/blame.c:25
+msgid "git blame [options] [rev-opts] [rev] [--] file"
+msgstr ""
+
+#: builtin/blame.c:30 builtin/shortlog.c:15
+msgid "[rev-opts] are documented in git-rev-list(1)"
+msgstr ""
+
+#: builtin/blame.c:2316
+msgid "Show blame entries as we find them, incrementally"
+msgstr ""
+
+#: builtin/blame.c:2317
+msgid "Show blank SHA-1 for boundary commits (Default: off)"
+msgstr ""
+
+#: builtin/blame.c:2318
+msgid "Do not treat root commits as boundaries (Default: off)"
+msgstr ""
+
+#: builtin/blame.c:2319
+#, fuzzy
+msgid "Show work cost statistics"
+msgstr "显示工作区状æ€"
+
+#: builtin/blame.c:2320
+msgid "Show output score for blame entries"
+msgstr ""
+
+#: builtin/blame.c:2321
+msgid "Show original filename (Default: auto)"
+msgstr ""
+
+#: builtin/blame.c:2322
+msgid "Show original linenumber (Default: off)"
+msgstr ""
+
+#: builtin/blame.c:2323
+msgid "Show in a format designed for machine consumption"
+msgstr ""
+
+#: builtin/blame.c:2324
+msgid "Show porcelain format with per-line commit information"
+msgstr ""
+
+#: builtin/blame.c:2325
+msgid "Use the same output mode as git-annotate (Default: off)"
+msgstr ""
+
+#: builtin/blame.c:2326
+msgid "Show raw timestamp (Default: off)"
+msgstr ""
+
+#: builtin/blame.c:2327
+msgid "Show long commit SHA1 (Default: off)"
+msgstr ""
+
+#: builtin/blame.c:2328
+msgid "Suppress author name and timestamp (Default: off)"
+msgstr ""
+
+#: builtin/blame.c:2329
+msgid "Show author email instead of name (Default: off)"
+msgstr ""
+
+#: builtin/blame.c:2330
+msgid "Ignore whitespace differences"
+msgstr ""
+
+#: builtin/blame.c:2331
+msgid "Spend extra cycles to find better match"
+msgstr ""
+
+#: builtin/blame.c:2332
+msgid "Use revisions from <file> instead of calling git-rev-list"
+msgstr ""
+
+#: builtin/blame.c:2333
+#, fuzzy
+msgid "Use <file>'s contents as the final image"
+msgstr "添加文件内容至索引"
+
+#: builtin/blame.c:2334 builtin/blame.c:2335
+msgid "score"
+msgstr ""
+
+#: builtin/blame.c:2334
+msgid "Find line copies within and across files"
+msgstr ""
+
+#: builtin/blame.c:2335
+msgid "Find line movements within and across files"
+msgstr ""
+
+#: builtin/blame.c:2336
+#, fuzzy
+msgid "n,m"
+msgstr "æ•°å­—"
+
+#: builtin/blame.c:2336
+msgid "Process only line range n,m, counting from 1"
+msgstr ""
+
+#: builtin/branch.c:23
+msgid "git branch [options] [-r | -a] [--merged | --no-merged]"
+msgstr ""
+
+#: builtin/branch.c:24
+msgid "git branch [options] [-l] [-f] <branchname> [<start-point>]"
+msgstr ""
+
+#: builtin/branch.c:25
+#, fuzzy
+msgid "git branch [options] [-r] (-d | -D) <branchname>..."
+msgstr "git apply [选项] [<è¡¥ä¸>...]"
+
+#: builtin/branch.c:26
+msgid "git branch [options] (-m | -M) [<oldbranch>] <newbranch>"
+msgstr ""
# 译者:ä¿æŒåŽŸæ¢è¡Œæ ¼å¼ï¼Œåœ¨è¾“出时 %s 的替代内容会让字符串å˜é•¿
-#: builtin/branch.c:144
+#: builtin/branch.c:145
#, c-format
msgid ""
"deleting branch '%s' that has been merged to\n"
@@ -1543,7 +2218,7 @@ msgstr ""
" '%s',但未åˆå¹¶åˆ° HEAD。"
# 译者:ä¿æŒåŽŸæ¢è¡Œæ ¼å¼ï¼Œåœ¨è¾“出时 %s 的替代内容会让字符串å˜é•¿
-#: builtin/branch.c:148
+#: builtin/branch.c:149
#, c-format
msgid ""
"not deleting branch '%s' that is not yet merged to\n"
@@ -1552,35 +2227,35 @@ msgstr ""
"并未删除分支 '%s', 虽然它已ç»åˆå¹¶åˆ° HEAD,\n"
" 然而å´å°šæœªè¢«åˆå¹¶åˆ°åˆ†æ”¯ '%s' 。"
-#: builtin/branch.c:180
+#: builtin/branch.c:181
msgid "cannot use -a with -d"
-msgstr "ä¸èƒ½å°† -a å’Œ -d 共用"
+msgstr "ä¸èƒ½å°† -a å’Œ -d åŒæ—¶ä½¿ç”¨"
-#: builtin/branch.c:186
+#: builtin/branch.c:187
msgid "Couldn't look up commit object for HEAD"
msgstr "无法查询 HEAD 指å‘çš„æ交对象"
-#: builtin/branch.c:191
+#: builtin/branch.c:192
#, c-format
msgid "Cannot delete the branch '%s' which you are currently on."
msgstr "无法删除您当å‰æ‰€åœ¨çš„分支 '%s'。"
-#: builtin/branch.c:202
+#: builtin/branch.c:203
#, c-format
msgid "remote branch '%s' not found."
msgstr "远程分支 '%s' 未å‘现。"
-#: builtin/branch.c:203
+#: builtin/branch.c:204
#, c-format
msgid "branch '%s' not found."
msgstr "分支 '%s' 未å‘现。"
-#: builtin/branch.c:210
+#: builtin/branch.c:211
#, c-format
msgid "Couldn't look up commit object for '%s'"
msgstr "无法查询 '%s' 指å‘çš„æ交对象"
-#: builtin/branch.c:216
+#: builtin/branch.c:217
#, c-format
msgid ""
"The branch '%s' is not fully merged.\n"
@@ -1589,126 +2264,258 @@ msgstr ""
"分支 '%s' 没有完全åˆå¹¶ã€‚\n"
"如果您确认è¦åˆ é™¤å®ƒï¼Œæ‰§è¡Œ 'git branch -D %s'。"
-#: builtin/branch.c:225
+#: builtin/branch.c:226
#, c-format
msgid "Error deleting remote branch '%s'"
msgstr "删除远程分支 '%s' 时出错"
-#: builtin/branch.c:226
+#: builtin/branch.c:227
#, c-format
msgid "Error deleting branch '%s'"
msgstr "删除分支 '%s' 时出错"
-#: builtin/branch.c:233
+#: builtin/branch.c:234
#, c-format
msgid "Deleted remote branch %s (was %s).\n"
msgstr "已删除远程分支 %s(曾为 %s)。\n"
-#: builtin/branch.c:234
+#: builtin/branch.c:235
#, c-format
msgid "Deleted branch %s (was %s).\n"
msgstr "已删除分支 %s(曾为 %s)。\n"
-#: builtin/branch.c:239
+#: builtin/branch.c:240
msgid "Update of config-file failed"
msgstr "无法更新 config 文件"
-#: builtin/branch.c:337
+#: builtin/branch.c:338
#, c-format
msgid "branch '%s' does not point at a commit"
msgstr "分支 '%s' 未指å‘一个æ交"
-#: builtin/branch.c:409
+#: builtin/branch.c:410
#, c-format
msgid "[%s: behind %d]"
msgstr "[%s:è½åŽ %d]"
-#: builtin/branch.c:411
+#: builtin/branch.c:412
#, c-format
msgid "[behind %d]"
msgstr "[è½åŽ %d]"
-#: builtin/branch.c:415
+#: builtin/branch.c:416
#, c-format
msgid "[%s: ahead %d]"
msgstr "[%s:领先 %d]"
-#: builtin/branch.c:417
+#: builtin/branch.c:418
#, c-format
msgid "[ahead %d]"
msgstr "[领先 %d]"
-#: builtin/branch.c:420
+#: builtin/branch.c:421
#, c-format
msgid "[%s: ahead %d, behind %d]"
msgstr "[%s:领先 %d,è½åŽ %d]"
-#: builtin/branch.c:423
+#: builtin/branch.c:424
#, c-format
msgid "[ahead %d, behind %d]"
msgstr "[领先 %d,è½åŽ %d]"
-#: builtin/branch.c:535
+#: builtin/branch.c:537
msgid "(no branch)"
msgstr "(éžåˆ†æ”¯ï¼‰"
-#: builtin/branch.c:600
+#: builtin/branch.c:602
msgid "some refs could not be read"
msgstr "一些引用ä¸èƒ½è¯»å–"
-#: builtin/branch.c:613
+#: builtin/branch.c:615
msgid "cannot rename the current branch while not on any."
msgstr "无法é‡å‘½å当å‰åˆ†æ”¯å› ä¸ºä¸å¤„于任何分支上。"
-#: builtin/branch.c:623
+#: builtin/branch.c:625
#, c-format
msgid "Invalid branch name: '%s'"
msgstr "无效的分支å:'%s'"
-#: builtin/branch.c:638
+#: builtin/branch.c:640
msgid "Branch rename failed"
msgstr "分支é‡å‘½å失败"
-#: builtin/branch.c:642
+#: builtin/branch.c:644
#, c-format
msgid "Renamed a misnamed branch '%s' away"
msgstr "é‡å‘½å掉一个错误命å的旧分支 '%s'"
-#: builtin/branch.c:646
+#: builtin/branch.c:648
#, c-format
msgid "Branch renamed to %s, but HEAD is not updated!"
msgstr "分支é‡å‘½å为 %s,但 HEAD 没有更新ï¼"
-#: builtin/branch.c:653
+#: builtin/branch.c:655
msgid "Branch is renamed, but update of config-file failed"
msgstr "分支被é‡å‘½å,但更新 config 文件失败"
-#: builtin/branch.c:668
+#: builtin/branch.c:670
#, c-format
msgid "malformed object name %s"
msgstr "éžæ³•çš„对象å %s"
-#: builtin/branch.c:692
+#: builtin/branch.c:694
#, c-format
msgid "could not write branch description template: %s"
msgstr "ä¸èƒ½å†™åˆ†æ”¯æ述模版:%s"
-#: builtin/branch.c:783
+#: builtin/branch.c:724
+#, fuzzy
+msgid "Generic options"
+msgstr "无效选项:%s"
+
+#: builtin/branch.c:726
+msgid "show hash and subject, give twice for upstream branch"
+msgstr ""
+
+#: builtin/branch.c:727
+msgid "suppress informational messages"
+msgstr ""
+
+#: builtin/branch.c:728
+msgid "set up tracking mode (see git-pull(1))"
+msgstr ""
+
+#: builtin/branch.c:730
+msgid "change upstream info"
+msgstr ""
+
+#: builtin/branch.c:734
+#, fuzzy
+msgid "use colored output"
+msgstr "ä¸èƒ½è¾“出é‡å®šå‘"
+
+#: builtin/branch.c:735
+#, fuzzy
+msgid "act on remote-tracking branches"
+msgstr "%s 没有æ¥è‡ª %s 的远程跟踪分支"
+
+#: builtin/branch.c:738 builtin/branch.c:744 builtin/branch.c:765
+#: builtin/branch.c:771 builtin/commit.c:1395 builtin/commit.c:1396
+#: builtin/commit.c:1397 builtin/commit.c:1398 builtin/tag.c:470
+#, fuzzy
+msgid "commit"
+msgstr "(åæ交)\n"
+
+#: builtin/branch.c:739 builtin/branch.c:745
+msgid "print only branches that contain the commit"
+msgstr ""
+
+#: builtin/branch.c:751
+msgid "Specific git-branch actions:"
+msgstr ""
+
+#: builtin/branch.c:752
+msgid "list both remote-tracking and local branches"
+msgstr ""
+
+#: builtin/branch.c:754
+msgid "delete fully merged branch"
+msgstr ""
+
+#: builtin/branch.c:755
+msgid "delete branch (even if not merged)"
+msgstr ""
+
+#: builtin/branch.c:756
+msgid "move/rename a branch and its reflog"
+msgstr ""
+
+#: builtin/branch.c:757
+msgid "move/rename a branch, even if target exists"
+msgstr ""
+
+#: builtin/branch.c:758
+#, fuzzy
+msgid "list branch names"
+msgstr "无效的分支å:'%s'"
+
+#: builtin/branch.c:759
+msgid "create the branch's reflog"
+msgstr ""
+
+#: builtin/branch.c:761
+msgid "edit the description for the branch"
+msgstr ""
+
+#: builtin/branch.c:762
+#, fuzzy
+msgid "force creation (when already exists)"
+msgstr "远程 %s å·²ç»å­˜åœ¨ã€‚"
+
+#: builtin/branch.c:765
+#, fuzzy
+msgid "print only not merged branches"
+msgstr "无法移除分支 %s"
+
+#: builtin/branch.c:771
+msgid "print only merged branches"
+msgstr ""
+
+#: builtin/branch.c:775
+msgid "list branches in columns"
+msgstr ""
+
+#: builtin/branch.c:788
msgid "Failed to resolve HEAD as a valid ref."
msgstr "无法将 HEAD 解æžä¸ºæœ‰æ•ˆå¼•ç”¨ã€‚"
-#: builtin/branch.c:788 builtin/clone.c:558
+#: builtin/branch.c:793 builtin/clone.c:561
msgid "HEAD not found below refs/heads!"
msgstr "HEAD 没有ä½äºŽ /refs/heads 之下ï¼"
-#: builtin/branch.c:808
+#: builtin/branch.c:813
msgid "--column and --verbose are incompatible"
msgstr "--column å’Œ --verbose ä¸å…¼å®¹"
-#: builtin/branch.c:857
+#: builtin/branch.c:864
+#, fuzzy, c-format
+msgid "branch '%s' does not exist"
+msgstr "版本库 '%s' ä¸å­˜åœ¨"
+
+#: builtin/branch.c:876
+#, c-format
+msgid "Branch '%s' has no upstream information"
+msgstr ""
+
+#: builtin/branch.c:891
msgid "-a and -r options to 'git branch' do not make sense with a branch name"
msgstr "'git branch' çš„ -a å’Œ -r 选项带一个分支åå‚数没有æ„义"
+#: builtin/branch.c:894
+#, c-format
+msgid ""
+"The --set-upstream flag is deprecated and will be removed. Consider using --"
+"track or --set-upstream-to\n"
+msgstr ""
+
+#: builtin/branch.c:911
+#, c-format
+msgid ""
+"\n"
+"If you wanted to make '%s' track '%s', do this:\n"
+"\n"
+msgstr ""
+
+#: builtin/branch.c:912
+#, fuzzy, c-format
+msgid " git branch -d %s\n"
+msgstr " HEAD分支:%s"
+
+#: builtin/branch.c:913
+#, c-format
+msgid " git branch --set-upstream-to %s\n"
+msgstr ""
+
#: builtin/bundle.c:47
#, c-format
msgid "%s is okay\n"
@@ -1722,100 +2529,238 @@ msgstr "需è¦ä¸€ä¸ªç‰ˆæœ¬åº“æ¥åˆ›å»ºåŒ…。"
msgid "Need a repository to unbundle."
msgstr "需è¦ä¸€ä¸ªç‰ˆæœ¬åº“æ¥è§£åŒ…。"
-#: builtin/checkout.c:113 builtin/checkout.c:146
+#: builtin/cat-file.c:247
+msgid "git cat-file (-t|-s|-e|-p|<type>|--textconv) <object>"
+msgstr ""
+
+#: builtin/cat-file.c:248
+msgid "git cat-file (--batch|--batch-check) < <list_of_objects>"
+msgstr ""
+
+#: builtin/cat-file.c:266
+msgid "<type> can be one of: blob, tree, commit, tag"
+msgstr ""
+
+#: builtin/cat-file.c:267
+#, fuzzy
+msgid "show object type"
+msgstr "å的对象类型。"
+
+#: builtin/cat-file.c:268
+#, fuzzy
+msgid "show object size"
+msgstr "å对象 %s"
+
+#: builtin/cat-file.c:270
+msgid "exit with zero when there's no error"
+msgstr ""
+
+#: builtin/cat-file.c:271
+msgid "pretty-print object's content"
+msgstr ""
+
+#: builtin/cat-file.c:273
+msgid "for blob objects, run textconv on object's content"
+msgstr ""
+
+#: builtin/cat-file.c:275
+msgid "show info and content of objects fed from the standard input"
+msgstr ""
+
+#: builtin/cat-file.c:278
+#, fuzzy
+msgid "show info about objects fed from the standard input"
+msgstr "ä¸èƒ½ä»Žæ ‡å‡†è¾“入中读å–日志信æ¯"
+
+#: builtin/check-attr.c:11
+msgid "git check-attr [-a | --all | attr...] [--] pathname..."
+msgstr ""
+
+#: builtin/check-attr.c:12
+msgid "git check-attr --stdin [-a | --all | attr...] < <list-of-paths>"
+msgstr ""
+
+#: builtin/check-attr.c:19
+msgid "report all attributes set on file"
+msgstr ""
+
+#: builtin/check-attr.c:20
+msgid "use .gitattributes only from the index"
+msgstr ""
+
+#: builtin/check-attr.c:21 builtin/hash-object.c:75
+#, fuzzy
+msgid "read file names from stdin"
+msgstr "(正从标准输入中读å–日志信æ¯ï¼‰\n"
+
+#: builtin/check-attr.c:23
+#, fuzzy
+msgid "input paths are terminated by a null character"
+msgstr "路径以 NUL 字符分隔"
+
+#: builtin/checkout-index.c:126
+msgid "git checkout-index [options] [--] [<file>...]"
+msgstr ""
+
+#: builtin/checkout-index.c:187
+msgid "check out all files in the index"
+msgstr ""
+
+#: builtin/checkout-index.c:188
+msgid "force overwrite of existing files"
+msgstr ""
+
+#: builtin/checkout-index.c:190
+msgid "no warning for existing files and files not in index"
+msgstr ""
+
+#: builtin/checkout-index.c:192
+#, fuzzy
+msgid "don't checkout new files"
+msgstr "ä¸èƒ½æ£€å‡º %s"
+
+#: builtin/checkout-index.c:194
+#, fuzzy
+msgid "update stat information in the index file"
+msgstr "无法写新的索引文件"
+
+#: builtin/checkout-index.c:200
+#, fuzzy
+msgid "read list of paths from the standard input"
+msgstr "(正从标准输入中读å–日志信æ¯ï¼‰\n"
+
+#: builtin/checkout-index.c:202
+msgid "write the content to temporary files"
+msgstr ""
+
+#: builtin/checkout-index.c:203 builtin/column.c:30
+msgid "string"
+msgstr ""
+
+#: builtin/checkout-index.c:204
+msgid "when creating files, prepend <string>"
+msgstr ""
+
+#: builtin/checkout-index.c:207
+msgid "copy out the files from named stage"
+msgstr ""
+
+#: builtin/checkout.c:25
+#, fuzzy
+msgid "git checkout [options] <branch>"
+msgstr "git apply [选项] [<è¡¥ä¸>...]"
+
+#: builtin/checkout.c:26
+#, fuzzy
+msgid "git checkout [options] [<branch>] -- <file>..."
+msgstr "git apply [选项] [<è¡¥ä¸>...]"
+
+#: builtin/checkout.c:116 builtin/checkout.c:149
#, c-format
msgid "path '%s' does not have our version"
msgstr "路径 '%s' 没有我们的版本"
-#: builtin/checkout.c:115 builtin/checkout.c:148
+#: builtin/checkout.c:118 builtin/checkout.c:151
#, c-format
msgid "path '%s' does not have their version"
msgstr "路径 '%s' 没有他们的版本"
-#: builtin/checkout.c:131
+#: builtin/checkout.c:134
#, c-format
msgid "path '%s' does not have all necessary versions"
msgstr "路径 '%s' 没有全部必须的版本"
-#: builtin/checkout.c:175
+#: builtin/checkout.c:178
#, c-format
msgid "path '%s' does not have necessary versions"
msgstr "路径 '%s' 没有必须的版本"
-#: builtin/checkout.c:192
+#: builtin/checkout.c:195
#, c-format
msgid "path '%s': cannot merge"
msgstr "path '%s':无法åˆå¹¶"
-#: builtin/checkout.c:209
+#: builtin/checkout.c:212
#, c-format
msgid "Unable to add merge result for '%s'"
msgstr "无法为 '%s' 添加åˆå¹¶ç»“æžœ"
-#: builtin/checkout.c:234 builtin/checkout.c:392
+#: builtin/checkout.c:236 builtin/checkout.c:239 builtin/checkout.c:242
+#: builtin/checkout.c:245
+#, fuzzy, c-format
+msgid "'%s' cannot be used with updating paths"
+msgstr "%s:%s ä¸èƒ½å’Œ %s åŒæ—¶ä½¿ç”¨"
+
+#: builtin/checkout.c:248 builtin/checkout.c:251
+#, fuzzy, c-format
+msgid "'%s' cannot be used with %s"
+msgstr "%s:%s ä¸èƒ½å’Œ %s åŒæ—¶ä½¿ç”¨"
+
+#: builtin/checkout.c:254
+#, c-format
+msgid "Cannot update paths and switch to branch '%s' at the same time."
+msgstr ""
+
+#: builtin/checkout.c:265 builtin/checkout.c:426
msgid "corrupt index file"
msgstr "æŸå的索引文件"
-#: builtin/checkout.c:264 builtin/checkout.c:271
+#: builtin/checkout.c:295 builtin/checkout.c:302
#, c-format
msgid "path '%s' is unmerged"
msgstr "路径 '%s' 未åˆå¹¶"
-#: builtin/checkout.c:302 builtin/checkout.c:498 builtin/clone.c:583
-#: builtin/merge.c:812
+#: builtin/checkout.c:333 builtin/checkout.c:534 builtin/clone.c:586
+#: builtin/merge.c:811
msgid "unable to write new index file"
msgstr "无法写新的索引文件"
-#: builtin/checkout.c:319 builtin/diff.c:302 builtin/merge.c:408
-msgid "diff_setup_done failed"
-msgstr "diff_setup_done 失败"
-
-#: builtin/checkout.c:414
+#: builtin/checkout.c:448
msgid "you need to resolve your current index first"
msgstr "您需è¦å…ˆè§£å†³å½“å‰ç´¢å¼•çš„冲çª"
-#: builtin/checkout.c:533
+#: builtin/checkout.c:569
#, c-format
msgid "Can not do reflog for '%s'\n"
msgstr "ä¸èƒ½å¯¹ '%s' 执行 reflog æ“作\n"
-#: builtin/checkout.c:566
+#: builtin/checkout.c:602
msgid "HEAD is now at"
msgstr "HEAD ç›®å‰ä½äºŽ"
-#: builtin/checkout.c:573
+#: builtin/checkout.c:609
#, c-format
msgid "Reset branch '%s'\n"
msgstr "é‡ç½®åˆ†æ”¯ '%s'\n"
-#: builtin/checkout.c:576
+#: builtin/checkout.c:612
#, c-format
msgid "Already on '%s'\n"
msgstr "å·²ç»ä½äºŽ '%s'\n"
-#: builtin/checkout.c:580
+#: builtin/checkout.c:616
#, c-format
msgid "Switched to and reset branch '%s'\n"
msgstr "切æ¢å¹¶é‡ç½®åˆ†æ”¯ '%s'\n"
-#: builtin/checkout.c:582
+#: builtin/checkout.c:618
#, c-format
msgid "Switched to a new branch '%s'\n"
msgstr "切æ¢åˆ°ä¸€ä¸ªæ–°åˆ†æ”¯ '%s'\n"
-#: builtin/checkout.c:584
+#: builtin/checkout.c:620
#, c-format
msgid "Switched to branch '%s'\n"
msgstr "切æ¢åˆ°åˆ†æ”¯ '%s'\n"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: builtin/checkout.c:640
+#: builtin/checkout.c:676
#, c-format
msgid " ... and %d more.\n"
msgstr " ... åŠå…¶å®ƒ %d 个。\n"
#. The singular version
-#: builtin/checkout.c:646
+#: builtin/checkout.c:682
#, c-format
msgid ""
"Warning: you are leaving %d commit behind, not connected to\n"
@@ -1836,7 +2781,7 @@ msgstr[1] ""
"\n"
"%s\n"
-#: builtin/checkout.c:664
+#: builtin/checkout.c:700
#, c-format
msgid ""
"If you want to keep them by creating a new branch, this may be a good time\n"
@@ -1851,105 +2796,201 @@ msgstr ""
" git branch new_branch_name %s\n"
"\n"
-#: builtin/checkout.c:694
+#: builtin/checkout.c:730
msgid "internal error in revision walk"
msgstr "在版本é历时é‡åˆ°å†…部错误"
-#: builtin/checkout.c:698
+#: builtin/checkout.c:734
msgid "Previous HEAD position was"
msgstr "之å‰çš„ HEAD ä½ç½®æ˜¯"
-#: builtin/checkout.c:724
+#: builtin/checkout.c:761 builtin/checkout.c:950
msgid "You are on a branch yet to be born"
msgstr "您ä½äºŽä¸€ä¸ªå°šæœªåˆå§‹åŒ–的分支"
#. case (1)
-#: builtin/checkout.c:855
+#: builtin/checkout.c:886
#, c-format
msgid "invalid reference: %s"
msgstr "无效引用:%s"
#. case (1): want a tree
-#: builtin/checkout.c:894
+#: builtin/checkout.c:925
#, c-format
msgid "reference is not a tree: %s"
msgstr "引用ä¸æ˜¯ä¸€ä¸ªæ ‘:%s"
-#: builtin/checkout.c:974
-msgid "-B cannot be used with -b"
-msgstr "-B ä¸èƒ½å’Œ -b 共用"
+#: builtin/checkout.c:961
+#, fuzzy
+msgid "paths cannot be used with switching branches"
+msgstr "--ours/--theirs 和切æ¢åˆ†æ”¯ä¸å…¼å®¹ã€‚"
-#: builtin/checkout.c:983
-msgid "--patch is incompatible with all other options"
-msgstr "--patch 选项和其他选项ä¸å…¼å®¹"
+#: builtin/checkout.c:964 builtin/checkout.c:968
+#, fuzzy, c-format
+msgid "'%s' cannot be used with switching branches"
+msgstr "%s:%s ä¸èƒ½å’Œ %s åŒæ—¶ä½¿ç”¨"
-#: builtin/checkout.c:986
-msgid "--detach cannot be used with -b/-B/--orphan"
-msgstr "--detach ä¸èƒ½å’Œ -b/-B/--orphan 共用"
+#: builtin/checkout.c:972 builtin/checkout.c:975 builtin/checkout.c:980
+#: builtin/checkout.c:983
+#, fuzzy, c-format
+msgid "'%s' cannot be used with '%s'"
+msgstr "%s:%s ä¸èƒ½å’Œ %s åŒæ—¶ä½¿ç”¨"
#: builtin/checkout.c:988
-msgid "--detach cannot be used with -t"
-msgstr "--detach ä¸èƒ½å’Œ -t 共用"
+#, fuzzy, c-format
+msgid "Cannot switch branch to a non-commit '%s'"
+msgstr "无法切æ¢åˆ†æ”¯åˆ°ä¸€ä¸ªéžæ交。"
-#: builtin/checkout.c:994
-msgid "--track needs a branch name"
-msgstr "--track 需è¦ä¸€ä¸ªåˆ†æ”¯å"
+#: builtin/checkout.c:1009 builtin/gc.c:177
+msgid "suppress progress reporting"
+msgstr ""
-#: builtin/checkout.c:1001
-msgid "Missing branch name; try -b"
-msgstr "缺少分支åï¼›å°è¯• -b"
+#: builtin/checkout.c:1010 builtin/checkout.c:1012 builtin/clone.c:89
+#: builtin/remote.c:169 builtin/remote.c:171
+#, fuzzy
+msgid "branch"
+msgstr "ä½äºŽåˆ†æ”¯ "
+
+#: builtin/checkout.c:1011
+msgid "create and checkout a new branch"
+msgstr ""
+
+#: builtin/checkout.c:1013
+msgid "create/reset and checkout a branch"
+msgstr ""
+
+#: builtin/checkout.c:1014
+#, fuzzy
+msgid "create reflog for new branch"
+msgstr "列出ã€åˆ›å»ºæˆ–删除分支"
+
+#: builtin/checkout.c:1015
+msgid "detach the HEAD at named commit"
+msgstr ""
+
+#: builtin/checkout.c:1016
+#, fuzzy
+msgid "set upstream info for new branch"
+msgstr "尚未给分支 '%s' 设置上游"
-#: builtin/checkout.c:1007
-msgid "--orphan and -b|-B are mutually exclusive"
-msgstr "--orphan 和 -b|-B 互斥"
+#: builtin/checkout.c:1018
+#, fuzzy
+msgid "new branch"
+msgstr "[新分支]"
-#: builtin/checkout.c:1009
-msgid "--orphan cannot be used with -t"
-msgstr "--orphan ä¸èƒ½å’Œ -t 共用"
+#: builtin/checkout.c:1018
+#, fuzzy
+msgid "new unparented branch"
+msgstr "没有当å‰åˆ†æ”¯ã€‚"
#: builtin/checkout.c:1019
-msgid "git checkout: -f and -m are incompatible"
-msgstr "git checkout:-f å’Œ -m ä¸å…¼å®¹"
+msgid "checkout our version for unmerged files"
+msgstr ""
+
+#: builtin/checkout.c:1021
+msgid "checkout their version for unmerged files"
+msgstr ""
+
+#: builtin/checkout.c:1023
+msgid "force checkout (throw away local modifications)"
+msgstr ""
+
+#: builtin/checkout.c:1024
+msgid "perform a 3-way merge with the new branch"
+msgstr ""
+
+#: builtin/checkout.c:1025 builtin/merge.c:215
+#, fuzzy
+msgid "update ignored files (default)"
+msgstr "更新文件失败"
+
+#: builtin/checkout.c:1026 builtin/log.c:1111 parse-options.h:241
+msgid "style"
+msgstr ""
+
+#: builtin/checkout.c:1027
+msgid "conflict style (merge or diff3)"
+msgstr ""
+
+#: builtin/checkout.c:1030
+msgid "second guess 'git checkout no-such-branch'"
+msgstr ""
+
+#: builtin/checkout.c:1054
+#, fuzzy
+msgid "-b, -B and --orphan are mutually exclusive"
+msgstr "-n 和 -k 互斥。"
+
+#: builtin/checkout.c:1071
+msgid "--track needs a branch name"
+msgstr "--track 需è¦ä¸€ä¸ªåˆ†æ”¯å"
+
+#: builtin/checkout.c:1078
+msgid "Missing branch name; try -b"
+msgstr "缺少分支åï¼›å°è¯• -b"
-#: builtin/checkout.c:1053
+#: builtin/checkout.c:1113
msgid "invalid path specification"
msgstr "无效的路径规格"
-#: builtin/checkout.c:1061
-#, c-format
+#: builtin/checkout.c:1120
+#, fuzzy, c-format
msgid ""
-"git checkout: updating paths is incompatible with switching branches.\n"
+"Cannot update paths and switch to branch '%s' at the same time.\n"
"Did you intend to checkout '%s' which can not be resolved as commit?"
msgstr ""
"git checkout:更新路径和切æ¢åˆ†æ”¯ä¸å…¼å®¹ã€‚\n"
"您是想è¦æ£€å‡º '%s' 但未能将其解æžä¸ºæ交么?"
-#: builtin/checkout.c:1063
-msgid "git checkout: updating paths is incompatible with switching branches."
-msgstr "git checkout:更新路径和切æ¢åˆ†æ”¯ä¸å…¼å®¹ã€‚"
-
-#: builtin/checkout.c:1068
-msgid "git checkout: --detach does not take a path argument"
+#: builtin/checkout.c:1125
+#, fuzzy, c-format
+msgid "git checkout: --detach does not take a path argument '%s'"
msgstr "git checkout:--detach ä¸è·Ÿè·¯å¾„å‚æ•°"
-#: builtin/checkout.c:1071
+#: builtin/checkout.c:1129
msgid ""
"git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
"checking out of the index."
msgstr ""
"git checkout:在从索引检出时,--ours/--theirsã€--force å’Œ --merge ä¸å…¼å®¹ã€‚"
-#: builtin/checkout.c:1090
-msgid "Cannot switch branch to a non-commit."
-msgstr "无法切æ¢åˆ†æ”¯åˆ°ä¸€ä¸ªéžæ交。"
+#: builtin/clean.c:19
+msgid "git clean [-d] [-f] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>..."
+msgstr ""
-#: builtin/checkout.c:1093
-msgid "--ours/--theirs is incompatible with switching branches."
-msgstr "--ours/--theirs 和切æ¢åˆ†æ”¯ä¸å…¼å®¹ã€‚"
+#: builtin/clean.c:51
+msgid "do not print names of files removed"
+msgstr ""
+
+#: builtin/clean.c:53
+msgid "force"
+msgstr ""
+
+#: builtin/clean.c:55
+#, fuzzy
+msgid "remove whole directories"
+msgstr "两个输出目录?"
+
+#: builtin/clean.c:56 builtin/describe.c:413 builtin/grep.c:802
+#: builtin/ls-files.c:491 builtin/name-rev.c:231 builtin/show-ref.c:199
+msgid "pattern"
+msgstr ""
+
+#: builtin/clean.c:57
+msgid "add <pattern> to ignore rules"
+msgstr ""
+
+#: builtin/clean.c:58
+msgid "remove ignored files, too"
+msgstr ""
+
+#: builtin/clean.c:60
+msgid "remove only ignored files"
+msgstr ""
#: builtin/clean.c:78
msgid "-x and -X cannot be used together"
-msgstr "-x å’Œ -X ä¸èƒ½å…±ç”¨"
+msgstr "-x å’Œ -X ä¸èƒ½åŒæ—¶ä½¿ç”¨"
#: builtin/clean.c:82
msgid ""
@@ -1989,22 +3030,115 @@ msgstr "ä¸ä¼šåˆ é™¤ %s\n"
msgid "Not removing %s\n"
msgstr "未删除 %s\n"
+#: builtin/clone.c:36
+msgid "git clone [options] [--] <repo> [<dir>]"
+msgstr ""
+
+#: builtin/clone.c:64 builtin/fetch.c:82 builtin/merge.c:212
+#: builtin/push.c:399
+msgid "force progress reporting"
+msgstr ""
+
+#: builtin/clone.c:66
+msgid "don't create a checkout"
+msgstr ""
+
+#: builtin/clone.c:67 builtin/clone.c:69 builtin/init-db.c:488
+#, fuzzy
+msgid "create a bare repository"
+msgstr "ä¸æ˜¯ä¸€ä¸ª git 版本库"
+
+#: builtin/clone.c:72
+msgid "create a mirror repository (implies bare)"
+msgstr ""
+
+#: builtin/clone.c:74
+msgid "to clone from a local repository"
+msgstr ""
+
+#: builtin/clone.c:76
+msgid "don't use local hardlinks, always copy"
+msgstr ""
+
+#: builtin/clone.c:78
+#, fuzzy
+msgid "setup as shared repository"
+msgstr "ä¸æ˜¯ä¸€ä¸ª git 版本库"
+
+#: builtin/clone.c:80 builtin/clone.c:82
+msgid "initialize submodules in the clone"
+msgstr ""
+
+#: builtin/clone.c:83 builtin/init-db.c:485
+#, fuzzy
+msgid "template-directory"
+msgstr "文件/目录"
+
+#: builtin/clone.c:84 builtin/init-db.c:486
+msgid "directory from which templates will be used"
+msgstr ""
+
+#: builtin/clone.c:86
+msgid "reference repository"
+msgstr ""
+
+#: builtin/clone.c:87 builtin/column.c:26 builtin/merge-file.c:44
+#, fuzzy
+msgid "name"
+msgstr "é‡å‘½å"
+
+#: builtin/clone.c:88
+msgid "use <name> instead of 'origin' to track upstream"
+msgstr ""
+
+#: builtin/clone.c:90
+msgid "checkout <branch> instead of the remote's HEAD"
+msgstr ""
+
+#: builtin/clone.c:92
+msgid "path to git-upload-pack on the remote"
+msgstr ""
+
+#: builtin/clone.c:93 builtin/fetch.c:83 builtin/grep.c:747
+msgid "depth"
+msgstr ""
+
+#: builtin/clone.c:94
+msgid "create a shallow clone of that depth"
+msgstr ""
+
+#: builtin/clone.c:96
+msgid "clone only one branch, HEAD or --branch"
+msgstr ""
+
+#: builtin/clone.c:97 builtin/init-db.c:494
+msgid "gitdir"
+msgstr ""
+
+#: builtin/clone.c:98 builtin/init-db.c:495
+msgid "separate git dir from working tree"
+msgstr ""
+
+#: builtin/clone.c:99
+msgid "key=value"
+msgstr ""
+
+#: builtin/clone.c:100
+#, fuzzy
+msgid "set config inside the new repository"
+msgstr "记录å˜æ›´åˆ°ç‰ˆæœ¬åº“"
+
#: builtin/clone.c:243
#, c-format
msgid "reference repository '%s' is not a local directory."
msgstr "引用版本库 '%s' ä¸æ˜¯ä¸€ä¸ªæœ¬åœ°ç›®å½•ã€‚"
-#: builtin/clone.c:302
-#, c-format
-msgid "failed to open '%s'"
-msgstr "无法打开 '%s'"
-
#: builtin/clone.c:306
#, c-format
msgid "failed to create directory '%s'"
msgstr "无法创建目录 '%s'"
-#: builtin/clone.c:308 builtin/diff.c:75
+#: builtin/clone.c:308 builtin/diff.c:77
#, c-format
msgid "failed to stat '%s'"
msgstr "无法枚举 '%s' 状æ€"
@@ -2019,11 +3153,6 @@ msgstr "%s 存在且ä¸æ˜¯ä¸€ä¸ªç›®å½•"
msgid "failed to stat %s\n"
msgstr "无法枚举 %s 状æ€\n"
-#: builtin/clone.c:341
-#, c-format
-msgid "failed to unlink '%s'"
-msgstr "无法删除 '%s'"
-
#: builtin/clone.c:346
#, c-format
msgid "failed to create link '%s'"
@@ -2039,85 +3168,124 @@ msgstr "无法拷è´æ–‡ä»¶è‡³ '%s'"
msgid "done.\n"
msgstr "完æˆã€‚\n"
-#: builtin/clone.c:440
+#: builtin/clone.c:443
#, c-format
msgid "Could not find remote branch %s to clone."
msgstr "ä¸èƒ½å‘现è¦å…‹éš†çš„远程分支 %s。"
-#: builtin/clone.c:549
+#: builtin/clone.c:552
msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n"
msgstr "远程 HEAD 指å‘一个ä¸å­˜åœ¨çš„引用,无法检出。\n"
-#: builtin/clone.c:639
+#: builtin/clone.c:642
msgid "Too many arguments."
msgstr "太多å‚数。"
-#: builtin/clone.c:643
+#: builtin/clone.c:646
msgid "You must specify a repository to clone."
msgstr "您必须指定一个版本库æ¥å…‹éš†ã€‚"
-#: builtin/clone.c:654
+#: builtin/clone.c:657
#, c-format
msgid "--bare and --origin %s options are incompatible."
msgstr "--bare å’Œ --origin %s 选项ä¸å…¼å®¹ã€‚"
-#: builtin/clone.c:668
+#: builtin/clone.c:671
#, c-format
msgid "repository '%s' does not exist"
msgstr "版本库 '%s' ä¸å­˜åœ¨"
-#: builtin/clone.c:673
+#: builtin/clone.c:676
msgid "--depth is ignored in local clones; use file:// instead."
msgstr "--depth 在本地克隆被忽略,改为 file:// å议试试。"
-#: builtin/clone.c:683
+#: builtin/clone.c:686
#, c-format
msgid "destination path '%s' already exists and is not an empty directory."
msgstr "目标路径 '%s' å·²ç»å­˜åœ¨ï¼Œå¹¶ä¸”ä¸æ˜¯ä¸€ä¸ªç©ºç›®å½•ã€‚"
-#: builtin/clone.c:693
+#: builtin/clone.c:696
#, c-format
msgid "working tree '%s' already exists."
msgstr "工作区 '%s' å·²ç»å­˜åœ¨ã€‚"
-#: builtin/clone.c:706 builtin/clone.c:720
+#: builtin/clone.c:709 builtin/clone.c:723
#, c-format
msgid "could not create leading directories of '%s'"
msgstr "ä¸èƒ½ä¸º '%s' 创建先导目录"
-#: builtin/clone.c:709
+#: builtin/clone.c:712
#, c-format
msgid "could not create work tree dir '%s'."
msgstr "ä¸èƒ½ä¸º '%s' 创建工作区目录。"
-#: builtin/clone.c:728
+#: builtin/clone.c:731
#, c-format
msgid "Cloning into bare repository '%s'...\n"
msgstr "克隆到裸版本库 '%s'...\n"
-#: builtin/clone.c:730
+#: builtin/clone.c:733
#, c-format
msgid "Cloning into '%s'...\n"
msgstr "正克隆到 '%s'...\n"
-#: builtin/clone.c:786
+#: builtin/clone.c:789
#, c-format
msgid "Don't know how to clone %s"
msgstr "ä¸çŸ¥é“如何克隆 %s"
-#: builtin/clone.c:835
+#: builtin/clone.c:838
#, c-format
msgid "Remote branch %s not found in upstream %s"
msgstr "远程分支 %s 在上游 %s 未å‘现"
-#: builtin/clone.c:842
+#: builtin/clone.c:845
msgid "You appear to have cloned an empty repository."
msgstr "您似乎克隆了一个空版本库。"
+#: builtin/column.c:9
+msgid "git column [options]"
+msgstr ""
+
+#: builtin/column.c:26
+msgid "lookup config vars"
+msgstr ""
+
+#: builtin/column.c:27 builtin/column.c:28
+#, fuzzy
+msgid "layout to use"
+msgstr "本地已过时"
+
+#: builtin/column.c:29
+msgid "Maximum width"
+msgstr ""
+
+#: builtin/column.c:30
+msgid "Padding space on left border"
+msgstr ""
+
+#: builtin/column.c:31
+msgid "Padding space on right border"
+msgstr ""
+
+#: builtin/column.c:32
+msgid "Padding space between columns"
+msgstr ""
+
#: builtin/column.c:51
msgid "--command must be the first argument"
msgstr "--command 必须是第一个å‚æ•°"
+#: builtin/commit.c:33
+#, fuzzy
+msgid "git commit [options] [--] <filepattern>..."
+msgstr "git apply [选项] [<è¡¥ä¸>...]"
+
+#: builtin/commit.c:38
+#, fuzzy
+msgid "git status [options] [--] <filepattern>..."
+msgstr "git apply [选项] [<è¡¥ä¸>...]"
+
#: builtin/commit.c:43
msgid ""
"Your name and email address were configured automatically based\n"
@@ -2166,93 +3334,93 @@ msgstr ""
"\n"
"å¦åˆ™ï¼Œè¯·ä½¿ç”¨å‘½ä»¤ 'git reset'\n"
-#: builtin/commit.c:253
+#: builtin/commit.c:256
msgid "failed to unpack HEAD tree object"
msgstr "无法解包 HEAD 树对象"
-#: builtin/commit.c:295
+#: builtin/commit.c:298
msgid "unable to create temporary index"
msgstr "ä¸èƒ½åˆ›å»ºä¸´æ—¶ç´¢å¼•"
-#: builtin/commit.c:301
+#: builtin/commit.c:304
msgid "interactive add failed"
msgstr "交互å¼æ·»åŠ å¤±è´¥"
-#: builtin/commit.c:334 builtin/commit.c:355 builtin/commit.c:405
+#: builtin/commit.c:337 builtin/commit.c:358 builtin/commit.c:408
msgid "unable to write new_index file"
msgstr "无法写 new_index 文件"
-#: builtin/commit.c:386
+#: builtin/commit.c:389
msgid "cannot do a partial commit during a merge."
msgstr "在åˆå¹¶è¿‡ç¨‹ä¸­ä¸èƒ½åšéƒ¨åˆ†æ交。"
-#: builtin/commit.c:388
+#: builtin/commit.c:391
msgid "cannot do a partial commit during a cherry-pick."
msgstr "在拣选过程中ä¸èƒ½åšéƒ¨åˆ†æ交。"
-#: builtin/commit.c:398
+#: builtin/commit.c:401
msgid "cannot read the index"
msgstr "无法读å–索引"
-#: builtin/commit.c:418
+#: builtin/commit.c:421
msgid "unable to write temporary index file"
msgstr "无法写临时索引文件"
-#: builtin/commit.c:493 builtin/commit.c:499
+#: builtin/commit.c:510 builtin/commit.c:516
#, c-format
msgid "invalid commit: %s"
msgstr "无效的æ交:%s"
-#: builtin/commit.c:522
+#: builtin/commit.c:539
msgid "malformed --author parameter"
msgstr "éžæ³•çš„ --author å‚æ•°"
-#: builtin/commit.c:582
+#: builtin/commit.c:600
#, c-format
msgid "Malformed ident string: '%s'"
msgstr "éžæ³•çš„身份字符串:'%s'"
-#: builtin/commit.c:620 builtin/commit.c:653 builtin/commit.c:967
+#: builtin/commit.c:638 builtin/commit.c:671 builtin/commit.c:985
#, c-format
msgid "could not lookup commit %s"
msgstr "ä¸èƒ½æŸ¥è¯¢æ交 %s"
-#: builtin/commit.c:632 builtin/shortlog.c:296
+#: builtin/commit.c:650 builtin/shortlog.c:296
#, c-format
msgid "(reading log message from standard input)\n"
msgstr "(正从标准输入中读å–日志信æ¯ï¼‰\n"
-#: builtin/commit.c:634
+#: builtin/commit.c:652
msgid "could not read log from standard input"
msgstr "ä¸èƒ½ä»Žæ ‡å‡†è¾“入中读å–日志信æ¯"
-#: builtin/commit.c:638
+#: builtin/commit.c:656
#, c-format
msgid "could not read log file '%s'"
msgstr "ä¸èƒ½è¯»å–日志文件 '%s'"
-#: builtin/commit.c:644
+#: builtin/commit.c:662
msgid "commit has empty message"
msgstr "æ交说明为空"
-#: builtin/commit.c:660
+#: builtin/commit.c:678
msgid "could not read MERGE_MSG"
msgstr "ä¸èƒ½è¯»å– MERGE_MSG"
-#: builtin/commit.c:664
+#: builtin/commit.c:682
msgid "could not read SQUASH_MSG"
msgstr "ä¸èƒ½è¯»å– SQUASH_MSG"
-#: builtin/commit.c:668
+#: builtin/commit.c:686
#, c-format
msgid "could not read '%s'"
msgstr "ä¸èƒ½è¯»å– '%s'"
-#: builtin/commit.c:720
+#: builtin/commit.c:738
msgid "could not write commit template"
msgstr "ä¸èƒ½å†™æ交模版"
-#: builtin/commit.c:731
+#: builtin/commit.c:749
#, c-format
msgid ""
"\n"
@@ -2262,11 +3430,11 @@ msgid ""
"and try again.\n"
msgstr ""
"\n"
-"看起æ¥æ‚¨æ­£åœ¨åšä¸€ä¸ªåˆå¹¶æ交。如果ä¸å¯¹ï¼Œè¯·åˆ é™¤æ–‡ä»¶\n"
+"似乎您正在åšä¸€ä¸ªåˆå¹¶æ交。如果ä¸å¯¹ï¼Œè¯·åˆ é™¤æ–‡ä»¶\n"
"\t%s\n"
"然åŽé‡è¯•ã€‚\n"
-#: builtin/commit.c:736
+#: builtin/commit.c:754
#, c-format
msgid ""
"\n"
@@ -2276,11 +3444,11 @@ msgid ""
"and try again.\n"
msgstr ""
"\n"
-"看起æ¥æ‚¨æ­£åœ¨åšä¸€ä¸ªæ‹£é€‰æ交。如果ä¸å¯¹ï¼Œè¯·åˆ é™¤æ–‡ä»¶\n"
+"似乎您正在åšä¸€ä¸ªæ‹£é€‰æ交。如果ä¸å¯¹ï¼Œè¯·åˆ é™¤æ–‡ä»¶\n"
"\t%s\n"
"然åŽé‡è¯•ã€‚\n"
-#: builtin/commit.c:748
+#: builtin/commit.c:766
msgid ""
"Please enter the commit message for your changes. Lines starting\n"
"with '#' will be ignored, and an empty message aborts the commit.\n"
@@ -2288,7 +3456,7 @@ msgstr ""
"请为您的å˜æ›´è¾“å…¥æ交说明。以 '#' 开始的行将被忽略,而一个空的æ交\n"
"说明将会终止æ交。\n"
-#: builtin/commit.c:753
+#: builtin/commit.c:771
msgid ""
"Please enter the commit message for your changes. Lines starting\n"
"with '#' will be kept; you may remove them yourself if you want to.\n"
@@ -2298,160 +3466,357 @@ msgstr ""
"如果您想这样åšçš„è¯ã€‚而一个空的æ交说明将会终止æ交。\n"
# 译者:为ä¿è¯åœ¨è¾“出中对é½ï¼Œæ³¨æ„调整å¥ä¸­ç©ºæ ¼ï¼
-#: builtin/commit.c:766
+#: builtin/commit.c:784
#, c-format
msgid "%sAuthor: %s"
msgstr "%s作者: %s"
# 译者:为ä¿è¯åœ¨è¾“出中对é½ï¼Œæ³¨æ„调整å¥ä¸­ç©ºæ ¼ï¼
-#: builtin/commit.c:773
+#: builtin/commit.c:791
#, c-format
msgid "%sCommitter: %s"
msgstr "%sæ交者: %s"
-#: builtin/commit.c:793
+#: builtin/commit.c:811
msgid "Cannot read index"
msgstr "无法读å–索引"
-#: builtin/commit.c:830
+#: builtin/commit.c:848
msgid "Error building trees"
msgstr "无法创建树对象"
-#: builtin/commit.c:845 builtin/tag.c:361
+#: builtin/commit.c:863 builtin/tag.c:361
#, c-format
msgid "Please supply the message using either -m or -F option.\n"
msgstr "请使用 -m 或者 -F 选项æä¾›æ交说明。\n"
-#: builtin/commit.c:942
+#: builtin/commit.c:960
#, c-format
msgid "No existing author found with '%s'"
msgstr "æ²¡æœ‰æ‰¾åˆ°åŒ¹é… '%s' 的作者"
-#: builtin/commit.c:957 builtin/commit.c:1157
+#: builtin/commit.c:975 builtin/commit.c:1175
#, c-format
msgid "Invalid untracked files mode '%s'"
msgstr "无效的未追踪文件å‚æ•° '%s'"
-#: builtin/commit.c:997
+#: builtin/commit.c:1015
msgid "Using both --reset-author and --author does not make sense"
msgstr "åŒæ—¶ä½¿ç”¨ --reset-author å’Œ --author 没有æ„义"
-#: builtin/commit.c:1008
+#: builtin/commit.c:1026
msgid "You have nothing to amend."
msgstr "您没有å¯ä¿®è¡¥çš„æ交。"
-#: builtin/commit.c:1011
+#: builtin/commit.c:1029
msgid "You are in the middle of a merge -- cannot amend."
msgstr "您正处于一个åˆå¹¶è¿‡ç¨‹ä¸­ -- 无法修补æ交。"
-#: builtin/commit.c:1013
+#: builtin/commit.c:1031
msgid "You are in the middle of a cherry-pick -- cannot amend."
msgstr "您正处于一个拣选过程中 -- 无法修补æ交。"
-#: builtin/commit.c:1016
+#: builtin/commit.c:1034
msgid "Options --squash and --fixup cannot be used together"
-msgstr "选项 --squash å’Œ --fixup ä¸èƒ½å…±ç”¨"
+msgstr "选项 --squash å’Œ --fixup ä¸èƒ½åŒæ—¶ä½¿ç”¨"
-#: builtin/commit.c:1026
+#: builtin/commit.c:1044
msgid "Only one of -c/-C/-F/--fixup can be used."
msgstr "åªèƒ½ç”¨ä¸€ä¸ª -c/-C/-F/--fixup 选项。"
-#: builtin/commit.c:1028
+#: builtin/commit.c:1046
msgid "Option -m cannot be combined with -c/-C/-F/--fixup."
-msgstr "选项 -m ä¸èƒ½å’Œ -c/-C/-F/--fixup 共用。"
+msgstr "选项 -m ä¸èƒ½å’Œ -c/-C/-F/--fixup åŒæ—¶ä½¿ç”¨ã€‚"
-#: builtin/commit.c:1036
+#: builtin/commit.c:1054
msgid "--reset-author can be used only with -C, -c or --amend."
-msgstr "--reset-author åªèƒ½å’Œ -Cã€-c 或 --amend 共用。"
+msgstr "--reset-author åªèƒ½å’Œ -Cã€-c 或 --amend åŒæ—¶ä½¿ç”¨ã€‚"
-#: builtin/commit.c:1053
+#: builtin/commit.c:1071
msgid "Only one of --include/--only/--all/--interactive/--patch can be used."
msgstr "åªèƒ½ç”¨ä¸€ä¸ª --include/--only/--all/--interactive/--patch 选项。"
-#: builtin/commit.c:1055
+#: builtin/commit.c:1073
msgid "No paths with --include/--only does not make sense."
msgstr "å‚æ•° --include/--only ä¸è·Ÿè·¯å¾„没有æ„义。"
-#: builtin/commit.c:1057
+#: builtin/commit.c:1075
msgid "Clever... amending the last one with dirty index."
msgstr "èªæ˜Ž... 在索引ä¸å¹²å‡€ä¸‹ä¿®è¡¥æœ€åŽçš„æ交。"
-#: builtin/commit.c:1059
+#: builtin/commit.c:1077
msgid "Explicit paths specified without -i nor -o; assuming --only paths..."
msgstr "指定了明确的路径而没有使用 -i 或 -o 选项;认为是 --only paths..."
-#: builtin/commit.c:1069 builtin/tag.c:577
+#: builtin/commit.c:1087 builtin/tag.c:577
#, c-format
msgid "Invalid cleanup mode %s"
msgstr "无效的清ç†æ¨¡å¼ %s"
-#: builtin/commit.c:1074
+#: builtin/commit.c:1092
msgid "Paths with -a does not make sense."
-msgstr "路径和 -a 选项共用没有æ„义。"
+msgstr "路径和 -a 选项åŒæ—¶ä½¿ç”¨æ²¡æœ‰æ„义。"
+
+#: builtin/commit.c:1189 builtin/commit.c:1417
+msgid "show status concisely"
+msgstr ""
+
+#: builtin/commit.c:1191 builtin/commit.c:1419
+msgid "show branch information"
+msgstr ""
+
+#: builtin/commit.c:1193 builtin/commit.c:1421 builtin/push.c:389
+msgid "machine-readable output"
+msgstr ""
+
+#: builtin/commit.c:1196 builtin/commit.c:1423
+msgid "terminate entries with NUL"
+msgstr ""
+
+#: builtin/commit.c:1198 builtin/commit.c:1426 builtin/fast-export.c:636
+#: builtin/fast-export.c:639 builtin/tag.c:461
+msgid "mode"
+msgstr ""
+
+#: builtin/commit.c:1199 builtin/commit.c:1426
+msgid "show untracked files, optional modes: all, normal, no. (Default: all)"
+msgstr ""
+
+#: builtin/commit.c:1202
+msgid "show ignored files"
+msgstr ""
+
+#: builtin/commit.c:1203 parse-options.h:151
+msgid "when"
+msgstr "何时"
+
+#: builtin/commit.c:1204
+msgid ""
+"ignore changes to submodules, optional when: all, dirty, untracked. "
+"(Default: all)"
+msgstr ""
+
+#: builtin/commit.c:1206
+#, fuzzy
+msgid "list untracked files in columns"
+msgstr "无效的未追踪文件å‚æ•° '%s'"
-#: builtin/commit.c:1257
+#: builtin/commit.c:1275
msgid "couldn't look up newly created commit"
msgstr "无法找到新创建的æ交"
-#: builtin/commit.c:1259
+#: builtin/commit.c:1277
msgid "could not parse newly created commit"
msgstr "ä¸èƒ½è§£æžæ–°åˆ›å»ºçš„æ交"
-#: builtin/commit.c:1300
+#: builtin/commit.c:1318
msgid "detached HEAD"
msgstr "分离头指针"
# 译者:中文字符串拼接,å¯åˆ é™¤å‰å¯¼ç©ºæ ¼
-#: builtin/commit.c:1302
+#: builtin/commit.c:1320
msgid " (root-commit)"
msgstr "(根æ交)"
-#: builtin/commit.c:1446
+#: builtin/commit.c:1387
+msgid "suppress summary after successful commit"
+msgstr ""
+
+#: builtin/commit.c:1388
+msgid "show diff in commit message template"
+msgstr ""
+
+#: builtin/commit.c:1390
+#, fuzzy
+msgid "Commit message options"
+msgstr "ä¸èƒ½å¾—到 %s çš„æ交说明"
+
+#: builtin/commit.c:1391 builtin/tag.c:459
+msgid "read message from file"
+msgstr ""
+
+#: builtin/commit.c:1392
+msgid "author"
+msgstr ""
+
+#: builtin/commit.c:1392
+#, fuzzy
+msgid "override author for commit"
+msgstr "åˆå¹¶æœªè¿”回æ交"
+
+#: builtin/commit.c:1393 builtin/gc.c:178
+msgid "date"
+msgstr ""
+
+#: builtin/commit.c:1393
+#, fuzzy
+msgid "override date for commit"
+msgstr "åˆå¹¶æœªè¿”回æ交"
+
+#: builtin/commit.c:1394 builtin/merge.c:206 builtin/notes.c:534
+#: builtin/notes.c:691 builtin/tag.c:457
+#, fuzzy
+msgid "message"
+msgstr "无 tag 说明?"
+
+#: builtin/commit.c:1394
+#, fuzzy
+msgid "commit message"
+msgstr "空æ交信æ¯ã€‚"
+
+#: builtin/commit.c:1395
+msgid "reuse and edit message from specified commit"
+msgstr ""
+
+#: builtin/commit.c:1396
+msgid "reuse message from specified commit"
+msgstr ""
+
+#: builtin/commit.c:1397
+msgid "use autosquash formatted message to fixup specified commit"
+msgstr ""
+
+#: builtin/commit.c:1398
+msgid "use autosquash formatted message to squash specified commit"
+msgstr ""
+
+#: builtin/commit.c:1399
+msgid "the commit is authored by me now (used with -C/-c/--amend)"
+msgstr ""
+
+#: builtin/commit.c:1400 builtin/log.c:1068 builtin/revert.c:109
+msgid "add Signed-off-by:"
+msgstr ""
+
+#: builtin/commit.c:1401
+msgid "use specified template file"
+msgstr ""
+
+#: builtin/commit.c:1402
+#, fuzzy
+msgid "force edit of commit"
+msgstr "åˆå¹¶æœªè¿”回æ交"
+
+#: builtin/commit.c:1403
+msgid "default"
+msgstr ""
+
+#: builtin/commit.c:1403 builtin/tag.c:462
+msgid "how to strip spaces and #comments from message"
+msgstr ""
+
+#: builtin/commit.c:1404
+#, fuzzy
+msgid "include status in commit message template"
+msgstr "ä¸èƒ½å†™æ交模版"
+
+#: builtin/commit.c:1405 builtin/merge.c:213 builtin/tag.c:463
+msgid "key id"
+msgstr ""
+
+#: builtin/commit.c:1406 builtin/merge.c:214
+msgid "GPG sign commit"
+msgstr ""
+
+#. end commit message options
+#: builtin/commit.c:1409
+msgid "Commit contents options"
+msgstr ""
+
+#: builtin/commit.c:1410
+msgid "commit all changed files"
+msgstr ""
+
+#: builtin/commit.c:1411
+msgid "add specified files to index for commit"
+msgstr ""
+
+#: builtin/commit.c:1412
+#, fuzzy
+msgid "interactively add files"
+msgstr "交互å¼æ·»åŠ å¤±è´¥"
+
+#: builtin/commit.c:1413
+#, fuzzy
+msgid "interactively add changes"
+msgstr "交互å¼æ·»åŠ å¤±è´¥"
+
+#: builtin/commit.c:1414
+#, fuzzy
+msgid "commit only specified files"
+msgstr "无法还原修改的文件"
+
+#: builtin/commit.c:1415
+msgid "bypass pre-commit hook"
+msgstr ""
+
+#: builtin/commit.c:1416
+#, fuzzy
+msgid "show what would be committed"
+msgstr "è¦æ交的å˜æ›´ï¼š"
+
+#: builtin/commit.c:1424
+msgid "amend previous commit"
+msgstr ""
+
+#: builtin/commit.c:1425
+msgid "bypass post-rewrite hook"
+msgstr ""
+
+#: builtin/commit.c:1430
+msgid "ok to record an empty change"
+msgstr ""
+
+#: builtin/commit.c:1433
+msgid "ok to record a change with an empty message"
+msgstr ""
+
+#: builtin/commit.c:1464
msgid "could not parse HEAD commit"
msgstr "ä¸èƒ½è§£æž HEAD æ交"
-#: builtin/commit.c:1484 builtin/merge.c:509
+#: builtin/commit.c:1502 builtin/merge.c:508
#, c-format
msgid "could not open '%s' for reading"
msgstr "ä¸èƒ½ä¸ºè¯»å…¥æ‰“å¼€ '%s'"
-#: builtin/commit.c:1491
+#: builtin/commit.c:1509
#, c-format
msgid "Corrupt MERGE_HEAD file (%s)"
msgstr "æŸåçš„ MERGE_HEAD 文件(%s)"
-#: builtin/commit.c:1498
+#: builtin/commit.c:1516
msgid "could not read MERGE_MODE"
msgstr "ä¸èƒ½è¯»å– MERGE_MODE"
-#: builtin/commit.c:1517
+#: builtin/commit.c:1535
#, c-format
msgid "could not read commit message: %s"
msgstr "ä¸èƒ½è¯»å–æ交说明:%s"
-#: builtin/commit.c:1531
+#: builtin/commit.c:1549
#, c-format
msgid "Aborting commit; you did not edit the message.\n"
msgstr "终止æ交;您未更改æ¥è‡ªæ¨¡ç‰ˆçš„æ交说明。\n"
-#: builtin/commit.c:1536
+#: builtin/commit.c:1554
#, c-format
msgid "Aborting commit due to empty commit message.\n"
msgstr "终止æ交因为æ交说明为空。\n"
-#: builtin/commit.c:1551 builtin/merge.c:936 builtin/merge.c:961
+#: builtin/commit.c:1569 builtin/merge.c:935 builtin/merge.c:960
msgid "failed to write commit object"
msgstr "无法写æ交对象"
-#: builtin/commit.c:1572
+#: builtin/commit.c:1590
msgid "cannot lock HEAD ref"
msgstr "无法é”定 HEAD 引用"
-#: builtin/commit.c:1576
+#: builtin/commit.c:1594
msgid "cannot update HEAD ref"
msgstr "无法更新 HEAD 引用"
-#: builtin/commit.c:1587
+#: builtin/commit.c:1605
msgid ""
"Repository has been updated, but unable to write\n"
"new_index file. Check that disk is not full or quota is\n"
@@ -2460,6 +3825,138 @@ msgstr ""
"版本库已更新,但无法写 new_index 文件。检查是å¦ç£ç›˜å·²æ»¡\n"
"或ç£ç›˜é…é¢å·²è€—尽,然åŽæ‰§è¡Œ \"git reset HEAD\" æ¢å¤ã€‚"
+#: builtin/config.c:7
+msgid "git config [options]"
+msgstr ""
+
+#: builtin/config.c:52
+msgid "Config file location"
+msgstr ""
+
+#: builtin/config.c:53
+#, fuzzy
+msgid "use global config file"
+msgstr "无法更新 config 文件"
+
+#: builtin/config.c:54
+msgid "use system config file"
+msgstr ""
+
+#: builtin/config.c:55
+#, fuzzy
+msgid "use repository config file"
+msgstr "需è¦ä¸€ä¸ªç‰ˆæœ¬åº“æ¥è§£åŒ…。"
+
+#: builtin/config.c:56
+#, fuzzy
+msgid "use given config file"
+msgstr "未预期的文件结æŸ"
+
+#: builtin/config.c:57
+#, fuzzy
+msgid "Action"
+msgstr "动作"
+
+#: builtin/config.c:58
+msgid "get value: name [value-regex]"
+msgstr ""
+
+#: builtin/config.c:59
+msgid "get all values: key [value-regex]"
+msgstr ""
+
+#: builtin/config.c:60
+msgid "get values for regexp: name-regex [value-regex]"
+msgstr ""
+
+#: builtin/config.c:61
+msgid "replace all matching variables: name value [value_regex]"
+msgstr ""
+
+#: builtin/config.c:62
+msgid "add a new variable: name value"
+msgstr ""
+
+#: builtin/config.c:63
+msgid "remove a variable: name [value-regex]"
+msgstr ""
+
+#: builtin/config.c:64
+msgid "remove all matches: name [value-regex]"
+msgstr ""
+
+#: builtin/config.c:65
+msgid "rename section: old-name new-name"
+msgstr ""
+
+#: builtin/config.c:66
+msgid "remove a section: name"
+msgstr ""
+
+#: builtin/config.c:67
+msgid "list all"
+msgstr ""
+
+#: builtin/config.c:68
+msgid "open an editor"
+msgstr ""
+
+#: builtin/config.c:69 builtin/config.c:70
+msgid "slot"
+msgstr ""
+
+#: builtin/config.c:69
+msgid "find the color configured: [default]"
+msgstr ""
+
+#: builtin/config.c:70
+msgid "find the color setting: [stdout-is-tty]"
+msgstr ""
+
+#: builtin/config.c:71
+msgid "Type"
+msgstr ""
+
+#: builtin/config.c:72
+msgid "value is \"true\" or \"false\""
+msgstr ""
+
+#: builtin/config.c:73
+msgid "value is decimal number"
+msgstr ""
+
+#: builtin/config.c:74
+msgid "value is --bool or --int"
+msgstr ""
+
+#: builtin/config.c:75
+msgid "value is a path (file or directory name)"
+msgstr ""
+
+#: builtin/config.c:76
+msgid "Other"
+msgstr ""
+
+#: builtin/config.c:77
+msgid "terminate values with NUL byte"
+msgstr ""
+
+#: builtin/config.c:78
+msgid "respect include directives on lookup"
+msgstr ""
+
+#: builtin/count-objects.c:69
+msgid "git count-objects [-v]"
+msgstr ""
+
+#: builtin/describe.c:15
+msgid "git describe [options] <committish>*"
+msgstr ""
+
+#: builtin/describe.c:16
+msgid "git describe [options] --dirty"
+msgstr ""
+
#: builtin/describe.c:234
#, c-format
msgid "annotated tag %s not available"
@@ -2532,6 +4029,52 @@ msgstr ""
"å‘现多于 %i 个 tag,列出最近的 %i 个\n"
"在 %s 放弃æœç´¢\n"
+#: builtin/describe.c:403
+msgid "find the tag that comes after the commit"
+msgstr ""
+
+#: builtin/describe.c:404
+msgid "debug search strategy on stderr"
+msgstr ""
+
+#: builtin/describe.c:405
+msgid "use any ref in .git/refs"
+msgstr ""
+
+#: builtin/describe.c:406
+msgid "use any tag in .git/refs/tags"
+msgstr ""
+
+#: builtin/describe.c:407
+msgid "always use long format"
+msgstr ""
+
+#: builtin/describe.c:410
+#, fuzzy
+msgid "only output exact matches"
+msgstr "没有 tag å‡†ç¡®åŒ¹é… '%s'"
+
+#: builtin/describe.c:412
+msgid "consider <n> most recent tags (default: 10)"
+msgstr ""
+
+#: builtin/describe.c:414
+#, fuzzy
+msgid "only consider tags matching <pattern>"
+msgstr "输出和模å¼åŒ¹é…çš„è¡Œ"
+
+#: builtin/describe.c:416 builtin/name-rev.c:238
+msgid "show abbreviated commit object as fallback"
+msgstr ""
+
+#: builtin/describe.c:417
+msgid "mark"
+msgstr ""
+
+#: builtin/describe.c:418
+msgid "append <mark> on dirty working tree (default: \"-dirty\")"
+msgstr ""
+
#: builtin/describe.c:436
msgid "--long is incompatible with --abbrev=0"
msgstr "--long 与 --abbrev=0 ä¸å…¼å®¹"
@@ -2542,113 +4085,239 @@ msgstr "没有å‘现å称,无法æ述任何东西。"
#: builtin/describe.c:482
msgid "--dirty is incompatible with committishes"
-msgstr "--dirty ä¸èƒ½ä¸Žæ交共用"
+msgstr "--dirty ä¸èƒ½ä¸Žæ交åŒæ—¶ä½¿ç”¨"
-#: builtin/diff.c:77
+#: builtin/diff.c:79
#, c-format
msgid "'%s': not a regular file or symlink"
msgstr "'%s':ä¸æ˜¯ä¸€ä¸ªæ­£è§„文件或符å·é“¾æŽ¥"
-#: builtin/diff.c:220
+#: builtin/diff.c:224
#, c-format
msgid "invalid option: %s"
msgstr "无效选项:%s"
-#: builtin/diff.c:297
+#: builtin/diff.c:301
msgid "Not a git repository"
msgstr "ä¸æ˜¯ä¸€ä¸ª git 版本库"
-#: builtin/diff.c:347
+#: builtin/diff.c:344
#, c-format
msgid "invalid object '%s' given."
msgstr "æ供了无效对象 '%s'。"
-#: builtin/diff.c:352
+#: builtin/diff.c:349
#, c-format
msgid "more than %d trees given: '%s'"
msgstr "æ供了超过 %d 个树对象:'%s'"
-#: builtin/diff.c:362
+#: builtin/diff.c:359
#, c-format
msgid "more than two blobs given: '%s'"
-msgstr "æ供了超过两个 blob 对象:'%s'"
+msgstr "æ供了超过两个二进制对象(blob):'%s'"
-#: builtin/diff.c:370
+#: builtin/diff.c:367
#, c-format
msgid "unhandled object '%s' given."
msgstr "æ供了无法处ç†çš„对象 '%s'。"
-#: builtin/fetch.c:200
+#: builtin/fast-export.c:22
+msgid "git fast-export [rev-list-opts]"
+msgstr ""
+
+#: builtin/fast-export.c:635
+#, fuzzy
+msgid "show progress after <n> objects"
+msgstr "显示å„ç§ç±»åž‹çš„对象"
+
+#: builtin/fast-export.c:637
+msgid "select handling of signed tags"
+msgstr ""
+
+#: builtin/fast-export.c:640
+msgid "select handling of tags that tag filtered objects"
+msgstr ""
+
+#: builtin/fast-export.c:643
+msgid "Dump marks to this file"
+msgstr ""
+
+#: builtin/fast-export.c:645
+msgid "Import marks from this file"
+msgstr ""
+
+#: builtin/fast-export.c:647
+msgid "Fake a tagger when tags lack one"
+msgstr ""
+
+#: builtin/fast-export.c:649
+msgid "Output full tree for each commit"
+msgstr ""
+
+#: builtin/fast-export.c:651
+msgid "Use the done feature to terminate the stream"
+msgstr ""
+
+#: builtin/fast-export.c:652
+msgid "Skip output of blob data"
+msgstr ""
+
+#: builtin/fetch.c:20
+#, fuzzy
+msgid "git fetch [<options>] [<repository> [<refspec>...]]"
+msgstr "git apply [选项] [<è¡¥ä¸>...]"
+
+#: builtin/fetch.c:21
+msgid "git fetch [<options>] <group>"
+msgstr ""
+
+#: builtin/fetch.c:22
+msgid "git fetch --multiple [<options>] [(<repository> | <group>)...]"
+msgstr ""
+
+#: builtin/fetch.c:23
+msgid "git fetch --all [<options>]"
+msgstr ""
+
+#: builtin/fetch.c:60
+msgid "fetch from all remotes"
+msgstr ""
+
+#: builtin/fetch.c:62
+msgid "append to .git/FETCH_HEAD instead of overwriting"
+msgstr ""
+
+#: builtin/fetch.c:64
+msgid "path to upload pack on remote end"
+msgstr ""
+
+#: builtin/fetch.c:65
+msgid "force overwrite of local branch"
+msgstr ""
+
+#: builtin/fetch.c:67
+msgid "fetch from multiple remotes"
+msgstr ""
+
+#: builtin/fetch.c:69
+#, fuzzy
+msgid "fetch all tags and associated objects"
+msgstr "更新远程引用和相关的对象"
+
+#: builtin/fetch.c:71
+msgid "do not fetch all tags (--no-tags)"
+msgstr ""
+
+#: builtin/fetch.c:73
+#, fuzzy
+msgid "prune remote-tracking branches no longer on remote"
+msgstr "%s 没有æ¥è‡ª %s 的远程跟踪分支"
+
+#: builtin/fetch.c:74
+msgid "on-demand"
+msgstr ""
+
+#: builtin/fetch.c:75
+msgid "control recursive fetching of submodules"
+msgstr ""
+
+#: builtin/fetch.c:79
+msgid "keep downloaded pack"
+msgstr ""
+
+#: builtin/fetch.c:81
+#, fuzzy
+msgid "allow updating of HEAD ref"
+msgstr "无法更新 HEAD 引用"
+
+#: builtin/fetch.c:84
+msgid "deepen history of shallow clone"
+msgstr ""
+
+#: builtin/fetch.c:85 builtin/log.c:1083
+msgid "dir"
+msgstr ""
+
+#: builtin/fetch.c:86
+#, fuzzy
+msgid "prepend this to submodule path output"
+msgstr "无法递归进å­æ¨¡ç»„路径 '$sm_path'"
+
+#: builtin/fetch.c:89
+msgid "default mode for recursion"
+msgstr ""
+
+#: builtin/fetch.c:201
msgid "Couldn't find remote ref HEAD"
msgstr "无法å‘现远程 HEAD 引用"
-#: builtin/fetch.c:253
+#: builtin/fetch.c:254
#, c-format
msgid "object %s not found"
msgstr "对象 %s 未å‘现"
-#: builtin/fetch.c:259
+#: builtin/fetch.c:260
msgid "[up to date]"
msgstr "[最新]"
-#: builtin/fetch.c:273
+#: builtin/fetch.c:274
#, c-format
msgid "! %-*s %-*s -> %s (can't fetch in current branch)"
msgstr "! %-*s %-*s -> %s (在当å‰åˆ†æ”¯ä¸‹ä¸èƒ½èŽ·å–)"
-#: builtin/fetch.c:274 builtin/fetch.c:360
+#: builtin/fetch.c:275 builtin/fetch.c:361
msgid "[rejected]"
msgstr "[已拒ç»]"
-#: builtin/fetch.c:285
+#: builtin/fetch.c:286
msgid "[tag update]"
msgstr "[tagæ›´æ–°]"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: builtin/fetch.c:287 builtin/fetch.c:322 builtin/fetch.c:340
+#: builtin/fetch.c:288 builtin/fetch.c:323 builtin/fetch.c:341
msgid " (unable to update local ref)"
msgstr " (ä¸èƒ½æ›´æ–°æœ¬åœ°å¼•ç”¨ï¼‰"
-#: builtin/fetch.c:305
+#: builtin/fetch.c:306
msgid "[new tag]"
msgstr "[æ–°tag]"
-#: builtin/fetch.c:308
+#: builtin/fetch.c:309
msgid "[new branch]"
msgstr "[新分支]"
-#: builtin/fetch.c:311
+#: builtin/fetch.c:312
msgid "[new ref]"
msgstr "[新引用]"
-#: builtin/fetch.c:356
+#: builtin/fetch.c:357
msgid "unable to update local ref"
msgstr "ä¸èƒ½æ›´æ–°æœ¬åœ°å¼•ç”¨"
-#: builtin/fetch.c:356
+#: builtin/fetch.c:357
msgid "forced update"
msgstr "强制更新"
-#: builtin/fetch.c:362
+#: builtin/fetch.c:363
msgid "(non-fast-forward)"
msgstr "(éžå¿«è¿›å¼ï¼‰"
-#: builtin/fetch.c:393 builtin/fetch.c:685
+#: builtin/fetch.c:394 builtin/fetch.c:686
#, c-format
msgid "cannot open %s: %s\n"
msgstr "无法打开 %s:%s\n"
-#: builtin/fetch.c:402
+#: builtin/fetch.c:403
#, c-format
msgid "%s did not send all necessary objects\n"
msgstr "%s 未å‘é€æ‰€æœ‰å¿…须的对象\n"
-#: builtin/fetch.c:488
+#: builtin/fetch.c:489
#, c-format
msgid "From %.*s\n"
msgstr "æ¥è‡ª %.*s\n"
-#: builtin/fetch.c:499
+#: builtin/fetch.c:500
#, c-format
msgid ""
"some local refs could not be updated; try running\n"
@@ -2658,82 +4327,204 @@ msgstr ""
" 'git remote prune %s' æ¥åˆ é™¤æ—§çš„ã€æœ‰å†²çªçš„分支"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: builtin/fetch.c:549
+#: builtin/fetch.c:550
#, c-format
msgid " (%s will become dangling)"
msgstr " (%s å°†æˆä¸ºæ‚¬ç©ºçŠ¶æ€ï¼‰"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: builtin/fetch.c:550
+#: builtin/fetch.c:551
#, c-format
msgid " (%s has become dangling)"
msgstr " (%s å·²æˆä¸ºæ‚¬ç©ºçŠ¶æ€ï¼‰"
-#: builtin/fetch.c:557
+#: builtin/fetch.c:558
msgid "[deleted]"
msgstr "[已删除]"
-#: builtin/fetch.c:558 builtin/remote.c:1055
+#: builtin/fetch.c:559 builtin/remote.c:1055
msgid "(none)"
msgstr "(无)"
-#: builtin/fetch.c:675
+#: builtin/fetch.c:676
#, c-format
msgid "Refusing to fetch into current branch %s of non-bare repository"
msgstr "æ‹’ç»èŽ·å–到éžè£¸ç‰ˆæœ¬åº“的当å‰åˆ†æ”¯ %s"
-#: builtin/fetch.c:709
+#: builtin/fetch.c:710
#, c-format
msgid "Don't know how to fetch from %s"
msgstr "ä¸çŸ¥é“如何从 %s 获å–"
-#: builtin/fetch.c:786
+#: builtin/fetch.c:787
#, c-format
msgid "Option \"%s\" value \"%s\" is not valid for %s"
msgstr "选项 \"%s\" 的值 \"%s\" 对于 %s 是无效的"
-#: builtin/fetch.c:789
+#: builtin/fetch.c:790
#, c-format
msgid "Option \"%s\" is ignored for %s\n"
msgstr "选项 \"%s\" 为 %s 所忽略\n"
-#: builtin/fetch.c:888
+#: builtin/fetch.c:892
#, c-format
msgid "Fetching %s\n"
msgstr "æ­£åœ¨èŽ·å– %s\n"
-#: builtin/fetch.c:890 builtin/remote.c:100
+#: builtin/fetch.c:894 builtin/remote.c:100
#, c-format
msgid "Could not fetch %s"
msgstr "ä¸èƒ½èŽ·å– %s"
-#: builtin/fetch.c:907
+#: builtin/fetch.c:913
msgid ""
"No remote repository specified. Please, specify either a URL or a\n"
"remote name from which new revisions should be fetched."
msgstr "未指定远程版本库。请通过一个URL或远程版本库å指定,用以获å–æ–°æ交。"
-#: builtin/fetch.c:927
+#: builtin/fetch.c:933
msgid "You need to specify a tag name."
msgstr "您需è¦æŒ‡å®šä¸€ä¸ª tag å称。"
-#: builtin/fetch.c:979
+#: builtin/fetch.c:985
msgid "fetch --all does not take a repository argument"
msgstr "fetch --all ä¸èƒ½å¸¦ä¸€ä¸ªç‰ˆæœ¬åº“å‚æ•°"
-#: builtin/fetch.c:981
+#: builtin/fetch.c:987
msgid "fetch --all does not make sense with refspecs"
msgstr "fetch --all 带引用表达å¼æ²¡æœ‰ä»»ä½•æ„义"
-#: builtin/fetch.c:992
+#: builtin/fetch.c:998
#, c-format
msgid "No such remote or remote group: %s"
msgstr "没有这样的远程或远程组:%s"
-#: builtin/fetch.c:1000
+#: builtin/fetch.c:1006
msgid "Fetching a group and specifying refspecs does not make sense"
msgstr "获å–组并指定引用表达å¼æ²¡æœ‰æ„义"
+#: builtin/fmt-merge-msg.c:13
+msgid "git fmt-merge-msg [-m <message>] [--log[=<n>]|--no-log] [--file <file>]"
+msgstr ""
+
+#: builtin/fmt-merge-msg.c:653 builtin/fmt-merge-msg.c:656 builtin/grep.c:786
+#: builtin/merge.c:188 builtin/show-branch.c:656 builtin/show-ref.c:192
+#: builtin/tag.c:448 parse-options.h:133 parse-options.h:235
+msgid "n"
+msgstr "æ•°å­—"
+
+#: builtin/fmt-merge-msg.c:654
+msgid "populate log with at most <n> entries from shortlog"
+msgstr ""
+
+#: builtin/fmt-merge-msg.c:657
+msgid "alias for --log (deprecated)"
+msgstr ""
+
+#: builtin/fmt-merge-msg.c:660
+msgid "text"
+msgstr ""
+
+#: builtin/fmt-merge-msg.c:661
+msgid "use <text> as start of message"
+msgstr ""
+
+#: builtin/fmt-merge-msg.c:662
+#, fuzzy
+msgid "file to read from"
+msgstr "ä¸èƒ½è¯» %s"
+
+#: builtin/for-each-ref.c:979
+#, fuzzy
+msgid "git for-each-ref [options] [<pattern>]"
+msgstr "git apply [选项] [<è¡¥ä¸>...]"
+
+#: builtin/for-each-ref.c:994
+msgid "quote placeholders suitably for shells"
+msgstr ""
+
+#: builtin/for-each-ref.c:996
+msgid "quote placeholders suitably for perl"
+msgstr ""
+
+#: builtin/for-each-ref.c:998
+msgid "quote placeholders suitably for python"
+msgstr ""
+
+#: builtin/for-each-ref.c:1000
+msgid "quote placeholders suitably for tcl"
+msgstr ""
+
+#: builtin/for-each-ref.c:1003
+msgid "show only <n> matched refs"
+msgstr ""
+
+#: builtin/for-each-ref.c:1004
+msgid "format"
+msgstr ""
+
+#: builtin/for-each-ref.c:1004
+msgid "format to use for the output"
+msgstr ""
+
+#: builtin/for-each-ref.c:1005
+msgid "key"
+msgstr ""
+
+#: builtin/for-each-ref.c:1006
+msgid "field name to sort on"
+msgstr ""
+
+#: builtin/fsck.c:608
+#, fuzzy
+msgid "git fsck [options] [<object>...]"
+msgstr "git apply [选项] [<è¡¥ä¸>...]"
+
+#: builtin/fsck.c:614
+msgid "show unreachable objects"
+msgstr ""
+
+#: builtin/fsck.c:615
+#, fuzzy
+msgid "show dangling objects"
+msgstr "索引对象中"
+
+#: builtin/fsck.c:616
+msgid "report tags"
+msgstr ""
+
+#: builtin/fsck.c:617
+msgid "report root nodes"
+msgstr ""
+
+#: builtin/fsck.c:618
+msgid "make index objects head nodes"
+msgstr ""
+
+#: builtin/fsck.c:619
+msgid "make reflogs head nodes (default)"
+msgstr ""
+
+#: builtin/fsck.c:620
+msgid "also consider packs and alternate objects"
+msgstr ""
+
+#: builtin/fsck.c:621
+msgid "enable more strict checking"
+msgstr ""
+
+#: builtin/fsck.c:623
+msgid "write dangling objects in .git/lost-found"
+msgstr ""
+
+#: builtin/fsck.c:624 builtin/prune.c:134
+msgid "show progress"
+msgstr ""
+
+#: builtin/gc.c:22
+msgid "git gc [options]"
+msgstr ""
+
#: builtin/gc.c:63
#, c-format
msgid "Invalid %s: '%s'"
@@ -2744,6 +4535,18 @@ msgstr "无效的 %s:'%s'"
msgid "insanely long object directory %.*s"
msgstr "ä¸æ­£å¸¸çš„长对象目录 %.*s"
+#: builtin/gc.c:179
+msgid "prune unreferenced objects"
+msgstr ""
+
+#: builtin/gc.c:181
+msgid "be more thorough (increased runtime)"
+msgstr ""
+
+#: builtin/gc.c:182
+msgid "enable auto-gc mode"
+msgstr ""
+
#: builtin/gc.c:221
#, c-format
msgid "Auto packing the repository for optimum performance.\n"
@@ -2763,89 +4566,317 @@ msgid ""
"There are too many unreachable loose objects; run 'git prune' to remove them."
msgstr "有太多ä¸å¯è¾¾çš„æ¾æ•£å¯¹è±¡ï¼Œè¿è¡Œ 'git prune' 删除它们。"
+#: builtin/grep.c:22
+msgid "git grep [options] [-e] <pattern> [<rev>...] [[--] <path>...]"
+msgstr ""
+
#: builtin/grep.c:216
#, c-format
msgid "grep: failed to create thread: %s"
msgstr "grep:无法创建线程:%s"
-#: builtin/grep.c:402
+#: builtin/grep.c:454
#, c-format
msgid "Failed to chdir: %s"
msgstr "无法切æ¢ç›®å½•ï¼š%s"
-#: builtin/grep.c:478 builtin/grep.c:512
+#: builtin/grep.c:530 builtin/grep.c:564
#, c-format
msgid "unable to read tree (%s)"
msgstr "无法读å–树(%s)"
-#: builtin/grep.c:526
+#: builtin/grep.c:578
#, c-format
msgid "unable to grep from object of type %s"
msgstr "无法抓å–æ¥è‡ªäºŽ %s 类型的对象"
-#: builtin/grep.c:584
+#: builtin/grep.c:636
#, c-format
msgid "switch `%c' expects a numerical value"
msgstr "开关 `%c' 期望一个数字值"
-#: builtin/grep.c:601
+#: builtin/grep.c:653
#, c-format
msgid "cannot open '%s'"
msgstr "ä¸èƒ½æ‰“å¼€ '%s'"
-#: builtin/grep.c:885
+#: builtin/grep.c:728
+msgid "search in index instead of in the work tree"
+msgstr ""
+
+#: builtin/grep.c:730
+msgid "find in contents not managed by git"
+msgstr ""
+
+# 译者:中文字符串拼接,å¯åˆ é™¤å‰å¯¼ç©ºæ ¼
+#: builtin/grep.c:732
+#, fuzzy
+msgid "search in both tracked and untracked files"
+msgstr "(使用 -u å‚数显示未跟踪的文件)"
+
+#: builtin/grep.c:734
+msgid "search also in ignored files"
+msgstr ""
+
+#: builtin/grep.c:737
+msgid "show non-matching lines"
+msgstr ""
+
+#: builtin/grep.c:739
+msgid "case insensitive matching"
+msgstr ""
+
+#: builtin/grep.c:741
+msgid "match patterns only at word boundaries"
+msgstr ""
+
+#: builtin/grep.c:743
+msgid "process binary files as text"
+msgstr ""
+
+#: builtin/grep.c:745
+msgid "don't match patterns in binary files"
+msgstr ""
+
+#: builtin/grep.c:748
+msgid "descend at most <depth> levels"
+msgstr ""
+
+#: builtin/grep.c:752
+msgid "use extended POSIX regular expressions"
+msgstr ""
+
+#: builtin/grep.c:755
+msgid "use basic POSIX regular expressions (default)"
+msgstr ""
+
+#: builtin/grep.c:758
+msgid "interpret patterns as fixed strings"
+msgstr ""
+
+#: builtin/grep.c:761
+msgid "use Perl-compatible regular expressions"
+msgstr ""
+
+#: builtin/grep.c:764
+msgid "show line numbers"
+msgstr ""
+
+#: builtin/grep.c:765
+msgid "don't show filenames"
+msgstr ""
+
+#: builtin/grep.c:766
+#, fuzzy
+msgid "show filenames"
+msgstr "%s文件:"
+
+#: builtin/grep.c:768
+msgid "show filenames relative to top directory"
+msgstr ""
+
+#: builtin/grep.c:770
+msgid "show only filenames instead of matching lines"
+msgstr ""
+
+#: builtin/grep.c:772
+msgid "synonym for --files-with-matches"
+msgstr ""
+
+#: builtin/grep.c:775
+msgid "show only the names of files without match"
+msgstr ""
+
+#: builtin/grep.c:777
+#, fuzzy
+msgid "print NUL after filenames"
+msgstr "为所有文件åå‰æ·»åŠ  <根目录>"
+
+#: builtin/grep.c:779
+msgid "show the number of matches instead of matching lines"
+msgstr ""
+
+#: builtin/grep.c:780
+msgid "highlight matches"
+msgstr ""
+
+#: builtin/grep.c:782
+msgid "print empty line between matches from different files"
+msgstr ""
+
+#: builtin/grep.c:784
+msgid "show filename only once above matches from same file"
+msgstr ""
+
+#: builtin/grep.c:787
+msgid "show <n> context lines before and after matches"
+msgstr ""
+
+#: builtin/grep.c:790
+msgid "show <n> context lines before matches"
+msgstr ""
+
+#: builtin/grep.c:792
+msgid "show <n> context lines after matches"
+msgstr ""
+
+#: builtin/grep.c:793
+msgid "shortcut for -C NUM"
+msgstr ""
+
+#: builtin/grep.c:796
+msgid "show a line with the function name before matches"
+msgstr ""
+
+#: builtin/grep.c:798
+msgid "show the surrounding function"
+msgstr ""
+
+#: builtin/grep.c:801
+msgid "read patterns from file"
+msgstr ""
+
+#: builtin/grep.c:803
+msgid "match <pattern>"
+msgstr ""
+
+#: builtin/grep.c:805
+msgid "combine patterns specified with -e"
+msgstr ""
+
+#: builtin/grep.c:817
+msgid "indicate hit with exit status without output"
+msgstr ""
+
+#: builtin/grep.c:819
+msgid "show only matches from files that match all patterns"
+msgstr ""
+
+#: builtin/grep.c:822
+msgid "pager"
+msgstr ""
+
+#: builtin/grep.c:822
+msgid "show matching files in the pager"
+msgstr ""
+
+#: builtin/grep.c:825
+msgid "allow calling of grep(1) (ignored by this build)"
+msgstr ""
+
+#: builtin/grep.c:826 builtin/show-ref.c:201
+msgid "show usage"
+msgstr ""
+
+#: builtin/grep.c:917
msgid "no pattern given."
msgstr "未æ供模å¼åŒ¹é…。"
-#: builtin/grep.c:899
+#: builtin/grep.c:931
#, c-format
msgid "bad object %s"
msgstr "å对象 %s"
-#: builtin/grep.c:940
+#: builtin/grep.c:972
msgid "--open-files-in-pager only works on the worktree"
msgstr "--open-files-in-pager 仅用于工作区"
-#: builtin/grep.c:963
+#: builtin/grep.c:995
msgid "--cached or --untracked cannot be used with --no-index."
-msgstr "--cached 或 --untracked ä¸èƒ½ä¸Ž --no-index 共用。"
+msgstr "--cached 或 --untracked ä¸èƒ½ä¸Ž --no-index åŒæ—¶ä½¿ç”¨ã€‚"
-#: builtin/grep.c:968
+#: builtin/grep.c:1000
msgid "--no-index or --untracked cannot be used with revs."
-msgstr "--no-index 或 --untracked ä¸èƒ½å’Œç‰ˆæœ¬å…±ç”¨ã€‚"
+msgstr "--no-index 或 --untracked ä¸èƒ½å’Œç‰ˆæœ¬åŒæ—¶ä½¿ç”¨ã€‚"
-#: builtin/grep.c:971
+#: builtin/grep.c:1003
msgid "--[no-]exclude-standard cannot be used for tracked contents."
msgstr "--[no-]exclude-standard ä¸èƒ½ç”¨äºŽå·²è·Ÿè¸ªå†…容。"
-#: builtin/grep.c:979
+#: builtin/grep.c:1011
msgid "both --cached and trees are given."
msgstr "åŒæ—¶ç»™å‡ºäº† --cached 和树对象。"
-#: builtin/help.c:59
+#: builtin/hash-object.c:60
+msgid ""
+"git hash-object [-t <type>] [-w] [--path=<file>|--no-filters] [--stdin] [--] "
+"<file>..."
+msgstr ""
+
+#: builtin/hash-object.c:61
+msgid "git hash-object --stdin-paths < <list-of-paths>"
+msgstr ""
+
+#: builtin/hash-object.c:72
+msgid "type"
+msgstr ""
+
+#: builtin/hash-object.c:72
+#, fuzzy
+msgid "object type"
+msgstr "å的对象类型。"
+
+#: builtin/hash-object.c:73
+msgid "write the object into the object database"
+msgstr ""
+
+#: builtin/hash-object.c:74
+msgid "read the object from stdin"
+msgstr ""
+
+#: builtin/hash-object.c:76
+msgid "store file as is without filters"
+msgstr ""
+
+#: builtin/hash-object.c:77
+msgid "process file as it were from this path"
+msgstr ""
+
+#: builtin/help.c:43
+#, fuzzy
+msgid "print all available commands"
+msgstr "在 '%s' 下å¯ç”¨çš„ git 命令"
+
+#: builtin/help.c:44
+msgid "show man page"
+msgstr ""
+
+#: builtin/help.c:45
+msgid "show manual in web browser"
+msgstr ""
+
+#: builtin/help.c:47
+msgid "show info page"
+msgstr ""
+
+#: builtin/help.c:53
+msgid "git help [--all] [--man|--web|--info] [command]"
+msgstr ""
+
+#: builtin/help.c:65
#, c-format
msgid "unrecognized help format '%s'"
msgstr "æœªèƒ½è¯†åˆ«çš„å¸®åŠ©æ ¼å¼ '%s'"
-#: builtin/help.c:87
+#: builtin/help.c:93
msgid "Failed to start emacsclient."
msgstr "无法å¯åŠ¨ emacsclient。"
-#: builtin/help.c:100
+#: builtin/help.c:106
msgid "Failed to parse emacsclient version."
msgstr "æ— æ³•è§£æž emacsclient 版本。"
-#: builtin/help.c:108
+#: builtin/help.c:114
#, c-format
msgid "emacsclient version '%d' too old (< 22)."
msgstr "emacsclient 版本 '%d' å¤ªè€ (< 22)。"
-#: builtin/help.c:126 builtin/help.c:154 builtin/help.c:163 builtin/help.c:171
+#: builtin/help.c:132 builtin/help.c:160 builtin/help.c:169 builtin/help.c:177
#, c-format
msgid "failed to exec '%s': %s"
msgstr "无法执行 '%s':%s"
-#: builtin/help.c:211
+#: builtin/help.c:217
#, c-format
msgid ""
"'%s': path for unsupported man viewer.\n"
@@ -2854,7 +4885,7 @@ msgstr ""
"'%s':ä¸æ”¯æŒçš„ man 手册查看器的路径。\n"
"请使用 'man.<tool>.cmd'。"
-#: builtin/help.c:223
+#: builtin/help.c:229
#, c-format
msgid ""
"'%s': cmd for supported man viewer.\n"
@@ -2863,266 +4894,307 @@ msgstr ""
"'%s': 支æŒçš„ man 手册查看器命令。\n"
"请使用 'man.<tool>.path'。"
-#: builtin/help.c:287
+#: builtin/help.c:299
msgid "The most commonly used git commands are:"
msgstr "最常用的 git 命令有:"
-#: builtin/help.c:355
+#: builtin/help.c:367
#, c-format
msgid "'%s': unknown man viewer."
msgstr "'%s':未知的 man 查看器。"
-#: builtin/help.c:372
+#: builtin/help.c:384
msgid "no man viewer handled the request"
msgstr "没有 man 查看器处ç†æ­¤è¯·æ±‚"
-#: builtin/help.c:380
+#: builtin/help.c:392
msgid "no info viewer handled the request"
msgstr "没有 info 查看器处ç†æ­¤è¯·æ±‚"
-#: builtin/help.c:391
-#, c-format
-msgid "'%s': not a documentation directory."
-msgstr "'%s':ä¸æ˜¯ä¸€ä¸ªæ–‡æ¡£ç›®å½•ã€‚"
-
-#: builtin/help.c:432 builtin/help.c:439
+#: builtin/help.c:447 builtin/help.c:454
#, c-format
msgid "usage: %s%s"
msgstr "用法:%s%s"
-#: builtin/help.c:453
+#: builtin/help.c:470
#, c-format
msgid "`git %s' is aliased to `%s'"
msgstr "`git %s' 是 `%s' 的别å"
-#: builtin/index-pack.c:169
+#: builtin/index-pack.c:170
#, c-format
msgid "object type mismatch at %s"
msgstr "%s 的对象类型ä¸åŒ¹é…"
-#: builtin/index-pack.c:189
+#: builtin/index-pack.c:190
msgid "object of unexpected type"
msgstr "æ„外的类型的对象"
-#: builtin/index-pack.c:226
+#: builtin/index-pack.c:227
#, c-format
msgid "cannot fill %d byte"
msgid_plural "cannot fill %d bytes"
msgstr[0] "无法填充 %d 字节"
msgstr[1] "无法填充 %d 字节"
-#: builtin/index-pack.c:236
+#: builtin/index-pack.c:237
msgid "early EOF"
msgstr "过早的文件结æŸç¬¦ï¼ˆEOF)"
-#: builtin/index-pack.c:237
+#: builtin/index-pack.c:238
msgid "read error on input"
msgstr "输入上的读错误"
-#: builtin/index-pack.c:249
+#: builtin/index-pack.c:250
msgid "used more bytes than were available"
msgstr "用掉了超过å¯ç”¨çš„字节"
-#: builtin/index-pack.c:256
+#: builtin/index-pack.c:257
msgid "pack too large for current definition of off_t"
msgstr "åŒ…å¤ªå¤§è¶…è¿‡äº†å½“å‰ off_t 的定义"
-#: builtin/index-pack.c:272
+#: builtin/index-pack.c:273
#, c-format
msgid "unable to create '%s'"
msgstr "ä¸èƒ½åˆ›å»º '%s'"
-#: builtin/index-pack.c:277
+#: builtin/index-pack.c:278
#, c-format
msgid "cannot open packfile '%s'"
msgstr "无法打开包文件 '%s'"
-#: builtin/index-pack.c:291
+#: builtin/index-pack.c:292
msgid "pack signature mismatch"
msgstr "包签åä¸åŒ¹é…"
-#: builtin/index-pack.c:311
+#: builtin/index-pack.c:294
+#, c-format
+msgid "pack version %<PRIu32> unsupported"
+msgstr ""
+
+#: builtin/index-pack.c:312
#, c-format
msgid "pack has bad object at offset %lu: %s"
msgstr "包中有错误的对象ä½äºŽ %lu:%s"
-#: builtin/index-pack.c:405
+#: builtin/index-pack.c:434
#, c-format
msgid "inflate returned %d"
msgstr "解压缩返回 %d"
-#: builtin/index-pack.c:450
+#: builtin/index-pack.c:483
msgid "offset value overflow for delta base object"
msgstr "å移值覆盖了 delta 基准对象"
-#: builtin/index-pack.c:458
+#: builtin/index-pack.c:491
msgid "delta base offset is out of bound"
msgstr "delta 基准å移越界"
-#: builtin/index-pack.c:466
+#: builtin/index-pack.c:499
#, c-format
msgid "unknown object type %d"
msgstr "未知对象类型 %d"
-#: builtin/index-pack.c:495
+#: builtin/index-pack.c:530
msgid "cannot pread pack file"
msgstr "无法读å–包文件"
-#: builtin/index-pack.c:497
+#: builtin/index-pack.c:532
#, c-format
msgid "premature end of pack file, %lu byte missing"
msgid_plural "premature end of pack file, %lu bytes missing"
msgstr[0] "包文件过早结æŸï¼Œç¼ºå°‘ %lu 字节"
msgstr[1] "包文件过早结æŸï¼Œç¼ºå°‘ %lu 字节"
-#: builtin/index-pack.c:510
+#: builtin/index-pack.c:558
msgid "serious inflate inconsistency"
msgstr "解压缩严é‡çš„ä¸ä¸€è‡´"
-#: builtin/index-pack.c:583
-#, c-format
-msgid "cannot read existing object %s"
-msgstr "ä¸èƒ½è¯»å–现存对象 %s"
-
-#: builtin/index-pack.c:586
+#: builtin/index-pack.c:649 builtin/index-pack.c:655 builtin/index-pack.c:678
+#: builtin/index-pack.c:712 builtin/index-pack.c:721
#, c-format
msgid "SHA1 COLLISION FOUND WITH %s !"
msgstr "å‘现 %s 出现 SHA1 冲çªï¼"
-#: builtin/index-pack.c:598
+#: builtin/index-pack.c:652 builtin/pack-objects.c:170
+#: builtin/pack-objects.c:262
+#, c-format
+msgid "unable to read %s"
+msgstr "ä¸èƒ½è¯» %s"
+
+#: builtin/index-pack.c:718
+#, c-format
+msgid "cannot read existing object %s"
+msgstr "ä¸èƒ½è¯»å–现存对象 %s"
+
+#: builtin/index-pack.c:732
#, c-format
msgid "invalid blob object %s"
-msgstr "无效的 blob 对象 %s"
+msgstr "无效的二进制对象(blob)%s"
-#: builtin/index-pack.c:610
+#: builtin/index-pack.c:747
#, c-format
msgid "invalid %s"
msgstr "无效的 %s"
-#: builtin/index-pack.c:612
+#: builtin/index-pack.c:749
msgid "Error in object"
msgstr "对象中出错"
-#: builtin/index-pack.c:614
+#: builtin/index-pack.c:751
#, c-format
msgid "Not all child objects of %s are reachable"
msgstr "%s 的所有å­å¯¹è±¡å¹¶éžéƒ½å¯è¾¾"
-#: builtin/index-pack.c:687 builtin/index-pack.c:713
+#: builtin/index-pack.c:821 builtin/index-pack.c:847
msgid "failed to apply delta"
msgstr "无法应用 delta"
-#: builtin/index-pack.c:850
+#: builtin/index-pack.c:986
msgid "Receiving objects"
msgstr "接收对象中"
-#: builtin/index-pack.c:850
+#: builtin/index-pack.c:986
msgid "Indexing objects"
msgstr "索引对象中"
-#: builtin/index-pack.c:872
+#: builtin/index-pack.c:1012
msgid "pack is corrupted (SHA1 mismatch)"
msgstr "包冲çªï¼ˆSHA1 ä¸åŒ¹é…)"
-#: builtin/index-pack.c:877
+#: builtin/index-pack.c:1017
msgid "cannot fstat packfile"
msgstr "ä¸èƒ½æžšä¸¾åŒ…文件状æ€"
-#: builtin/index-pack.c:880
+#: builtin/index-pack.c:1020
msgid "pack has junk at the end"
msgstr "包的结尾有垃圾数æ®"
-#: builtin/index-pack.c:903
+#: builtin/index-pack.c:1031
+msgid "confusion beyond insanity in parse_pack_objects()"
+msgstr "parse_pack_objects() 中é‡åˆ°ä¸å¯ç†å–»çš„问题"
+
+#: builtin/index-pack.c:1054
msgid "Resolving deltas"
msgstr "å¤„ç† delta 中"
-#: builtin/index-pack.c:954
+#: builtin/index-pack.c:1064
+#, fuzzy, c-format
+msgid "unable to create thread: %s"
+msgstr "grep:无法创建线程:%s"
+
+#: builtin/index-pack.c:1106
msgid "confusion beyond insanity"
msgstr "ä¸å¯ç†å–»"
-#: builtin/index-pack.c:973
+#: builtin/index-pack.c:1112
+#, c-format
+msgid "completed with %d local objects"
+msgstr ""
+
+#: builtin/index-pack.c:1121
+#, c-format
+msgid "Unexpected tail checksum for %s (disk corruption?)"
+msgstr ""
+
+#: builtin/index-pack.c:1125
#, c-format
msgid "pack has %d unresolved delta"
msgid_plural "pack has %d unresolved deltas"
msgstr[0] "包有 %d 个未解决的 delta"
msgstr[1] "包有 %d 个未解决的 delta"
-#: builtin/index-pack.c:998
+#: builtin/index-pack.c:1150
#, c-format
msgid "unable to deflate appended object (%d)"
msgstr "ä¸èƒ½ç¼©å°é™„加对象(%d)"
-#: builtin/index-pack.c:1077
+#: builtin/index-pack.c:1229
#, c-format
msgid "local object %s is corrupt"
msgstr "本地对象 %s å·²æŸå"
-#: builtin/index-pack.c:1101
+#: builtin/index-pack.c:1253
msgid "error while closing pack file"
msgstr "关闭包文件时出错"
-#: builtin/index-pack.c:1114
+#: builtin/index-pack.c:1266
#, c-format
msgid "cannot write keep file '%s'"
msgstr "无法写ä¿ç•™æ–‡ä»¶ '%s'"
-#: builtin/index-pack.c:1122
+#: builtin/index-pack.c:1274
#, c-format
msgid "cannot close written keep file '%s'"
msgstr "无法关闭ä¿ç•™æ–‡ä»¶ '%s'"
-#: builtin/index-pack.c:1135
+#: builtin/index-pack.c:1287
msgid "cannot store pack file"
msgstr "无法存储包文件"
-#: builtin/index-pack.c:1146
+#: builtin/index-pack.c:1298
msgid "cannot store index file"
msgstr "无法存储索引文件"
-#: builtin/index-pack.c:1247
+#: builtin/index-pack.c:1331
+#, fuzzy, c-format
+msgid "bad pack.indexversion=%<PRIu32>"
+msgstr "å的索引版本 '%s'"
+
+#: builtin/index-pack.c:1337
+#, c-format
+msgid "invalid number of threads specified (%d)"
+msgstr ""
+
+#: builtin/index-pack.c:1341 builtin/index-pack.c:1514
+#, c-format
+msgid "no threads support, ignoring %s"
+msgstr ""
+
+#: builtin/index-pack.c:1399
#, c-format
msgid "Cannot open existing pack file '%s'"
msgstr "无法打开现存包文件 '%s'"
-#: builtin/index-pack.c:1249
+#: builtin/index-pack.c:1401
#, c-format
msgid "Cannot open existing pack idx file for '%s'"
msgstr "无法为 %s 打开包索引文件"
-#: builtin/index-pack.c:1296
+#: builtin/index-pack.c:1448
#, c-format
msgid "non delta: %d object"
msgid_plural "non delta: %d objects"
msgstr[0] "éž delta:%d 个对象"
msgstr[1] "éž delta:%d 个对象"
-#: builtin/index-pack.c:1303
+#: builtin/index-pack.c:1455
#, c-format
msgid "chain length = %d: %lu object"
msgid_plural "chain length = %d: %lu objects"
msgstr[0] "链长 = %d: %lu 对象"
msgstr[1] "链长 = %d: %lu 对象"
-#: builtin/index-pack.c:1330
+#: builtin/index-pack.c:1482
msgid "Cannot come back to cwd"
msgstr "无法返回当å‰å·¥ä½œç›®å½•"
-#: builtin/index-pack.c:1374 builtin/index-pack.c:1377
-#: builtin/index-pack.c:1389 builtin/index-pack.c:1393
+#: builtin/index-pack.c:1526 builtin/index-pack.c:1529
+#: builtin/index-pack.c:1541 builtin/index-pack.c:1545
#, c-format
msgid "bad %s"
msgstr "错误选项 %s"
-#: builtin/index-pack.c:1407
+#: builtin/index-pack.c:1559
msgid "--fix-thin cannot be used without --stdin"
-msgstr "--fix-thin ä¸èƒ½å’Œ --stdin 共用"
+msgstr "--fix-thin ä¸èƒ½å’Œ --stdin åŒæ—¶ä½¿ç”¨"
-#: builtin/index-pack.c:1411 builtin/index-pack.c:1421
+#: builtin/index-pack.c:1563 builtin/index-pack.c:1573
#, c-format
msgid "packfile name '%s' does not end with '.pack'"
msgstr "包å '%s' 没有以 '.pack' 结尾"
-#: builtin/index-pack.c:1430
+#: builtin/index-pack.c:1582
msgid "--verify with no packfile name given"
msgstr "--verify 没有æ供包åå‚æ•°"
@@ -3196,22 +5268,22 @@ msgstr "没有从 '%2$s' å¤åˆ¶å¸¦æœ‰é”™è¯¯ç‰ˆæœ¬ %1$d 的模版"
msgid "insane git directory %s"
msgstr "ä¸æ­£å¸¸çš„ git 目录 %s"
-#: builtin/init-db.c:322 builtin/init-db.c:325
+#: builtin/init-db.c:323 builtin/init-db.c:326
#, c-format
msgid "%s already exists"
msgstr "%s å·²ç»å­˜åœ¨"
-#: builtin/init-db.c:354
+#: builtin/init-db.c:355
#, c-format
msgid "unable to handle file type %d"
msgstr "ä¸èƒ½å¤„ç† %d 类型的文件"
-#: builtin/init-db.c:357
+#: builtin/init-db.c:358
#, c-format
msgid "unable to move %s to %s"
msgstr "ä¸èƒ½ç§»åŠ¨ %s 至 %s"
-#: builtin/init-db.c:362
+#: builtin/init-db.c:363
#, c-format
msgid "Could not create git link %s"
msgstr "ä¸èƒ½åˆ›å»º git link %s"
@@ -3221,39 +5293,58 @@ msgstr "ä¸èƒ½åˆ›å»º git link %s"
#. * existing" or "Initialized empty", the second " shared" or
#. * "", and the last '%s%s' is the verbatim directory name.
#.
-#: builtin/init-db.c:419
+#: builtin/init-db.c:420
#, c-format
msgid "%s%s Git repository in %s%s\n"
msgstr "%s%s Git 版本库于 %s%s\n"
-#: builtin/init-db.c:420
+#: builtin/init-db.c:421
msgid "Reinitialized existing"
msgstr "é‡æ–°åˆå§‹åŒ–现存的"
-#: builtin/init-db.c:420
+#: builtin/init-db.c:421
msgid "Initialized empty"
msgstr "åˆå§‹åŒ–空的"
# 译者:中文字符串拼接,å¯åˆ é™¤å‰å¯¼ç©ºæ ¼
-#: builtin/init-db.c:421
+#: builtin/init-db.c:422
msgid " shared"
msgstr "共享"
-#: builtin/init-db.c:440
+#: builtin/init-db.c:441
msgid "cannot tell cwd"
msgstr "无法获知当å‰è·¯å¾„"
-#: builtin/init-db.c:521 builtin/init-db.c:528
+#: builtin/init-db.c:467
+msgid ""
+"git init [-q | --quiet] [--bare] [--template=<template-directory>] [--shared"
+"[=<permissions>]] [directory]"
+msgstr ""
+
+#: builtin/init-db.c:490
+msgid "permissions"
+msgstr ""
+
+#: builtin/init-db.c:491
+msgid "specify that the git repository is to be shared amongst several users"
+msgstr ""
+
+#: builtin/init-db.c:493 builtin/prune-packed.c:77
+#, fuzzy
+msgid "be quiet"
+msgstr "更加安é™"
+
+#: builtin/init-db.c:522 builtin/init-db.c:529
#, c-format
msgid "cannot mkdir %s"
msgstr "ä¸èƒ½åˆ›å»ºç›®å½• %s"
-#: builtin/init-db.c:532
+#: builtin/init-db.c:533
#, c-format
msgid "cannot chdir to %s"
msgstr "ä¸èƒ½åˆ‡æ¢ç›®å½•åˆ° %s"
-#: builtin/init-db.c:554
+#: builtin/init-db.c:555
#, c-format
msgid ""
"%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-"
@@ -3262,113 +5353,413 @@ msgstr ""
"ä¸å…许 %s(或 --work-tree=<directory>)而没有指定 %s(或 --git-"
"dir=<directory>)"
-#: builtin/init-db.c:578
+#: builtin/init-db.c:579
msgid "Cannot access current working directory"
msgstr "ä¸èƒ½è®¿é—®å½“å‰å·¥ä½œç›®å½•"
-#: builtin/init-db.c:585
+#: builtin/init-db.c:586
#, c-format
msgid "Cannot access work tree '%s'"
msgstr "ä¸èƒ½è®¿é—®å·¥ä½œåŒº '%s'"
-#: builtin/log.c:188
+#: builtin/log.c:37
+#, fuzzy
+msgid "git log [<options>] [<since>..<until>] [[--] <path>...]\n"
+msgstr "git apply [选项] [<è¡¥ä¸>...]"
+
+#: builtin/log.c:38
+#, fuzzy
+msgid " or: git show [options] <object>..."
+msgstr "git apply [选项] [<è¡¥ä¸>...]"
+
+#: builtin/log.c:100
+msgid "suppress diff output"
+msgstr ""
+
+#: builtin/log.c:101
+#, fuzzy
+msgid "show source"
+msgstr "åçš„æº"
+
+#: builtin/log.c:102
+msgid "decorate options"
+msgstr ""
+
+#: builtin/log.c:189
#, c-format
msgid "Final output: %d %s\n"
msgstr "最终输出:%d %s\n"
-#: builtin/log.c:401 builtin/log.c:489
+#: builtin/log.c:403 builtin/log.c:494
#, c-format
msgid "Could not read object %s"
msgstr "ä¸èƒ½è¯»å–对象 %s"
-#: builtin/log.c:513
+#: builtin/log.c:518
#, c-format
msgid "Unknown type: %d"
msgstr "未知类型:%d"
-#: builtin/log.c:602
+#: builtin/log.c:608
msgid "format.headers without value"
msgstr "format.headers 没有值"
-#: builtin/log.c:676
+#: builtin/log.c:682
msgid "name of output directory is too long"
msgstr "输出目录å太长"
-#: builtin/log.c:687
+#: builtin/log.c:693
#, c-format
msgid "Cannot open patch file %s"
msgstr "无法打开补ä¸æ–‡ä»¶ %s"
-#: builtin/log.c:701
+#: builtin/log.c:707
msgid "Need exactly one range."
msgstr "åªéœ€è¦ä¸€ä¸ªèŒƒå›´ã€‚"
-#: builtin/log.c:709
+#: builtin/log.c:715
msgid "Not a range."
msgstr "ä¸æ˜¯ä¸€ä¸ªèŒƒå›´ã€‚"
-#: builtin/log.c:786
+#: builtin/log.c:789
msgid "Cover letter needs email format"
msgstr "ä¿¡å°éœ€è¦é‚®ä»¶åœ°å€æ ¼å¼"
-#: builtin/log.c:859
+#: builtin/log.c:862
#, c-format
msgid "insane in-reply-to: %s"
msgstr "ä¸æ­£å¸¸çš„ in-reply-to:%s"
-#: builtin/log.c:932
+#: builtin/log.c:890
+msgid "git format-patch [options] [<since> | <revision range>]"
+msgstr ""
+
+#: builtin/log.c:935
msgid "Two output directories?"
msgstr "两个输出目录?"
-#: builtin/log.c:1153
+#: builtin/log.c:1063
+msgid "use [PATCH n/m] even with a single patch"
+msgstr ""
+
+#: builtin/log.c:1066
+msgid "use [PATCH] even with multiple patches"
+msgstr ""
+
+#: builtin/log.c:1070
+msgid "print patches to standard out"
+msgstr ""
+
+#: builtin/log.c:1072
+msgid "generate a cover letter"
+msgstr ""
+
+#: builtin/log.c:1074
+msgid "use simple number sequence for output file names"
+msgstr ""
+
+#: builtin/log.c:1075
+msgid "sfx"
+msgstr ""
+
+#: builtin/log.c:1076
+msgid "use <sfx> instead of '.patch'"
+msgstr ""
+
+#: builtin/log.c:1078
+msgid "start numbering patches at <n> instead of 1"
+msgstr ""
+
+#: builtin/log.c:1080
+msgid "Use [<prefix>] instead of [PATCH]"
+msgstr ""
+
+#: builtin/log.c:1083
+msgid "store resulting files in <dir>"
+msgstr ""
+
+#: builtin/log.c:1086
+msgid "don't strip/add [PATCH]"
+msgstr ""
+
+#: builtin/log.c:1089
+msgid "don't output binary diffs"
+msgstr ""
+
+#: builtin/log.c:1091
+msgid "don't include a patch matching a commit upstream"
+msgstr ""
+
+#: builtin/log.c:1093
+msgid "show patch format instead of default (patch + stat)"
+msgstr ""
+
+#: builtin/log.c:1095
+#, fuzzy
+msgid "Messaging"
+msgstr "åˆå¹¶ï¼š"
+
+# 译者:注æ„ä¿æŒå¥å°¾ç©ºæ ¼
+#: builtin/log.c:1096
+#, fuzzy
+msgid "header"
+msgstr "领先 "
+
+#: builtin/log.c:1097
+msgid "add email header"
+msgstr ""
+
+#: builtin/log.c:1098 builtin/log.c:1100
+msgid "email"
+msgstr ""
+
+#: builtin/log.c:1098
+msgid "add To: header"
+msgstr ""
+
+#: builtin/log.c:1100
+msgid "add Cc: header"
+msgstr ""
+
+#: builtin/log.c:1102
+msgid "message-id"
+msgstr ""
+
+#: builtin/log.c:1103
+msgid "make first mail a reply to <message-id>"
+msgstr ""
+
+#: builtin/log.c:1104 builtin/log.c:1107
+msgid "boundary"
+msgstr ""
+
+#: builtin/log.c:1105
+msgid "attach the patch"
+msgstr ""
+
+#: builtin/log.c:1108
+#, fuzzy
+msgid "inline the patch"
+msgstr "忽略补ä¸ä¸­çš„添加的文件"
+
+#: builtin/log.c:1112
+msgid "enable message threading, styles: shallow, deep"
+msgstr ""
+
+#: builtin/log.c:1114
+msgid "signature"
+msgstr ""
+
+#: builtin/log.c:1115
+msgid "add a signature"
+msgstr ""
+
+#: builtin/log.c:1117
+#, fuzzy
+msgid "don't print the patch filenames"
+msgstr "无法打开补ä¸æ–‡ä»¶ %s"
+
+#: builtin/log.c:1157
#, c-format
msgid "bogus committer info %s"
msgstr "虚å‡çš„æäº¤è€…ä¿¡æ¯ %s"
-#: builtin/log.c:1198
+#: builtin/log.c:1202
msgid "-n and -k are mutually exclusive."
msgstr "-n 和 -k 互斥。"
-#: builtin/log.c:1200
+#: builtin/log.c:1204
msgid "--subject-prefix and -k are mutually exclusive."
msgstr "--subject-prefix 和 -k 互斥。"
-#: builtin/log.c:1208
+#: builtin/log.c:1212
msgid "--name-only does not make sense"
msgstr "--name-only æ— æ„义"
-#: builtin/log.c:1210
+#: builtin/log.c:1214
msgid "--name-status does not make sense"
msgstr "--name-status æ— æ„义"
-#: builtin/log.c:1212
+#: builtin/log.c:1216
msgid "--check does not make sense"
msgstr "--check æ— æ„义"
-#: builtin/log.c:1235
+#: builtin/log.c:1239
msgid "standard output, or directory, which one?"
msgstr "标准输出或目录,哪一个?"
-#: builtin/log.c:1237
+#: builtin/log.c:1241
#, c-format
msgid "Could not create directory '%s'"
msgstr "ä¸èƒ½åˆ›å»ºç›®å½• '%s'"
-#: builtin/log.c:1390
+#: builtin/log.c:1394
msgid "Failed to create output files"
msgstr "无法创建输出文件"
-#: builtin/log.c:1494
+#: builtin/log.c:1443
+msgid "git cherry [-v] [<upstream> [<head> [<limit>]]]"
+msgstr ""
+
+#: builtin/log.c:1498
#, c-format
msgid ""
"Could not find a tracked remote branch, please specify <upstream> manually.\n"
msgstr "ä¸èƒ½æ‰¾åˆ°è·Ÿè¸ªçš„远程分支,请手工指定 <upstream>。\n"
-#: builtin/log.c:1510 builtin/log.c:1512 builtin/log.c:1524
+#: builtin/log.c:1511 builtin/log.c:1513 builtin/log.c:1525
#, c-format
msgid "Unknown commit %s"
msgstr "未知æ交 %s"
+#: builtin/ls-files.c:408
+#, fuzzy
+msgid "git ls-files [options] [<file>...]"
+msgstr "git apply [选项] [<è¡¥ä¸>...]"
+
+#: builtin/ls-files.c:463
+msgid "identify the file status with tags"
+msgstr ""
+
+#: builtin/ls-files.c:465
+msgid "use lowercase letters for 'assume unchanged' files"
+msgstr ""
+
+#: builtin/ls-files.c:467
+msgid "show cached files in the output (default)"
+msgstr ""
+
+#: builtin/ls-files.c:469
+#, fuzzy
+msgid "show deleted files in the output"
+msgstr "删除的文件 %s ä»æœ‰å†…容"
+
+#: builtin/ls-files.c:471
+msgid "show modified files in the output"
+msgstr ""
+
+#: builtin/ls-files.c:473
+msgid "show other files in the output"
+msgstr ""
+
+#: builtin/ls-files.c:475
+msgid "show ignored files in the output"
+msgstr ""
+
+#: builtin/ls-files.c:478
+msgid "show staged contents' object name in the output"
+msgstr ""
+
+#: builtin/ls-files.c:480
+msgid "show files on the filesystem that need to be removed"
+msgstr ""
+
+#: builtin/ls-files.c:482
+msgid "show 'other' directories' name only"
+msgstr ""
+
+#: builtin/ls-files.c:485
+#, fuzzy
+msgid "don't show empty directories"
+msgstr "两个输出目录?"
+
+#: builtin/ls-files.c:488
+msgid "show unmerged files in the output"
+msgstr ""
+
+#: builtin/ls-files.c:490
+msgid "show resolve-undo information"
+msgstr ""
+
+#: builtin/ls-files.c:492
+#, fuzzy
+msgid "skip files matching pattern"
+msgstr "输出和模å¼åŒ¹é…çš„è¡Œ"
+
+#: builtin/ls-files.c:495
+msgid "exclude patterns are read from <file>"
+msgstr ""
+
+#: builtin/ls-files.c:498
+msgid "read additional per-directory exclude patterns in <file>"
+msgstr ""
+
+#: builtin/ls-files.c:500
+msgid "add the standard git exclusions"
+msgstr ""
+
+#: builtin/ls-files.c:503
+msgid "make the output relative to the project top directory"
+msgstr ""
+
+#: builtin/ls-files.c:506
+msgid "if any <file> is not in the index, treat this as an error"
+msgstr ""
+
+#: builtin/ls-files.c:507
+msgid "tree-ish"
+msgstr ""
+
+#: builtin/ls-files.c:508
+msgid "pretend that paths removed since <tree-ish> are still present"
+msgstr ""
+
+#: builtin/ls-files.c:510
+msgid "show debugging data"
+msgstr ""
+
+#: builtin/ls-tree.c:27
+#, fuzzy
+msgid "git ls-tree [<options>] <tree-ish> [<path>...]"
+msgstr "git apply [选项] [<è¡¥ä¸>...]"
+
+#: builtin/ls-tree.c:125
+msgid "only show trees"
+msgstr ""
+
+#: builtin/ls-tree.c:127
+#, fuzzy
+msgid "recurse into subtrees"
+msgstr "å˜åŸºåˆ°è¿œç¨‹ %s"
+
+#: builtin/ls-tree.c:129
+msgid "show trees when recursing"
+msgstr ""
+
+#: builtin/ls-tree.c:132
+msgid "terminate entries with NUL byte"
+msgstr ""
+
+#: builtin/ls-tree.c:133
+#, fuzzy
+msgid "include object size"
+msgstr "æ供了无效对象 '%s'。"
+
+#: builtin/ls-tree.c:135 builtin/ls-tree.c:137
+msgid "list only filenames"
+msgstr ""
+
+#: builtin/ls-tree.c:140
+msgid "use full path names"
+msgstr ""
+
+#: builtin/ls-tree.c:142
+msgid "list entire tree; not just current directory (implies --full-name)"
+msgstr ""
+
+#: builtin/merge.c:43
+#, fuzzy
+msgid "git merge [options] [<commit>...]"
+msgstr "git apply [选项] [<è¡¥ä¸>...]"
+
+#: builtin/merge.c:44
+msgid "git merge [options] <msg> HEAD <commit>"
+msgstr ""
+
+#: builtin/merge.c:45
+msgid "git merge --abort"
+msgstr ""
+
#: builtin/merge.c:90
msgid "switch `m' requires a value"
msgstr "开关 `m' 需è¦ä¸€ä¸ªå€¼"
@@ -3388,6 +5779,71 @@ msgstr "å¯ç”¨çš„策略有:"
msgid "Available custom strategies are:"
msgstr "å¯ç”¨çš„自定义策略有:"
+#: builtin/merge.c:183
+msgid "do not show a diffstat at the end of the merge"
+msgstr ""
+
+#: builtin/merge.c:186
+msgid "show a diffstat at the end of the merge"
+msgstr ""
+
+#: builtin/merge.c:187
+msgid "(synonym to --stat)"
+msgstr ""
+
+#: builtin/merge.c:189
+msgid "add (at most <n>) entries from shortlog to merge commit message"
+msgstr ""
+
+#: builtin/merge.c:192
+#, fuzzy
+msgid "create a single commit instead of doing a merge"
+msgstr "在åˆå¹¶è¿‡ç¨‹ä¸­ä¸èƒ½åšéƒ¨åˆ†æ交。"
+
+#: builtin/merge.c:194
+msgid "perform a commit if the merge succeeds (default)"
+msgstr ""
+
+#: builtin/merge.c:196
+#, fuzzy
+msgid "edit message before committing"
+msgstr "尚未暂存以备æ交的å˜æ›´ï¼š"
+
+#: builtin/merge.c:198
+#, fuzzy
+msgid "allow fast-forward (default)"
+msgstr "å¯å¿«è¿›"
+
+#: builtin/merge.c:200
+msgid "abort if fast-forward is not possible"
+msgstr ""
+
+#: builtin/merge.c:202 builtin/notes.c:867 builtin/revert.c:112
+msgid "strategy"
+msgstr ""
+
+#: builtin/merge.c:203
+#, fuzzy
+msgid "merge strategy to use"
+msgstr "å°è¯•åˆå¹¶ç­–ç•¥ %s...\n"
+
+#: builtin/merge.c:204
+msgid "option=value"
+msgstr ""
+
+#: builtin/merge.c:205
+msgid "option for selected merge strategy"
+msgstr ""
+
+#: builtin/merge.c:207
+msgid "merge commit message (for a non-fast-forward merge)"
+msgstr ""
+
+#: builtin/merge.c:211
+#, fuzzy
+msgid "abort the current in-progress merge"
+msgstr "无法ä¿å­˜å½“å‰ç´¢å¼•çŠ¶æ€"
+
#: builtin/merge.c:240
msgid "could not run stash."
msgstr "ä¸èƒ½è¿›è¡Œè¿›åº¦ä¿å­˜ã€‚"
@@ -3428,53 +5884,49 @@ msgstr "å®Œæˆ SQUASH_MSG"
msgid "No merge message -- not updating HEAD\n"
msgstr "æ— åˆå¹¶ä¿¡æ¯ -- 未更新 HEAD\n"
-#: builtin/merge.c:437
+#: builtin/merge.c:436
#, c-format
msgid "'%s' does not point to a commit"
msgstr "'%s' 没有指å‘一个æ交"
-#: builtin/merge.c:536
+#: builtin/merge.c:535
#, c-format
msgid "Bad branch.%s.mergeoptions string: %s"
msgstr "åçš„ branch.%s.mergeoptions 字符串:%s"
-#: builtin/merge.c:629
+#: builtin/merge.c:628
msgid "git write-tree failed to write a tree"
msgstr "git write-tree 无法写入一树对象"
-#: builtin/merge.c:679
+#: builtin/merge.c:678
msgid "failed to read the cache"
msgstr "无法读å–缓存"
-#: builtin/merge.c:697
-msgid "Unable to write index."
-msgstr "ä¸èƒ½å†™ç´¢å¼•ã€‚"
-
-#: builtin/merge.c:710
+#: builtin/merge.c:709
msgid "Not handling anything other than two heads merge."
msgstr "ä¸èƒ½å¤„ç†ä¸¤ä¸ªå¤´åˆå¹¶ä¹‹å¤–的任何æ“作。"
-#: builtin/merge.c:724
+#: builtin/merge.c:723
#, c-format
msgid "Unknown option for merge-recursive: -X%s"
msgstr "merge-recursive 的未知选项:-X%s"
-#: builtin/merge.c:738
+#: builtin/merge.c:737
#, c-format
msgid "unable to write %s"
msgstr "ä¸èƒ½å†™ %s"
-#: builtin/merge.c:877
+#: builtin/merge.c:876
#, c-format
msgid "Could not read from '%s'"
msgstr "ä¸èƒ½ä»Ž '%s' 读å–"
-#: builtin/merge.c:886
+#: builtin/merge.c:885
#, c-format
msgid "Not committing merge; use 'git commit' to complete the merge.\n"
msgstr "未æ交åˆå¹¶ï¼Œä½¿ç”¨ 'git commit' 完æˆæ­¤æ¬¡åˆå¹¶ã€‚\n"
-#: builtin/merge.c:892
+#: builtin/merge.c:891
msgid ""
"Please enter a commit message to explain why this merge is necessary,\n"
"especially if it merges an updated upstream into a topic branch.\n"
@@ -3487,52 +5939,52 @@ msgstr ""
"\n"
"以 '#' 开头的行将被忽略,而且空æ交说明将会终止æ交。\n"
-#: builtin/merge.c:916
+#: builtin/merge.c:915
msgid "Empty commit message."
msgstr "空æ交信æ¯ã€‚"
-#: builtin/merge.c:928
+#: builtin/merge.c:927
#, c-format
msgid "Wonderful.\n"
msgstr "太棒了。\n"
-#: builtin/merge.c:993
+#: builtin/merge.c:992
#, c-format
msgid "Automatic merge failed; fix conflicts and then commit the result.\n"
msgstr "自动åˆå¹¶å¤±è´¥ï¼Œä¿®æ­£å†²çªç„¶åŽæ交修正的结果。\n"
-#: builtin/merge.c:1009
+#: builtin/merge.c:1008
#, c-format
msgid "'%s' is not a commit"
msgstr "'%s' ä¸æ˜¯ä¸€ä¸ªæ交"
-#: builtin/merge.c:1050
+#: builtin/merge.c:1049
msgid "No current branch."
msgstr "没有当å‰åˆ†æ”¯ã€‚"
-#: builtin/merge.c:1052
+#: builtin/merge.c:1051
msgid "No remote for the current branch."
msgstr "当å‰åˆ†æ”¯æ²¡æœ‰å¯¹åº”的远程版本库。"
-#: builtin/merge.c:1054
+#: builtin/merge.c:1053
msgid "No default upstream defined for the current branch."
msgstr "当å‰åˆ†æ”¯æ²¡æœ‰å®šä¹‰é»˜è®¤çš„上游分支。"
-#: builtin/merge.c:1059
+#: builtin/merge.c:1058
#, c-format
msgid "No remote tracking branch for %s from %s"
msgstr "%s 没有æ¥è‡ª %s 的远程跟踪分支"
-#: builtin/merge.c:1146 builtin/merge.c:1303
+#: builtin/merge.c:1145 builtin/merge.c:1302
#, c-format
msgid "%s - not something we can merge"
msgstr "%s - ä¸èƒ½è¢«åˆå¹¶"
-#: builtin/merge.c:1214
+#: builtin/merge.c:1213
msgid "There is no merge to abort (MERGE_HEAD missing)."
msgstr "没有è¦ç»ˆæ­¢çš„åˆå¹¶ï¼ˆMERGE_HEAD 丢失)。"
-#: builtin/merge.c:1230 git-pull.sh:31
+#: builtin/merge.c:1229 git-pull.sh:31
msgid ""
"You have not concluded your merge (MERGE_HEAD exists).\n"
"Please, commit your changes before you can merge."
@@ -3540,11 +5992,11 @@ msgstr ""
"您尚未结æŸæ‚¨çš„åˆå¹¶ï¼ˆå­˜åœ¨ MERGE_HEAD)。\n"
"请在åˆå¹¶å‰å…ˆæ交您的修改。"
-#: builtin/merge.c:1233 git-pull.sh:34
+#: builtin/merge.c:1232 git-pull.sh:34
msgid "You have not concluded your merge (MERGE_HEAD exists)."
msgstr "您尚未结æŸæ‚¨çš„åˆå¹¶ï¼ˆå­˜åœ¨ MERGE_HEAD)。"
-#: builtin/merge.c:1237
+#: builtin/merge.c:1236
msgid ""
"You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
"Please, commit your changes before you can merge."
@@ -3552,83 +6004,184 @@ msgstr ""
"您尚未结æŸæ‚¨çš„拣选(存在 CHERRY_PICK_HEAD)。\n"
"请在åˆå¹¶å‰å…ˆæ交您的修改。"
-#: builtin/merge.c:1240
+#: builtin/merge.c:1239
msgid "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)."
msgstr "您尚未结æŸæ‚¨çš„拣选(存在 CHERRY_PICK_HEAD)。"
-#: builtin/merge.c:1249
+#: builtin/merge.c:1248
msgid "You cannot combine --squash with --no-ff."
-msgstr "您ä¸èƒ½å°† --squash 与 --no-ff 共用。"
+msgstr "您ä¸èƒ½å°† --squash 与 --no-ff åŒæ—¶ä½¿ç”¨ã€‚"
-#: builtin/merge.c:1254
+#: builtin/merge.c:1253
msgid "You cannot combine --no-ff with --ff-only."
-msgstr "您ä¸èƒ½å°† --no-ff 与 --ff-only 共用。"
+msgstr "您ä¸èƒ½å°† --no-ff 与 --ff-only åŒæ—¶ä½¿ç”¨ã€‚"
-#: builtin/merge.c:1261
+#: builtin/merge.c:1260
msgid "No commit specified and merge.defaultToUpstream not set."
msgstr "未指定æ交并且 merge.defaultToUpstream 未设置。"
-#: builtin/merge.c:1293
+#: builtin/merge.c:1292
msgid "Can merge only exactly one commit into empty head"
msgstr "åªèƒ½å°†ä¸€ä¸ªæ交åˆå¹¶åˆ°ç©ºåˆ†æ”¯ä¸Š"
-#: builtin/merge.c:1296
+#: builtin/merge.c:1295
msgid "Squash commit into empty head not supported yet"
msgstr "å°šä¸æ”¯æŒåˆ°ç©ºåˆ†æ”¯çš„压缩æ交"
-#: builtin/merge.c:1298
+#: builtin/merge.c:1297
msgid "Non-fast-forward commit does not make sense into an empty head"
msgstr "到空分支的éžå¿«è¿›å¼æ交没有æ„义"
-#: builtin/merge.c:1413
+#: builtin/merge.c:1412
#, c-format
msgid "Updating %s..%s\n"
msgstr "æ›´æ–° %s..%s\n"
-#: builtin/merge.c:1451
+#: builtin/merge.c:1450
#, c-format
msgid "Trying really trivial in-index merge...\n"
msgstr "å°è¯•éžå¸¸å°çš„索引内åˆå¹¶...\n"
-#: builtin/merge.c:1458
+#: builtin/merge.c:1457
#, c-format
msgid "Nope.\n"
msgstr "无。\n"
-#: builtin/merge.c:1490
+#: builtin/merge.c:1489
msgid "Not possible to fast-forward, aborting."
msgstr "无法快进,终止。"
-#: builtin/merge.c:1513 builtin/merge.c:1592
+#: builtin/merge.c:1512 builtin/merge.c:1591
#, c-format
msgid "Rewinding the tree to pristine...\n"
msgstr "将树回滚至原始状æ€...\n"
-#: builtin/merge.c:1517
+#: builtin/merge.c:1516
#, c-format
msgid "Trying merge strategy %s...\n"
msgstr "å°è¯•åˆå¹¶ç­–ç•¥ %s...\n"
-#: builtin/merge.c:1583
+#: builtin/merge.c:1582
#, c-format
msgid "No merge strategy handled the merge.\n"
msgstr "没有åˆå¹¶ç­–略处ç†æ­¤åˆå¹¶ã€‚\n"
-#: builtin/merge.c:1585
+#: builtin/merge.c:1584
#, c-format
msgid "Merge with strategy %s failed.\n"
msgstr "使用策略 %s åˆå¹¶å¤±è´¥ã€‚\n"
-#: builtin/merge.c:1594
+#: builtin/merge.c:1593
#, c-format
msgid "Using the %s to prepare resolving by hand.\n"
msgstr "使用 %s 以准备手工解决。\n"
-#: builtin/merge.c:1606
+#: builtin/merge.c:1605
#, c-format
msgid "Automatic merge went well; stopped before committing as requested\n"
msgstr "自动åˆå¹¶è¿›å±•é¡ºåˆ©ï¼ŒæŒ‰è¦æ±‚在æ交å‰åœæ­¢\n"
+#: builtin/merge-base.c:26
+msgid "git merge-base [-a|--all] <commit> <commit>..."
+msgstr ""
+
+#: builtin/merge-base.c:27
+msgid "git merge-base [-a|--all] --octopus <commit>..."
+msgstr ""
+
+#: builtin/merge-base.c:28
+msgid "git merge-base --independent <commit>..."
+msgstr ""
+
+#: builtin/merge-base.c:29
+msgid "git merge-base --is-ancestor <commit> <commit>"
+msgstr ""
+
+#: builtin/merge-base.c:98
+#, fuzzy
+msgid "output all common ancestors"
+msgstr "å‘现 %u 个共åŒç¥–先:"
+
+#: builtin/merge-base.c:99
+msgid "find ancestors for a single n-way merge"
+msgstr ""
+
+#: builtin/merge-base.c:100
+msgid "list revs not reachable from others"
+msgstr ""
+
+#: builtin/merge-base.c:102
+msgid "is the first one ancestor of the other?"
+msgstr ""
+
+#: builtin/merge-file.c:8
+msgid ""
+"git merge-file [options] [-L name1 [-L orig [-L name2]]] file1 orig_file "
+"file2"
+msgstr ""
+
+#: builtin/merge-file.c:33
+msgid "send results to standard output"
+msgstr ""
+
+#: builtin/merge-file.c:34
+msgid "use a diff3 based merge"
+msgstr ""
+
+#: builtin/merge-file.c:35
+msgid "for conflicts, use our version"
+msgstr ""
+
+#: builtin/merge-file.c:37
+msgid "for conflicts, use their version"
+msgstr ""
+
+#: builtin/merge-file.c:39
+msgid "for conflicts, use a union version"
+msgstr ""
+
+#: builtin/merge-file.c:42
+msgid "for conflicts, use this marker size"
+msgstr ""
+
+#: builtin/merge-file.c:43
+msgid "do not warn about conflicts"
+msgstr ""
+
+#: builtin/merge-file.c:45
+msgid "set labels for file1/orig_file/file2"
+msgstr ""
+
+#: builtin/mktree.c:67
+msgid "git mktree [-z] [--missing] [--batch]"
+msgstr ""
+
+#: builtin/mktree.c:153
+msgid "input is NUL terminated"
+msgstr ""
+
+#: builtin/mktree.c:154 builtin/write-tree.c:24
+#, fuzzy
+msgid "allow missing objects"
+msgstr "接收对象中"
+
+#: builtin/mktree.c:155
+msgid "allow creation of more than one tree"
+msgstr ""
+
+#: builtin/mv.c:14
+msgid "git mv [options] <source>... <destination>"
+msgstr ""
+
+#: builtin/mv.c:64
+msgid "force move/rename even if target exists"
+msgstr ""
+
+#: builtin/mv.c:65
+#, fuzzy
+msgid "skip move/rename errors"
+msgstr "程åºé”™è¯¯"
+
#: builtin/mv.c:108
#, c-format
msgid "Checking rename of '%s' to '%s'\n"
@@ -3691,6 +6244,151 @@ msgstr "é‡å‘½å %s 至 %s\n"
msgid "renaming '%s' failed"
msgstr "é‡å‘½å '%s' 失败"
+#: builtin/name-rev.c:175
+#, fuzzy
+msgid "git name-rev [options] <commit>..."
+msgstr "git apply [选项] [<è¡¥ä¸>...]"
+
+#: builtin/name-rev.c:176
+msgid "git name-rev [options] --all"
+msgstr ""
+
+#: builtin/name-rev.c:177
+msgid "git name-rev [options] --stdin"
+msgstr ""
+
+#: builtin/name-rev.c:229
+msgid "print only names (no SHA-1)"
+msgstr ""
+
+#: builtin/name-rev.c:230
+msgid "only use tags to name the commits"
+msgstr ""
+
+#: builtin/name-rev.c:232
+#, fuzzy
+msgid "only use refs matching <pattern>"
+msgstr "输出和模å¼åŒ¹é…çš„è¡Œ"
+
+#: builtin/name-rev.c:234
+msgid "list all commits reachable from all refs"
+msgstr ""
+
+#: builtin/name-rev.c:235
+msgid "read from stdin"
+msgstr ""
+
+#: builtin/name-rev.c:236
+msgid "allow to print `undefined` names"
+msgstr ""
+
+#: builtin/notes.c:23
+msgid "git notes [--ref <notes_ref>] [list [<object>]]"
+msgstr ""
+
+#: builtin/notes.c:24
+msgid ""
+"git notes [--ref <notes_ref>] add [-f] [-m <msg> | -F <file> | (-c | -C) "
+"<object>] [<object>]"
+msgstr ""
+
+#: builtin/notes.c:25
+msgid "git notes [--ref <notes_ref>] copy [-f] <from-object> <to-object>"
+msgstr ""
+
+#: builtin/notes.c:26
+msgid ""
+"git notes [--ref <notes_ref>] append [-m <msg> | -F <file> | (-c | -C) "
+"<object>] [<object>]"
+msgstr ""
+
+#: builtin/notes.c:27
+msgid "git notes [--ref <notes_ref>] edit [<object>]"
+msgstr ""
+
+#: builtin/notes.c:28
+msgid "git notes [--ref <notes_ref>] show [<object>]"
+msgstr ""
+
+#: builtin/notes.c:29
+msgid ""
+"git notes [--ref <notes_ref>] merge [-v | -q] [-s <strategy> ] <notes_ref>"
+msgstr ""
+
+#: builtin/notes.c:30
+msgid "git notes merge --commit [-v | -q]"
+msgstr ""
+
+#: builtin/notes.c:31
+msgid "git notes merge --abort [-v | -q]"
+msgstr ""
+
+#: builtin/notes.c:32
+msgid "git notes [--ref <notes_ref>] remove [<object>...]"
+msgstr ""
+
+#: builtin/notes.c:33
+msgid "git notes [--ref <notes_ref>] prune [-n | -v]"
+msgstr ""
+
+#: builtin/notes.c:34
+msgid "git notes [--ref <notes_ref>] get-ref"
+msgstr ""
+
+#: builtin/notes.c:39
+msgid "git notes [list [<object>]]"
+msgstr ""
+
+#: builtin/notes.c:44
+#, fuzzy
+msgid "git notes add [<options>] [<object>]"
+msgstr "git apply [选项] [<è¡¥ä¸>...]"
+
+#: builtin/notes.c:49
+msgid "git notes copy [<options>] <from-object> <to-object>"
+msgstr ""
+
+#: builtin/notes.c:50
+msgid "git notes copy --stdin [<from-object> <to-object>]..."
+msgstr ""
+
+#: builtin/notes.c:55
+#, fuzzy
+msgid "git notes append [<options>] [<object>]"
+msgstr "git apply [选项] [<è¡¥ä¸>...]"
+
+#: builtin/notes.c:60
+msgid "git notes edit [<object>]"
+msgstr ""
+
+#: builtin/notes.c:65
+msgid "git notes show [<object>]"
+msgstr ""
+
+#: builtin/notes.c:70
+msgid "git notes merge [<options>] <notes_ref>"
+msgstr ""
+
+#: builtin/notes.c:71
+msgid "git notes merge --commit [<options>]"
+msgstr ""
+
+#: builtin/notes.c:72
+msgid "git notes merge --abort [<options>]"
+msgstr ""
+
+#: builtin/notes.c:77
+msgid "git notes remove [<object>]"
+msgstr ""
+
+#: builtin/notes.c:82
+msgid "git notes prune [<options>]"
+msgstr ""
+
+#: builtin/notes.c:87
+msgid "git notes get-ref"
+msgstr ""
+
#: builtin/notes.c:139
#, c-format
msgid "unable to start 'show' for object '%s'"
@@ -3798,6 +6496,37 @@ msgstr "å‚数太多"
msgid "No note found for object %s."
msgstr "未å‘现对象 %s 的注解。"
+#: builtin/notes.c:535 builtin/notes.c:692
+#, fuzzy
+msgid "note contents as a string"
+msgstr "注解内容被留在文件 %s 中"
+
+#: builtin/notes.c:538 builtin/notes.c:695
+#, fuzzy
+msgid "note contents in a file"
+msgstr "无法存储索引文件"
+
+#: builtin/notes.c:540 builtin/notes.c:543 builtin/notes.c:697
+#: builtin/notes.c:700 builtin/tag.c:476
+#, fuzzy
+msgid "object"
+msgstr "å对象 %s"
+
+#: builtin/notes.c:541 builtin/notes.c:698
+#, fuzzy
+msgid "reuse and edit specified note object"
+msgstr "ä¸èƒ½å†™æ³¨è§£å¯¹è±¡"
+
+#: builtin/notes.c:544 builtin/notes.c:701
+#, fuzzy
+msgid "reuse specified note object"
+msgstr "ä¸èƒ½å†™æ³¨è§£å¯¹è±¡"
+
+#: builtin/notes.c:546 builtin/notes.c:614
+#, fuzzy
+msgid "replace existing notes"
+msgstr "ä¸èƒ½è¯»å–现存对象 %s"
+
#: builtin/notes.c:580
#, c-format
msgid ""
@@ -3810,6 +6539,15 @@ msgstr "ä¸èƒ½æ·»åŠ æ³¨è§£ã€‚å‘现对象 %s 已存在注解。使用 '-f' 覆ç›
msgid "Overwriting existing notes for object %s\n"
msgstr "覆盖对象 %s 现存注解\n"
+#: builtin/notes.c:615
+#, fuzzy
+msgid "read objects from stdin"
+msgstr "å对象 %s"
+
+#: builtin/notes.c:617
+msgid "load rewriting config for <command> (implies --stdin)"
+msgstr ""
+
#: builtin/notes.c:635
msgid "too few parameters"
msgstr "å‚数太少"
@@ -3835,36 +6573,263 @@ msgstr ""
"å­å‘½ä»¤ 'edit' 的选项 -m/-F/-c/-C 已弃用。\n"
"请æ¢ç”¨ 'git notes add -f -m/-F/-c/-C'。\n"
+#: builtin/notes.c:864
+#, fuzzy
+msgid "General options"
+msgstr "无效选项:%s"
+
+#: builtin/notes.c:866
+msgid "Merge options"
+msgstr ""
+
+#: builtin/notes.c:868
+msgid ""
+"resolve notes conflicts using the given strategy (manual/ours/theirs/union/"
+"cat_sort_uniq)"
+msgstr ""
+
+#: builtin/notes.c:870
+msgid "Committing unmerged notes"
+msgstr ""
+
+#: builtin/notes.c:872
+msgid "finalize notes merge by committing unmerged notes"
+msgstr ""
+
+#: builtin/notes.c:874
+msgid "Aborting notes merge resolution"
+msgstr ""
+
+#: builtin/notes.c:876
+#, fuzzy
+msgid "abort notes merge"
+msgstr "path '%s':无法åˆå¹¶"
+
#: builtin/notes.c:971
#, c-format
msgid "Object %s has no note\n"
msgstr "对象 %s 没有注解\n"
+#: builtin/notes.c:983
+msgid "attempt to remove non-existent note is not an error"
+msgstr ""
+
+#: builtin/notes.c:986
+#, fuzzy
+msgid "read object names from the standard input"
+msgstr "(正从标准输入中读å–日志信æ¯ï¼‰\n"
+
+#: builtin/notes.c:1067
+msgid "notes_ref"
+msgstr ""
+
+#: builtin/notes.c:1068
+msgid "use notes from <notes_ref>"
+msgstr ""
+
#: builtin/notes.c:1103 builtin/remote.c:1598
#, c-format
msgid "Unknown subcommand: %s"
msgstr "未知å­å‘½ä»¤ï¼š%s"
-#: builtin/pack-objects.c:2337
+#: builtin/pack-objects.c:23
+msgid "git pack-objects --stdout [options...] [< ref-list | < object-list]"
+msgstr ""
+
+#: builtin/pack-objects.c:24
+msgid "git pack-objects [options...] base-name [< ref-list | < object-list]"
+msgstr ""
+
+#: builtin/pack-objects.c:183 builtin/pack-objects.c:186
+#, c-format
+msgid "deflate error (%d)"
+msgstr "压缩错误 (%d)"
+
+#: builtin/pack-objects.c:2398
#, c-format
msgid "unsupported index version %s"
msgstr "ä¸æ”¯æŒçš„索引版本 %s"
-#: builtin/pack-objects.c:2341
+#: builtin/pack-objects.c:2402
#, c-format
msgid "bad index version '%s'"
msgstr "å的索引版本 '%s'"
-#: builtin/pack-objects.c:2364
+#: builtin/pack-objects.c:2425
#, c-format
msgid "option %s does not accept negative form"
msgstr "选项 %s ä¸æŽ¥å—å¦å®šæ ¼å¼"
-#: builtin/pack-objects.c:2368
+#: builtin/pack-objects.c:2429
#, c-format
msgid "unable to parse value '%s' for option %s"
msgstr "ä¸èƒ½è§£æžé€‰é¡¹ %1$s 的值 '%2$s'"
+#: builtin/pack-objects.c:2448
+msgid "do not show progress meter"
+msgstr ""
+
+#: builtin/pack-objects.c:2450
+msgid "show progress meter"
+msgstr ""
+
+#: builtin/pack-objects.c:2452
+msgid "show progress meter during object writing phase"
+msgstr ""
+
+#: builtin/pack-objects.c:2455
+msgid "similar to --all-progress when progress meter is shown"
+msgstr ""
+
+#: builtin/pack-objects.c:2456
+msgid "version[,offset]"
+msgstr ""
+
+#: builtin/pack-objects.c:2457
+msgid "write the pack index file in the specified idx format version"
+msgstr ""
+
+#: builtin/pack-objects.c:2460
+#, fuzzy
+msgid "maximum size of each output pack file"
+msgstr "无法创建输出文件"
+
+#: builtin/pack-objects.c:2462
+msgid "ignore borrowed objects from alternate object store"
+msgstr ""
+
+#: builtin/pack-objects.c:2464
+#, fuzzy
+msgid "ignore packed objects"
+msgstr "ä¸èƒ½è¯»å–对象 %s"
+
+#: builtin/pack-objects.c:2466
+msgid "limit pack window by objects"
+msgstr ""
+
+#: builtin/pack-objects.c:2468
+msgid "limit pack window by memory in addition to object limit"
+msgstr ""
+
+#: builtin/pack-objects.c:2470
+msgid "maximum length of delta chain allowed in the resulting pack"
+msgstr ""
+
+#: builtin/pack-objects.c:2472
+#, fuzzy
+msgid "reuse existing deltas"
+msgstr "å¤„ç† delta 中"
+
+#: builtin/pack-objects.c:2474
+#, fuzzy
+msgid "reuse existing objects"
+msgstr "ä¸èƒ½è¯»å–现存对象 %s"
+
+#: builtin/pack-objects.c:2476
+msgid "use OFS_DELTA objects"
+msgstr ""
+
+#: builtin/pack-objects.c:2478
+msgid "use threads when searching for best delta matches"
+msgstr ""
+
+#: builtin/pack-objects.c:2480
+msgid "do not create an empty pack output"
+msgstr ""
+
+#: builtin/pack-objects.c:2482
+#, fuzzy
+msgid "read revision arguments from standard input"
+msgstr "(正从标准输入中读å–日志信æ¯ï¼‰\n"
+
+#: builtin/pack-objects.c:2484
+msgid "limit the objects to those that are not yet packed"
+msgstr ""
+
+#: builtin/pack-objects.c:2487
+msgid "include objects reachable from any reference"
+msgstr ""
+
+#: builtin/pack-objects.c:2490
+msgid "include objects referred by reflog entries"
+msgstr ""
+
+#: builtin/pack-objects.c:2493
+msgid "output pack to stdout"
+msgstr ""
+
+#: builtin/pack-objects.c:2495
+msgid "include tag objects that refer to objects to be packed"
+msgstr ""
+
+#: builtin/pack-objects.c:2497
+msgid "keep unreachable objects"
+msgstr ""
+
+#: builtin/pack-objects.c:2498 parse-options.h:141
+msgid "time"
+msgstr "时间"
+
+#: builtin/pack-objects.c:2499
+msgid "unpack unreachable objects newer than <time>"
+msgstr ""
+
+#: builtin/pack-objects.c:2502
+msgid "create thin packs"
+msgstr ""
+
+#: builtin/pack-objects.c:2504
+msgid "ignore packs that have companion .keep file"
+msgstr ""
+
+#: builtin/pack-objects.c:2506
+msgid "pack compression level"
+msgstr ""
+
+#: builtin/pack-objects.c:2508
+#, fuzzy
+msgid "do not hide commits by grafts"
+msgstr "ä¸èƒ½å†™æ交模版"
+
+#: builtin/pack-refs.c:6
+msgid "git pack-refs [options]"
+msgstr ""
+
+#: builtin/pack-refs.c:14
+msgid "pack everything"
+msgstr ""
+
+#: builtin/pack-refs.c:15
+msgid "prune loose refs (default)"
+msgstr ""
+
+#: builtin/prune-packed.c:7
+msgid "git prune-packed [-n|--dry-run] [-q|--quiet]"
+msgstr ""
+
+#: builtin/prune.c:12
+msgid "git prune [-n] [-v] [--expire <time>] [--] [<head>...]"
+msgstr ""
+
+#: builtin/prune.c:132
+#, fuzzy
+msgid "do not remove, show only"
+msgstr "ä¸ä¼šåˆ é™¤ %s\n"
+
+#: builtin/prune.c:133
+#, fuzzy
+msgid "report pruned objects"
+msgstr "ä¸èƒ½è¯»å–对象 %s"
+
+#: builtin/prune.c:136
+msgid "expire objects older than <time>"
+msgstr ""
+
+#: builtin/push.c:14
+#, fuzzy
+msgid "git push [<options>] [<repository> [<refspec>...]]"
+msgstr "git apply [选项] [<è¡¥ä¸>...]"
+
#: builtin/push.c:45
msgid "tag shorthand without <tag>"
msgstr "tag 简写没有跟 <tag> å‚æ•°"
@@ -3947,12 +6912,44 @@ msgstr ""
"您正推é€è‡³è¿œç¨‹ '%s'(其并éžå½“å‰åˆ†æ”¯ '%s' 的上游),\n"
"而没有告诉我è¦æŽ¨é€ä»€ä¹ˆã€æ›´æ–°å“ªä¸ªè¿œç¨‹åˆ†æ”¯ã€‚"
-#: builtin/push.c:174
+# 译者:字符串首行行首è¦æ·»åŠ â€œwarning: â€å­—串,故此首行è¦è¾ƒå…¶ä½™è¡ŒçŸ­
+#: builtin/push.c:151
+msgid ""
+"push.default is unset; its implicit value is changing in\n"
+"Git 2.0 from 'matching' to 'simple'. To squelch this message\n"
+"and maintain the current behavior after the default changes, use:\n"
+"\n"
+" git config --global push.default matching\n"
+"\n"
+"To squelch this message and adopt the new behavior now, use:\n"
+"\n"
+" git config --global push.default simple\n"
+"\n"
+"See 'git help config' and search for 'push.default' for further "
+"information.\n"
+"(the 'simple' mode was introduced in Git 1.7.11. Use the similar mode\n"
+"'current' instead of 'simple' if you sometimes use older versions of Git)"
+msgstr ""
+"push.default 未设置,它的默认值将会在 Git 2.0 由 'matching'\n"
+"修改为 'simple'。若è¦ä¸å†æ˜¾ç¤ºæœ¬ä¿¡æ¯å¹¶åœ¨å…¶é»˜è®¤å€¼æ”¹å˜åŽç»´æŒå½“å‰ä½¿ç”¨ä¹ æƒ¯ï¼Œ\n"
+"进行如下设置:\n"
+"\n"
+" git config --global push.default matching\n"
+"\n"
+"è‹¥è¦ä¸å†æ˜¾ç¤ºæœ¬ä¿¡æ¯å¹¶ä»ŽçŽ°åœ¨å¼€å§‹é‡‡ç”¨æ–°çš„使用习惯,设置:\n"
+"\n"
+" git config --global push.default simple\n"
+"\n"
+"å‚è§ 'git help config' 并查找 'push.default' 以获å–更多信æ¯ã€‚\n"
+"('simple' 模å¼ç”± Git 1.7.11 版本引入。如果您有时è¦ä½¿ç”¨è€ç‰ˆæœ¬çš„ Git,\n"
+"为ä¿æŒå…¼å®¹ï¼Œè¯·ç”¨ 'current' 代替 'simple' 模å¼ï¼‰"
+
+#: builtin/push.c:199
msgid ""
"You didn't specify any refspecs to push, and push.default is \"nothing\"."
msgstr "您没有为推é€æŒ‡å®šä»»ä½•å¼•ç”¨è¡¨è¾¾å¼ï¼Œå¹¶ä¸” push.default 为 \"nothing\"。"
-#: builtin/push.c:181
+#: builtin/push.c:206
msgid ""
"Updates were rejected because the tip of your current branch is behind\n"
"its remote counterpart. Merge the remote changes (e.g. 'git pull')\n"
@@ -3963,18 +6960,19 @@ msgstr ""
"å†æ¬¡æŽ¨é€å‰ï¼Œå…ˆä¸Žè¿œç¨‹å˜æ›´åˆå¹¶ï¼ˆå¦‚ 'git pull')。详è§\n"
"'git push --help' 中的 'Note about fast-forwards' å°èŠ‚。"
-#: builtin/push.c:187
+#: builtin/push.c:212
msgid ""
"Updates were rejected because a pushed branch tip is behind its remote\n"
"counterpart. If you did not intend to push that branch, you may want to\n"
-"specify branches to push or set the 'push.default' configuration\n"
-"variable to 'current' or 'upstream' to push only the current branch."
+"specify branches to push or set the 'push.default' configuration variable\n"
+"to 'simple', 'current' or 'upstream' to push only the current branch."
msgstr ""
"更新被拒ç»ï¼Œå› ä¸ºæŽ¨é€çš„一个分支的最新æ交è½åŽäºŽå…¶å¯¹åº”的远程分支。\n"
"如果您并éžæœ‰æ„推é€è¯¥åˆ†æ”¯ï¼Œæ‚¨å¯ä»¥åœ¨æŽ¨é€æ—¶æŒ‡å®šè¦æŽ¨é€çš„分支,或者将\n"
-"é…ç½®å˜é‡ 'push.default' 设置为 'current' 或 'upstream' 以便åªæŽ¨é€å½“å‰åˆ†æ”¯ã€‚"
+"é…ç½®å˜é‡ 'push.default' 设置为 'simple'ã€'current' 或 'upstream'\n"
+"以便åªæŽ¨é€å½“å‰åˆ†æ”¯ã€‚"
-#: builtin/push.c:193
+#: builtin/push.c:218
msgid ""
"Updates were rejected because a pushed branch tip is behind its remote\n"
"counterpart. Check out this branch and merge the remote changes\n"
@@ -3985,22 +6983,22 @@ msgstr ""
"检出该分支并与远程å˜æ›´åˆå¹¶ï¼ˆå¦‚ 'git pull'),然åŽå†æŽ¨é€ã€‚详è§\n"
"'git push --help' 中的 'Note about fast-forwards' å°èŠ‚。"
-#: builtin/push.c:233
+#: builtin/push.c:258
#, c-format
msgid "Pushing to %s\n"
msgstr "推é€åˆ° %s\n"
-#: builtin/push.c:237
+#: builtin/push.c:262
#, c-format
msgid "failed to push some refs to '%s'"
msgstr "无法推é€ä¸€äº›å¼•ç”¨åˆ° '%s'"
-#: builtin/push.c:269
+#: builtin/push.c:294
#, c-format
msgid "bad repository '%s'"
msgstr "å的版本库 '%s'"
-#: builtin/push.c:270
+#: builtin/push.c:295
msgid ""
"No configured push destination.\n"
"Either specify the URL from the command-line or configure a remote "
@@ -4021,34 +7019,241 @@ msgstr ""
"\n"
" git push <name>\n"
-#: builtin/push.c:285
+#: builtin/push.c:310
msgid "--all and --tags are incompatible"
msgstr "--all å’Œ --tags ä¸å…¼å®¹"
-#: builtin/push.c:286
+#: builtin/push.c:311
msgid "--all can't be combined with refspecs"
-msgstr "--all ä¸èƒ½å’Œå¼•ç”¨è¡¨è¾¾å¼å…±ç”¨"
+msgstr "--all ä¸èƒ½å’Œå¼•ç”¨è¡¨è¾¾å¼åŒæ—¶ä½¿ç”¨"
-#: builtin/push.c:291
+#: builtin/push.c:316
msgid "--mirror and --tags are incompatible"
msgstr "--mirror å’Œ --tags ä¸å…¼å®¹"
-#: builtin/push.c:292
+#: builtin/push.c:317
msgid "--mirror can't be combined with refspecs"
-msgstr "--mirror ä¸èƒ½å’Œå¼•ç”¨è¡¨è¾¾å¼å…±ç”¨"
+msgstr "--mirror ä¸èƒ½å’Œå¼•ç”¨è¡¨è¾¾å¼åŒæ—¶ä½¿ç”¨"
-#: builtin/push.c:297
+#: builtin/push.c:322
msgid "--all and --mirror are incompatible"
msgstr "--all å’Œ --mirror ä¸å…¼å®¹"
-#: builtin/push.c:385
+#: builtin/push.c:382
+#, fuzzy
+msgid "repository"
+msgstr "å的版本库 '%s'"
+
+#: builtin/push.c:383
+msgid "push all refs"
+msgstr ""
+
+#: builtin/push.c:384
+msgid "mirror all refs"
+msgstr ""
+
+#: builtin/push.c:386
+#, fuzzy
+msgid "delete refs"
+msgstr "删除"
+
+#: builtin/push.c:387
+msgid "push tags (can't be used with --all or --mirror)"
+msgstr ""
+
+#: builtin/push.c:390
+#, fuzzy
+msgid "force updates"
+msgstr "强制更新"
+
+#: builtin/push.c:391
+msgid "check"
+msgstr ""
+
+#: builtin/push.c:392
+msgid "control recursive pushing of submodules"
+msgstr ""
+
+#: builtin/push.c:394
+msgid "use thin pack"
+msgstr ""
+
+#: builtin/push.c:395 builtin/push.c:396
+msgid "receive pack program"
+msgstr ""
+
+#: builtin/push.c:397
+msgid "set upstream for git pull/status"
+msgstr ""
+
+#: builtin/push.c:400
+msgid "prune locally removed refs"
+msgstr ""
+
+#: builtin/push.c:410
msgid "--delete is incompatible with --all, --mirror and --tags"
msgstr "--delete 与 --allã€--mirror åŠ --tags ä¸å…¼å®¹"
-#: builtin/push.c:387
+#: builtin/push.c:412
msgid "--delete doesn't make sense without any refs"
msgstr "--delete 未接任何引用没有æ„义"
+#: builtin/read-tree.c:36
+msgid ""
+"git read-tree [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>] "
+"[-u [--exclude-per-directory=<gitignore>] | -i]] [--no-sparse-checkout] [--"
+"index-output=<file>] (--empty | <tree-ish1> [<tree-ish2> [<tree-ish3>]])"
+msgstr ""
+
+#: builtin/read-tree.c:108
+#, fuzzy
+msgid "write resulting index to <file>"
+msgstr "æŸå的索引文件"
+
+#: builtin/read-tree.c:111
+#, fuzzy
+msgid "only empty the index"
+msgstr "ä¸èƒ½è¯»å–索引"
+
+#: builtin/read-tree.c:113
+#, fuzzy
+msgid "Merging"
+msgstr "åˆå¹¶ï¼š"
+
+#: builtin/read-tree.c:115
+msgid "perform a merge in addition to a read"
+msgstr ""
+
+#: builtin/read-tree.c:117
+msgid "3-way merge if no file level merging required"
+msgstr ""
+
+#: builtin/read-tree.c:119
+msgid "3-way merge in presence of adds and removes"
+msgstr ""
+
+#: builtin/read-tree.c:121
+msgid "same as -m, but discard unmerged entries"
+msgstr ""
+
+#: builtin/read-tree.c:122
+#, fuzzy
+msgid "<subdirectory>/"
+msgstr "目录/文件"
+
+#: builtin/read-tree.c:123
+msgid "read the tree into the index under <subdirectory>/"
+msgstr ""
+
+#: builtin/read-tree.c:126
+msgid "update working tree with merge result"
+msgstr ""
+
+#: builtin/read-tree.c:128
+#, fuzzy
+msgid "gitignore"
+msgstr "忽略的"
+
+#: builtin/read-tree.c:129
+msgid "allow explicitly ignored files to be overwritten"
+msgstr ""
+
+#: builtin/read-tree.c:132
+#, fuzzy
+msgid "don't check the working tree after merging"
+msgstr "显示工作区状æ€"
+
+#: builtin/read-tree.c:133
+msgid "don't update the index or the work tree"
+msgstr ""
+
+#: builtin/read-tree.c:135
+msgid "skip applying sparse checkout filter"
+msgstr ""
+
+#: builtin/read-tree.c:137
+msgid "debug unpack-trees"
+msgstr ""
+
+#: builtin/remote.c:11
+msgid "git remote [-v | --verbose]"
+msgstr ""
+
+#: builtin/remote.c:12
+msgid ""
+"git remote add [-t <branch>] [-m <master>] [-f] [--tags|--no-tags] [--"
+"mirror=<fetch|push>] <name> <url>"
+msgstr ""
+
+#: builtin/remote.c:13 builtin/remote.c:32
+msgid "git remote rename <old> <new>"
+msgstr ""
+
+#: builtin/remote.c:14 builtin/remote.c:37
+msgid "git remote remove <name>"
+msgstr ""
+
+#: builtin/remote.c:15
+msgid "git remote set-head <name> (-a | -d | <branch>)"
+msgstr ""
+
+#: builtin/remote.c:16
+msgid "git remote [-v | --verbose] show [-n] <name>"
+msgstr ""
+
+#: builtin/remote.c:17
+msgid "git remote prune [-n | --dry-run] <name>"
+msgstr ""
+
+#: builtin/remote.c:18
+msgid ""
+"git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]"
+msgstr ""
+
+#: builtin/remote.c:19
+msgid "git remote set-branches [--add] <name> <branch>..."
+msgstr ""
+
+#: builtin/remote.c:20 builtin/remote.c:68
+msgid "git remote set-url [--push] <name> <newurl> [<oldurl>]"
+msgstr ""
+
+#: builtin/remote.c:21 builtin/remote.c:69
+msgid "git remote set-url --add <name> <newurl>"
+msgstr ""
+
+#: builtin/remote.c:22 builtin/remote.c:70
+msgid "git remote set-url --delete <name> <url>"
+msgstr ""
+
+#: builtin/remote.c:27
+msgid "git remote add [<options>] <name> <url>"
+msgstr ""
+
+#: builtin/remote.c:42
+msgid "git remote set-head <name> (-a | -d | <branch>])"
+msgstr ""
+
+#: builtin/remote.c:47
+msgid "git remote set-branches <name> <branch>..."
+msgstr ""
+
+#: builtin/remote.c:48
+msgid "git remote set-branches --add <name> <branch>..."
+msgstr ""
+
+#: builtin/remote.c:53
+msgid "git remote show [<options>] <name>"
+msgstr ""
+
+#: builtin/remote.c:58
+msgid "git remote prune [<options>] <name>"
+msgstr ""
+
+#: builtin/remote.c:63
+msgid "git remote update [<options>] [<group> | <remote>]..."
+msgstr ""
+
#: builtin/remote.c:98
#, c-format
msgid "Updating %s"
@@ -4067,13 +7272,43 @@ msgstr ""
msgid "unknown mirror argument: %s"
msgstr "未知的镜åƒå‚数:%s"
+#: builtin/remote.c:163
+#, fuzzy
+msgid "fetch the remote branches"
+msgstr " 远程分支:%s"
+
+#: builtin/remote.c:165
+msgid "import all tags and associated objects when fetching"
+msgstr ""
+
+#: builtin/remote.c:168
+msgid "or do not fetch any tag at all (--no-tags)"
+msgstr ""
+
+#: builtin/remote.c:170
+msgid "branch(es) to track"
+msgstr ""
+
+#: builtin/remote.c:171
+#, fuzzy
+msgid "master branch"
+msgstr " 远程分支:%s"
+
+#: builtin/remote.c:172
+msgid "push|fetch"
+msgstr ""
+
+#: builtin/remote.c:173
+msgid "set up remote as a mirror to push to or fetch from"
+msgstr ""
+
#: builtin/remote.c:185
msgid "specifying a master branch makes no sense with --mirror"
msgstr "指定一个 master 分支并使用 --mirror 选项没有æ„义"
#: builtin/remote.c:187
msgid "specifying branches to track makes sense only with fetch mirrors"
-msgstr "指定è¦è·Ÿè¸ªçš„分支åªåœ¨ä¸ŽèŽ·å–é•œåƒå…±ç”¨æ‰æœ‰æ„义"
+msgstr "指定è¦è·Ÿè¸ªçš„分支åªåœ¨ä¸ŽèŽ·å–é•œåƒåŒæ—¶ä½¿ç”¨æ‰æœ‰æ„义"
#: builtin/remote.c:195 builtin/remote.c:646
#, c-format
@@ -4259,6 +7494,11 @@ msgstr " %-*s 强制推é€è‡³ %s"
msgid " %-*s pushes to %s"
msgstr " %-*s 推é€è‡³ %s"
+#: builtin/remote.c:1091
+#, fuzzy
+msgid "do not query remotes"
+msgstr "ä¸ä¼šåˆ é™¤ %s\n"
+
#: builtin/remote.c:1118
#, c-format
msgid "* remote %s"
@@ -4318,6 +7558,14 @@ msgid_plural " Local refs configured for 'git push'%s:"
msgstr[0] " 为 'git push' é…置的本地引用%s:"
msgstr[1] " 为 'git push' é…置的本地引用%s:"
+#: builtin/remote.c:1199
+msgid "set refs/remotes/<name>/HEAD according to remote"
+msgstr ""
+
+#: builtin/remote.c:1201
+msgid "delete refs/remotes/<name>/HEAD"
+msgstr ""
+
#: builtin/remote.c:1216
msgid "Cannot determine remote HEAD"
msgstr "无法确定远程 HEAD"
@@ -4373,15 +7621,37 @@ msgstr " * [将删除] %s"
msgid " * [pruned] %s"
msgstr " * [已删除] %s"
+#: builtin/remote.c:1321
+msgid "prune remotes after fetching"
+msgstr ""
+
#: builtin/remote.c:1387 builtin/remote.c:1461
#, c-format
msgid "No such remote '%s'"
msgstr "没有此远程 '%s'"
+#: builtin/remote.c:1407
+#, fuzzy
+msgid "add branch"
+msgstr "ä½äºŽåˆ†æ”¯ "
+
#: builtin/remote.c:1414
msgid "no remote specified"
msgstr "未指定远程"
+#: builtin/remote.c:1436
+msgid "manipulate push URLs"
+msgstr ""
+
+#: builtin/remote.c:1438
+msgid "add URL"
+msgstr ""
+
+#: builtin/remote.c:1440
+#, fuzzy
+msgid "delete URLs"
+msgstr "删除"
+
#: builtin/remote.c:1447
msgid "--add --delete doesn't make sense"
msgstr "--add --delete æ— æ„义"
@@ -4400,6 +7670,56 @@ msgstr "未找到此URL:%s"
msgid "Will not delete all non-push URLs"
msgstr "å°†ä¸ä¼šåˆ é™¤æ‰€æœ‰éžæŽ¨é€URL地å€"
+#: builtin/remote.c:1569
+msgid "be verbose; must be placed before a subcommand"
+msgstr ""
+
+#: builtin/replace.c:17
+msgid "git replace [-f] <object> <replacement>"
+msgstr ""
+
+#: builtin/replace.c:18
+msgid "git replace -d <object>..."
+msgstr ""
+
+#: builtin/replace.c:19
+msgid "git replace -l [<pattern>]"
+msgstr ""
+
+#: builtin/replace.c:118
+msgid "list replace refs"
+msgstr ""
+
+#: builtin/replace.c:119
+msgid "delete replace refs"
+msgstr ""
+
+#: builtin/replace.c:120
+msgid "replace the ref if it exists"
+msgstr ""
+
+#: builtin/rerere.c:11
+msgid "git rerere [clear | forget path... | status | remaining | diff | gc]"
+msgstr ""
+
+#: builtin/rerere.c:56
+#, fuzzy
+msgid "register clean resolutions in index"
+msgstr "%s:已ç»å­˜åœ¨äºŽç´¢å¼•ä¸­"
+
+#: builtin/reset.c:25
+msgid ""
+"git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]"
+msgstr ""
+
+#: builtin/reset.c:26
+msgid "git reset [-q] <commit> [--] <paths>..."
+msgstr ""
+
+#: builtin/reset.c:27
+msgid "git reset --patch [<commit>] [--] [<paths>...]"
+msgstr ""
+
#: builtin/reset.c:33
msgid "mixed"
msgstr "æ··æ‚"
@@ -4456,53 +7776,182 @@ msgstr "é‡ç½®åŽæ’¤å‡ºæš‚存区的å˜æ›´ï¼š"
msgid "Cannot do a %s reset in the middle of a merge."
msgstr "在åˆå¹¶è¿‡ç¨‹ä¸­ä¸èƒ½åš%sé‡ç½®æ“作。"
-#: builtin/reset.c:297
+#: builtin/reset.c:238
+msgid "be quiet, only report errors"
+msgstr ""
+
+#: builtin/reset.c:240
+msgid "reset HEAD and index"
+msgstr ""
+
+#: builtin/reset.c:241
+msgid "reset only HEAD"
+msgstr ""
+
+#: builtin/reset.c:243 builtin/reset.c:245
+msgid "reset HEAD, index and working tree"
+msgstr ""
+
+#: builtin/reset.c:247
+msgid "reset HEAD but keep local changes"
+msgstr ""
+
+#: builtin/reset.c:303
#, c-format
msgid "Could not parse object '%s'."
msgstr "ä¸èƒ½è§£æžå¯¹è±¡ '%s'。"
-#: builtin/reset.c:302
+#: builtin/reset.c:308
msgid "--patch is incompatible with --{hard,mixed,soft}"
msgstr "--patch 与 --{hard,mixed,soft} ä¸å…¼å®¹"
-#: builtin/reset.c:311
+#: builtin/reset.c:317
msgid "--mixed with paths is deprecated; use 'git reset -- <paths>' instead."
-msgstr "--mixed 带路径已弃用,代之以 'git reset -- <paths>'。"
+msgstr "--mixed 带路径已弃用,而是用 'git reset -- <paths>'。"
# 译者:汉字之间无空格,故删除%så‰åŽç©ºæ ¼
-#: builtin/reset.c:313
+#: builtin/reset.c:319
#, c-format
msgid "Cannot do %s reset with paths."
msgstr "ä¸èƒ½å¸¦è·¯å¾„进行%sé‡ç½®ã€‚"
# 译者:汉字之间无空格,故删除%så‰åŽç©ºæ ¼
-#: builtin/reset.c:325
+#: builtin/reset.c:331
#, c-format
msgid "%s reset is not allowed in a bare repository"
msgstr "ä¸èƒ½å¯¹è£¸ç‰ˆæœ¬åº“进行%sé‡ç½®"
-#: builtin/reset.c:341
+#: builtin/reset.c:347
#, c-format
msgid "Could not reset index file to revision '%s'."
msgstr "ä¸èƒ½é‡ç½®ç´¢å¼•æ–‡ä»¶è‡³ç‰ˆæœ¬ '%s'。"
+#: builtin/rev-parse.c:339
+#, fuzzy
+msgid "git rev-parse --parseopt [options] -- [<args>...]"
+msgstr "git apply [选项] [<è¡¥ä¸>...]"
+
+#: builtin/rev-parse.c:344
+msgid "keep the `--` passed as an arg"
+msgstr ""
+
+#: builtin/rev-parse.c:346
+msgid "stop parsing after the first non-option argument"
+msgstr ""
+
+#: builtin/rev-parse.c:464
+msgid ""
+"git rev-parse --parseopt [options] -- [<args>...]\n"
+" or: git rev-parse --sq-quote [<arg>...]\n"
+" or: git rev-parse [options] [<arg>...]\n"
+"\n"
+"Run \"git rev-parse --parseopt -h\" for more information on the first usage."
+msgstr ""
+
+#: builtin/revert.c:22
+msgid "git revert [options] <commit-ish>"
+msgstr ""
+
+#: builtin/revert.c:23
+msgid "git revert <subcommand>"
+msgstr ""
+
+#: builtin/revert.c:28
+msgid "git cherry-pick [options] <commit-ish>"
+msgstr ""
+
+#: builtin/revert.c:29
+#, fuzzy
+msgid "git cherry-pick <subcommand>"
+msgstr "拣选失败"
+
#: builtin/revert.c:70 builtin/revert.c:92
#, c-format
msgid "%s: %s cannot be used with %s"
-msgstr "%s:%s ä¸èƒ½å’Œ %s 共用"
+msgstr "%s:%s ä¸èƒ½å’Œ %s åŒæ—¶ä½¿ç”¨"
+
+#: builtin/revert.c:103
+msgid "end revert or cherry-pick sequence"
+msgstr ""
-#: builtin/revert.c:131
+#: builtin/revert.c:104
+msgid "resume revert or cherry-pick sequence"
+msgstr ""
+
+#: builtin/revert.c:105
+msgid "cancel revert or cherry-pick sequence"
+msgstr ""
+
+#: builtin/revert.c:106
+#, fuzzy
+msgid "don't automatically commit"
+msgstr "ä¸èƒ½ä½œä¸ºåˆå§‹æ交还原"
+
+#: builtin/revert.c:107
+#, fuzzy
+msgid "edit the commit message"
+msgstr "空æ交信æ¯ã€‚"
+
+#: builtin/revert.c:110
+msgid "parent number"
+msgstr ""
+
+#: builtin/revert.c:112
+#, fuzzy
+msgid "merge strategy"
+msgstr "å°è¯•åˆå¹¶ç­–ç•¥ %s...\n"
+
+#: builtin/revert.c:113
+#, fuzzy
+msgid "option"
+msgstr "动作"
+
+#: builtin/revert.c:114
+#, fuzzy
+msgid "option for merge strategy"
+msgstr "å°è¯•åˆå¹¶ç­–ç•¥ %s...\n"
+
+#: builtin/revert.c:125
+msgid "append commit name"
+msgstr ""
+
+#: builtin/revert.c:126
+#, fuzzy
+msgid "allow fast-forward"
+msgstr "(éžå¿«è¿›å¼ï¼‰"
+
+#: builtin/revert.c:127
+#, fuzzy
+msgid "preserve initially empty commits"
+msgstr "ä¸èƒ½ä½œä¸ºåˆå§‹æ交还原"
+
+#: builtin/revert.c:128
+#, fuzzy
+msgid "allow commits with empty messages"
+msgstr "æ交说明为空"
+
+#: builtin/revert.c:129
+#, fuzzy
+msgid "keep redundant, empty commits"
+msgstr "åˆå¹¶æœªè¿”回æ交"
+
+#: builtin/revert.c:133
msgid "program error"
msgstr "程åºé”™è¯¯"
-#: builtin/revert.c:221
+#: builtin/revert.c:223
msgid "revert failed"
msgstr "还原失败"
-#: builtin/revert.c:236
+#: builtin/revert.c:238
msgid "cherry-pick failed"
msgstr "拣选失败"
+#: builtin/rm.c:14
+#, fuzzy
+msgid "git rm [options] [--] <file>..."
+msgstr "git apply [选项] [<è¡¥ä¸>...]"
+
#: builtin/rm.c:109
#, c-format
msgid ""
@@ -4530,6 +7979,28 @@ msgstr ""
"'%s' 有本地修改\n"
"(使用 --cached ä¿å­˜æ–‡ä»¶ï¼Œæˆ–用 -f 强制删除)"
+#: builtin/rm.c:134
+#, fuzzy
+msgid "do not list removed files"
+msgstr "无法还原修改的文件"
+
+#: builtin/rm.c:135
+#, fuzzy
+msgid "only remove from the index"
+msgstr "ä¸èƒ½ä»Žç´¢å¼•ä¸­ç§»é™¤ %s"
+
+#: builtin/rm.c:136
+msgid "override the up-to-date check"
+msgstr ""
+
+#: builtin/rm.c:137
+msgid "allow recursive removal"
+msgstr ""
+
+#: builtin/rm.c:139
+msgid "exit with a zero status even if nothing matched"
+msgstr ""
+
#: builtin/rm.c:194
#, c-format
msgid "not removing '%s' recursively without -r"
@@ -4540,11 +8011,199 @@ msgstr "未æä¾› -r 选项ä¸ä¼šé€’归删除 '%s'"
msgid "git rm: unable to remove %s"
msgstr "git rm:ä¸èƒ½åˆ é™¤ %s"
+#: builtin/shortlog.c:13
+msgid "git shortlog [-n] [-s] [-e] [-w] [rev-opts] [--] [<commit-id>... ]"
+msgstr ""
+
#: builtin/shortlog.c:157
#, c-format
msgid "Missing author: %s"
msgstr "缺少作者:%s"
+#: builtin/shortlog.c:253
+msgid "sort output according to the number of commits per author"
+msgstr ""
+
+#: builtin/shortlog.c:255
+msgid "Suppress commit descriptions, only provides commit count"
+msgstr ""
+
+#: builtin/shortlog.c:257
+msgid "Show the email address of each author"
+msgstr ""
+
+#: builtin/shortlog.c:258
+msgid "w[,i1[,i2]]"
+msgstr ""
+
+#: builtin/shortlog.c:259
+msgid "Linewrap output"
+msgstr ""
+
+#: builtin/show-branch.c:9
+msgid ""
+"git show-branch [-a|--all] [-r|--remotes] [--topo-order | --date-order] [--"
+"current] [--color[=<when>] | --no-color] [--sparse] [--more=<n> | --list | --"
+"independent | --merge-base] [--no-name | --sha1-name] [--topics] [(<rev> | "
+"<glob>)...]"
+msgstr ""
+
+#: builtin/show-branch.c:10
+msgid "git show-branch (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]"
+msgstr ""
+
+#: builtin/show-branch.c:651
+#, fuzzy
+msgid "show remote-tracking and local branches"
+msgstr "%s 没有æ¥è‡ª %s 的远程跟踪分支"
+
+#: builtin/show-branch.c:653
+#, fuzzy
+msgid "show remote-tracking branches"
+msgstr "%s 没有æ¥è‡ª %s 的远程跟踪分支"
+
+#: builtin/show-branch.c:655
+msgid "color '*!+-' corresponding to the branch"
+msgstr ""
+
+#: builtin/show-branch.c:657
+msgid "show <n> more commits after the common ancestor"
+msgstr ""
+
+#: builtin/show-branch.c:659
+msgid "synonym to more=-1"
+msgstr ""
+
+#: builtin/show-branch.c:660
+msgid "suppress naming strings"
+msgstr ""
+
+#: builtin/show-branch.c:662
+#, fuzzy
+msgid "include the current branch"
+msgstr "没有当å‰åˆ†æ”¯ã€‚"
+
+#: builtin/show-branch.c:664
+#, fuzzy
+msgid "name commits with their object names"
+msgstr "ä¸èƒ½å†™æ³¨è§£å¯¹è±¡"
+
+#: builtin/show-branch.c:666
+msgid "show possible merge bases"
+msgstr ""
+
+#: builtin/show-branch.c:668
+msgid "show refs unreachable from any other ref"
+msgstr ""
+
+#: builtin/show-branch.c:670
+msgid "show commits in topological order"
+msgstr ""
+
+#: builtin/show-branch.c:672
+msgid "show only commits not on the first branch"
+msgstr ""
+
+#: builtin/show-branch.c:674
+msgid "show merges reachable from only one tip"
+msgstr ""
+
+#: builtin/show-branch.c:676
+msgid "show commits where no parent comes before its children"
+msgstr ""
+
+#: builtin/show-branch.c:678
+msgid "<n>[,<base>]"
+msgstr ""
+
+#: builtin/show-branch.c:679
+msgid "show <n> most recent ref-log entries starting at base"
+msgstr ""
+
+#: builtin/show-ref.c:10
+msgid ""
+"git show-ref [-q|--quiet] [--verify] [--head] [-d|--dereference] [-s|--hash"
+"[=<n>]] [--abbrev[=<n>]] [--tags] [--heads] [--] [pattern*] "
+msgstr ""
+
+#: builtin/show-ref.c:11
+msgid "git show-ref --exclude-existing[=pattern] < ref-list"
+msgstr ""
+
+#: builtin/show-ref.c:182
+#, fuzzy
+msgid "only show tags (can be combined with heads)"
+msgstr "--all ä¸èƒ½å’Œå¼•ç”¨è¡¨è¾¾å¼åŒæ—¶ä½¿ç”¨"
+
+#: builtin/show-ref.c:183
+#, fuzzy
+msgid "only show heads (can be combined with tags)"
+msgstr "--all ä¸èƒ½å’Œå¼•ç”¨è¡¨è¾¾å¼åŒæ—¶ä½¿ç”¨"
+
+#: builtin/show-ref.c:184
+msgid "stricter reference checking, requires exact ref path"
+msgstr ""
+
+#: builtin/show-ref.c:187 builtin/show-ref.c:189
+msgid "show the HEAD reference"
+msgstr ""
+
+#: builtin/show-ref.c:191
+#, fuzzy
+msgid "dereference tags into object IDs"
+msgstr "引用ä¸æ˜¯ä¸€ä¸ªæ ‘:%s"
+
+#: builtin/show-ref.c:193
+msgid "only show SHA1 hash using <n> digits"
+msgstr ""
+
+#: builtin/show-ref.c:197
+msgid "do not print results to stdout (useful with --verify)"
+msgstr ""
+
+#: builtin/show-ref.c:199
+msgid "show refs from stdin that aren't in local repository"
+msgstr ""
+
+#: builtin/symbolic-ref.c:7
+msgid "git symbolic-ref [options] name [ref]"
+msgstr ""
+
+#: builtin/symbolic-ref.c:38
+msgid "suppress error message for non-symbolic (detached) refs"
+msgstr ""
+
+#: builtin/symbolic-ref.c:39
+msgid "shorten ref output"
+msgstr ""
+
+#: builtin/symbolic-ref.c:40 builtin/update-ref.c:18
+msgid "reason"
+msgstr ""
+
+#: builtin/symbolic-ref.c:40 builtin/update-ref.c:18
+msgid "reason of the update"
+msgstr ""
+
+#: builtin/tag.c:22
+msgid ""
+"git tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]"
+msgstr ""
+
+#: builtin/tag.c:23
+msgid "git tag -d <tagname>..."
+msgstr ""
+
+#: builtin/tag.c:24
+msgid ""
+"git tag -l [-n[<num>]] [--contains <commit>] [--points-at <object>] \n"
+"\t\t[<pattern>...]"
+msgstr ""
+
+#: builtin/tag.c:26
+msgid "git tag -v <tagname>..."
+msgstr ""
+
#: builtin/tag.c:60
#, c-format
msgid "malformed object at '%s'"
@@ -4633,21 +8292,81 @@ msgstr "开关 'points-at' 需è¦ä¸€ä¸ªå¯¹è±¡"
msgid "malformed object name '%s'"
msgstr "éžæ³•çš„对象å '%s'"
+#: builtin/tag.c:447
+msgid "list tag names"
+msgstr ""
+
+#: builtin/tag.c:449
+msgid "print <n> lines of each tag message"
+msgstr ""
+
+#: builtin/tag.c:451
+#, fuzzy
+msgid "delete tags"
+msgstr "删除"
+
+#: builtin/tag.c:452
+msgid "verify tags"
+msgstr ""
+
+#: builtin/tag.c:454
+msgid "Tag creation options"
+msgstr ""
+
+#: builtin/tag.c:456
+#, fuzzy
+msgid "annotated tag, needs a message"
+msgstr "注释 tag %s 没有嵌入å称"
+
+#: builtin/tag.c:458
+#, fuzzy
+msgid "tag message"
+msgstr "无 tag 说明?"
+
+#: builtin/tag.c:460
+msgid "annotated and GPG-signed tag"
+msgstr ""
+
+#: builtin/tag.c:464
+#, fuzzy
+msgid "use another key to sign the tag"
+msgstr "无法签署 tag"
+
+#: builtin/tag.c:465
+msgid "replace the tag if exists"
+msgstr ""
+
+#: builtin/tag.c:466
+msgid "show tag list in columns"
+msgstr ""
+
+#: builtin/tag.c:468
+msgid "Tag listing options"
+msgstr ""
+
+#: builtin/tag.c:471
+msgid "print only tags that contain the commit"
+msgstr ""
+
+#: builtin/tag.c:477
+msgid "print only tags of the object"
+msgstr ""
+
#: builtin/tag.c:506
msgid "--column and -n are incompatible"
msgstr "--column å’Œ -n ä¸å…¼å®¹"
#: builtin/tag.c:523
msgid "-n option is only allowed with -l."
-msgstr "-n 选项åªå…许和 -l 共用。"
+msgstr "-n 选项åªå…许和 -l åŒæ—¶ä½¿ç”¨ã€‚"
#: builtin/tag.c:525
msgid "--contains option is only allowed with -l."
-msgstr "--contains 选项åªå…许和 -l 共用。"
+msgstr "--contains 选项åªå…许和 -l åŒæ—¶ä½¿ç”¨ã€‚"
#: builtin/tag.c:527
msgid "--points-at option is only allowed with -l."
-msgstr "--points-at 选项åªå…许和 -l 共用。"
+msgstr "--points-at 选项åªå…许和 -l åŒæ—¶ä½¿ç”¨ã€‚"
#: builtin/tag.c:535
msgid "only one -F or -m option is allowed."
@@ -4682,25 +8401,187 @@ msgstr "%s:ä¸èƒ½æ›´æ–°å¼•ç”¨"
msgid "Updated tag '%s' (was %s)\n"
msgstr "已更新tag '%s'(曾为 %s)\n"
-#: git.c:16
-msgid "See 'git help <command>' for more information on a specific command."
-msgstr "å‚è§ 'git help <command>' 以获得该特定命令的详细信æ¯ã€‚"
+#: builtin/update-index.c:401
+#, fuzzy
+msgid "git update-index [options] [--] [<file>...]"
+msgstr "git apply [选项] [<è¡¥ä¸>...]"
-#: parse-options.h:133 parse-options.h:235
-msgid "n"
-msgstr "æ•°å­—"
+#: builtin/update-index.c:717
+msgid "continue refresh even when index needs update"
+msgstr ""
-#: parse-options.h:141
-msgid "time"
-msgstr "时间"
+#: builtin/update-index.c:720
+msgid "refresh: ignore submodules"
+msgstr ""
-#: parse-options.h:149
-msgid "file"
-msgstr "文件"
+#: builtin/update-index.c:723
+#, fuzzy
+msgid "do not ignore new files"
+msgstr "无法存储索引文件"
-#: parse-options.h:151
-msgid "when"
-msgstr "何时"
+#: builtin/update-index.c:725
+msgid "let files replace directories and vice-versa"
+msgstr ""
+
+#: builtin/update-index.c:727
+msgid "notice files missing from worktree"
+msgstr ""
+
+#: builtin/update-index.c:729
+msgid "refresh even if index contains unmerged entries"
+msgstr ""
+
+#: builtin/update-index.c:732
+msgid "refresh stat information"
+msgstr ""
+
+#: builtin/update-index.c:736
+msgid "like --refresh, but ignore assume-unchanged setting"
+msgstr ""
+
+#: builtin/update-index.c:740
+msgid "<mode> <object> <path>"
+msgstr ""
+
+#: builtin/update-index.c:741
+#, fuzzy
+msgid "add the specified entry to the index"
+msgstr "添加文件内容至索引"
+
+#: builtin/update-index.c:745
+msgid "(+/-)x"
+msgstr ""
+
+#: builtin/update-index.c:746
+msgid "override the executable bit of the listed files"
+msgstr ""
+
+#: builtin/update-index.c:750
+msgid "mark files as \"not changing\""
+msgstr ""
+
+#: builtin/update-index.c:753
+msgid "clear assumed-unchanged bit"
+msgstr ""
+
+#: builtin/update-index.c:756
+msgid "mark files as \"index-only\""
+msgstr ""
+
+#: builtin/update-index.c:759
+msgid "clear skip-worktree bit"
+msgstr ""
+
+#: builtin/update-index.c:762
+msgid "add to index only; do not add content to object database"
+msgstr ""
+
+#: builtin/update-index.c:764
+msgid "remove named paths even if present in worktree"
+msgstr ""
+
+#: builtin/update-index.c:766
+msgid "with --stdin: input lines are terminated by null bytes"
+msgstr ""
+
+#: builtin/update-index.c:768
+#, fuzzy
+msgid "read list of paths to be updated from standard input"
+msgstr "(正从标准输入中读å–日志信æ¯ï¼‰\n"
+
+#: builtin/update-index.c:772
+#, fuzzy
+msgid "add entries from standard input to the index"
+msgstr "ä¸èƒ½ä»Žæ ‡å‡†è¾“入中读å–日志信æ¯"
+
+#: builtin/update-index.c:776
+msgid "repopulate stages #2 and #3 for the listed paths"
+msgstr ""
+
+#: builtin/update-index.c:780
+msgid "only update entries that differ from HEAD"
+msgstr ""
+
+#: builtin/update-index.c:784
+msgid "ignore files missing from worktree"
+msgstr ""
+
+#: builtin/update-index.c:787
+msgid "report actions to standard output"
+msgstr ""
+
+#: builtin/update-index.c:789
+msgid "(for porcelains) forget saved unresolved conflicts"
+msgstr ""
+
+#: builtin/update-index.c:793
+msgid "write index in this format"
+msgstr ""
+
+#: builtin/update-ref.c:7
+msgid "git update-ref [options] -d <refname> [<oldval>]"
+msgstr ""
+
+#: builtin/update-ref.c:8
+msgid "git update-ref [options] <refname> <newval> [<oldval>]"
+msgstr ""
+
+#: builtin/update-ref.c:19
+msgid "delete the reference"
+msgstr ""
+
+#: builtin/update-ref.c:21
+msgid "update <refname> not the one it points to"
+msgstr ""
+
+#: builtin/update-server-info.c:6
+msgid "git update-server-info [--force]"
+msgstr ""
+
+#: builtin/update-server-info.c:14
+msgid "update the info files from scratch"
+msgstr ""
+
+#: builtin/verify-pack.c:56
+msgid "git verify-pack [-v|--verbose] [-s|--stat-only] <pack>..."
+msgstr ""
+
+#: builtin/verify-pack.c:66
+#, fuzzy
+msgid "verbose"
+msgstr "冗长输出"
+
+#: builtin/verify-pack.c:68
+msgid "show statistics only"
+msgstr ""
+
+#: builtin/verify-tag.c:17
+msgid "git verify-tag [-v|--verbose] <tag>..."
+msgstr ""
+
+#: builtin/verify-tag.c:73
+msgid "print tag contents"
+msgstr ""
+
+#: builtin/write-tree.c:13
+msgid "git write-tree [--missing-ok] [--prefix=<prefix>/]"
+msgstr ""
+
+#: builtin/write-tree.c:26
+msgid "<prefix>/"
+msgstr ""
+
+#: builtin/write-tree.c:27
+msgid "write tree object for a subdirectory <prefix>"
+msgstr ""
+
+#: builtin/write-tree.c:30
+msgid "only useful for debugging"
+msgstr ""
+
+#: git.c:16
+msgid "See 'git help <command>' for more information on a specific command."
+msgstr "å‚è§ 'git help <command>' 以获得该特定命令的详细信æ¯ã€‚"
#: parse-options.h:156
msgid "no-op (backward compatibility)"
@@ -4810,15 +8691,14 @@ msgstr "您需è¦å…ˆè®¾ç½®ä½ çš„æ交者信æ¯"
msgid ""
"You seem to have moved HEAD since the last 'am' failure.\n"
"Not rewinding to ORIG_HEAD"
-msgstr ""
-"您好åƒåœ¨ä¸Šä¸€æ¬¡ 'am' 失败åŽç§»åŠ¨äº† HEAD。未回退至 ORIG_HEAD"
+msgstr "您好åƒåœ¨ä¸Šä¸€æ¬¡ 'am' 失败åŽç§»åŠ¨äº† HEAD。未回退至 ORIG_HEAD"
#: git-am.sh:105
#, sh-format
msgid ""
-"When you have resolved this problem run \"$cmdline --resolved\".\n"
-"If you would prefer to skip this patch, instead run \"$cmdline --skip\".\n"
-"To restore the original branch and stop patching run \"$cmdline --abort\"."
+"When you have resolved this problem, run \"$cmdline --resolved\".\n"
+"If you prefer to skip this patch, run \"$cmdline --skip\" instead.\n"
+"To restore the original branch and stop patching, run \"$cmdline --abort\"."
msgstr ""
"当您解决了此问题åŽï¼Œæ‰§è¡Œ \"$cmdline --resolved\"。\n"
"如果您想跳过此补ä¸ï¼Œåˆ™æ‰§è¡Œ \"$cmdline --skip\"。\n"
@@ -4830,7 +8710,11 @@ msgstr "无法求助于三路åˆå¹¶ã€‚"
#: git-am.sh:137
msgid "Repository lacks necessary blobs to fall back on 3-way merge."
-msgstr "版本库缺ä¹å¿…è¦çš„ blob æ•°æ®ä»¥è¿›è¡Œä¸‰è·¯åˆå¹¶ã€‚"
+msgstr "版本库缺ä¹å¿…è¦çš„二进制对象(blob)以进行三路åˆå¹¶ã€‚"
+
+#: git-am.sh:139
+msgid "Using index info to reconstruct a base tree..."
+msgstr "更新索引信æ¯ä»¥é‡å»ºåŸºæ ‘..."
#: git-am.sh:154
msgid ""
@@ -4838,48 +8722,56 @@ msgid ""
"It does not apply to blobs recorded in its index."
msgstr ""
"您是å¦æ›¾æ‰‹åŠ¨ç¼–辑过您的补ä¸ï¼Ÿ\n"
-"无法应用补ä¸åˆ°ç´¢å¼•ä¸­çš„æ•°æ®ä¸Šã€‚"
+"无法应用补ä¸åˆ°ç´¢å¼•ä¸­çš„二进制对象(blob)上。"
#: git-am.sh:163
msgid "Falling back to patching base and 3-way merge..."
msgstr "转而在基础版本上打补ä¸åŠè¿›è¡Œä¸‰è·¯åˆå¹¶..."
-#: git-am.sh:275
+#: git-am.sh:179
+msgid "Failed to merge in the changes."
+msgstr "无法åˆå¹¶å˜æ›´ã€‚"
+
+#: git-am.sh:274
msgid "Only one StGIT patch series can be applied at once"
msgstr "一次åªèƒ½æœ‰ä¸€ä¸ª StGIT è¡¥ä¸é˜Ÿåˆ—被应用"
-#: git-am.sh:362
+#: git-am.sh:361
#, sh-format
msgid "Patch format $patch_format is not supported."
msgstr "ä¸æ”¯æŒ $patch_format è¡¥ä¸æ ¼å¼ã€‚"
-#: git-am.sh:364
+#: git-am.sh:363
msgid "Patch format detection failed."
msgstr "è¡¥ä¸æ ¼å¼æ£€æµ‹å¤±è´¥ã€‚"
-#: git-am.sh:418
-msgid "-d option is no longer supported. Do not use."
-msgstr "ä¸å†æ”¯æŒ -d 选项。ä¸è¦ä½¿ç”¨ã€‚"
+#: git-am.sh:389
+msgid ""
+"The -b/--binary option has been a no-op for long time, and\n"
+"it will be removed. Please do not use it anymore."
+msgstr ""
+"å‚æ•° -b/--binary å·²ç»å¾ˆé•¿æ—¶é—´ä¸åšä»»ä½•å®žè´¨æ“作了,并且将被删除。\n"
+"请ä¸è¦å†ä½¿ç”¨å®ƒäº†ã€‚"
-#: git-am.sh:481
+#: git-am.sh:477
#, sh-format
msgid "previous rebase directory $dotest still exists but mbox given."
msgstr "之å‰çš„å˜åŸºç›®å½• $dotest ä»ç„¶å­˜åœ¨ä½†ç»™å‡ºäº†mbox。"
-#: git-am.sh:486
+#: git-am.sh:482
msgid "Please make up your mind. --skip or --abort?"
msgstr "请下决心。--skip 或是 --abort ?"
-#: git-am.sh:513
+#: git-am.sh:509
msgid "Resolve operation not in progress, we are not resuming."
msgstr "解决æ“作未进行,我们ä¸ä¼šç»§ç»­ã€‚"
-#: git-am.sh:579
+#: git-am.sh:575
#, sh-format
msgid "Dirty index: cannot apply patches (dirty: $files)"
msgstr "è„的索引:ä¸èƒ½åº”用补ä¸ï¼ˆè„文件:$files)"
-#: git-am.sh:671
+#: git-am.sh:679
#, sh-format
msgid ""
"Patch is empty. Was it split wrong?\n"
@@ -4890,15 +8782,15 @@ msgstr ""
"如果您想è¦è·³è¿‡è¿™ä¸ªè¡¥ä¸ï¼Œæ‰§è¡Œ \"$cmdline --skip\"。\n"
"è¦æ¢å¤åŽŸåˆ†æ”¯å¹¶åœæ­¢æ‰“è¡¥ä¸ï¼Œæ‰§è¡Œ \"$cmdline --abort\"。"
-#: git-am.sh:708
+#: git-am.sh:706
msgid "Patch does not have a valid e-mail address."
msgstr "è¡¥ä¸ä¸­æ²¡æœ‰ä¸€ä¸ªæœ‰æ•ˆçš„邮件地å€ã€‚"
-#: git-am.sh:755
+#: git-am.sh:753
msgid "cannot be interactive without stdin connected to a terminal."
msgstr "标准输入没有和终端关è”,ä¸èƒ½è¿›è¡Œäº¤äº’å¼æ“作。"
-#: git-am.sh:759
+#: git-am.sh:757
msgid "Commit Body is:"
msgstr "æ交内容为:"
@@ -4906,16 +8798,16 @@ msgstr "æ交内容为:"
#. TRANSLATORS: Make sure to include [y], [n], [e], [v] and [a]
#. in your translation. The program will only accept English
#. input at this point.
-#: git-am.sh:766
+#: git-am.sh:764
msgid "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all "
msgstr "应用?[y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all "
-#: git-am.sh:802
+#: git-am.sh:800
#, sh-format
msgid "Applying: $FIRSTLINE"
msgstr "正应用:$FIRSTLINE"
-#: git-am.sh:823
+#: git-am.sh:821
msgid ""
"No changes - did you forget to use 'git add'?\n"
"If there is nothing left to stage, chances are that something else\n"
@@ -4925,23 +8817,29 @@ msgstr ""
"如果没有什么è¦æ·»åŠ åˆ°æš‚存区的,则很å¯èƒ½æ˜¯å…¶å®ƒæ交已ç»å¼•å…¥äº†ç›¸åŒçš„å˜æ›´ã€‚\n"
"您也许想è¦è·³è¿‡è¿™ä¸ªè¡¥ä¸ã€‚"
-#: git-am.sh:831
+#: git-am.sh:829
msgid ""
"You still have unmerged paths in your index\n"
"did you forget to use 'git add'?"
-msgstr ""
-"您的索引中ä»æœ‰æœªåˆå¹¶çš„路径。您是å¦å¿˜äº†æ‰§è¡Œ 'git add'?"
+msgstr "您的索引中ä»æœ‰æœªåˆå¹¶çš„路径。您是å¦å¿˜äº†æ‰§è¡Œ 'git add'?"
-#: git-am.sh:847
+#: git-am.sh:845
msgid "No changes -- Patch already applied."
msgstr "没有å˜æ›´ -- è¡¥ä¸å·²ç»åº”用过。"
-#: git-am.sh:857
+#: git-am.sh:855
#, sh-format
msgid "Patch failed at $msgnum $FIRSTLINE"
msgstr "è¡¥ä¸å¤±è´¥äºŽ $msgnum $FIRSTLINE"
-#: git-am.sh:873
+#: git-am.sh:858
+#, sh-format
+msgid ""
+"The copy of the patch that failed is found in:\n"
+" $dotest/patch"
+msgstr ""
+
+#: git-am.sh:876
msgid "applying to an empty history"
msgstr "正应用到一个空历å²ä¸Š"
@@ -5142,6 +9040,123 @@ msgstr "无法将多个分支åˆå¹¶åˆ°ç©ºåˆ†æ”¯"
msgid "Cannot rebase onto multiple branches"
msgstr "无法å˜åŸºåˆ°å¤šä¸ªåˆ†æ”¯"
+#: git-rebase.sh:52
+msgid ""
+"When you have resolved this problem, run \"git rebase --continue\".\n"
+"If you prefer to skip this patch, run \"git rebase --skip\" instead.\n"
+"To check out the original branch and stop rebasing, run \"git rebase --abort"
+"\"."
+msgstr ""
+"当您解决了此问题åŽï¼Œæ‰§è¡Œ \"git rebase --continue\"。\n"
+"如果您想跳过此补ä¸ï¼Œåˆ™æ‰§è¡Œ \"git rebase --skip\"。\n"
+"è¦æ¢å¤åŽŸåˆ†æ”¯å¹¶åœæ­¢å˜åŸºï¼Œæ‰§è¡Œ \"git rebase --abort\"。"
+
+#: git-rebase.sh:159
+msgid "The pre-rebase hook refused to rebase."
+msgstr "é’©å­ pre-rebase æ‹’ç»å˜åŸºã€‚"
+
+#: git-rebase.sh:164
+msgid "It looks like git-am is in progress. Cannot rebase."
+msgstr "似乎正处于在 git-am 的执行过程中。无法å˜åŸºã€‚"
+
+#: git-rebase.sh:295
+msgid "The --exec option must be used with the --interactive option"
+msgstr "选项 --exec 必须和选项 --interactive åŒæ—¶ä½¿ç”¨"
+
+#: git-rebase.sh:300
+msgid "No rebase in progress?"
+msgstr "没有正在进行的å˜åŸºï¼Ÿ"
+
+#: git-rebase.sh:313
+msgid "Cannot read HEAD"
+msgstr "ä¸èƒ½è¯»å– HEAD"
+
+#: git-rebase.sh:316
+msgid ""
+"You must edit all merge conflicts and then\n"
+"mark them as resolved using git add"
+msgstr ""
+"您必须编辑所有的åˆå¹¶å†²çªï¼Œç„¶åŽé€šè¿‡ git add\n"
+"命令将它们标记为已解决"
+
+#: git-rebase.sh:334
+#, sh-format
+msgid "Could not move back to $head_name"
+msgstr "无法移回 $head_name"
+
+#: git-rebase.sh:350
+#, sh-format
+msgid ""
+"It seems that there is already a $state_dir_base directory, and\n"
+"I wonder if you are in the middle of another rebase. If that is the\n"
+"case, please try\n"
+"\t$cmd_live_rebase\n"
+"If that is not the case, please\n"
+"\t$cmd_clear_stale_rebase\n"
+"and run me again. I am stopping in case you still have something\n"
+"valuable there."
+msgstr ""
+"好åƒå·²æœ‰ä¸€ä¸ª $state_dir_base 目录,我怀疑您正处于å¦å¤–一个å˜åŸºè¿‡ç¨‹ä¸­ã€‚\n"
+"如果是这样,请å°è¯•æ‰§è¡Œ\n"
+"\t$cmd_live_rebase\n"
+"如果ä¸æ˜¯è¿™æ ·ï¼Œè¯·æ‰§è¡Œ\n"
+"\t$cmd_clear_stale_rebase\n"
+"然åŽå†é‡æ–°æ‰§è¡Œå˜åŸºã€‚为é¿å…您丢失é‡è¦æ•°æ®ï¼Œæˆ‘å·²ç»åœæ­¢å½“å‰æ“作。"
+
+#: git-rebase.sh:395
+#, sh-format
+msgid "invalid upstream $upstream_name"
+msgstr "无效的上游 $upstream_name"
+
+#: git-rebase.sh:419
+#, sh-format
+msgid "$onto_name: there are more than one merge bases"
+msgstr "$onto_name: 有一个以上的åˆå¹¶åŸºå‡†"
+
+#: git-rebase.sh:422 git-rebase.sh:426
+#, sh-format
+msgid "$onto_name: there is no merge base"
+msgstr "$onto_name: 没有åˆå¹¶åŸºå‡†"
+
+#: git-rebase.sh:431
+#, sh-format
+msgid "Does not point to a valid commit: $onto_name"
+msgstr "没有指å‘一个有效的æ交:$onto_name"
+
+#: git-rebase.sh:454
+#, sh-format
+msgid "fatal: no such branch: $branch_name"
+msgstr "严é‡é”™è¯¯ï¼šæ— æ­¤åˆ†æ”¯ï¼š$branch_name"
+
+#: git-rebase.sh:474
+msgid "Please commit or stash them."
+msgstr "请æ交或为它们ä¿å­˜è¿›åº¦ã€‚"
+
+#: git-rebase.sh:492
+#, sh-format
+msgid "Current branch $branch_name is up to date."
+msgstr "当å‰åˆ†æ”¯ $branch_name 是最新的。"
+
+#: git-rebase.sh:495
+#, sh-format
+msgid "Current branch $branch_name is up to date, rebase forced."
+msgstr "当å‰åˆ†æ”¯ $branch_name 是最新的,强制å˜åŸºã€‚"
+
+#: git-rebase.sh:506
+#, sh-format
+msgid "Changes from $mb to $onto:"
+msgstr "å˜æ›´ä»Ž $mb 到 $onto:"
+
+#. Detach HEAD and reset the tree
+#: git-rebase.sh:515
+msgid "First, rewinding head to replay your work on top of it..."
+msgstr "首先,é‡ç½®å¤´æŒ‡é’ˆä»¥ä¾¿åœ¨ä¸Šé¢é‡æ”¾æ‚¨çš„工作..."
+
+#: git-rebase.sh:523
+#, sh-format
+msgid "Fast-forwarded $branch_name to $onto_name."
+msgstr "快进 $branch_name 至 $onto_name。"
+
#: git-stash.sh:51
msgid "git stash clear with parameters is unimplemented"
msgstr "git stash clear ä¸æ”¯æŒå‚æ•°"
@@ -5249,59 +9264,59 @@ msgstr "ä¸èƒ½ä¿å­˜ç´¢å¼•æ ‘"
msgid "Cannot unstage modified files"
msgstr "无法还原修改的文件"
-#: git-stash.sh:474
+#: git-stash.sh:475
msgid "Index was not unstashed."
msgstr "索引的进度没有被æ¢å¤ã€‚"
-#: git-stash.sh:491
+#: git-stash.sh:492
#, sh-format
msgid "Dropped ${REV} ($s)"
msgstr "丢弃了 ${REV} ($s)"
-#: git-stash.sh:492
+#: git-stash.sh:493
#, sh-format
msgid "${REV}: Could not drop stash entry"
msgstr "${REV}:ä¸èƒ½ä¸¢å¼ƒè¿›åº¦æ¡ç›®"
-#: git-stash.sh:499
+#: git-stash.sh:500
msgid "No branch name specified"
msgstr "未指定分支å"
-#: git-stash.sh:570
+#: git-stash.sh:571
msgid "(To restore them type \"git stash apply\")"
msgstr "(为æ¢å¤æ•°æ®è¾“å…¥ \"git stash apply\")"
-#: git-submodule.sh:56
+#: git-submodule.sh:88
#, sh-format
msgid "cannot strip one component off url '$remoteurl'"
msgstr "无法从 url '$remoteurl' 剥离一个组件"
-#: git-submodule.sh:109
+#: git-submodule.sh:167
#, sh-format
msgid "No submodule mapping found in .gitmodules for path '$sm_path'"
msgstr "未在 .gitmodules 中å‘现路径 '$sm_path' çš„å­æ¨¡ç»„映射"
-#: git-submodule.sh:150
+#: git-submodule.sh:211
#, sh-format
msgid "Clone of '$url' into submodule path '$sm_path' failed"
msgstr "无法克隆 '$url' 到å­æ¨¡ç»„路径 '$sm_path'"
-#: git-submodule.sh:160
+#: git-submodule.sh:223
#, sh-format
msgid "Gitdir '$a' is part of the submodule path '$b' or vice versa"
msgstr "Gitdir '$a' 在å­æ¨¡ç»„路径 '$b' 之下或者相å"
-#: git-submodule.sh:249
+#: git-submodule.sh:312
#, sh-format
msgid "repo URL: '$repo' must be absolute or begin with ./|../"
msgstr "版本库URL:'$repo' 必须是ç»å¯¹è·¯å¾„或以 ./|../ 起始"
-#: git-submodule.sh:266
+#: git-submodule.sh:329
#, sh-format
msgid "'$sm_path' already exists in the index"
msgstr "'$sm_path' å·²ç»å­˜åœ¨äºŽç´¢å¼•ä¸­"
-#: git-submodule.sh:270
+#: git-submodule.sh:333
#, sh-format
msgid ""
"The following path is ignored by one of your .gitignore files:\n"
@@ -5312,62 +9327,62 @@ msgstr ""
"$sm_path\n"
"如果您确实想添加它,使用 -f å‚数。"
-#: git-submodule.sh:281
+#: git-submodule.sh:344
#, sh-format
msgid "Adding existing repo at '$sm_path' to the index"
msgstr "添加ä½äºŽ '$sm_path' 的现存版本库到索引"
-#: git-submodule.sh:283
+#: git-submodule.sh:346
#, sh-format
msgid "'$sm_path' already exists and is not a valid git repo"
msgstr "'$sm_path' 已存在且ä¸æ˜¯ä¸€ä¸ªæœ‰æ•ˆçš„ git 版本库"
-#: git-submodule.sh:297
+#: git-submodule.sh:360
#, sh-format
msgid "Unable to checkout submodule '$sm_path'"
msgstr "ä¸èƒ½æ£€å‡ºå­æ¨¡ç»„ '$sm_path'"
-#: git-submodule.sh:302
+#: git-submodule.sh:365
#, sh-format
msgid "Failed to add submodule '$sm_path'"
msgstr "无法添加å­æ¨¡ç»„ '$sm_path'"
-#: git-submodule.sh:307
+#: git-submodule.sh:370
#, sh-format
msgid "Failed to register submodule '$sm_path'"
msgstr "无法注册å­æ¨¡ç»„ '$sm_path'"
-#: git-submodule.sh:349
+#: git-submodule.sh:413
#, sh-format
msgid "Entering '$prefix$sm_path'"
msgstr "正在进入 '$prefix$sm_path'"
-#: git-submodule.sh:363
+#: git-submodule.sh:427
#, sh-format
msgid "Stopping at '$sm_path'; script returned non-zero status."
msgstr "åœæ­¢äºŽ '$sm_path',脚本返回éžé›¶å€¼ã€‚"
-#: git-submodule.sh:406
+#: git-submodule.sh:471
#, sh-format
msgid "No url found for submodule path '$sm_path' in .gitmodules"
msgstr "在 .gitmodules 中未找到å­æ¨¡ç»„路径 '$sm_path' çš„ url"
-#: git-submodule.sh:415
+#: git-submodule.sh:480
#, sh-format
msgid "Failed to register url for submodule path '$sm_path'"
msgstr "无法为å­æ¨¡ç»„路径 '$sm_path' 注册 url"
-#: git-submodule.sh:417
+#: git-submodule.sh:482
#, sh-format
msgid "Submodule '$name' ($url) registered for path '$sm_path'"
msgstr "å­æ¨¡ç»„ '$name' ($url) 已为路径 '$sm_path' 注册"
-#: git-submodule.sh:425
+#: git-submodule.sh:490
#, sh-format
msgid "Failed to register update mode for submodule path '$sm_path'"
msgstr "无法为å­æ¨¡ç»„路径 '$sm_path' 注册更新模å¼"
-#: git-submodule.sh:524
+#: git-submodule.sh:590
#, sh-format
msgid ""
"Submodule path '$sm_path' not initialized\n"
@@ -5376,96 +9391,130 @@ msgstr ""
"å­æ¨¡ç»„路径 '$sm_path' 没有åˆå§‹åŒ–\n"
"也许您想用 'update --init'?"
-#: git-submodule.sh:537
+#: git-submodule.sh:603
#, sh-format
msgid "Unable to find current revision in submodule path '$sm_path'"
msgstr "无法在å­æ¨¡ç»„路径 '$sm_path' 中找到当å‰ç‰ˆæœ¬"
-#: git-submodule.sh:556
+#: git-submodule.sh:622
#, sh-format
msgid "Unable to fetch in submodule path '$sm_path'"
msgstr "无法在å­æ¨¡ç»„路径 '$sm_path' 中获å–"
-#: git-submodule.sh:570
+#: git-submodule.sh:636
#, sh-format
msgid "Unable to rebase '$sha1' in submodule path '$sm_path'"
msgstr "无法在å­æ¨¡ç»„路径 '$sm_path' 中å˜åŸº '$sha1'"
-#: git-submodule.sh:571
+#: git-submodule.sh:637
#, sh-format
msgid "Submodule path '$sm_path': rebased into '$sha1'"
msgstr "å­æ¨¡ç»„路径 '$sm_path':å˜åŸºè‡³ '$sha1'"
-#: git-submodule.sh:576
+#: git-submodule.sh:642
#, sh-format
msgid "Unable to merge '$sha1' in submodule path '$sm_path'"
msgstr "无法åˆå¹¶ '$sha1' 到å­æ¨¡ç»„路径 '$sm_path' 中"
-#: git-submodule.sh:577
+#: git-submodule.sh:643
#, sh-format
msgid "Submodule path '$sm_path': merged in '$sha1'"
msgstr "å­æ¨¡ç»„路径 '$sm_path':已åˆå¹¶å…¥ '$sha1'"
-#: git-submodule.sh:582
+#: git-submodule.sh:648
#, sh-format
msgid "Unable to checkout '$sha1' in submodule path '$sm_path'"
msgstr "无法在å­æ¨¡ç»„路径 '$sm_path' 中检出 '$sha1'"
-#: git-submodule.sh:583
+#: git-submodule.sh:649
#, sh-format
msgid "Submodule path '$sm_path': checked out '$sha1'"
msgstr "å­æ¨¡ç»„路径 '$sm_path':检出 '$sha1'"
-#: git-submodule.sh:605 git-submodule.sh:928
+#: git-submodule.sh:671 git-submodule.sh:995
#, sh-format
msgid "Failed to recurse into submodule path '$sm_path'"
msgstr "无法递归进å­æ¨¡ç»„路径 '$sm_path'"
-#: git-submodule.sh:713
-msgid "--cached cannot be used with --files"
-msgstr "--cached ä¸èƒ½å’Œ --files 共用"
+#: git-submodule.sh:779
+msgid "The --cached option cannot be used with the --files option"
+msgstr "选项 --cached ä¸èƒ½å’Œé€‰é¡¹ --files åŒæ—¶ä½¿ç”¨"
#. unexpected type
-#: git-submodule.sh:753
+#: git-submodule.sh:819
#, sh-format
msgid "unexpected mode $mod_dst"
msgstr "æ„å¤–çš„æ¨¡å¼ $mod_dst"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: git-submodule.sh:771
+#: git-submodule.sh:837
#, sh-format
msgid " Warn: $name doesn't contain commit $sha1_src"
msgstr " 警告:$name 未包å«æ交 $sha1_src"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: git-submodule.sh:774
+#: git-submodule.sh:840
#, sh-format
msgid " Warn: $name doesn't contain commit $sha1_dst"
msgstr " 警告:$name 未包å«æ交 $sha1_dst"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: git-submodule.sh:777
+#: git-submodule.sh:843
#, sh-format
msgid " Warn: $name doesn't contain commits $sha1_src and $sha1_dst"
msgstr " 警告:$name 未包å«æ交 $sha1_src å’Œ $sha1_dst"
-#: git-submodule.sh:802
+#: git-submodule.sh:868
msgid "blob"
-msgstr "blob"
+msgstr "二进制对象"
-#: git-submodule.sh:803
-msgid "submodule"
-msgstr "å­æ¨¡ç»„"
-
-#: git-submodule.sh:840
+#: git-submodule.sh:906
msgid "# Submodules changed but not updated:"
msgstr "# å­æ¨¡ç»„已修改但尚未更新:"
-#: git-submodule.sh:842
+#: git-submodule.sh:908
msgid "# Submodule changes to be committed:"
msgstr "è¦æ交的å­æ¨¡ç»„å˜æ›´ï¼š"
-#: git-submodule.sh:974
+#: git-submodule.sh:1054
#, sh-format
msgid "Synchronizing submodule url for '$name'"
msgstr "为 '$name' åŒæ­¥å­æ¨¡ç»„ url"
+
+# 译者:中文字符串拼接,å¯åˆ é™¤å‰å¯¼ç©ºæ ¼
+#~ msgid " (use \"git add\" to track)"
+#~ msgstr "(使用 \"git add\" 建立跟踪)"
+
+#~ msgid "-B cannot be used with -b"
+#~ msgstr "-B ä¸èƒ½å’Œ -b åŒæ—¶ä½¿ç”¨"
+
+#~ msgid "--patch is incompatible with all other options"
+#~ msgstr "--patch 选项和其他选项ä¸å…¼å®¹"
+
+#~ msgid "--detach cannot be used with -b/-B/--orphan"
+#~ msgstr "--detach ä¸èƒ½å’Œ -b/-B/--orphan åŒæ—¶ä½¿ç”¨"
+
+#~ msgid "--detach cannot be used with -t"
+#~ msgstr "--detach ä¸èƒ½å’Œ -t åŒæ—¶ä½¿ç”¨"
+
+#~ msgid "--orphan and -b|-B are mutually exclusive"
+#~ msgstr "--orphan 和 -b|-B 互斥"
+
+#~ msgid "--orphan cannot be used with -t"
+#~ msgstr "--orphan ä¸èƒ½å’Œ -t åŒæ—¶ä½¿ç”¨"
+
+#~ msgid "git checkout: -f and -m are incompatible"
+#~ msgstr "git checkout:-f å’Œ -m ä¸å…¼å®¹"
+
+#~ msgid ""
+#~ "git checkout: updating paths is incompatible with switching branches."
+#~ msgstr "git checkout:更新路径和切æ¢åˆ†æ”¯ä¸å…¼å®¹ã€‚"
+
+#~ msgid "diff setup failed"
+#~ msgstr "diff 设置失败"
+
+#~ msgid "merge-recursive: disk full?"
+#~ msgstr "merge-recursive:ç£ç›˜å·²æ»¡ï¼Ÿ"
+
+#~ msgid "diff_setup_done failed"
+#~ msgstr "diff_setup_done 失败"
diff --git a/read-cache.c b/read-cache.c
index d8543e4..fda78bc 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -17,6 +17,10 @@
static struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really);
+/* Mask for the name length in ce_flags in the on-disk index */
+
+#define CE_NAMEMASK (0x0fff)
+
/* Index extensions.
*
* The first letter should be 'A'..'Z' for extensions that are not
@@ -54,8 +58,8 @@ void rename_index_entry_at(struct index_state *istate, int nr, const char *new_n
new = xmalloc(cache_entry_size(namelen));
copy_cache_entry(new, old);
- new->ce_flags &= ~(CE_STATE_MASK | CE_NAMEMASK);
- new->ce_flags |= (namelen >= CE_NAMEMASK ? CE_NAMEMASK : namelen);
+ new->ce_flags &= ~CE_STATE_MASK;
+ new->ce_namelen = namelen;
memcpy(new->name, new_name, namelen + 1);
cache_tree_invalidate_path(istate->cache_tree, old->name);
@@ -395,17 +399,10 @@ int df_name_compare(const char *name1, int len1, int mode1,
return c1 - c2;
}
-int cache_name_compare(const char *name1, int flags1, const char *name2, int flags2)
+int cache_name_stage_compare(const char *name1, int len1, int stage1, const char *name2, int len2, int stage2)
{
- int len1, len2, len, cmp;
-
- len1 = flags1 & CE_NAMEMASK;
- if (CE_NAMEMASK <= len1)
- len1 = strlen(name1 + CE_NAMEMASK) + CE_NAMEMASK;
- len2 = flags2 & CE_NAMEMASK;
- if (CE_NAMEMASK <= len2)
- len2 = strlen(name2 + CE_NAMEMASK) + CE_NAMEMASK;
- len = len1 < len2 ? len1 : len2;
+ int len = len1 < len2 ? len1 : len2;
+ int cmp;
cmp = memcmp(name1, name2, len);
if (cmp)
@@ -415,18 +412,19 @@ int cache_name_compare(const char *name1, int flags1, const char *name2, int fla
if (len1 > len2)
return 1;
- /* Compare stages */
- flags1 &= CE_STAGEMASK;
- flags2 &= CE_STAGEMASK;
-
- if (flags1 < flags2)
+ if (stage1 < stage2)
return -1;
- if (flags1 > flags2)
+ if (stage1 > stage2)
return 1;
return 0;
}
-int index_name_pos(const struct index_state *istate, const char *name, int namelen)
+int cache_name_compare(const char *name1, int len1, const char *name2, int len2)
+{
+ return cache_name_stage_compare(name1, len1, 0, name2, len2, 0);
+}
+
+static int index_name_stage_pos(const struct index_state *istate, const char *name, int namelen, int stage)
{
int first, last;
@@ -435,7 +433,7 @@ int index_name_pos(const struct index_state *istate, const char *name, int namel
while (last > first) {
int next = (last + first) >> 1;
struct cache_entry *ce = istate->cache[next];
- int cmp = cache_name_compare(name, namelen, ce->name, ce->ce_flags);
+ int cmp = cache_name_stage_compare(name, namelen, stage, ce->name, ce_namelen(ce), ce_stage(ce));
if (!cmp)
return next;
if (cmp < 0) {
@@ -447,6 +445,11 @@ int index_name_pos(const struct index_state *istate, const char *name, int namel
return -first-1;
}
+int index_name_pos(const struct index_state *istate, const char *name, int namelen)
+{
+ return index_name_stage_pos(istate, name, namelen, 0);
+}
+
/* Remove entry, return true if there are more entries to go.. */
int remove_index_entry_at(struct index_state *istate, int pos)
{
@@ -586,7 +589,7 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
size = cache_entry_size(namelen);
ce = xcalloc(1, size);
memcpy(ce->name, path, namelen);
- ce->ce_flags = namelen;
+ ce->ce_namelen = namelen;
if (!intent_only)
fill_stat_cache_info(ce, st);
else
@@ -688,7 +691,8 @@ struct cache_entry *make_cache_entry(unsigned int mode,
hashcpy(ce->sha1, sha1);
memcpy(ce->name, path, len);
- ce->ce_flags = create_ce_flags(len, stage);
+ ce->ce_flags = create_ce_flags(stage);
+ ce->ce_namelen = len;
ce->ce_mode = create_ce_mode(mode);
if (refresh)
@@ -825,7 +829,7 @@ static int has_dir_name(struct index_state *istate,
}
len = slash - name;
- pos = index_name_pos(istate, name, create_ce_flags(len, stage));
+ pos = index_name_stage_pos(istate, name, len, stage);
if (pos >= 0) {
/*
* Found one, but not so fast. This could
@@ -915,7 +919,7 @@ static int add_index_entry_with_check(struct index_state *istate, struct cache_e
int new_only = option & ADD_CACHE_NEW_ONLY;
cache_tree_invalidate_path(istate->cache_tree, ce->name);
- pos = index_name_pos(istate, ce->name, ce->ce_flags);
+ pos = index_name_stage_pos(istate, ce->name, ce_namelen(ce), ce_stage(ce));
/* existing match? Just replace it. */
if (pos >= 0) {
@@ -947,7 +951,7 @@ static int add_index_entry_with_check(struct index_state *istate, struct cache_e
if (!ok_to_replace)
return error("'%s' appears as both a file and as a directory",
ce->name);
- pos = index_name_pos(istate, ce->name, ce->ce_flags);
+ pos = index_name_stage_pos(istate, ce->name, ce_namelen(ce), ce_stage(ce));
pos = -pos-1;
}
return pos + 1;
@@ -1124,7 +1128,7 @@ int refresh_index(struct index_state *istate, unsigned int flags, const char **p
continue;
if (pathspec &&
- !match_pathspec(pathspec, ce->name, strlen(ce->name), 0, seen))
+ !match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, seen))
filtered = 1;
if (ce_stage(ce)) {
@@ -1324,7 +1328,8 @@ static struct cache_entry *cache_entry_from_ondisk(struct ondisk_cache_entry *on
ce->ce_uid = ntoh_l(ondisk->uid);
ce->ce_gid = ntoh_l(ondisk->gid);
ce->ce_size = ntoh_l(ondisk->size);
- ce->ce_flags = flags;
+ ce->ce_flags = flags & ~CE_NAMEMASK;
+ ce->ce_namelen = len;
hashcpy(ce->sha1, ondisk->sha1);
memcpy(ce->name, name, len);
ce->name[len] = '\0';
@@ -1647,6 +1652,8 @@ static void ce_smudge_racily_clean_entry(struct cache_entry *ce)
static char *copy_cache_entry_to_ondisk(struct ondisk_cache_entry *ondisk,
struct cache_entry *ce)
{
+ short flags;
+
ondisk->ctime.sec = htonl(ce->ce_ctime.sec);
ondisk->mtime.sec = htonl(ce->ce_mtime.sec);
ondisk->ctime.nsec = htonl(ce->ce_ctime.nsec);
@@ -1658,7 +1665,10 @@ static char *copy_cache_entry_to_ondisk(struct ondisk_cache_entry *ondisk,
ondisk->gid = htonl(ce->ce_gid);
ondisk->size = htonl(ce->ce_size);
hashcpy(ondisk->sha1, ce->sha1);
- ondisk->flags = htons(ce->ce_flags);
+
+ flags = ce->ce_flags;
+ flags |= (ce_namelen(ce) >= CE_NAMEMASK ? CE_NAMEMASK : ce_namelen(ce));
+ ondisk->flags = htons(flags);
if (ce->ce_flags & CE_EXTENDED) {
struct ondisk_cache_entry_extended *ondisk2;
ondisk2 = (struct ondisk_cache_entry_extended *)ondisk;
@@ -1844,11 +1854,12 @@ int read_index_unmerged(struct index_state *istate)
if (!ce_stage(ce))
continue;
unmerged = 1;
- len = strlen(ce->name);
+ len = ce_namelen(ce);
size = cache_entry_size(len);
new_ce = xcalloc(1, size);
memcpy(new_ce->name, ce->name, len);
- new_ce->ce_flags = create_ce_flags(len, 0) | CE_CONFLICTED;
+ new_ce->ce_flags = create_ce_flags(0) | CE_CONFLICTED;
+ new_ce->ce_namelen = len;
new_ce->ce_mode = ce->ce_mode;
if (add_index_entry(istate, new_ce, 0))
return error("%s: cannot drop to stage #0",
diff --git a/remote-curl.c b/remote-curl.c
index 3ec474f..10fa8f1 100644
--- a/remote-curl.c
+++ b/remote-curl.c
@@ -95,15 +95,16 @@ static struct discovery* discover_refs(const char *service)
struct strbuf buffer = STRBUF_INIT;
struct discovery *last = last_discovery;
char *refs_url;
- int http_ret, is_http = 0, proto_git_candidate = 1;
+ int http_ret, maybe_smart = 0;
if (last && !strcmp(service, last->service))
return last;
free_discovery(last);
strbuf_addf(&buffer, "%sinfo/refs", url);
- if (!prefixcmp(url, "http://") || !prefixcmp(url, "https://")) {
- is_http = 1;
+ if ((!prefixcmp(url, "http://") || !prefixcmp(url, "https://")) &&
+ git_env_bool("GIT_SMART_HTTP", 1)) {
+ maybe_smart = 1;
if (!strchr(url, '?'))
strbuf_addch(&buffer, '?');
else
@@ -113,19 +114,6 @@ static struct discovery* discover_refs(const char *service)
refs_url = strbuf_detach(&buffer, NULL);
http_ret = http_get_strbuf(refs_url, &buffer, HTTP_NO_CACHE);
-
- /* try again with "plain" url (no ? or & appended) */
- if (http_ret != HTTP_OK && http_ret != HTTP_NOAUTH) {
- free(refs_url);
- strbuf_reset(&buffer);
-
- proto_git_candidate = 0;
- strbuf_addf(&buffer, "%sinfo/refs", url);
- refs_url = strbuf_detach(&buffer, NULL);
-
- http_ret = http_get_strbuf(refs_url, &buffer, HTTP_NO_CACHE);
- }
-
switch (http_ret) {
case HTTP_OK:
break;
@@ -144,8 +132,7 @@ static struct discovery* discover_refs(const char *service)
last->buf_alloc = strbuf_detach(&buffer, &last->len);
last->buf = last->buf_alloc;
- if (is_http && proto_git_candidate
- && 5 <= last->len && last->buf[4] == '#') {
+ if (maybe_smart && 5 <= last->len && last->buf[4] == '#') {
/* smart HTTP response; validate that the service
* pkt-line matches our request.
*/
@@ -393,7 +380,7 @@ static int probe_rpc(struct rpc_state *rpc)
curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 0);
curl_easy_setopt(slot->curl, CURLOPT_POST, 1);
curl_easy_setopt(slot->curl, CURLOPT_URL, rpc->service_url);
- curl_easy_setopt(slot->curl, CURLOPT_ENCODING, "");
+ curl_easy_setopt(slot->curl, CURLOPT_ENCODING, NULL);
curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, "0000");
curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE, 4);
curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, headers);
@@ -449,7 +436,7 @@ static int post_rpc(struct rpc_state *rpc)
curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 0);
curl_easy_setopt(slot->curl, CURLOPT_POST, 1);
curl_easy_setopt(slot->curl, CURLOPT_URL, rpc->service_url);
- curl_easy_setopt(slot->curl, CURLOPT_ENCODING, "");
+ curl_easy_setopt(slot->curl, CURLOPT_ENCODING, "gzip");
headers = curl_slist_append(headers, rpc->hdr_content_type);
headers = curl_slist_append(headers, rpc->hdr_accept);
diff --git a/rerere.c b/rerere.c
index 651c5de..a6a5cd5 100644
--- a/rerere.c
+++ b/rerere.c
@@ -25,7 +25,7 @@ const char *rerere_path(const char *hex, const char *file)
return git_path("rr-cache/%s/%s", hex, file);
}
-int has_rerere_resolution(const char *hex)
+static int has_rerere_resolution(const char *hex)
{
struct stat st;
return !stat(rerere_path(hex, "postimage"), &st);
@@ -544,13 +544,13 @@ static int do_plain_rerere(struct string_list *rr, int fd)
if (has_rerere_resolution(name)) {
if (!merge(name, path)) {
- if (rerere_autoupdate)
+ const char *msg;
+ if (rerere_autoupdate) {
string_list_insert(&update, path);
- fprintf(stderr,
- "%s '%s' using previous resolution.\n",
- rerere_autoupdate
- ? "Staged" : "Resolved",
- path);
+ msg = "Staged '%s' using previous resolution.\n";
+ } else
+ msg = "Resolved '%s' using previous resolution.\n";
+ fprintf(stderr, msg, path);
goto mark_resolved;
}
}
diff --git a/rerere.h b/rerere.h
index fcd8bc1..156d2aa 100644
--- a/rerere.h
+++ b/rerere.h
@@ -16,7 +16,6 @@ extern void *RERERE_RESOLVED;
extern int setup_rerere(struct string_list *, int);
extern int rerere(int);
extern const char *rerere_path(const char *hex, const char *file);
-extern int has_rerere_resolution(const char *hex);
extern int rerere_forget(const char **);
extern int rerere_remaining(struct string_list *);
extern void rerere_clear(struct string_list *);
diff --git a/revision.c b/revision.c
index 7210496..a09e60b 100644
--- a/revision.c
+++ b/revision.c
@@ -1002,7 +1002,7 @@ static int add_parents_only(struct rev_info *revs, const char *arg_, int flags)
flags ^= UNINTERESTING;
arg++;
}
- if (get_sha1(arg, sha1))
+ if (get_sha1_committish(arg, sha1))
return 0;
while (1) {
it = get_reference(revs, arg, sha1, 0);
@@ -1116,16 +1116,16 @@ static void prepare_show_merge(struct rev_info *revs)
revs->limited = 1;
}
-int handle_revision_arg(const char *arg_, struct rev_info *revs,
- int flags,
- int cant_be_filename)
+int handle_revision_arg(const char *arg_, struct rev_info *revs, int flags, unsigned revarg_opt)
{
- unsigned mode;
+ struct object_context oc;
char *dotdot;
struct object *object;
unsigned char sha1[20];
int local_flags;
const char *arg = arg_;
+ int cant_be_filename = revarg_opt & REVARG_CANNOT_BE_FILENAME;
+ unsigned get_sha1_flags = 0;
dotdot = strstr(arg, "..");
if (dotdot) {
@@ -1155,8 +1155,8 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs,
return -1;
}
}
- if (!get_sha1(this, from_sha1) &&
- !get_sha1(next, sha1)) {
+ if (!get_sha1_committish(this, from_sha1) &&
+ !get_sha1_committish(next, sha1)) {
struct commit *a, *b;
struct commit_list *exclude;
@@ -1215,13 +1215,17 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs,
local_flags = UNINTERESTING;
arg++;
}
- if (get_sha1_with_mode(arg, sha1, &mode))
+
+ if (revarg_opt & REVARG_COMMITTISH)
+ get_sha1_flags = GET_SHA1_COMMITTISH;
+
+ if (get_sha1_with_context(arg, get_sha1_flags, sha1, &oc))
return revs->ignore_missing ? 0 : -1;
if (!cant_be_filename)
verify_non_filename(revs->prefix, arg);
object = get_reference(revs, arg, sha1, flags ^ local_flags);
add_rev_cmdline(revs, object, arg_, REV_CMD_REV, flags ^ local_flags);
- add_pending_object_with_mode(revs, object, arg, mode);
+ add_pending_object_with_mode(revs, object, arg, oc.mode);
return 0;
}
@@ -1271,7 +1275,7 @@ static void read_revisions_from_stdin(struct rev_info *revs,
}
die("options not supported in --stdin mode");
}
- if (handle_revision_arg(sb.buf, revs, 0, 1))
+ if (handle_revision_arg(sb.buf, revs, 0, REVARG_CANNOT_BE_FILENAME))
die("bad revision '%s'", sb.buf);
}
if (seen_dashdash)
@@ -1308,7 +1312,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
!strcmp(arg, "--no-walk") || !strcmp(arg, "--do-walk") ||
!strcmp(arg, "--bisect") || !prefixcmp(arg, "--glob=") ||
!prefixcmp(arg, "--branches=") || !prefixcmp(arg, "--tags=") ||
- !prefixcmp(arg, "--remotes="))
+ !prefixcmp(arg, "--remotes=") || !prefixcmp(arg, "--no-walk="))
{
unkv[(*unkc)++] = arg;
return 1;
@@ -1591,9 +1595,14 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
} else if ((argcount = parse_long_opt("committer", argv, &optarg))) {
add_header_grep(revs, GREP_HEADER_COMMITTER, optarg);
return argcount;
+ } else if ((argcount = parse_long_opt("grep-reflog", argv, &optarg))) {
+ add_header_grep(revs, GREP_HEADER_REFLOG, optarg);
+ return argcount;
} else if ((argcount = parse_long_opt("grep", argv, &optarg))) {
add_message_grep(revs, optarg);
return argcount;
+ } else if (!strcmp(arg, "--grep-debug")) {
+ revs->grep_filter.debug = 1;
} else if (!strcmp(arg, "--extended-regexp") || !strcmp(arg, "-E")) {
revs->grep_filter.regflags |= REG_EXTENDED;
} else if (!strcmp(arg, "--regexp-ignore-case") || !strcmp(arg, "-i")) {
@@ -1703,7 +1712,18 @@ static int handle_revision_pseudo_opt(const char *submodule,
} else if (!strcmp(arg, "--not")) {
*flags ^= UNINTERESTING;
} else if (!strcmp(arg, "--no-walk")) {
- revs->no_walk = 1;
+ revs->no_walk = REVISION_WALK_NO_WALK_SORTED;
+ } else if (!prefixcmp(arg, "--no-walk=")) {
+ /*
+ * Detached form ("--no-walk X" as opposed to "--no-walk=X")
+ * not allowed, since the argument is optional.
+ */
+ if (!strcmp(arg + 10, "sorted"))
+ revs->no_walk = REVISION_WALK_NO_WALK_SORTED;
+ else if (!strcmp(arg + 10, "unsorted"))
+ revs->no_walk = REVISION_WALK_NO_WALK_UNSORTED;
+ else
+ return error("invalid argument to --no-walk");
} else if (!strcmp(arg, "--do-walk")) {
revs->no_walk = 0;
} else {
@@ -1722,7 +1742,7 @@ static int handle_revision_pseudo_opt(const char *submodule,
*/
int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct setup_revision_opt *opt)
{
- int i, flags, left, seen_dashdash, read_from_stdin, got_rev_arg = 0;
+ int i, flags, left, seen_dashdash, read_from_stdin, got_rev_arg = 0, revarg_opt;
struct cmdline_pathspec prune_data;
const char *submodule = NULL;
@@ -1750,6 +1770,9 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
/* Second, deal with arguments and options */
flags = 0;
+ revarg_opt = opt ? opt->revarg_opt : 0;
+ if (seen_dashdash)
+ revarg_opt |= REVARG_CANNOT_BE_FILENAME;
read_from_stdin = 0;
for (left = i = 1; i < argc; i++) {
const char *arg = argv[i];
@@ -1785,7 +1808,8 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
continue;
}
- if (handle_revision_arg(arg, revs, flags, seen_dashdash)) {
+
+ if (handle_revision_arg(arg, revs, flags, revarg_opt)) {
int j;
if (seen_dashdash || *arg == '^')
die("bad revision '%s'", arg);
@@ -1836,11 +1860,11 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
if (revs->def && !revs->pending.nr && !got_rev_arg) {
unsigned char sha1[20];
struct object *object;
- unsigned mode;
- if (get_sha1_with_mode(revs->def, sha1, &mode))
+ struct object_context oc;
+ if (get_sha1_with_context(revs->def, 0, sha1, &oc))
die("bad default revision '%s'", revs->def);
object = get_reference(revs, revs->def, sha1, 0);
- add_pending_object_with_mode(revs, object, revs->def, mode);
+ add_pending_object_with_mode(revs, object, revs->def, oc.mode);
}
/* Did the user ask for any diff output? Run the diff! */
@@ -1884,6 +1908,8 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
if (revs->reflog_info && revs->graph)
die("cannot combine --walk-reflogs with --graph");
+ if (!revs->reflog_info && revs->grep_filter.use_reflog_filter)
+ die("cannot use --grep-reflog without --walk-reflogs");
return left;
}
@@ -2121,10 +2147,11 @@ int prepare_revision_walk(struct rev_info *revs)
}
e++;
}
- commit_list_sort_by_date(&revs->commits);
if (!revs->leak_pending)
free(list);
+ if (revs->no_walk != REVISION_WALK_NO_WALK_UNSORTED)
+ commit_list_sort_by_date(&revs->commits);
if (revs->no_walk)
return 0;
if (revs->limited)
@@ -2188,10 +2215,38 @@ static int rewrite_parents(struct rev_info *revs, struct commit *commit)
static int commit_match(struct commit *commit, struct rev_info *opt)
{
+ int retval;
+ struct strbuf buf = STRBUF_INIT;
if (!opt->grep_filter.pattern_list && !opt->grep_filter.header_list)
return 1;
- return grep_buffer(&opt->grep_filter,
- commit->buffer, strlen(commit->buffer));
+
+ /* Prepend "fake" headers as needed */
+ if (opt->grep_filter.use_reflog_filter) {
+ strbuf_addstr(&buf, "reflog ");
+ get_reflog_message(&buf, opt->reflog_info);
+ strbuf_addch(&buf, '\n');
+ }
+
+ /* Copy the commit to temporary if we are using "fake" headers */
+ if (buf.len)
+ strbuf_addstr(&buf, commit->buffer);
+
+ /* Append "fake" message parts as needed */
+ if (opt->show_notes) {
+ if (!buf.len)
+ strbuf_addstr(&buf, commit->buffer);
+ format_display_notes(commit->object.sha1, &buf,
+ get_log_output_encoding(), 0);
+ }
+
+ /* Find either in the commit object, or in the temporary */
+ if (buf.len)
+ retval = grep_buffer(&opt->grep_filter, buf.buf, buf.len);
+ else
+ retval = grep_buffer(&opt->grep_filter,
+ commit->buffer, strlen(commit->buffer));
+ strbuf_release(&buf);
+ return retval;
}
static inline int want_ancestry(struct rev_info *revs)
@@ -2374,29 +2429,28 @@ static struct commit *get_revision_internal(struct rev_info *revs)
}
/*
- * Now pick up what they want to give us
+ * If our max_count counter has reached zero, then we are done. We
+ * don't simply return NULL because we still might need to show
+ * boundary commits. But we want to avoid calling get_revision_1, which
+ * might do a considerable amount of work finding the next commit only
+ * for us to throw it away.
+ *
+ * If it is non-zero, then either we don't have a max_count at all
+ * (-1), or it is still counting, in which case we decrement.
*/
- c = get_revision_1(revs);
- if (c) {
- while (0 < revs->skip_count) {
- revs->skip_count--;
- c = get_revision_1(revs);
- if (!c)
- break;
+ if (revs->max_count) {
+ c = get_revision_1(revs);
+ if (c) {
+ while (0 < revs->skip_count) {
+ revs->skip_count--;
+ c = get_revision_1(revs);
+ if (!c)
+ break;
+ }
}
- }
- /*
- * Check the max_count.
- */
- switch (revs->max_count) {
- case -1:
- break;
- case 0:
- c = NULL;
- break;
- default:
- revs->max_count--;
+ if (revs->max_count > 0)
+ revs->max_count--;
}
if (c)
diff --git a/revision.h b/revision.h
index 863f4f6..a95bd0b 100644
--- a/revision.h
+++ b/revision.h
@@ -41,6 +41,10 @@ struct rev_cmdline_info {
} *rev;
};
+#define REVISION_WALK_WALK 0
+#define REVISION_WALK_NO_WALK_SORTED 1
+#define REVISION_WALK_NO_WALK_UNSORTED 2
+
struct rev_info {
/* Starting list */
struct commit_list *commits;
@@ -62,7 +66,7 @@ struct rev_info {
/* Traversal flags */
unsigned int dense:1,
prune:1,
- no_walk:1,
+ no_walk:2,
show_all:1,
remove_empty_trees:1,
simplify_history:1,
@@ -184,6 +188,7 @@ struct setup_revision_opt {
void (*tweak)(struct rev_info *, struct setup_revision_opt *);
const char *submodule;
int assume_dashdash;
+ unsigned revarg_opt;
};
extern void init_revisions(struct rev_info *revs, const char *prefix);
@@ -191,7 +196,9 @@ extern int setup_revisions(int argc, const char **argv, struct rev_info *revs, s
extern void parse_revision_opt(struct rev_info *revs, struct parse_opt_ctx_t *ctx,
const struct option *options,
const char * const usagestr[]);
-extern int handle_revision_arg(const char *arg, struct rev_info *revs,int flags,int cant_be_filename);
+#define REVARG_CANNOT_BE_FILENAME 01
+#define REVARG_COMMITTISH 02
+extern int handle_revision_arg(const char *arg, struct rev_info *revs, int flags, unsigned revarg_opt);
extern void reset_revision_walk(void);
extern int prepare_revision_walk(struct rev_info *revs);
diff --git a/run-command.c b/run-command.c
index f9922b9..1101ef7 100644
--- a/run-command.c
+++ b/run-command.c
@@ -53,13 +53,14 @@ static void mark_child_for_cleanup(pid_t pid)
static void clear_child_for_cleanup(pid_t pid)
{
- struct child_to_clean **last, *p;
+ struct child_to_clean **pp;
- last = &children_to_clean;
- for (p = children_to_clean; p; p = p->next) {
- if (p->pid == pid) {
- *last = p->next;
- free(p);
+ for (pp = &children_to_clean; *pp; pp = &(*pp)->next) {
+ struct child_to_clean *clean_me = *pp;
+
+ if (clean_me->pid == pid) {
+ *pp = clean_me->next;
+ free(clean_me);
return;
}
}
diff --git a/sequencer.c b/sequencer.c
index bf078f2..e3723d2 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -17,7 +17,9 @@
#define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
-void remove_sequencer_state(void)
+const char sign_off_header[] = "Signed-off-by: ";
+
+static void remove_sequencer_state(void)
{
struct strbuf seq_dir = STRBUF_INIT;
@@ -233,6 +235,9 @@ static int do_recursive_merge(struct commit *base, struct commit *next,
die(_("%s: Unable to write new index file"), action_name(opts));
rollback_lock_file(&index_lock);
+ if (opts->signoff)
+ append_signoff(msgbuf, 0);
+
if (!clean) {
int i;
strbuf_addstr(msgbuf, "\nConflicts:\n");
@@ -311,6 +316,9 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,
if (allow_empty)
argv_array_push(&array, "--allow-empty");
+ if (opts->allow_empty_message)
+ argv_array_push(&array, "--allow-empty-message");
+
rc = run_command_v_opt(array.argv, RUN_GIT_CMD);
argv_array_clear(&array);
return rc;
@@ -543,7 +551,11 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
static void prepare_revs(struct replay_opts *opts)
{
- if (opts->action != REPLAY_REVERT)
+ /*
+ * picking (but not reverting) ranges (but not individual revisions)
+ * should be done in reverse
+ */
+ if (opts->action == REPLAY_PICK && !opts->revs->no_walk)
opts->revs->reverse ^= 1;
if (prepare_revision_walk(opts->revs))
@@ -1004,3 +1016,63 @@ int sequencer_pick_revisions(struct replay_opts *opts)
save_opts(opts);
return pick_commits(todo_list, opts);
}
+
+static int ends_rfc2822_footer(struct strbuf *sb, int ignore_footer)
+{
+ int ch;
+ int hit = 0;
+ int i, j, k;
+ int len = sb->len - ignore_footer;
+ int first = 1;
+ const char *buf = sb->buf;
+
+ for (i = len - 1; i > 0; i--) {
+ if (hit && buf[i] == '\n')
+ break;
+ hit = (buf[i] == '\n');
+ }
+
+ while (i < len - 1 && buf[i] == '\n')
+ i++;
+
+ for (; i < len; i = k) {
+ for (k = i; k < len && buf[k] != '\n'; k++)
+ ; /* do nothing */
+ k++;
+
+ if ((buf[k] == ' ' || buf[k] == '\t') && !first)
+ continue;
+
+ first = 0;
+
+ for (j = 0; i + j < len; j++) {
+ ch = buf[i + j];
+ if (ch == ':')
+ break;
+ if (isalnum(ch) ||
+ (ch == '-'))
+ continue;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+void append_signoff(struct strbuf *msgbuf, int ignore_footer)
+{
+ struct strbuf sob = STRBUF_INIT;
+ int i;
+
+ strbuf_addstr(&sob, sign_off_header);
+ strbuf_addstr(&sob, fmt_name(getenv("GIT_COMMITTER_NAME"),
+ getenv("GIT_COMMITTER_EMAIL")));
+ strbuf_addch(&sob, '\n');
+ for (i = msgbuf->len - 1 - ignore_footer; i > 0 && msgbuf->buf[i - 1] != '\n'; i--)
+ ; /* do nothing */
+ if (prefixcmp(msgbuf->buf + i, sob.buf)) {
+ if (!i || !ends_rfc2822_footer(msgbuf, ignore_footer))
+ strbuf_splice(msgbuf, msgbuf->len - ignore_footer, 0, "\n", 1);
+ strbuf_splice(msgbuf, msgbuf->len - ignore_footer, 0, sob.buf, sob.len);
+ }
+ strbuf_release(&sob);
+}
diff --git a/sequencer.h b/sequencer.h
index aa5f17c..9d57d57 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -30,6 +30,7 @@ struct replay_opts {
int allow_ff;
int allow_rerere_auto;
int allow_empty;
+ int allow_empty_message;
int keep_redundant_commits;
int mainline;
@@ -43,9 +44,10 @@ struct replay_opts {
struct rev_info *revs;
};
-/* Removes SEQ_DIR. */
-extern void remove_sequencer_state(void);
-
int sequencer_pick_revisions(struct replay_opts *opts);
+extern const char sign_off_header[];
+
+void append_signoff(struct strbuf *msgbuf, int ignore_footer);
+
#endif
diff --git a/setup.c b/setup.c
index 7663a4c..3a1b2fd 100644
--- a/setup.c
+++ b/setup.c
@@ -77,9 +77,6 @@ static void NORETURN die_verify_filename(const char *prefix,
const char *arg,
int diagnose_misspelt_rev)
{
- unsigned char sha1[20];
- unsigned mode;
-
if (!diagnose_misspelt_rev)
die("%s: no such path in the working tree.\n"
"Use 'git <command> -- <path>...' to specify paths that do not exist locally.",
@@ -88,11 +85,10 @@ static void NORETURN die_verify_filename(const char *prefix,
* Saying "'(icase)foo' does not exist in the index" when the
* user gave us ":(icase)foo" is just stupid. A magic pathspec
* begins with a colon and is followed by a non-alnum; do not
- * let get_sha1_with_mode_1(only_to_die=1) to even trigger.
+ * let maybe_die_on_misspelt_object_name() even trigger.
*/
if (!(arg[0] == ':' && !isalnum(arg[1])))
- /* try a detailed diagnostic ... */
- get_sha1_with_mode_1(arg, sha1, &mode, 1, prefix);
+ maybe_die_on_misspelt_object_name(arg, prefix);
/* ... or fall back the most general message. */
die("ambiguous argument '%s': unknown revision or path not in the working tree.\n"
diff --git a/sha1-array.c b/sha1-array.c
index b2f47f9..6f4a224 100644
--- a/sha1-array.c
+++ b/sha1-array.c
@@ -14,7 +14,7 @@ static int void_hashcmp(const void *a, const void *b)
return hashcmp(a, b);
}
-void sha1_array_sort(struct sha1_array *array)
+static void sha1_array_sort(struct sha1_array *array)
{
qsort(array->sha1, array->nr, sizeof(*array->sha1), void_hashcmp);
array->sorted = 1;
diff --git a/sha1-array.h b/sha1-array.h
index 4499b5d..72bb33b 100644
--- a/sha1-array.h
+++ b/sha1-array.h
@@ -11,7 +11,6 @@ struct sha1_array {
#define SHA1_ARRAY_INIT { NULL, 0, 0, 0 }
void sha1_array_append(struct sha1_array *array, const unsigned char *sha1);
-void sha1_array_sort(struct sha1_array *array);
int sha1_array_lookup(struct sha1_array *array, const unsigned char *sha1);
void sha1_array_clear(struct sha1_array *array);
diff --git a/sha1_file.c b/sha1_file.c
index af5cfbd..9152974 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -731,6 +731,24 @@ void free_pack_by_name(const char *pack_name)
}
}
+static unsigned int get_max_fd_limit(void)
+{
+#ifdef RLIMIT_NOFILE
+ struct rlimit lim;
+
+ if (getrlimit(RLIMIT_NOFILE, &lim))
+ die_errno("cannot get RLIMIT_NOFILE");
+
+ return lim.rlim_cur;
+#elif defined(_SC_OPEN_MAX)
+ return sysconf(_SC_OPEN_MAX);
+#elif defined(OPEN_MAX)
+ return OPEN_MAX;
+#else
+ return 1; /* see the caller ;-) */
+#endif
+}
+
/*
* Do not call this directly as this leaks p->pack_fd on error return;
* call open_packed_git() instead.
@@ -747,13 +765,7 @@ static int open_packed_git_1(struct packed_git *p)
return error("packfile %s index unavailable", p->pack_name);
if (!pack_max_fds) {
- struct rlimit lim;
- unsigned int max_fds;
-
- if (getrlimit(RLIMIT_NOFILE, &lim))
- die_errno("cannot get RLIMIT_NOFILE");
-
- max_fds = lim.rlim_cur;
+ unsigned int max_fds = get_max_fd_limit();
/* Save 3 for stdin/stdout/stderr, 22 for work */
if (25 < max_fds)
diff --git a/sha1_name.c b/sha1_name.c
index 5d81ea0..95003c7 100644
--- a/sha1_name.c
+++ b/sha1_name.c
@@ -9,14 +9,82 @@
static int get_sha1_oneline(const char *, unsigned char *, struct commit_list *);
-static int find_short_object_filename(int len, const char *name, unsigned char *sha1)
+typedef int (*disambiguate_hint_fn)(const unsigned char *, void *);
+
+struct disambiguate_state {
+ disambiguate_hint_fn fn;
+ void *cb_data;
+ unsigned char candidate[20];
+ unsigned candidate_exists:1;
+ unsigned candidate_checked:1;
+ unsigned candidate_ok:1;
+ unsigned disambiguate_fn_used:1;
+ unsigned ambiguous:1;
+ unsigned always_call_fn:1;
+};
+
+static void update_candidates(struct disambiguate_state *ds, const unsigned char *current)
+{
+ if (ds->always_call_fn) {
+ ds->ambiguous = ds->fn(current, ds->cb_data) ? 1 : 0;
+ return;
+ }
+ if (!ds->candidate_exists) {
+ /* this is the first candidate */
+ hashcpy(ds->candidate, current);
+ ds->candidate_exists = 1;
+ return;
+ } else if (!hashcmp(ds->candidate, current)) {
+ /* the same as what we already have seen */
+ return;
+ }
+
+ if (!ds->fn) {
+ /* cannot disambiguate between ds->candidate and current */
+ ds->ambiguous = 1;
+ return;
+ }
+
+ if (!ds->candidate_checked) {
+ ds->candidate_ok = ds->fn(ds->candidate, ds->cb_data);
+ ds->disambiguate_fn_used = 1;
+ ds->candidate_checked = 1;
+ }
+
+ if (!ds->candidate_ok) {
+ /* discard the candidate; we know it does not satisify fn */
+ hashcpy(ds->candidate, current);
+ ds->candidate_checked = 0;
+ return;
+ }
+
+ /* if we reach this point, we know ds->candidate satisfies fn */
+ if (ds->fn(current, ds->cb_data)) {
+ /*
+ * if both current and candidate satisfy fn, we cannot
+ * disambiguate.
+ */
+ ds->candidate_ok = 0;
+ ds->ambiguous = 1;
+ }
+
+ /* otherwise, current can be discarded and candidate is still good */
+}
+
+static void find_short_object_filename(int len, const char *hex_pfx, struct disambiguate_state *ds)
{
struct alternate_object_database *alt;
char hex[40];
- int found = 0;
static struct alternate_object_database *fakeent;
if (!fakeent) {
+ /*
+ * Create a "fake" alternate object database that
+ * points to our own object database, to make it
+ * easier to get a temporary working space in
+ * alt->name/alt->base while iterating over the
+ * object databases including our own.
+ */
const char *objdir = get_object_directory();
int objdir_len = strlen(objdir);
int entlen = objdir_len + 43;
@@ -27,33 +95,28 @@ static int find_short_object_filename(int len, const char *name, unsigned char *
}
fakeent->next = alt_odb_list;
- sprintf(hex, "%.2s", name);
- for (alt = fakeent; alt && found < 2; alt = alt->next) {
+ sprintf(hex, "%.2s", hex_pfx);
+ for (alt = fakeent; alt && !ds->ambiguous; alt = alt->next) {
struct dirent *de;
DIR *dir;
- sprintf(alt->name, "%.2s/", name);
+ sprintf(alt->name, "%.2s/", hex_pfx);
dir = opendir(alt->base);
if (!dir)
continue;
- while ((de = readdir(dir)) != NULL) {
+
+ while (!ds->ambiguous && (de = readdir(dir)) != NULL) {
+ unsigned char sha1[20];
+
if (strlen(de->d_name) != 38)
continue;
- if (memcmp(de->d_name, name + 2, len - 2))
+ if (memcmp(de->d_name, hex_pfx + 2, len - 2))
continue;
- if (!found) {
- memcpy(hex + 2, de->d_name, 38);
- found++;
- }
- else if (memcmp(hex + 2, de->d_name, 38)) {
- found = 2;
- break;
- }
+ memcpy(hex + 2, de->d_name, 38);
+ if (!get_sha1_hex(hex, sha1))
+ update_candidates(ds, sha1);
}
closedir(dir);
}
- if (found == 1)
- return get_sha1_hex(hex, sha1) == 0;
- return found;
}
static int match_sha(unsigned len, const unsigned char *a, const unsigned char *b)
@@ -71,103 +134,157 @@ static int match_sha(unsigned len, const unsigned char *a, const unsigned char *
return 1;
}
-static int find_short_packed_object(int len, const unsigned char *match, unsigned char *sha1)
+static void unique_in_pack(int len,
+ const unsigned char *bin_pfx,
+ struct packed_git *p,
+ struct disambiguate_state *ds)
{
- struct packed_git *p;
- const unsigned char *found_sha1 = NULL;
- int found = 0;
-
- prepare_packed_git();
- for (p = packed_git; p && found < 2; p = p->next) {
- uint32_t num, last;
- uint32_t first = 0;
- open_pack_index(p);
- num = p->num_objects;
- last = num;
- while (first < last) {
- uint32_t mid = (first + last) / 2;
- const unsigned char *now;
- int cmp;
-
- now = nth_packed_object_sha1(p, mid);
- cmp = hashcmp(match, now);
- if (!cmp) {
- first = mid;
- break;
- }
- if (cmp > 0) {
- first = mid+1;
- continue;
- }
- last = mid;
+ uint32_t num, last, i, first = 0;
+ const unsigned char *current = NULL;
+
+ open_pack_index(p);
+ num = p->num_objects;
+ last = num;
+ while (first < last) {
+ uint32_t mid = (first + last) / 2;
+ const unsigned char *current;
+ int cmp;
+
+ current = nth_packed_object_sha1(p, mid);
+ cmp = hashcmp(bin_pfx, current);
+ if (!cmp) {
+ first = mid;
+ break;
}
- if (first < num) {
- const unsigned char *now, *next;
- now = nth_packed_object_sha1(p, first);
- if (match_sha(len, match, now)) {
- next = nth_packed_object_sha1(p, first+1);
- if (!next|| !match_sha(len, match, next)) {
- /* unique within this pack */
- if (!found) {
- found_sha1 = now;
- found++;
- }
- else if (hashcmp(found_sha1, now)) {
- found = 2;
- break;
- }
- }
- else {
- /* not even unique within this pack */
- found = 2;
- break;
- }
- }
+ if (cmp > 0) {
+ first = mid+1;
+ continue;
}
+ last = mid;
+ }
+
+ /*
+ * At this point, "first" is the location of the lowest object
+ * with an object name that could match "bin_pfx". See if we have
+ * 0, 1 or more objects that actually match(es).
+ */
+ for (i = first; i < num && !ds->ambiguous; i++) {
+ current = nth_packed_object_sha1(p, i);
+ if (!match_sha(len, bin_pfx, current))
+ break;
+ update_candidates(ds, current);
}
- if (found == 1)
- hashcpy(sha1, found_sha1);
- return found;
+}
+
+static void find_short_packed_object(int len, const unsigned char *bin_pfx,
+ struct disambiguate_state *ds)
+{
+ struct packed_git *p;
+
+ prepare_packed_git();
+ for (p = packed_git; p && !ds->ambiguous; p = p->next)
+ unique_in_pack(len, bin_pfx, p, ds);
}
#define SHORT_NAME_NOT_FOUND (-1)
#define SHORT_NAME_AMBIGUOUS (-2)
-static int find_unique_short_object(int len, char *canonical,
- unsigned char *res, unsigned char *sha1)
+static int finish_object_disambiguation(struct disambiguate_state *ds,
+ unsigned char *sha1)
{
- int has_unpacked, has_packed;
- unsigned char unpacked_sha1[20], packed_sha1[20];
+ if (ds->ambiguous)
+ return SHORT_NAME_AMBIGUOUS;
- prepare_alt_odb();
- has_unpacked = find_short_object_filename(len, canonical, unpacked_sha1);
- has_packed = find_short_packed_object(len, res, packed_sha1);
- if (!has_unpacked && !has_packed)
+ if (!ds->candidate_exists)
return SHORT_NAME_NOT_FOUND;
- if (1 < has_unpacked || 1 < has_packed)
+
+ if (!ds->candidate_checked)
+ /*
+ * If this is the only candidate, there is no point
+ * calling the disambiguation hint callback.
+ *
+ * On the other hand, if the current candidate
+ * replaced an earlier candidate that did _not_ pass
+ * the disambiguation hint callback, then we do have
+ * more than one objects that match the short name
+ * given, so we should make sure this one matches;
+ * otherwise, if we discovered this one and the one
+ * that we previously discarded in the reverse order,
+ * we would end up showing different results in the
+ * same repository!
+ */
+ ds->candidate_ok = (!ds->disambiguate_fn_used ||
+ ds->fn(ds->candidate, ds->cb_data));
+
+ if (!ds->candidate_ok)
return SHORT_NAME_AMBIGUOUS;
- if (has_unpacked != has_packed) {
- hashcpy(sha1, (has_packed ? packed_sha1 : unpacked_sha1));
+
+ hashcpy(sha1, ds->candidate);
+ return 0;
+}
+
+static int disambiguate_commit_only(const unsigned char *sha1, void *cb_data_unused)
+{
+ int kind = sha1_object_info(sha1, NULL);
+ return kind == OBJ_COMMIT;
+}
+
+static int disambiguate_committish_only(const unsigned char *sha1, void *cb_data_unused)
+{
+ struct object *obj;
+ int kind;
+
+ kind = sha1_object_info(sha1, NULL);
+ if (kind == OBJ_COMMIT)
+ return 1;
+ if (kind != OBJ_TAG)
return 0;
- }
- /* Both have unique ones -- do they match? */
- if (hashcmp(packed_sha1, unpacked_sha1))
- return SHORT_NAME_AMBIGUOUS;
- hashcpy(sha1, packed_sha1);
+
+ /* We need to do this the hard way... */
+ obj = deref_tag(lookup_object(sha1), NULL, 0);
+ if (obj && obj->type == OBJ_COMMIT)
+ return 1;
return 0;
}
-static int get_short_sha1(const char *name, int len, unsigned char *sha1,
- int quietly)
+static int disambiguate_tree_only(const unsigned char *sha1, void *cb_data_unused)
{
- int i, status;
- char canonical[40];
- unsigned char res[20];
+ int kind = sha1_object_info(sha1, NULL);
+ return kind == OBJ_TREE;
+}
- if (len < MINIMUM_ABBREV || len > 40)
- return -1;
- hashclr(res);
- memset(canonical, 'x', 40);
+static int disambiguate_treeish_only(const unsigned char *sha1, void *cb_data_unused)
+{
+ struct object *obj;
+ int kind;
+
+ kind = sha1_object_info(sha1, NULL);
+ if (kind == OBJ_TREE || kind == OBJ_COMMIT)
+ return 1;
+ if (kind != OBJ_TAG)
+ return 0;
+
+ /* We need to do this the hard way... */
+ obj = deref_tag(lookup_object(sha1), NULL, 0);
+ if (obj && (obj->type == OBJ_TREE || obj->type == OBJ_COMMIT))
+ return 1;
+ return 0;
+}
+
+static int disambiguate_blob_only(const unsigned char *sha1, void *cb_data_unused)
+{
+ int kind = sha1_object_info(sha1, NULL);
+ return kind == OBJ_BLOB;
+}
+
+static int prepare_prefixes(const char *name, int len,
+ unsigned char *bin_pfx,
+ char *hex_pfx)
+{
+ int i;
+
+ hashclr(bin_pfx);
+ memset(hex_pfx, 'x', 40);
for (i = 0; i < len ;i++) {
unsigned char c = name[i];
unsigned char val;
@@ -181,18 +298,76 @@ static int get_short_sha1(const char *name, int len, unsigned char *sha1,
}
else
return -1;
- canonical[i] = c;
+ hex_pfx[i] = c;
if (!(i & 1))
val <<= 4;
- res[i >> 1] |= val;
+ bin_pfx[i >> 1] |= val;
}
+ return 0;
+}
+
+static int get_short_sha1(const char *name, int len, unsigned char *sha1,
+ unsigned flags)
+{
+ int status;
+ char hex_pfx[40];
+ unsigned char bin_pfx[20];
+ struct disambiguate_state ds;
+ int quietly = !!(flags & GET_SHA1_QUIETLY);
+
+ if (len < MINIMUM_ABBREV || len > 40)
+ return -1;
+ if (prepare_prefixes(name, len, bin_pfx, hex_pfx) < 0)
+ return -1;
+
+ prepare_alt_odb();
+
+ memset(&ds, 0, sizeof(ds));
+ if (flags & GET_SHA1_COMMIT)
+ ds.fn = disambiguate_commit_only;
+ else if (flags & GET_SHA1_COMMITTISH)
+ ds.fn = disambiguate_committish_only;
+ else if (flags & GET_SHA1_TREE)
+ ds.fn = disambiguate_tree_only;
+ else if (flags & GET_SHA1_TREEISH)
+ ds.fn = disambiguate_treeish_only;
+ else if (flags & GET_SHA1_BLOB)
+ ds.fn = disambiguate_blob_only;
+
+ find_short_object_filename(len, hex_pfx, &ds);
+ find_short_packed_object(len, bin_pfx, &ds);
+ status = finish_object_disambiguation(&ds, sha1);
- status = find_unique_short_object(i, canonical, res, sha1);
if (!quietly && (status == SHORT_NAME_AMBIGUOUS))
- return error("short SHA1 %.*s is ambiguous.", len, canonical);
+ return error("short SHA1 %.*s is ambiguous.", len, hex_pfx);
return status;
}
+
+int for_each_abbrev(const char *prefix, each_abbrev_fn fn, void *cb_data)
+{
+ char hex_pfx[40];
+ unsigned char bin_pfx[20];
+ struct disambiguate_state ds;
+ int len = strlen(prefix);
+
+ if (len < MINIMUM_ABBREV || len > 40)
+ return -1;
+ if (prepare_prefixes(prefix, len, bin_pfx, hex_pfx) < 0)
+ return -1;
+
+ prepare_alt_odb();
+
+ memset(&ds, 0, sizeof(ds));
+ ds.always_call_fn = 1;
+ ds.cb_data = cb_data;
+ ds.fn = fn;
+
+ find_short_object_filename(len, hex_pfx, &ds);
+ find_short_packed_object(len, bin_pfx, &ds);
+ return ds.ambiguous;
+}
+
const char *find_unique_abbrev(const unsigned char *sha1, int len)
{
int status, exists;
@@ -204,7 +379,7 @@ const char *find_unique_abbrev(const unsigned char *sha1, int len)
return hex;
while (len < 40) {
unsigned char sha1_ret[20];
- status = get_short_sha1(hex, len, sha1_ret, 1);
+ status = get_short_sha1(hex, len, sha1_ret, GET_SHA1_QUIETLY);
if (exists
? !status
: status == SHORT_NAME_NOT_FOUND) {
@@ -255,7 +430,7 @@ static inline int upstream_mark(const char *string, int len)
return 0;
}
-static int get_sha1_1(const char *name, int len, unsigned char *sha1);
+static int get_sha1_1(const char *name, int len, unsigned char *sha1, unsigned lookup_flags);
static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
{
@@ -292,7 +467,7 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
ret = interpret_branch_name(str+at, &buf);
if (ret > 0) {
/* substitute this branch name and restart */
- return get_sha1_1(buf.buf, buf.len, sha1);
+ return get_sha1_1(buf.buf, buf.len, sha1, 0);
} else if (ret == 0) {
return -1;
}
@@ -362,7 +537,7 @@ static int get_parent(const char *name, int len,
unsigned char *result, int idx)
{
unsigned char sha1[20];
- int ret = get_sha1_1(name, len, sha1);
+ int ret = get_sha1_1(name, len, sha1, GET_SHA1_COMMITTISH);
struct commit *commit;
struct commit_list *p;
@@ -395,7 +570,7 @@ static int get_nth_ancestor(const char *name, int len,
struct commit *commit;
int ret;
- ret = get_sha1_1(name, len, sha1);
+ ret = get_sha1_1(name, len, sha1, GET_SHA1_COMMITTISH);
if (ret)
return ret;
commit = lookup_commit_reference(sha1);
@@ -441,6 +616,7 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)
unsigned char outer[20];
const char *sp;
unsigned int expected_type = 0;
+ unsigned lookup_flags = 0;
struct object *o;
/*
@@ -476,7 +652,10 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)
else
return -1;
- if (get_sha1_1(name, sp - name - 2, outer))
+ if (expected_type == OBJ_COMMIT)
+ lookup_flags = GET_SHA1_COMMITTISH;
+
+ if (get_sha1_1(name, sp - name - 2, outer, lookup_flags))
return -1;
o = parse_object(outer);
@@ -525,6 +704,7 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)
static int get_describe_name(const char *name, int len, unsigned char *sha1)
{
const char *cp;
+ unsigned flags = GET_SHA1_QUIETLY | GET_SHA1_COMMIT;
for (cp = name + len - 1; name + 2 <= cp; cp--) {
char ch = *cp;
@@ -535,14 +715,14 @@ static int get_describe_name(const char *name, int len, unsigned char *sha1)
if (ch == 'g' && cp[-1] == '-') {
cp++;
len -= cp - name;
- return get_short_sha1(cp, len, sha1, 1);
+ return get_short_sha1(cp, len, sha1, flags);
}
}
}
return -1;
}
-static int get_sha1_1(const char *name, int len, unsigned char *sha1)
+static int get_sha1_1(const char *name, int len, unsigned char *sha1, unsigned lookup_flags)
{
int ret, has_suffix;
const char *cp;
@@ -587,7 +767,7 @@ static int get_sha1_1(const char *name, int len, unsigned char *sha1)
if (!ret)
return 0;
- return get_short_sha1(name, len, sha1, 0);
+ return get_short_sha1(name, len, sha1, lookup_flags);
}
/*
@@ -769,7 +949,7 @@ int get_sha1_mb(const char *name, unsigned char *sha1)
struct strbuf sb;
strbuf_init(&sb, dots - name);
strbuf_add(&sb, name, dots - name);
- st = get_sha1(sb.buf, sha1_tmp);
+ st = get_sha1_committish(sb.buf, sha1_tmp);
strbuf_release(&sb);
}
if (st)
@@ -778,7 +958,7 @@ int get_sha1_mb(const char *name, unsigned char *sha1)
if (!one)
return -1;
- if (get_sha1(dots[3] ? (dots + 3) : "HEAD", sha1_tmp))
+ if (get_sha1_committish(dots[3] ? (dots + 3) : "HEAD", sha1_tmp))
return -1;
two = lookup_commit_reference_gently(sha1_tmp, 0);
if (!two)
@@ -905,7 +1085,52 @@ int strbuf_check_branch_ref(struct strbuf *sb, const char *name)
int get_sha1(const char *name, unsigned char *sha1)
{
struct object_context unused;
- return get_sha1_with_context(name, sha1, &unused);
+ return get_sha1_with_context(name, 0, sha1, &unused);
+}
+
+/*
+ * Many callers know that the user meant to name a committish by
+ * syntactical positions where the object name appears. Calling this
+ * function allows the machinery to disambiguate shorter-than-unique
+ * abbreviated object names between committish and others.
+ *
+ * Note that this does NOT error out when the named object is not a
+ * committish. It is merely to give a hint to the disambiguation
+ * machinery.
+ */
+int get_sha1_committish(const char *name, unsigned char *sha1)
+{
+ struct object_context unused;
+ return get_sha1_with_context(name, GET_SHA1_COMMITTISH,
+ sha1, &unused);
+}
+
+int get_sha1_treeish(const char *name, unsigned char *sha1)
+{
+ struct object_context unused;
+ return get_sha1_with_context(name, GET_SHA1_TREEISH,
+ sha1, &unused);
+}
+
+int get_sha1_commit(const char *name, unsigned char *sha1)
+{
+ struct object_context unused;
+ return get_sha1_with_context(name, GET_SHA1_COMMIT,
+ sha1, &unused);
+}
+
+int get_sha1_tree(const char *name, unsigned char *sha1)
+{
+ struct object_context unused;
+ return get_sha1_with_context(name, GET_SHA1_TREE,
+ sha1, &unused);
+}
+
+int get_sha1_blob(const char *name, unsigned char *sha1)
+{
+ struct object_context unused;
+ return get_sha1_with_context(name, GET_SHA1_BLOB,
+ sha1, &unused);
}
/* Must be called only when object_name:filename doesn't exist. */
@@ -1004,16 +1229,6 @@ static void diagnose_invalid_index_path(int stage,
}
-int get_sha1_with_mode_1(const char *name, unsigned char *sha1, unsigned *mode,
- int only_to_die, const char *prefix)
-{
- struct object_context oc;
- int ret;
- ret = get_sha1_with_context_1(name, sha1, &oc, only_to_die, prefix);
- *mode = oc.mode;
- return ret;
-}
-
static char *resolve_relative_path(const char *rel)
{
if (prefixcmp(rel, "./") && prefixcmp(rel, "../"))
@@ -1031,20 +1246,24 @@ static char *resolve_relative_path(const char *rel)
rel);
}
-int get_sha1_with_context_1(const char *name, unsigned char *sha1,
- struct object_context *oc,
- int only_to_die, const char *prefix)
+static int get_sha1_with_context_1(const char *name,
+ unsigned flags,
+ const char *prefix,
+ unsigned char *sha1,
+ struct object_context *oc)
{
int ret, bracket_depth;
int namelen = strlen(name);
const char *cp;
+ int only_to_die = flags & GET_SHA1_ONLY_TO_DIE;
memset(oc, 0, sizeof(*oc));
oc->mode = S_IFINVALID;
- ret = get_sha1_1(name, namelen, sha1);
+ ret = get_sha1_1(name, namelen, sha1, flags);
if (!ret)
return ret;
- /* sha1:path --> object name of path in ent sha1
+ /*
+ * sha1:path --> object name of path in ent sha1
* :path -> object name of absolute path in index
* :./path -> object name of path relative to cwd in index
* :[0-3]:path -> object name of path in index at stage
@@ -1119,7 +1338,7 @@ int get_sha1_with_context_1(const char *name, unsigned char *sha1,
strncpy(object_name, name, cp-name);
object_name[cp-name] = '\0';
}
- if (!get_sha1_1(name, cp-name, tree_sha1)) {
+ if (!get_sha1_1(name, cp-name, tree_sha1, GET_SHA1_TREEISH)) {
const char *filename = cp+1;
char *new_filename = NULL;
@@ -1146,3 +1365,22 @@ int get_sha1_with_context_1(const char *name, unsigned char *sha1,
}
return ret;
}
+
+/*
+ * Call this function when you know "name" given by the end user must
+ * name an object but it doesn't; the function _may_ die with a better
+ * diagnostic message than "no such object 'name'", e.g. "Path 'doc' does not
+ * exist in 'HEAD'" when given "HEAD:doc", or it may return in which case
+ * you have a chance to diagnose the error further.
+ */
+void maybe_die_on_misspelt_object_name(const char *name, const char *prefix)
+{
+ struct object_context oc;
+ unsigned char sha1[20];
+ get_sha1_with_context_1(name, GET_SHA1_ONLY_TO_DIE, prefix, sha1, &oc);
+}
+
+int get_sha1_with_context(const char *str, unsigned flags, unsigned char *sha1, struct object_context *orc)
+{
+ return get_sha1_with_context_1(str, flags, NULL, sha1, orc);
+}
diff --git a/strbuf.c b/strbuf.c
index ec88266..0510f76 100644
--- a/strbuf.c
+++ b/strbuf.c
@@ -445,8 +445,8 @@ static int is_rfc3986_unreserved(char ch)
ch == '-' || ch == '_' || ch == '.' || ch == '~';
}
-void strbuf_add_urlencode(struct strbuf *sb, const char *s, size_t len,
- int reserved)
+static void strbuf_add_urlencode(struct strbuf *sb, const char *s, size_t len,
+ int reserved)
{
strbuf_grow(sb, len);
while (len--) {
@@ -465,15 +465,6 @@ void strbuf_addstr_urlencode(struct strbuf *sb, const char *s,
strbuf_add_urlencode(sb, s, strlen(s), reserved);
}
-void strbuf_addf_ln(struct strbuf *sb, const char *fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
- strbuf_vaddf(sb, fmt, ap);
- va_end(ap);
- strbuf_addch(sb, '\n');
-}
-
int printf_ln(const char *fmt, ...)
{
int ret;
diff --git a/strbuf.h b/strbuf.h
index b888d40..be941ee 100644
--- a/strbuf.h
+++ b/strbuf.h
@@ -99,8 +99,6 @@ __attribute__((format (printf,2,3)))
extern void strbuf_addf(struct strbuf *sb, const char *fmt, ...);
__attribute__((format (printf,2,0)))
extern void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap);
-__attribute__((format (printf,2,3)))
-extern void strbuf_addf_ln(struct strbuf *sb, const char *fmt, ...);
extern void strbuf_add_lines(struct strbuf *sb, const char *prefix, const char *buf, size_t size);
@@ -126,8 +124,6 @@ extern int launch_editor(const char *path, struct strbuf *buffer, const char *co
extern int strbuf_branchname(struct strbuf *sb, const char *name);
extern int strbuf_check_branch_ref(struct strbuf *sb, const char *name);
-extern void strbuf_add_urlencode(struct strbuf *, const char *, size_t,
- int reserved);
extern void strbuf_addstr_urlencode(struct strbuf *, const char *,
int reserved);
diff --git a/string-list.c b/string-list.c
index d9810ab..c54b816 100644
--- a/string-list.c
+++ b/string-list.c
@@ -92,6 +92,23 @@ struct string_list_item *string_list_lookup(struct string_list *list, const char
return list->items + i;
}
+void string_list_remove_duplicates(struct string_list *list, int free_util)
+{
+ if (list->nr > 1) {
+ int src, dst;
+ for (src = dst = 1; src < list->nr; src++) {
+ if (!strcmp(list->items[dst - 1].string, list->items[src].string)) {
+ if (list->strdup_strings)
+ free(list->items[src].string);
+ if (free_util)
+ free(list->items[src].util);
+ } else
+ list->items[dst++] = list->items[src];
+ }
+ list->nr = dst;
+ }
+}
+
int for_each_string_list(struct string_list *list,
string_list_each_func_t fn, void *cb_data)
{
@@ -102,6 +119,43 @@ int for_each_string_list(struct string_list *list,
return ret;
}
+void filter_string_list(struct string_list *list, int free_util,
+ string_list_each_func_t want, void *cb_data)
+{
+ int src, dst = 0;
+ for (src = 0; src < list->nr; src++) {
+ if (want(&list->items[src], cb_data)) {
+ list->items[dst++] = list->items[src];
+ } else {
+ if (list->strdup_strings)
+ free(list->items[src].string);
+ if (free_util)
+ free(list->items[src].util);
+ }
+ }
+ list->nr = dst;
+}
+
+char *string_list_longest_prefix(const struct string_list *prefixes,
+ const char *string)
+{
+ int i, max_len = -1;
+ char *retval = NULL;
+
+ for (i = 0; i < prefixes->nr; i++) {
+ char *prefix = prefixes->items[i].string;
+ if (!prefixcmp(string, prefix)) {
+ int len = strlen(prefix);
+ if (len > max_len) {
+ retval = prefix;
+ max_len = len;
+ }
+ }
+ }
+
+ return retval;
+}
+
void string_list_clear(struct string_list *list, int free_util)
{
if (list->items) {
@@ -148,13 +202,23 @@ void print_string_list(const struct string_list *p, const char *text)
printf("%s:%p\n", p->items[i].string, p->items[i].util);
}
-struct string_list_item *string_list_append(struct string_list *list, const char *string)
+struct string_list_item *string_list_append_nodup(struct string_list *list,
+ char *string)
{
+ struct string_list_item *retval;
ALLOC_GROW(list->items, list->nr + 1, list->alloc);
- list->items[list->nr].string =
- list->strdup_strings ? xstrdup(string) : (char *)string;
- list->items[list->nr].util = NULL;
- return list->items + list->nr++;
+ retval = &list->items[list->nr++];
+ retval->string = string;
+ retval->util = NULL;
+ return retval;
+}
+
+struct string_list_item *string_list_append(struct string_list *list,
+ const char *string)
+{
+ return string_list_append_nodup(
+ list,
+ list->strdup_strings ? xstrdup(string) : (char *)string);
}
static int cmp_items(const void *a, const void *b)
@@ -194,3 +258,56 @@ void unsorted_string_list_delete_item(struct string_list *list, int i, int free_
list->items[i] = list->items[list->nr-1];
list->nr--;
}
+
+int string_list_split(struct string_list *list, const char *string,
+ int delim, int maxsplit)
+{
+ int count = 0;
+ const char *p = string, *end;
+
+ if (!list->strdup_strings)
+ die("internal error in string_list_split(): "
+ "list->strdup_strings must be set");
+ for (;;) {
+ count++;
+ if (maxsplit >= 0 && count > maxsplit) {
+ string_list_append(list, p);
+ return count;
+ }
+ end = strchr(p, delim);
+ if (end) {
+ string_list_append_nodup(list, xmemdupz(p, end - p));
+ p = end + 1;
+ } else {
+ string_list_append(list, p);
+ return count;
+ }
+ }
+}
+
+int string_list_split_in_place(struct string_list *list, char *string,
+ int delim, int maxsplit)
+{
+ int count = 0;
+ char *p = string, *end;
+
+ if (list->strdup_strings)
+ die("internal error in string_list_split_in_place(): "
+ "list->strdup_strings must not be set");
+ for (;;) {
+ count++;
+ if (maxsplit >= 0 && count > maxsplit) {
+ string_list_append(list, p);
+ return count;
+ }
+ end = strchr(p, delim);
+ if (end) {
+ *end = '\0';
+ string_list_append(list, p);
+ p = end + 1;
+ } else {
+ string_list_append(list, p);
+ return count;
+ }
+ }
+}
diff --git a/string-list.h b/string-list.h
index 0684cb7..5efd07b 100644
--- a/string-list.h
+++ b/string-list.h
@@ -29,6 +29,24 @@ int for_each_string_list(struct string_list *list,
#define for_each_string_list_item(item,list) \
for (item = (list)->items; item < (list)->items + (list)->nr; ++item)
+/*
+ * Apply want to each item in list, retaining only the ones for which
+ * the function returns true. If free_util is true, call free() on
+ * the util members of any items that have to be deleted. Preserve
+ * the order of the items that are retained.
+ */
+void filter_string_list(struct string_list *list, int free_util,
+ string_list_each_func_t want, void *cb_data);
+
+/*
+ * Return the longest string in prefixes that is a prefix (in the
+ * sense of prefixcmp()) of string, or NULL if no such prefix exists.
+ * This function does not require the string_list to be sorted (it
+ * does a linear search).
+ */
+char *string_list_longest_prefix(const struct string_list *prefixes, const char *string);
+
+
/* Use these functions only on sorted lists: */
int string_list_has_string(const struct string_list *list, const char *string);
int string_list_find_insert_index(const struct string_list *list, const char *string,
@@ -38,11 +56,64 @@ struct string_list_item *string_list_insert_at_index(struct string_list *list,
int insert_at, const char *string);
struct string_list_item *string_list_lookup(struct string_list *list, const char *string);
+/*
+ * Remove all but the first of consecutive entries with the same
+ * string value. If free_util is true, call free() on the util
+ * members of any items that have to be deleted.
+ */
+void string_list_remove_duplicates(struct string_list *sorted_list, int free_util);
+
+
/* Use these functions only on unsorted lists: */
+
+/*
+ * Add string to the end of list. If list->strdup_string is set, then
+ * string is copied; otherwise the new string_list_entry refers to the
+ * input string.
+ */
struct string_list_item *string_list_append(struct string_list *list, const char *string);
+
+/*
+ * Like string_list_append(), except string is never copied. When
+ * list->strdup_strings is set, this function can be used to hand
+ * ownership of a malloc()ed string to list without making an extra
+ * copy.
+ */
+struct string_list_item *string_list_append_nodup(struct string_list *list, char *string);
+
void sort_string_list(struct string_list *list);
int unsorted_string_list_has_string(struct string_list *list, const char *string);
struct string_list_item *unsorted_string_list_lookup(struct string_list *list,
const char *string);
+
void unsorted_string_list_delete_item(struct string_list *list, int i, int free_util);
+
+/*
+ * Split string into substrings on character delim and append the
+ * substrings to list. The input string is not modified.
+ * list->strdup_strings must be set, as new memory needs to be
+ * allocated to hold the substrings. If maxsplit is non-negative,
+ * then split at most maxsplit times. Return the number of substrings
+ * appended to list.
+ *
+ * Examples:
+ * string_list_split(l, "foo:bar:baz", ':', -1) -> ["foo", "bar", "baz"]
+ * string_list_split(l, "foo:bar:baz", ':', 0) -> ["foo:bar:baz"]
+ * string_list_split(l, "foo:bar:baz", ':', 1) -> ["foo", "bar:baz"]
+ * string_list_split(l, "foo:bar:", ':', -1) -> ["foo", "bar", ""]
+ * string_list_split(l, "", ':', -1) -> [""]
+ * string_list_split(l, ":", ':', -1) -> ["", ""]
+ */
+int string_list_split(struct string_list *list, const char *string,
+ int delim, int maxsplit);
+
+/*
+ * Like string_list_split(), except that string is split in-place: the
+ * delimiter characters in string are overwritten with NULs, and the
+ * new string_list_items point into string (which therefore must not
+ * be modified or freed while the string_list is in use).
+ * list->strdup_strings must *not* be set.
+ */
+int string_list_split_in_place(struct string_list *list, char *string,
+ int delim, int maxsplit);
#endif /* STRING_LIST_H */
diff --git a/submodule.c b/submodule.c
index 19dc6a6..50f213e 100644
--- a/submodule.c
+++ b/submodule.c
@@ -588,13 +588,13 @@ static void calculate_changed_submodule_paths(void)
initialized_fetch_ref_tips = 0;
}
-int fetch_populated_submodules(int num_options, const char **options,
+int fetch_populated_submodules(const struct argv_array *options,
const char *prefix, int command_line_option,
int quiet)
{
- int i, result = 0, argc = 0, default_argc;
+ int i, result = 0;
struct child_process cp;
- const char **argv;
+ struct argv_array argv = ARGV_ARRAY_INIT;
struct string_list_item *name_for_path;
const char *work_tree = get_git_work_tree();
if (!work_tree)
@@ -604,17 +604,13 @@ int fetch_populated_submodules(int num_options, const char **options,
if (read_cache() < 0)
die("index file corrupt");
- /* 6: "fetch" (options) --recurse-submodules-default default "--submodule-prefix" prefix NULL */
- argv = xcalloc(num_options + 6, sizeof(const char *));
- argv[argc++] = "fetch";
- for (i = 0; i < num_options; i++)
- argv[argc++] = options[i];
- argv[argc++] = "--recurse-submodules-default";
- default_argc = argc++;
- argv[argc++] = "--submodule-prefix";
+ argv_array_push(&argv, "fetch");
+ for (i = 0; i < options->argc; i++)
+ argv_array_push(&argv, options->argv[i]);
+ argv_array_push(&argv, "--recurse-submodules-default");
+ /* default value, "--submodule-prefix" and its value are added later */
memset(&cp, 0, sizeof(cp));
- cp.argv = argv;
cp.env = local_repo_env;
cp.git_cmd = 1;
cp.no_stdin = 1;
@@ -674,16 +670,21 @@ int fetch_populated_submodules(int num_options, const char **options,
if (!quiet)
printf("Fetching submodule %s%s\n", prefix, ce->name);
cp.dir = submodule_path.buf;
- argv[default_argc] = default_argv;
- argv[argc] = submodule_prefix.buf;
+ argv_array_push(&argv, default_argv);
+ argv_array_push(&argv, "--submodule-prefix");
+ argv_array_push(&argv, submodule_prefix.buf);
+ cp.argv = argv.argv;
if (run_command(&cp))
result = 1;
+ argv_array_pop(&argv);
+ argv_array_pop(&argv);
+ argv_array_pop(&argv);
}
strbuf_release(&submodule_path);
strbuf_release(&submodule_git_dir);
strbuf_release(&submodule_prefix);
}
- free(argv);
+ argv_array_clear(&argv);
out:
string_list_clear(&changed_submodule_paths, 1);
return result;
@@ -788,7 +789,7 @@ static int find_first_merges(struct object_array *result, const char *path,
die("revision walk setup failed");
while ((commit = get_revision(&revs)) != NULL) {
struct object *o = &(commit->object);
- if (in_merge_bases(b, &commit, 1))
+ if (in_merge_bases(b, commit))
add_object_array(o, NULL, &merges);
}
reset_revision_walk();
@@ -803,7 +804,7 @@ static int find_first_merges(struct object_array *result, const char *path,
contains_another = 0;
for (j = 0; j < merges.nr; j++) {
struct commit *m2 = (struct commit *) merges.objects[j].item;
- if (i != j && in_merge_bases(m2, &m1, 1)) {
+ if (i != j && in_merge_bases(m2, m1)) {
contains_another = 1;
break;
}
@@ -865,18 +866,18 @@ int merge_submodule(unsigned char result[20], const char *path,
}
/* check whether both changes are forward */
- if (!in_merge_bases(commit_base, &commit_a, 1) ||
- !in_merge_bases(commit_base, &commit_b, 1)) {
+ if (!in_merge_bases(commit_base, commit_a) ||
+ !in_merge_bases(commit_base, commit_b)) {
MERGE_WARNING(path, "commits don't follow merge-base");
return 0;
}
/* Case #1: a is contained in b or vice versa */
- if (in_merge_bases(commit_a, &commit_b, 1)) {
+ if (in_merge_bases(commit_a, commit_b)) {
hashcpy(result, b);
return 1;
}
- if (in_merge_bases(commit_b, &commit_a, 1)) {
+ if (in_merge_bases(commit_b, commit_a)) {
hashcpy(result, a);
return 1;
}
diff --git a/submodule.h b/submodule.h
index e105b0e..594b50d 100644
--- a/submodule.h
+++ b/submodule.h
@@ -2,6 +2,7 @@
#define SUBMODULE_H
struct diff_options;
+struct argv_array;
enum {
RECURSE_SUBMODULES_ON_DEMAND = -1,
@@ -23,7 +24,7 @@ void show_submodule_summary(FILE *f, const char *path,
const char *del, const char *add, const char *reset);
void set_config_fetch_recurse_submodules(int value);
void check_for_new_submodule_commits(unsigned char new_sha1[20]);
-int fetch_populated_submodules(int num_options, const char **options,
+int fetch_populated_submodules(const struct argv_array *options,
const char *prefix, int command_line_option,
int quiet);
unsigned is_submodule_modified(const char *path, int ignore_untracked);
diff --git a/symlinks.c b/symlinks.c
index 2900367..c2b41a8 100644
--- a/symlinks.c
+++ b/symlinks.c
@@ -1,5 +1,8 @@
#include "cache.h"
+static int threaded_check_leading_path(struct cache_def *cache, const char *name, int len);
+static int threaded_has_dirs_only_path(struct cache_def *cache, const char *name, int len, int prefix_len);
+
/*
* Returns the length (on a path component basis) of the longest
* common prefix match of 'name_a' and 'name_b'.
@@ -231,7 +234,7 @@ int check_leading_path(const char *name, int len)
* Return path length if leading path exists and is neither a
* directory nor a symlink.
*/
-int threaded_check_leading_path(struct cache_def *cache, const char *name, int len)
+static int threaded_check_leading_path(struct cache_def *cache, const char *name, int len)
{
int flags;
int match_len = lstat_cache_matchlen(cache, name, len, &flags,
@@ -263,7 +266,7 @@ int has_dirs_only_path(const char *name, int len, int prefix_len)
* 'prefix_len', thus we then allow for symlinks in the prefix part as
* long as those points to real existing directories.
*/
-int threaded_has_dirs_only_path(struct cache_def *cache, const char *name, int len, int prefix_len)
+static int threaded_has_dirs_only_path(struct cache_def *cache, const char *name, int len, int prefix_len)
{
return lstat_cache(cache, name, len,
FL_DIR|FL_FULLPATH, prefix_len) &
diff --git a/t/Git-SVN/00compile.t b/t/Git-SVN/00compile.t
new file mode 100644
index 0000000..c92fee4
--- /dev/null
+++ b/t/Git-SVN/00compile.t
@@ -0,0 +1,14 @@
+#!/usr/bin/env perl
+
+use strict;
+use warnings;
+
+use Test::More tests => 7;
+
+require_ok 'Git::SVN';
+require_ok 'Git::SVN::Utils';
+require_ok 'Git::SVN::Ra';
+require_ok 'Git::SVN::Log';
+require_ok 'Git::SVN::Migration';
+require_ok 'Git::IndexInfo';
+require_ok 'Git::SVN::GlobSpec';
diff --git a/t/Git-SVN/Utils/add_path_to_url.t b/t/Git-SVN/Utils/add_path_to_url.t
new file mode 100644
index 0000000..bfbd878
--- /dev/null
+++ b/t/Git-SVN/Utils/add_path_to_url.t
@@ -0,0 +1,27 @@
+#!/usr/bin/env perl
+
+use strict;
+use warnings;
+
+use Test::More 'no_plan';
+
+use Git::SVN::Utils qw(
+ add_path_to_url
+);
+
+# A reference cannot be a hash key, so we use an array.
+my @tests = (
+ ["http://x.com", "bar"] => 'http://x.com/bar',
+ ["http://x.com", ""] => 'http://x.com',
+ ["http://x.com/foo/", undef] => 'http://x.com/foo/',
+ ["http://x.com/foo/", "/bar/baz/"] => 'http://x.com/foo/bar/baz/',
+ ["http://x.com", 'per%cent'] => 'http://x.com/per%25cent',
+);
+
+while(@tests) {
+ my($have, $want) = splice @tests, 0, 2;
+
+ my $args = join ", ", map { qq['$_'] } map { defined($_) ? $_ : 'undef' } @$have;
+ my $name = "add_path_to_url($args) eq $want";
+ is add_path_to_url(@$have), $want, $name;
+}
diff --git a/t/Git-SVN/Utils/can_compress.t b/t/Git-SVN/Utils/can_compress.t
new file mode 100644
index 0000000..d7b49b8
--- /dev/null
+++ b/t/Git-SVN/Utils/can_compress.t
@@ -0,0 +1,11 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Test::More 'no_plan';
+
+use Git::SVN::Utils qw(can_compress);
+
+# !! is the "convert this to boolean" operator.
+is !!can_compress(), !!eval { require Compress::Zlib };
diff --git a/t/Git-SVN/Utils/canonicalize_url.t b/t/Git-SVN/Utils/canonicalize_url.t
new file mode 100644
index 0000000..05795ab
--- /dev/null
+++ b/t/Git-SVN/Utils/canonicalize_url.t
@@ -0,0 +1,26 @@
+#!/usr/bin/env perl
+
+# Test our own home rolled URL canonicalizer. Test the private one
+# directly because we can't predict what the SVN API is doing to do.
+
+use strict;
+use warnings;
+
+use Test::More 'no_plan';
+
+use Git::SVN::Utils;
+my $canonicalize_url = \&Git::SVN::Utils::_canonicalize_url_ourselves;
+
+my %tests = (
+ "http://x.com" => "http://x.com",
+ "http://x.com/" => "http://x.com",
+ "http://x.com/foo/bar" => "http://x.com/foo/bar",
+ "http://x.com//foo//bar//" => "http://x.com/foo/bar",
+ "http://x.com/ /%/" => "http://x.com/%20%20/%25",
+);
+
+for my $arg (keys %tests) {
+ my $want = $tests{$arg};
+
+ is $canonicalize_url->($arg), $want, "canonicalize_url('$arg') => $want";
+}
diff --git a/t/Git-SVN/Utils/collapse_dotdot.t b/t/Git-SVN/Utils/collapse_dotdot.t
new file mode 100644
index 0000000..1da1cce
--- /dev/null
+++ b/t/Git-SVN/Utils/collapse_dotdot.t
@@ -0,0 +1,23 @@
+#!/usr/bin/env perl
+
+use strict;
+use warnings;
+
+use Test::More 'no_plan';
+
+use Git::SVN::Utils;
+my $collapse_dotdot = \&Git::SVN::Utils::_collapse_dotdot;
+
+my %tests = (
+ "foo/bar/baz" => "foo/bar/baz",
+ ".." => "..",
+ "foo/.." => "",
+ "/foo/bar/../../baz" => "/baz",
+ "deeply/.././deeply/nested" => "./deeply/nested",
+);
+
+for my $arg (keys %tests) {
+ my $want = $tests{$arg};
+
+ is $collapse_dotdot->($arg), $want, "_collapse_dotdot('$arg') => $want";
+}
diff --git a/t/Git-SVN/Utils/fatal.t b/t/Git-SVN/Utils/fatal.t
new file mode 100644
index 0000000..49e1438
--- /dev/null
+++ b/t/Git-SVN/Utils/fatal.t
@@ -0,0 +1,34 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Test::More 'no_plan';
+
+BEGIN {
+ # Override exit at BEGIN time before Git::SVN::Utils is loaded
+ # so it will see our local exit later.
+ *CORE::GLOBAL::exit = sub(;$) {
+ return @_ ? CORE::exit($_[0]) : CORE::exit();
+ };
+}
+
+use Git::SVN::Utils qw(fatal);
+
+# fatal()
+{
+ # Capture the exit code and prevent exit.
+ my $exit_status;
+ no warnings 'redefine';
+ local *CORE::GLOBAL::exit = sub { $exit_status = $_[0] || 0 };
+
+ # Trap fatal's message to STDERR
+ my $stderr;
+ close STDERR;
+ ok open STDERR, ">", \$stderr;
+
+ fatal "Some", "Stuff", "Happened";
+
+ is $stderr, "Some Stuff Happened\n";
+ is $exit_status, 1;
+}
diff --git a/t/Git-SVN/Utils/join_paths.t b/t/Git-SVN/Utils/join_paths.t
new file mode 100644
index 0000000..d4488e7
--- /dev/null
+++ b/t/Git-SVN/Utils/join_paths.t
@@ -0,0 +1,32 @@
+#!/usr/bin/env perl
+
+use strict;
+use warnings;
+
+use Test::More 'no_plan';
+
+use Git::SVN::Utils qw(
+ join_paths
+);
+
+# A reference cannot be a hash key, so we use an array.
+my @tests = (
+ [] => '',
+ ["/x.com", "bar"] => '/x.com/bar',
+ ["x.com", ""] => 'x.com',
+ ["/x.com/foo/", undef, "bar"] => '/x.com/foo/bar',
+ ["x.com/foo/", "/bar/baz/"] => 'x.com/foo/bar/baz/',
+ ["foo", "bar"] => 'foo/bar',
+ ["/foo/bar", "baz", "/biff"] => '/foo/bar/baz/biff',
+ ["", undef, "."] => '.',
+ [] => '',
+
+);
+
+while(@tests) {
+ my($have, $want) = splice @tests, 0, 2;
+
+ my $args = join ", ", map { qq['$_'] } map { defined($_) ? $_ : 'undef' } @$have;
+ my $name = "join_paths($args) eq '$want'";
+ is join_paths(@$have), $want, $name;
+}
diff --git a/t/README b/t/README
index 4c3ea25..e4128e5 100644
--- a/t/README
+++ b/t/README
@@ -625,6 +625,15 @@ use these, and "test_set_prereq" for how to define your own.
Git was compiled with USE_LIBPCRE=YesPlease. Wrap any tests
that use git-grep --perl-regexp or git-grep -P in these.
+ - CASE_INSENSITIVE_FS
+
+ Test is run on a case insensitive file system.
+
+ - UTF8_NFD_TO_NFC
+
+ Test is run on a filesystem which converts decomposed utf-8 (nfd)
+ to precomposed utf-8 (nfc).
+
Tips for Writing Tests
----------------------
diff --git a/t/lib-bash.sh b/t/lib-bash.sh
new file mode 100644
index 0000000..11397f7
--- /dev/null
+++ b/t/lib-bash.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+#
+# Ensures that tests are run under Bash; primarily intended for running tests
+# of the completion script.
+
+if test -n "$BASH" && test -z "$POSIXLY_CORRECT"; then
+ # we are in full-on bash mode
+ true
+elif type bash >/dev/null 2>&1; then
+ # execute in full-on bash mode
+ unset POSIXLY_CORRECT
+ exec bash "$0" "$@"
+else
+ echo '1..0 #SKIP skipping bash completion tests; bash not available'
+ exit 0
+fi
+
+. ./test-lib.sh
diff --git a/t/lib-credential.sh b/t/lib-credential.sh
index 4a37cd7..3c43ff1 100755
--- a/t/lib-credential.sh
+++ b/t/lib-credential.sh
@@ -4,10 +4,24 @@
# stdout and stderr should be provided on stdin,
# separated by "--".
check() {
+ credential_opts=
+ credential_cmd=$1
+ shift
+ for arg in "$@"; do
+ credential_opts="$credential_opts -c credential.helper='$arg'"
+ done
read_chunk >stdin &&
read_chunk >expect-stdout &&
read_chunk >expect-stderr &&
- test-credential "$@" <stdin >stdout 2>stderr &&
+ if ! eval "git $credential_opts credential $credential_cmd <stdin >stdout 2>stderr"; then
+ echo "git credential failed with code $?" &&
+ cat stderr &&
+ false
+ fi &&
+ if test_have_prereq MINGW
+ then
+ dos2unix -q stderr
+ fi &&
test_cmp expect-stdout stdout &&
test_cmp expect-stderr stderr
}
@@ -41,7 +55,7 @@ reject() {
echo protocol=$2
echo host=$3
echo username=$4
- ) | test-credential reject $1
+ ) | git -c credential.helper=$1 credential reject
}
helper_test() {
@@ -52,6 +66,8 @@ helper_test() {
protocol=https
host=example.com
--
+ protocol=https
+ host=example.com
username=askpass-username
password=askpass-password
--
@@ -74,6 +90,8 @@ helper_test() {
protocol=https
host=example.com
--
+ protocol=https
+ host=example.com
username=store-user
password=store-pass
--
@@ -85,6 +103,8 @@ helper_test() {
protocol=http
host=example.com
--
+ protocol=http
+ host=example.com
username=askpass-username
password=askpass-password
--
@@ -98,6 +118,8 @@ helper_test() {
protocol=https
host=other.tld
--
+ protocol=https
+ host=other.tld
username=askpass-username
password=askpass-password
--
@@ -112,6 +134,8 @@ helper_test() {
host=example.com
username=other
--
+ protocol=https
+ host=example.com
username=other
password=askpass-password
--
@@ -133,6 +157,9 @@ helper_test() {
host=path.tld
path=bar.git
--
+ protocol=http
+ host=path.tld
+ path=bar.git
username=askpass-username
password=askpass-password
--
@@ -150,6 +177,8 @@ helper_test() {
protocol=https
host=example.com
--
+ protocol=https
+ host=example.com
username=askpass-username
password=askpass-password
--
@@ -176,6 +205,8 @@ helper_test() {
host=example.com
username=user1
--
+ protocol=https
+ host=example.com
username=user1
password=pass1
EOF
@@ -184,6 +215,8 @@ helper_test() {
host=example.com
username=user2
--
+ protocol=https
+ host=example.com
username=user2
password=pass2
EOF
@@ -200,6 +233,8 @@ helper_test() {
host=example.com
username=user1
--
+ protocol=https
+ host=example.com
username=user1
password=askpass-password
--
@@ -213,6 +248,8 @@ helper_test() {
host=example.com
username=user2
--
+ protocol=https
+ host=example.com
username=user2
password=pass2
EOF
@@ -234,6 +271,8 @@ helper_test_timeout() {
protocol=https
host=timeout.tld
--
+ protocol=https
+ host=timeout.tld
username=askpass-username
password=askpass-password
--
diff --git a/t/lib-git-p4.sh b/t/lib-git-p4.sh
index 121e380..7061dce 100644
--- a/t/lib-git-p4.sh
+++ b/t/lib-git-p4.sh
@@ -2,6 +2,10 @@
# Library code for git p4 tests
#
+# p4 tests never use the top-level repo; always build/clone into
+# a subdirectory called "$git"
+TEST_NO_CREATE_REPO=NoThanks
+
. ./test-lib.sh
if ! test_have_prereq PYTHON; then
@@ -22,28 +26,54 @@ testid=${this_test#t}
git_p4_test_start=9800
P4DPORT=$((10669 + ($testid - $git_p4_test_start)))
-export P4PORT=localhost:$P4DPORT
-export P4CLIENT=client
-export P4EDITOR=:
+P4PORT=localhost:$P4DPORT
+P4CLIENT=client
+P4EDITOR=:
+export P4PORT P4CLIENT P4EDITOR
db="$TRASH_DIRECTORY/db"
-cli="$TRASH_DIRECTORY/cli"
+cli=$(test-path-utils real_path "$TRASH_DIRECTORY/cli")
git="$TRASH_DIRECTORY/git"
pidfile="$TRASH_DIRECTORY/p4d.pid"
start_p4d() {
mkdir -p "$db" "$cli" "$git" &&
+ rm -f "$pidfile" &&
(
p4d -q -r "$db" -p $P4DPORT &
echo $! >"$pidfile"
) &&
- for i in 1 2 3 4 5 ; do
- p4 info >/dev/null 2>&1 && break || true &&
- echo waiting for p4d to start &&
+
+ # This gives p4d a long time to start up, as it can be
+ # quite slow depending on the machine. Set this environment
+ # variable to something smaller to fail faster in, say,
+ # an automated test setup. If the p4d process dies, that
+ # will be caught with the "kill -0" check below.
+ i=${P4D_START_PATIENCE:-300}
+ pid=$(cat "$pidfile")
+ ready=
+ while test $i -gt 0
+ do
+ # succeed when p4 client commands start to work
+ if p4 info >/dev/null 2>&1
+ then
+ ready=true
+ break
+ fi
+ # fail if p4d died
+ kill -0 $pid 2>/dev/null || break
+ echo waiting for p4d to start
sleep 1
- done &&
- # complain if it never started
- p4 info >/dev/null &&
+ i=$(( $i - 1 ))
+ done
+
+ if test -z "$ready"
+ then
+ # p4d failed to start
+ return 1
+ fi
+
+ # build a client
(
cd "$cli" &&
p4 client -i <<-EOF
@@ -53,6 +83,7 @@ start_p4d() {
View: //depot/... //client/...
EOF
)
+ return 0
}
kill_p4d() {
@@ -69,5 +100,36 @@ kill_p4d() {
}
cleanup_git() {
- rm -rf "$git"
+ rm -rf "$git" &&
+ mkdir "$git"
+}
+
+marshal_dump() {
+ what=$1 &&
+ line=${2:-1} &&
+ cat >"$TRASH_DIRECTORY/marshal-dump.py" <<-EOF &&
+ import marshal
+ import sys
+ for i in range($line):
+ d = marshal.load(sys.stdin)
+ print d['$what']
+ EOF
+ "$PYTHON_PATH" "$TRASH_DIRECTORY/marshal-dump.py"
+}
+
+#
+# Construct a client with this list of View lines
+#
+client_view() {
+ (
+ cat <<-EOF &&
+ Client: client
+ Description: client
+ Root: $cli
+ View:
+ EOF
+ for arg ; do
+ printf "\t$arg\n"
+ done
+ ) | p4 client -i
}
diff --git a/t/lib-httpd.sh b/t/lib-httpd.sh
index 0f31ef9..02f442b 100644
--- a/t/lib-httpd.sh
+++ b/t/lib-httpd.sh
@@ -43,6 +43,10 @@ TEST_PATH="$TEST_DIRECTORY"/lib-httpd
HTTPD_ROOT_PATH="$PWD"/httpd
HTTPD_DOCUMENT_ROOT_PATH=$HTTPD_ROOT_PATH/www
+# hack to suppress apache PassEnv warnings
+GIT_VALGRIND=$GIT_VALGRIND; export GIT_VALGRIND
+GIT_VALGRIND_OPTIONS=$GIT_VALGRIND_OPTIONS; export GIT_VALGRIND_OPTIONS
+
if ! test -x "$LIB_HTTPD_PATH"
then
skip_all="skipping test, no web server found at '$LIB_HTTPD_PATH'"
diff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf
index ec8618d..49d5d87 100644
--- a/t/lib-httpd/apache.conf
+++ b/t/lib-httpd/apache.conf
@@ -42,6 +42,9 @@ ErrorLog error.log
</IfModule>
</IfVersion>
+PassEnv GIT_VALGRIND
+PassEnv GIT_VALGRIND_OPTIONS
+
Alias /dumb/ www/
Alias /auth/dumb/ www/auth/dumb/
@@ -60,7 +63,7 @@ Alias /auth/dumb/ www/auth/dumb/
</LocationMatch>
ScriptAliasMatch /smart_*[^/]*/(.*) ${GIT_EXEC_PATH}/git-http-backend/$1
<Directory ${GIT_EXEC_PATH}>
- Options None
+ Options FollowSymlinks
</Directory>
<Files ${GIT_EXEC_PATH}/git-http-backend>
Options ExecCGI
diff --git a/t/perf/.gitignore b/t/perf/.gitignore
index 50f5cc1..982eb8e 100644
--- a/t/perf/.gitignore
+++ b/t/perf/.gitignore
@@ -1,2 +1,3 @@
-build/
-test-results/
+/build/
+/test-results/
+/trash directory*/
diff --git a/t/perf/perf-lib.sh b/t/perf/perf-lib.sh
index a1361e5..a816fbc 100644
--- a/t/perf/perf-lib.sh
+++ b/t/perf/perf-lib.sh
@@ -42,6 +42,7 @@ else
fi
TEST_NO_CREATE_REPO=t
+TEST_NO_MALLOC_CHECK=t
. ../test-lib.sh
diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh
index ccb5435..08677df 100755
--- a/t/t0000-basic.sh
+++ b/t/t0000-basic.sh
@@ -18,16 +18,6 @@ swapping compression and hashing order, the person who is making the
modification *should* take notice and update the test vectors here.
'
-################################################################
-# It appears that people try to run tests without building...
-
-../git >/dev/null
-if test $? != 1
-then
- echo >&2 'You do not seem to have built git yet.'
- exit 1
-fi
-
. ./test-lib.sh
################################################################
@@ -450,24 +440,6 @@ test_expect_success 'update-index D/F conflict' '
test $numpath0 = 1
'
-test_expect_success SYMLINKS 'real path works as expected' '
- mkdir first &&
- ln -s ../.git first/.git &&
- mkdir second &&
- ln -s ../first second/other &&
- mkdir third &&
- dir="$(cd .git; pwd -P)" &&
- dir2=third/../second/other/.git &&
- test "$dir" = "$(test-path-utils real_path $dir2)" &&
- file="$dir"/index &&
- test "$file" = "$(test-path-utils real_path $dir2/index)" &&
- basename=blub &&
- test "$dir/$basename" = "$(cd .git && test-path-utils real_path "$basename")" &&
- ln -s ../first/file .git/syml &&
- sym="$(cd first; pwd -P)"/file &&
- test "$sym" = "$(test-path-utils real_path "$dir2/syml")"
-'
-
test_expect_success 'very long name in the index handled sanely' '
a=a && # 1
diff --git a/t/t0003-attributes.sh b/t/t0003-attributes.sh
index 51f3045..febc45c 100755
--- a/t/t0003-attributes.sh
+++ b/t/t0003-attributes.sh
@@ -123,16 +123,6 @@ test_expect_success 'attribute matching is case insensitive when core.ignorecase
'
-test_expect_success 'check whether FS is case-insensitive' '
- mkdir junk &&
- echo good >junk/CamelCase &&
- echo bad >junk/camelcase &&
- if test "$(cat junk/CamelCase)" != good
- then
- test_set_prereq CASE_INSENSITIVE_FS
- fi
-'
-
test_expect_success CASE_INSENSITIVE_FS 'additional case insensitivity tests' '
test_must_fail attr_check a/B/D/g "a/b/d/*" "-c core.ignorecase=0" &&
test_must_fail attr_check A/B/D/NO "a/b/d/*" "-c core.ignorecase=0" &&
diff --git a/t/t0006-date.sh b/t/t0006-date.sh
index 1d29810..e53cf6d 100755
--- a/t/t0006-date.sh
+++ b/t/t0006-date.sh
@@ -11,7 +11,7 @@ check_show() {
echo "$t -> $2" >expect
test_expect_${3:-success} "relative date ($2)" "
test-date show $t >actual &&
- test_cmp expect actual
+ test_i18ncmp expect actual
"
}
diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh
index e3f354a..244a43c 100755
--- a/t/t0040-parse-options.sh
+++ b/t/t0040-parse-options.sh
@@ -51,7 +51,7 @@ EOF
test_expect_success 'test help' '
test_must_fail test-parse-options -h > output 2> output.err &&
test ! -s output.err &&
- test_cmp expect output
+ test_i18ncmp expect output
'
mv expect expect.err
@@ -79,6 +79,17 @@ check() {
test_cmp expect output
}
+check_i18n() {
+ what="$1" &&
+ shift &&
+ expect="$1" &&
+ shift &&
+ sed "s/^$what .*/$what $expect/" <expect.template >expect &&
+ test-parse-options $* >output 2>output.err &&
+ test ! -s output.err &&
+ test_i18ncmp expect output
+}
+
check_unknown() {
case "$1" in
--*)
@@ -92,6 +103,19 @@ check_unknown() {
test_cmp expect output.err
}
+check_unknown_i18n() {
+ case "$1" in
+ --*)
+ echo error: unknown option \`${1#--}\' >expect ;;
+ -*)
+ echo error: unknown switch \`${1#-}\' >expect ;;
+ esac &&
+ cat expect.err >>expect &&
+ test_must_fail test-parse-options $* >output 2>output.err &&
+ test ! -s output &&
+ test_i18ncmp expect output.err
+}
+
test_expect_success 'OPT_BOOL() #1' 'check boolean: 1 --yes'
test_expect_success 'OPT_BOOL() #2' 'check boolean: 1 --no-doubt'
test_expect_success 'OPT_BOOL() #3' 'check boolean: 1 -D'
@@ -104,8 +128,8 @@ test_expect_success 'OPT_BOOL() is idempotent #2' 'check boolean: 1 -DB'
test_expect_success 'OPT_BOOL() negation #1' 'check boolean: 0 -D --no-yes'
test_expect_success 'OPT_BOOL() negation #2' 'check boolean: 0 -D --no-no-doubt'
-test_expect_success 'OPT_BOOL() no negation #1' 'check_unknown --fear'
-test_expect_success 'OPT_BOOL() no negation #2' 'check_unknown --no-no-fear'
+test_expect_success 'OPT_BOOL() no negation #1' 'check_unknown_i18n --fear'
+test_expect_success 'OPT_BOOL() no negation #2' 'check_unknown_i18n --no-no-fear'
test_expect_success 'OPT_BOOL() positivation' 'check boolean: 0 -D --doubt'
@@ -310,8 +334,8 @@ EOF
test_expect_success 'OPT_CALLBACK() and callback errors work' '
test_must_fail test-parse-options --no-length > output 2> output.err &&
- test_cmp expect output &&
- test_cmp expect.err output.err
+ test_i18ncmp expect output &&
+ test_i18ncmp expect.err output.err
'
cat > expect <<EOF
diff --git a/t/t0050-filesystem.sh b/t/t0050-filesystem.sh
index 1542cf6..78816d9 100755
--- a/t/t0050-filesystem.sh
+++ b/t/t0050-filesystem.sh
@@ -7,48 +7,26 @@ test_description='Various filesystem issues'
auml=$(printf '\303\244')
aumlcdiar=$(printf '\141\314\210')
-case_insensitive=
-unibad=
-no_symlinks=
-test_expect_success 'see what we expect' '
-
- test_case=test_expect_success &&
- test_unicode=test_expect_success &&
- mkdir junk &&
- echo good >junk/CamelCase &&
- echo bad >junk/camelcase &&
- if test "$(cat junk/CamelCase)" != good
- then
- test_case=test_expect_failure &&
- case_insensitive=t
- fi &&
- rm -fr junk &&
- mkdir junk &&
- >junk/"$auml" &&
- case "$(cd junk && echo *)" in
- "$aumlcdiar")
- test_unicode=test_expect_failure &&
- unibad=t
- ;;
- *) ;;
- esac &&
- rm -fr junk &&
- {
- ln -s x y 2> /dev/null &&
- test -h y 2> /dev/null ||
- no_symlinks=1 &&
- rm -f y
- }
-'
-
-test "$case_insensitive" &&
+if test_have_prereq CASE_INSENSITIVE_FS
+then
say "will test on a case insensitive filesystem"
-test "$unibad" &&
+ test_case=test_expect_failure
+else
+ test_case=test_expect_success
+fi
+
+if test_have_prereq UTF8_NFD_TO_NFC
+then
say "will test on a unicode corrupting filesystem"
-test "$no_symlinks" &&
+ test_unicode=test_expect_failure
+else
+ test_unicode=test_expect_success
+fi
+
+test_have_prereq SYMLINKS ||
say "will test on a filesystem lacking symbolic links"
-if test "$case_insensitive"
+if test_have_prereq CASE_INSENSITIVE_FS
then
test_expect_success "detection of case insensitive filesystem during repo init" '
@@ -62,18 +40,18 @@ test_expect_success "detection of case insensitive filesystem during repo init"
'
fi
-if test "$no_symlinks"
+if test_have_prereq SYMLINKS
then
test_expect_success "detection of filesystem w/o symlink support during repo init" '
- v=$(git config --bool core.symlinks) &&
- test "$v" = false
+ test_must_fail git config --bool core.symlinks ||
+ test "$(git config --bool core.symlinks)" = true
'
else
test_expect_success "detection of filesystem w/o symlink support during repo init" '
- test_must_fail git config --bool core.symlinks ||
- test "$(git config --bool core.symlinks)" = true
+ v=$(git config --bool core.symlinks) &&
+ test "$v" = false
'
fi
diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh
index 53cf1f8..4ef2345 100755
--- a/t/t0060-path-utils.sh
+++ b/t/t0060-path-utils.sh
@@ -139,4 +139,63 @@ test_expect_success 'strip_path_suffix' '
test c:/msysgit = $(test-path-utils strip_path_suffix \
c:/msysgit/libexec//git-core libexec/git-core)
'
+
+test_expect_success 'absolute path rejects the empty string' '
+ test_must_fail test-path-utils absolute_path ""
+'
+
+test_expect_success 'real path rejects the empty string' '
+ test_must_fail test-path-utils real_path ""
+'
+
+test_expect_success POSIX 'real path works on absolute paths 1' '
+ nopath="hopefully-absent-path" &&
+ test "/" = "$(test-path-utils real_path "/")" &&
+ test "/$nopath" = "$(test-path-utils real_path "/$nopath")"
+'
+
+test_expect_success 'real path works on absolute paths 2' '
+ nopath="hopefully-absent-path" &&
+ # Find an existing top-level directory for the remaining tests:
+ d=$(pwd -P | sed -e "s|^\([^/]*/[^/]*\)/.*|\1|") &&
+ test "$d" = "$(test-path-utils real_path "$d")" &&
+ test "$d/$nopath" = "$(test-path-utils real_path "$d/$nopath")"
+'
+
+test_expect_success POSIX 'real path removes extra leading slashes' '
+ nopath="hopefully-absent-path" &&
+ test "/" = "$(test-path-utils real_path "///")" &&
+ test "/$nopath" = "$(test-path-utils real_path "///$nopath")" &&
+ # Find an existing top-level directory for the remaining tests:
+ d=$(pwd -P | sed -e "s|^\([^/]*/[^/]*\)/.*|\1|") &&
+ test "$d" = "$(test-path-utils real_path "//$d")" &&
+ test "$d/$nopath" = "$(test-path-utils real_path "//$d/$nopath")"
+'
+
+test_expect_success 'real path removes other extra slashes' '
+ nopath="hopefully-absent-path" &&
+ # Find an existing top-level directory for the remaining tests:
+ d=$(pwd -P | sed -e "s|^\([^/]*/[^/]*\)/.*|\1|") &&
+ test "$d" = "$(test-path-utils real_path "$d///")" &&
+ test "$d/$nopath" = "$(test-path-utils real_path "$d///$nopath")"
+'
+
+test_expect_success SYMLINKS 'real path works on symlinks' '
+ mkdir first &&
+ ln -s ../.git first/.git &&
+ mkdir second &&
+ ln -s ../first second/other &&
+ mkdir third &&
+ dir="$(cd .git; pwd -P)" &&
+ dir2=third/../second/other/.git &&
+ test "$dir" = "$(test-path-utils real_path $dir2)" &&
+ file="$dir"/index &&
+ test "$file" = "$(test-path-utils real_path $dir2/index)" &&
+ basename=blub &&
+ test "$dir/$basename" = "$(cd .git && test-path-utils real_path "$basename")" &&
+ ln -s ../first/file .git/syml &&
+ sym="$(cd first; pwd -P)"/file &&
+ test "$sym" = "$(test-path-utils real_path "$dir2/syml")"
+'
+
test_done
diff --git a/t/t0063-string-list.sh b/t/t0063-string-list.sh
new file mode 100755
index 0000000..41c8826
--- /dev/null
+++ b/t/t0063-string-list.sh
@@ -0,0 +1,121 @@
+#!/bin/sh
+#
+# Copyright (c) 2012 Michael Haggerty
+#
+
+test_description='Test string list functionality'
+
+. ./test-lib.sh
+
+test_split () {
+ cat >expected &&
+ test_expect_success "split $1 at $2, max $3" "
+ test-string-list split '$1' '$2' '$3' >actual &&
+ test_cmp expected actual &&
+ test-string-list split_in_place '$1' '$2' '$3' >actual &&
+ test_cmp expected actual
+ "
+}
+
+test_longest_prefix () {
+ test "$(test-string-list longest_prefix "$1" "$2")" = "$3"
+}
+
+test_no_longest_prefix () {
+ test_must_fail test-string-list longest_prefix "$1" "$2"
+}
+
+test_split "foo:bar:baz" ":" "-1" <<EOF
+3
+[0]: "foo"
+[1]: "bar"
+[2]: "baz"
+EOF
+
+test_split "foo:bar:baz" ":" "0" <<EOF
+1
+[0]: "foo:bar:baz"
+EOF
+
+test_split "foo:bar:baz" ":" "1" <<EOF
+2
+[0]: "foo"
+[1]: "bar:baz"
+EOF
+
+test_split "foo:bar:baz" ":" "2" <<EOF
+3
+[0]: "foo"
+[1]: "bar"
+[2]: "baz"
+EOF
+
+test_split "foo:bar:" ":" "-1" <<EOF
+3
+[0]: "foo"
+[1]: "bar"
+[2]: ""
+EOF
+
+test_split "" ":" "-1" <<EOF
+1
+[0]: ""
+EOF
+
+test_split ":" ":" "-1" <<EOF
+2
+[0]: ""
+[1]: ""
+EOF
+
+test_expect_success "test filter_string_list" '
+ test "x-" = "x$(test-string-list filter - y)" &&
+ test "x-" = "x$(test-string-list filter no y)" &&
+ test yes = "$(test-string-list filter yes y)" &&
+ test yes = "$(test-string-list filter no:yes y)" &&
+ test yes = "$(test-string-list filter yes:no y)" &&
+ test y1:y2 = "$(test-string-list filter y1:y2 y)" &&
+ test y2:y1 = "$(test-string-list filter y2:y1 y)" &&
+ test "x-" = "x$(test-string-list filter x1:x2 y)"
+'
+
+test_expect_success "test remove_duplicates" '
+ test "x-" = "x$(test-string-list remove_duplicates -)" &&
+ test "x" = "x$(test-string-list remove_duplicates "")" &&
+ test a = "$(test-string-list remove_duplicates a)" &&
+ test a = "$(test-string-list remove_duplicates a:a)" &&
+ test a = "$(test-string-list remove_duplicates a:a:a:a:a)" &&
+ test a:b = "$(test-string-list remove_duplicates a:b)" &&
+ test a:b = "$(test-string-list remove_duplicates a:a:b)" &&
+ test a:b = "$(test-string-list remove_duplicates a:b:b)" &&
+ test a:b:c = "$(test-string-list remove_duplicates a:b:c)" &&
+ test a:b:c = "$(test-string-list remove_duplicates a:a:b:c)" &&
+ test a:b:c = "$(test-string-list remove_duplicates a:b:b:c)" &&
+ test a:b:c = "$(test-string-list remove_duplicates a:b:c:c)" &&
+ test a:b:c = "$(test-string-list remove_duplicates a:a:b:b:c:c)" &&
+ test a:b:c = "$(test-string-list remove_duplicates a:a:a:b:b:b:c:c:c)"
+'
+
+test_expect_success "test longest_prefix" '
+ test_no_longest_prefix - '' &&
+ test_no_longest_prefix - x &&
+ test_longest_prefix "" x "" &&
+ test_longest_prefix x x x &&
+ test_longest_prefix "" foo "" &&
+ test_longest_prefix : foo "" &&
+ test_longest_prefix f foo f &&
+ test_longest_prefix foo foobar foo &&
+ test_longest_prefix foo foo foo &&
+ test_no_longest_prefix bar foo &&
+ test_no_longest_prefix bar:bar foo &&
+ test_no_longest_prefix foobar foo &&
+ test_longest_prefix foo:bar foo foo &&
+ test_longest_prefix foo:bar bar bar &&
+ test_longest_prefix foo::bar foo foo &&
+ test_longest_prefix foo:foobar foo foo &&
+ test_longest_prefix foobar:foo foo foo &&
+ test_longest_prefix foo: bar "" &&
+ test_longest_prefix :foo bar ""
+'
+
+test_done
diff --git a/t/t0201-gettext-fallbacks.sh b/t/t0201-gettext-fallbacks.sh
index 52b1c27..5d80a98 100755
--- a/t/t0201-gettext-fallbacks.sh
+++ b/t/t0201-gettext-fallbacks.sh
@@ -51,16 +51,16 @@ test_expect_success 'eval_gettext: our eval_gettext() fallback can interpolate v
test_expect_success 'eval_gettext: our eval_gettext() fallback can interpolate variables with spaces' '
cmdline="git am" &&
export cmdline;
- printf "When you have resolved this problem run git am --resolved." >expect &&
- eval_gettext "When you have resolved this problem run \$cmdline --resolved." >actual
+ printf "When you have resolved this problem, run git am --resolved." >expect &&
+ eval_gettext "When you have resolved this problem, run \$cmdline --resolved." >actual
test_i18ncmp expect actual
'
test_expect_success 'eval_gettext: our eval_gettext() fallback can interpolate variables with spaces and quotes' '
cmdline="git am" &&
export cmdline;
- printf "When you have resolved this problem run \"git am --resolved\"." >expect &&
- eval_gettext "When you have resolved this problem run \"\$cmdline --resolved\"." >actual
+ printf "When you have resolved this problem, run \"git am --resolved\"." >expect &&
+ eval_gettext "When you have resolved this problem, run \"\$cmdline --resolved\"." >actual
test_i18ncmp expect actual
'
diff --git a/t/t0300-credentials.sh b/t/t0300-credentials.sh
index 20e28e3..538ea5f 100755
--- a/t/t0300-credentials.sh
+++ b/t/t0300-credentials.sh
@@ -82,6 +82,9 @@ test_expect_success 'credential_fill passes along metadata' '
host=example.com
path=foo.git
--
+ protocol=ftp
+ host=example.com
+ path=foo.git
username=one
password=two
--
@@ -213,6 +216,8 @@ test_expect_success 'match configured credential' '
host=example.com
path=repo.git
--
+ protocol=https
+ host=example.com
username=foo
password=bar
--
@@ -225,6 +230,8 @@ test_expect_success 'do not match configured credential' '
protocol=https
host=bar
--
+ protocol=https
+ host=bar
username=askpass-username
password=askpass-password
--
@@ -239,6 +246,8 @@ test_expect_success 'pull username from config' '
protocol=https
host=example.com
--
+ protocol=https
+ host=example.com
username=foo
password=askpass-password
--
@@ -252,6 +261,8 @@ test_expect_success 'http paths can be part of context' '
host=example.com
path=foo.git
--
+ protocol=https
+ host=example.com
username=foo
password=bar
--
@@ -265,6 +276,9 @@ test_expect_success 'http paths can be part of context' '
host=example.com
path=foo.git
--
+ protocol=https
+ host=example.com
+ path=foo.git
username=foo
password=bar
--
diff --git a/t/t1050-large.sh b/t/t1050-large.sh
index 55ed955..fd10528 100755
--- a/t/t1050-large.sh
+++ b/t/t1050-large.sh
@@ -130,10 +130,27 @@ test_expect_success 'git-show a large file' '
'
+test_expect_success 'index-pack' '
+ git clone file://"`pwd`"/.git foo &&
+ GIT_DIR=non-existent git index-pack --strict --verify foo/.git/objects/pack/*.pack
+'
+
test_expect_success 'repack' '
git repack -ad
'
+test_expect_success 'pack-objects with large loose object' '
+ SHA1=`git hash-object huge` &&
+ test_create_repo loose &&
+ echo $SHA1 | git pack-objects --stdout |
+ GIT_ALLOC_LIMIT=0 GIT_DIR=loose/.git git unpack-objects &&
+ echo $SHA1 | GIT_DIR=loose/.git git pack-objects pack &&
+ test_create_repo packed &&
+ mv pack-* packed/.git/objects/pack &&
+ GIT_DIR=packed/.git git cat-file blob $SHA1 >actual &&
+ cmp huge actual
+'
+
test_expect_success 'tar achiving' '
git archive --format=tar HEAD >/dev/null
'
diff --git a/t/t1100-commit-tree-options.sh b/t/t1100-commit-tree-options.sh
index a3b7723..f8457f9 100755
--- a/t/t1100-commit-tree-options.sh
+++ b/t/t1100-commit-tree-options.sh
@@ -47,6 +47,7 @@ test_expect_success \
test_expect_success 'flags and then non flags' '
+ test_tick &&
echo comment text |
git commit-tree $(cat treeid) >commitid &&
echo comment text |
diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh
index a477453..e127f35 100755
--- a/t/t1300-repo-config.sh
+++ b/t/t1300-repo-config.sh
@@ -391,7 +391,7 @@ test_expect_success 'get bool variable with empty value' \
test_expect_success 'no arguments, but no crash' '
test_must_fail git config >output 2>&1 &&
- grep usage output
+ test_i18ngrep usage output
'
cat > .git/config << EOF
diff --git a/t/t1304-default-acl.sh b/t/t1304-default-acl.sh
index 2b962cf..79045ab 100755
--- a/t/t1304-default-acl.sh
+++ b/t/t1304-default-acl.sh
@@ -14,16 +14,15 @@ umask 077
# We need an arbitrary other user give permission to using ACLs. root
# is a good candidate: exists on all unices, and it has permission
# anyway, so we don't create a security hole running the testsuite.
-
-setfacl_out="$(setfacl -m u:root:rwx . 2>&1)"
-setfacl_ret=$?
-
-if test $setfacl_ret != 0
-then
- say "Unable to use setfacl (output: '$setfacl_out'; return code: '$setfacl_ret')"
-else
- test_set_prereq SETFACL
-fi
+test_expect_success 'checking for a working acl setup' '
+ if setfacl -m d:m:rwx -m u:root:rwx . &&
+ getfacl . | grep user:root:rwx &&
+ touch should-have-readable-acl &&
+ getfacl should-have-readable-acl | egrep "mask::?rw-"
+ then
+ test_set_prereq SETFACL
+ fi
+'
if test -z "$LOGNAME"
then
diff --git a/t/t1306-xdg-files.sh b/t/t1306-xdg-files.sh
new file mode 100755
index 0000000..8b14ab1
--- /dev/null
+++ b/t/t1306-xdg-files.sh
@@ -0,0 +1,197 @@
+#!/bin/sh
+#
+# Copyright (c) 2012 Valentin Duperray, Lucien Kong, Franck Jonas,
+# Thomas Nguy, Khoi Nguyen
+# Grenoble INP Ensimag
+#
+
+test_description='Compatibility with $XDG_CONFIG_HOME/git/ files'
+
+. ./test-lib.sh
+
+test_expect_success 'read config: xdg file exists and ~/.gitconfig doesn'\''t' '
+ mkdir -p .config/git &&
+ echo "[alias]" >.config/git/config &&
+ echo " myalias = !echo in_config" >>.config/git/config &&
+ echo in_config >expected &&
+ git myalias >actual &&
+ test_cmp expected actual
+'
+
+
+test_expect_success 'read config: xdg file exists and ~/.gitconfig exists' '
+ >.gitconfig &&
+ echo "[alias]" >.gitconfig &&
+ echo " myalias = !echo in_gitconfig" >>.gitconfig &&
+ echo in_gitconfig >expected &&
+ git myalias >actual &&
+ test_cmp expected actual
+'
+
+
+test_expect_success 'read with --get: xdg file exists and ~/.gitconfig doesn'\''t' '
+ rm .gitconfig &&
+ echo "[user]" >.config/git/config &&
+ echo " name = read_config" >>.config/git/config &&
+ echo read_config >expected &&
+ git config --get user.name >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success '"$XDG_CONFIG_HOME overrides $HOME/.config/git' '
+ mkdir -p "$HOME"/xdg/git &&
+ echo "[user]name = in_xdg" >"$HOME"/xdg/git/config &&
+ echo in_xdg >expected &&
+ XDG_CONFIG_HOME="$HOME"/xdg git config --get-all user.name >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'read with --get: xdg file exists and ~/.gitconfig exists' '
+ >.gitconfig &&
+ echo "[user]" >.gitconfig &&
+ echo " name = read_gitconfig" >>.gitconfig &&
+ echo read_gitconfig >expected &&
+ git config --get user.name >actual &&
+ test_cmp expected actual
+'
+
+
+test_expect_success 'read with --list: xdg file exists and ~/.gitconfig doesn'\''t' '
+ rm .gitconfig &&
+ echo user.name=read_config >expected &&
+ git config --global --list >actual &&
+ test_cmp expected actual
+'
+
+
+test_expect_success 'read with --list: xdg file exists and ~/.gitconfig exists' '
+ >.gitconfig &&
+ echo "[user]" >.gitconfig &&
+ echo " name = read_gitconfig" >>.gitconfig &&
+ echo user.name=read_gitconfig >expected &&
+ git config --global --list >actual &&
+ test_cmp expected actual
+'
+
+
+test_expect_success 'Setup' '
+ git init git &&
+ cd git &&
+ echo foo >to_be_excluded
+'
+
+
+test_expect_success 'Exclusion of a file in the XDG ignore file' '
+ mkdir -p "$HOME"/.config/git/ &&
+ echo to_be_excluded >"$HOME"/.config/git/ignore &&
+ test_must_fail git add to_be_excluded
+'
+
+test_expect_success '$XDG_CONFIG_HOME overrides $HOME/.config/git/ignore' '
+ mkdir -p "$HOME"/xdg/git &&
+ echo content >excluded_by_xdg_only &&
+ echo excluded_by_xdg_only >"$HOME"/xdg/git/ignore &&
+ test_when_finished "git read-tree --empty" &&
+ (XDG_CONFIG_HOME="$HOME/xdg" &&
+ export XDG_CONFIG_HOME &&
+ git add to_be_excluded &&
+ test_must_fail git add excluded_by_xdg_only
+ )
+'
+
+test_expect_success 'Exclusion in both XDG and local ignore files' '
+ echo to_be_excluded >.gitignore &&
+ test_must_fail git add to_be_excluded
+'
+
+
+test_expect_success 'Exclusion in a non-XDG global ignore file' '
+ rm .gitignore &&
+ echo >"$HOME"/.config/git/ignore &&
+ echo to_be_excluded >"$HOME"/my_gitignore &&
+ git config core.excludesfile "$HOME"/my_gitignore &&
+ test_must_fail git add to_be_excluded
+'
+
+test_expect_success 'Checking XDG ignore file when HOME is unset' '
+ >expected &&
+ (sane_unset HOME &&
+ git config --unset core.excludesfile &&
+ git ls-files --exclude-standard --ignored >actual) &&
+ test_cmp expected actual
+'
+
+test_expect_success 'Checking attributes in the XDG attributes file' '
+ echo foo >f &&
+ git check-attr -a f >actual &&
+ test_line_count -eq 0 actual &&
+ echo "f attr_f" >"$HOME"/.config/git/attributes &&
+ echo "f: attr_f: set" >expected &&
+ git check-attr -a f >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'Checking XDG attributes when HOME is unset' '
+ >expected &&
+ (sane_unset HOME &&
+ git check-attr -a f >actual) &&
+ test_cmp expected actual
+'
+
+test_expect_success '$XDG_CONFIG_HOME overrides $HOME/.config/git/attributes' '
+ mkdir -p "$HOME"/xdg/git &&
+ echo "f attr_f=xdg" >"$HOME"/xdg/git/attributes &&
+ echo "f: attr_f: xdg" >expected &&
+ XDG_CONFIG_HOME="$HOME/xdg" git check-attr -a f >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'Checking attributes in both XDG and local attributes files' '
+ echo "f -attr_f" >.gitattributes &&
+ echo "f: attr_f: unset" >expected &&
+ git check-attr -a f >actual &&
+ test_cmp expected actual
+'
+
+
+test_expect_success 'Checking attributes in a non-XDG global attributes file' '
+ test_might_fail rm .gitattributes &&
+ echo "f attr_f=test" >"$HOME"/my_gitattributes &&
+ git config core.attributesfile "$HOME"/my_gitattributes &&
+ echo "f: attr_f: test" >expected &&
+ git check-attr -a f >actual &&
+ test_cmp expected actual
+'
+
+
+test_expect_success 'write: xdg file exists and ~/.gitconfig doesn'\''t' '
+ mkdir -p "$HOME"/.config/git &&
+ >"$HOME"/.config/git/config &&
+ test_might_fail rm "$HOME"/.gitconfig &&
+ git config --global user.name "write_config" &&
+ echo "[user]" >expected &&
+ echo " name = write_config" >>expected &&
+ test_cmp expected "$HOME"/.config/git/config
+'
+
+
+test_expect_success 'write: xdg file exists and ~/.gitconfig exists' '
+ >"$HOME"/.gitconfig &&
+ git config --global user.name "write_gitconfig" &&
+ echo "[user]" >expected &&
+ echo " name = write_gitconfig" >>expected &&
+ test_cmp expected "$HOME"/.gitconfig
+'
+
+
+test_expect_success 'write: ~/.config/git/ exists and config file doesn'\''t' '
+ test_might_fail rm "$HOME"/.gitconfig &&
+ test_might_fail rm "$HOME"/.config/git/config &&
+ git config --global user.name "write_gitconfig" &&
+ echo "[user]" >expected &&
+ echo " name = write_gitconfig" >>expected &&
+ test_cmp expected "$HOME"/.gitconfig
+'
+
+
+test_done
diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh
index bf7a2cd..08aa24c 100755
--- a/t/t1450-fsck.sh
+++ b/t/t1450-fsck.sh
@@ -177,9 +177,7 @@ test_expect_success 'tag pointing to something else than its type' '
test_when_finished "remove_object $tag" &&
echo $tag >.git/refs/tags/wrong &&
test_when_finished "git update-ref -d refs/tags/wrong" &&
- test_must_fail git fsck --tags 2>out &&
- cat out &&
- grep "error in tag.*broken links" out
+ test_must_fail git fsck --tags
'
test_expect_success 'cleaned up' '
diff --git a/t/t1502-rev-parse-parseopt.sh b/t/t1502-rev-parse-parseopt.sh
index 1efd7f7..13c88c9 100755
--- a/t/t1502-rev-parse-parseopt.sh
+++ b/t/t1502-rev-parse-parseopt.sh
@@ -41,7 +41,7 @@ EOF
test_expect_success 'test --parseopt help output' '
test_expect_code 129 git rev-parse --parseopt -- -h > output < optionspec &&
- test_cmp expect output
+ test_i18ncmp expect output
'
cat > expect <<EOF
diff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh
new file mode 100755
index 0000000..6b3d797
--- /dev/null
+++ b/t/t1512-rev-parse-disambiguation.sh
@@ -0,0 +1,264 @@
+#!/bin/sh
+
+test_description='object name disambiguation
+
+Create blobs, trees, commits and a tag that all share the same
+prefix, and make sure "git rev-parse" can take advantage of
+type information to disambiguate short object names that are
+not necessarily unique.
+
+The final history used in the test has five commits, with the bottom
+one tagged as v1.0.0. They all have one regular file each.
+
+ +-------------------------------------------+
+ | |
+ | .-------b3wettvi---- ad2uee |
+ | / / |
+ | a2onsxbvj---czy8f73t--ioiley5o |
+ | |
+ +-------------------------------------------+
+
+'
+
+. ./test-lib.sh
+
+test_expect_success 'blob and tree' '
+ test_tick &&
+ (
+ for i in 0 1 2 3 4 5 6 7 8 9
+ do
+ echo $i
+ done
+ echo
+ echo b1rwzyc3
+ ) >a0blgqsjc &&
+
+ # create one blob 0000000000b36
+ git add a0blgqsjc &&
+
+ # create one tree 0000000000cdc
+ git write-tree
+'
+
+test_expect_success 'warn ambiguity when no candidate matches type hint' '
+ test_must_fail git rev-parse --verify 000000000^{commit} 2>actual &&
+ grep "short SHA1 000000000 is ambiguous" actual
+'
+
+test_expect_success 'disambiguate tree-ish' '
+ # feed tree-ish in an unambiguous way
+ git rev-parse --verify 0000000000cdc:a0blgqsjc &&
+
+ # ambiguous at the object name level, but there is only one
+ # such tree-ish (the other is a blob)
+ git rev-parse --verify 000000000:a0blgqsjc
+'
+
+test_expect_success 'disambiguate blob' '
+ sed -e "s/|$//" >patch <<-EOF &&
+ diff --git a/frotz b/frotz
+ index 000000000..ffffff 100644
+ --- a/frotz
+ +++ b/frotz
+ @@ -10,3 +10,4 @@
+ 9
+ |
+ b1rwzyc3
+ +irwry
+ EOF
+ (
+ GIT_INDEX_FILE=frotz &&
+ export GIT_INDEX_FILE &&
+ git apply --build-fake-ancestor frotz patch &&
+ git cat-file blob :frotz >actual
+ ) &&
+ test_cmp a0blgqsjc actual
+'
+
+test_expect_success 'disambiguate tree' '
+ commit=$(echo "d7xm" | git commit-tree 000000000) &&
+ test $(git rev-parse $commit^{tree}) = $(git rev-parse 0000000000cdc)
+'
+
+test_expect_success 'first commit' '
+ # create one commit 0000000000e4f
+ git commit -m a2onsxbvj
+'
+
+test_expect_success 'disambiguate commit-ish' '
+ # feed commit-ish in an unambiguous way
+ git rev-parse --verify 0000000000e4f^{commit} &&
+
+ # ambiguous at the object name level, but there is only one
+ # such commit (the others are tree and blob)
+ git rev-parse --verify 000000000^{commit} &&
+
+ # likewise
+ git rev-parse --verify 000000000^0
+'
+
+test_expect_success 'disambiguate commit' '
+ commit=$(echo "hoaxj" | git commit-tree 0000000000cdc -p 000000000) &&
+ test $(git rev-parse $commit^) = $(git rev-parse 0000000000e4f)
+'
+
+test_expect_success 'log name1..name2 takes only commit-ishes on both ends' '
+ git log 000000000..000000000 &&
+ git log ..000000000 &&
+ git log 000000000.. &&
+ git log 000000000...000000000 &&
+ git log ...000000000 &&
+ git log 000000000...
+'
+
+test_expect_success 'rev-parse name1..name2 takes only commit-ishes on both ends' '
+ git rev-parse 000000000..000000000 &&
+ git rev-parse ..000000000 &&
+ git rev-parse 000000000..
+'
+
+test_expect_success 'git log takes only commit-ish' '
+ git log 000000000
+'
+
+test_expect_success 'git reset takes only commit-ish' '
+ git reset 000000000
+'
+
+test_expect_success 'first tag' '
+ # create one tag 0000000000f8f
+ git tag -a -m j7cp83um v1.0.0
+'
+
+test_expect_failure 'two semi-ambiguous commit-ish' '
+ # Once the parser becomes ultra-smart, it could notice that
+ # 110282 before ^{commit} name many different objects, but
+ # that only two (HEAD and v1.0.0 tag) can be peeled to commit,
+ # and that peeling them down to commit yield the same commit
+ # without ambiguity.
+ git rev-parse --verify 110282^{commit} &&
+
+ # likewise
+ git log 000000000..000000000 &&
+ git log ..000000000 &&
+ git log 000000000.. &&
+ git log 000000000...000000000 &&
+ git log ...000000000 &&
+ git log 000000000...
+'
+
+test_expect_failure 'three semi-ambiguous tree-ish' '
+ # Likewise for tree-ish. HEAD, v1.0.0 and HEAD^{tree} share
+ # the prefix but peeling them to tree yields the same thing
+ git rev-parse --verify 000000000^{tree}
+'
+
+test_expect_success 'parse describe name' '
+ # feed an unambiguous describe name
+ git rev-parse --verify v1.0.0-0-g0000000000e4f &&
+
+ # ambiguous at the object name level, but there is only one
+ # such commit (others are blob, tree and tag)
+ git rev-parse --verify v1.0.0-0-g000000000
+'
+
+test_expect_success 'more history' '
+ # commit 0000000000043
+ git mv a0blgqsjc d12cr3h8t &&
+ echo h62xsjeu >>d12cr3h8t &&
+ git add d12cr3h8t &&
+
+ test_tick &&
+ git commit -m czy8f73t &&
+
+ # commit 00000000008ec
+ git mv d12cr3h8t j000jmpzn &&
+ echo j08bekfvt >>j000jmpzn &&
+ git add j000jmpzn &&
+
+ test_tick &&
+ git commit -m ioiley5o &&
+
+ # commit 0000000005b0
+ git checkout v1.0.0^0 &&
+ git mv a0blgqsjc f5518nwu &&
+
+ for i in h62xsjeu j08bekfvt kg7xflhm
+ do
+ echo $i
+ done >>f5518nwu &&
+ git add f5518nwu &&
+
+ test_tick &&
+ git commit -m b3wettvi &&
+ side=$(git rev-parse HEAD) &&
+
+ # commit 000000000066
+ git checkout master &&
+
+ # If you use recursive, merge will fail and you will need to
+ # clean up a0blgqsjc as well. If you use resolve, merge will
+ # succeed.
+ test_might_fail git merge --no-commit -s recursive $side &&
+ git rm -f f5518nwu j000jmpzn &&
+
+ test_might_fail git rm -f a0blgqsjc &&
+ (
+ git cat-file blob $side:f5518nwu
+ echo j3l0i9s6
+ ) >ab2gs879 &&
+ git add ab2gs879 &&
+
+ test_tick &&
+ git commit -m ad2uee
+
+'
+
+test_expect_failure 'parse describe name taking advantage of generation' '
+ # ambiguous at the object name level, but there is only one
+ # such commit at generation 0
+ git rev-parse --verify v1.0.0-0-g000000000 &&
+
+ # likewise for generation 2 and 4
+ git rev-parse --verify v1.0.0-2-g000000000 &&
+ git rev-parse --verify v1.0.0-4-g000000000
+'
+
+# Note: because rev-parse does not even try to disambiguate based on
+# the generation number, this test currently succeeds for a wrong
+# reason. When it learns to use the generation number, the previous
+# test should succeed, and also this test should fail because the
+# describe name used in the test with generation number can name two
+# commits. Make sure that such a future enhancement does not randomly
+# pick one.
+test_expect_success 'parse describe name not ignoring ambiguity' '
+ # ambiguous at the object name level, and there are two such
+ # commits at generation 1
+ test_must_fail git rev-parse --verify v1.0.0-1-g000000000
+'
+
+test_expect_success 'ambiguous commit-ish' '
+ # Now there are many commits that begin with the
+ # common prefix, none of these should pick one at
+ # random. They all should result in ambiguity errors.
+ test_must_fail git rev-parse --verify 110282^{commit} &&
+
+ # likewise
+ test_must_fail git log 000000000..000000000 &&
+ test_must_fail git log ..000000000 &&
+ test_must_fail git log 000000000.. &&
+ test_must_fail git log 000000000...000000000 &&
+ test_must_fail git log ...000000000 &&
+ test_must_fail git log 000000000...
+'
+
+test_expect_success 'rev-parse --disambiguate' '
+ # The test creates 16 objects that share the prefix and two
+ # commits created by commit-tree in earlier tests share a
+ # different prefix.
+ git rev-parse --disambiguate=000000000 >actual &&
+ test $(wc -l <actual) = 16 &&
+ test "$(sed -e "s/^\(.........\).*/\1/" actual | sort -u)" = 000000000
+'
+
+test_done
diff --git a/t/t2006-checkout-index-basic.sh b/t/t2006-checkout-index-basic.sh
index b855983..57cbdfe 100755
--- a/t/t2006-checkout-index-basic.sh
+++ b/t/t2006-checkout-index-basic.sh
@@ -7,7 +7,7 @@ test_description='basic checkout-index tests
test_expect_success 'checkout-index --gobbledegook' '
test_expect_code 129 git checkout-index --gobbledegook 2>err &&
- grep "[Uu]sage" err
+ test_i18ngrep "[Uu]sage" err
'
test_expect_success 'checkout-index -h in broken repository' '
@@ -18,7 +18,7 @@ test_expect_success 'checkout-index -h in broken repository' '
>.git/index &&
test_expect_code 129 git checkout-index -h >usage 2>&1
) &&
- grep "[Uu]sage" broken/usage
+ test_i18ngrep "[Uu]sage" broken/usage
'
test_done
diff --git a/t/t2107-update-index-basic.sh b/t/t2107-update-index-basic.sh
index 0dbbb00..a6405d3 100755
--- a/t/t2107-update-index-basic.sh
+++ b/t/t2107-update-index-basic.sh
@@ -15,7 +15,7 @@ test_expect_success 'update-index --nonsense fails' '
test_expect_success 'update-index --nonsense dumps usage' '
test_expect_code 129 git update-index --nonsense 2>err &&
- grep "[Uu]sage: git update-index" err
+ test_i18ngrep "[Uu]sage: git update-index" err
'
test_expect_success 'update-index -h with corrupt index' '
@@ -26,7 +26,7 @@ test_expect_success 'update-index -h with corrupt index' '
>.git/index &&
test_expect_code 129 git update-index -h >usage 2>&1
) &&
- grep "[Uu]sage: git update-index" broken/usage
+ test_i18ngrep "[Uu]sage: git update-index" broken/usage
'
test_expect_success '--cacheinfo does not accept blob null sha1' '
diff --git a/t/t3004-ls-files-basic.sh b/t/t3004-ls-files-basic.sh
index 490e052..8d9bc3c 100755
--- a/t/t3004-ls-files-basic.sh
+++ b/t/t3004-ls-files-basic.sh
@@ -22,7 +22,7 @@ test_expect_success 'ls-files with nonexistent path' '
test_expect_success 'ls-files with nonsense option' '
test_expect_code 129 git ls-files --nonsense 2>actual &&
- grep "[Uu]sage: git ls-files" actual
+ test_i18ngrep "[Uu]sage: git ls-files" actual
'
test_expect_success 'ls-files -h in corrupt repository' '
@@ -33,7 +33,7 @@ test_expect_success 'ls-files -h in corrupt repository' '
>.git/index &&
test_expect_code 129 git ls-files -h >usage 2>&1
) &&
- grep "[Uu]sage: git ls-files " broken/usage
+ test_i18ngrep "[Uu]sage: git ls-files " broken/usage
'
test_done
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index a17f8b2..79c8d01 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -31,7 +31,7 @@ test_expect_success 'branch -h in broken repository' '
>.git/refs/heads/master &&
test_expect_code 129 git branch -h >usage 2>&1
) &&
- grep "[Uu]sage" broken/usage
+ test_i18ngrep "[Uu]sage" broken/usage
'
test_expect_success \
@@ -74,7 +74,7 @@ test_expect_success \
test_expect_success \
'git branch -m dumps usage' \
'test_expect_code 129 git branch -m 2>err &&
- grep "[Uu]sage: git branch" err'
+ test_i18ngrep "[Uu]sage: git branch" err'
test_expect_success \
'git branch -m m m/m should work' \
@@ -369,6 +369,76 @@ test_expect_success \
'git tag foobar &&
test_must_fail git branch --track my11 foobar'
+test_expect_success 'use --set-upstream-to modify HEAD' \
+ 'test_config branch.master.remote foo &&
+ test_config branch.master.merge foo &&
+ git branch my12
+ git branch --set-upstream-to my12 &&
+ test "$(git config branch.master.remote)" = "." &&
+ test "$(git config branch.master.merge)" = "refs/heads/my12"'
+
+test_expect_success 'use --set-upstream-to modify a particular branch' \
+ 'git branch my13
+ git branch --set-upstream-to master my13 &&
+ test "$(git config branch.my13.remote)" = "." &&
+ test "$(git config branch.my13.merge)" = "refs/heads/master"'
+
+test_expect_success '--unset-upstream should fail if given a non-existent branch' \
+ 'test_must_fail git branch --unset-upstream i-dont-exist'
+
+test_expect_success 'test --unset-upstream on HEAD' \
+ 'git branch my14
+ test_config branch.master.remote foo &&
+ test_config branch.master.merge foo &&
+ git branch --set-upstream-to my14 &&
+ git branch --unset-upstream &&
+ test_must_fail git config branch.master.remote &&
+ test_must_fail git config branch.master.merge &&
+ # fail for a branch without upstream set
+ test_must_fail git branch --unset-upstream
+'
+
+test_expect_success 'test --unset-upstream on a particular branch' \
+ 'git branch my15
+ git branch --set-upstream-to master my14 &&
+ git branch --unset-upstream my14 &&
+ test_must_fail git config branch.my14.remote &&
+ test_must_fail git config branch.my14.merge'
+
+test_expect_success '--set-upstream shows message when creating a new branch that exists as remote-tracking' \
+ 'git update-ref refs/remotes/origin/master HEAD &&
+ git branch --set-upstream origin/master 2>actual &&
+ test_when_finished git update-ref -d refs/remotes/origin/master &&
+ test_when_finished git branch -d origin/master &&
+ cat >expected <<EOF &&
+The --set-upstream flag is deprecated and will be removed. Consider using --track or --set-upstream-to
+
+If you wanted to make '"'master'"' track '"'origin/master'"', do this:
+
+ git branch -d origin/master
+ git branch --set-upstream-to origin/master
+EOF
+ test_cmp expected actual
+'
+
+test_expect_success '--set-upstream with two args only shows the deprecation message' \
+ 'git branch --set-upstream master my13 2>actual &&
+ test_when_finished git branch --unset-upstream master &&
+ cat >expected <<EOF &&
+The --set-upstream flag is deprecated and will be removed. Consider using --track or --set-upstream-to
+EOF
+ test_cmp expected actual
+'
+
+test_expect_success '--set-upstream with one arg only shows the deprecation message if the branch existed' \
+ 'git branch --set-upstream my13 2>actual &&
+ test_when_finished git branch --unset-upstream my13 &&
+ cat >expected <<EOF &&
+The --set-upstream flag is deprecated and will be removed. Consider using --track or --set-upstream-to
+EOF
+ test_cmp expected actual
+'
+
# Keep this test last, as it changes the current branch
cat >expect <<EOF
$_z40 $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000 branch: Created from master
diff --git a/t/t3300-funny-names.sh b/t/t3300-funny-names.sh
index 1f35e55..7480d6e 100755
--- a/t/t3300-funny-names.sh
+++ b/t/t3300-funny-names.sh
@@ -11,6 +11,16 @@ tree, index, and tree objects.
. ./test-lib.sh
+HT=' '
+
+echo 2>/dev/null > "Name with an${HT}HT"
+if ! test -f "Name with an${HT}HT"
+then
+ # since FAT/NTFS does not allow tabs in filenames, skip this test
+ skip_all='Your filesystem does not allow tabs in filenames'
+ test_done
+fi
+
p0='no-funny'
p1='tabs ," (dq) and spaces'
p2='just space'
@@ -23,21 +33,9 @@ test_expect_success 'setup' '
EOF
{ cat "$p0" >"$p1" || :; } &&
- { echo "Foo Bar Baz" >"$p2" || :; } &&
-
- if test -f "$p1" && cmp "$p0" "$p1"
- then
- test_set_prereq TABS_IN_FILENAMES
- fi
+ { echo "Foo Bar Baz" >"$p2" || :; }
'
-if ! test_have_prereq TABS_IN_FILENAMES
-then
- # since FAT/NTFS does not allow tabs in filenames, skip this test
- skip_all='Your filesystem does not allow tabs in filenames'
- test_done
-fi
-
test_expect_success 'setup: populate index and tree' '
git update-index --add "$p0" "$p2" &&
t0=$(git write-tree)
diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh
index 7788ae0..1de0ebd 100755
--- a/t/t3400-rebase.sh
+++ b/t/t3400-rebase.sh
@@ -68,24 +68,24 @@ test_expect_success 'rebase against master' '
test_expect_success 'rebase against master twice' '
git rebase master >out &&
- grep "Current branch my-topic-branch is up to date" out
+ test_i18ngrep "Current branch my-topic-branch is up to date" out
'
test_expect_success 'rebase against master twice with --force' '
git rebase --force-rebase master >out &&
- grep "Current branch my-topic-branch is up to date, rebase forced" out
+ test_i18ngrep "Current branch my-topic-branch is up to date, rebase forced" out
'
test_expect_success 'rebase against master twice from another branch' '
git checkout my-topic-branch^ &&
git rebase master my-topic-branch >out &&
- grep "Current branch my-topic-branch is up to date" out
+ test_i18ngrep "Current branch my-topic-branch is up to date" out
'
test_expect_success 'rebase fast-forward to master' '
git checkout my-topic-branch^ &&
git rebase my-topic-branch >out &&
- grep "Fast-forwarded HEAD to my-topic-branch" out
+ test_i18ngrep "Fast-forwarded HEAD to my-topic-branch" out
'
test_expect_success 'the rebase operation should not have destroyed author information' '
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 025c1c6..32fdc99 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -118,6 +118,17 @@ test_expect_success 'rebase -i with the exec command checks tree cleanness' '
git rebase --continue
'
+test_expect_success 'rebase -i with exec of inexistent command' '
+ git checkout master &&
+ test_when_finished "git rebase --abort" &&
+ (
+ FAKE_LINES="exec_this-command-does-not-exist 1" &&
+ export FAKE_LINES &&
+ test_must_fail git rebase -i HEAD^ >actual 2>&1
+ ) &&
+ ! grep "Maybe git-rebase is broken" actual
+'
+
test_expect_success 'no changes are a nop' '
git checkout branch2 &&
git rebase -i F &&
@@ -755,4 +766,178 @@ test_expect_success 'rebase-i history with funny messages' '
test_cmp expect actual
'
+
+test_expect_success 'prepare for rebase -i --exec' '
+ git checkout master &&
+ git checkout -b execute &&
+ test_commit one_exec main.txt one_exec &&
+ test_commit two_exec main.txt two_exec &&
+ test_commit three_exec main.txt three_exec
+'
+
+
+test_expect_success 'running "git rebase -i --exec git show HEAD"' '
+ git rebase -i --exec "git show HEAD" HEAD~2 >actual &&
+ (
+ FAKE_LINES="1 exec_git_show_HEAD 2 exec_git_show_HEAD" &&
+ export FAKE_LINES &&
+ git rebase -i HEAD~2 >expect
+ ) &&
+ sed -e "1,9d" expect >expected &&
+ test_cmp expected actual
+'
+
+
+test_expect_success 'running "git rebase --exec git show HEAD -i"' '
+ git reset --hard execute &&
+ git rebase --exec "git show HEAD" -i HEAD~2 >actual &&
+ (
+ FAKE_LINES="1 exec_git_show_HEAD 2 exec_git_show_HEAD" &&
+ export FAKE_LINES &&
+ git rebase -i HEAD~2 >expect
+ ) &&
+ sed -e "1,9d" expect >expected &&
+ test_cmp expected actual
+'
+
+
+test_expect_success 'running "git rebase -ix git show HEAD"' '
+ git reset --hard execute &&
+ git rebase -ix "git show HEAD" HEAD~2 >actual &&
+ (
+ FAKE_LINES="1 exec_git_show_HEAD 2 exec_git_show_HEAD" &&
+ export FAKE_LINES &&
+ git rebase -i HEAD~2 >expect
+ ) &&
+ sed -e "1,9d" expect >expected &&
+ test_cmp expected actual
+'
+
+
+test_expect_success 'rebase -ix with several <CMD>' '
+ git reset --hard execute &&
+ git rebase -ix "git show HEAD; pwd" HEAD~2 >actual &&
+ (
+ FAKE_LINES="1 exec_git_show_HEAD;_pwd 2 exec_git_show_HEAD;_pwd" &&
+ export FAKE_LINES &&
+ git rebase -i HEAD~2 >expect
+ ) &&
+ sed -e "1,9d" expect >expected &&
+ test_cmp expected actual
+'
+
+
+test_expect_success 'rebase -ix with several instances of --exec' '
+ git reset --hard execute &&
+ git rebase -i --exec "git show HEAD" --exec "pwd" HEAD~2 >actual &&
+ (
+ FAKE_LINES="1 exec_git_show_HEAD exec_pwd 2
+ exec_git_show_HEAD exec_pwd" &&
+ export FAKE_LINES &&
+ git rebase -i HEAD~2 >expect
+ ) &&
+ sed -e "1,11d" expect >expected &&
+ test_cmp expected actual
+'
+
+
+test_expect_success 'rebase -ix with --autosquash' '
+ git reset --hard execute &&
+ git checkout -b autosquash &&
+ echo second >second.txt &&
+ git add second.txt &&
+ git commit -m "fixup! two_exec" &&
+ echo bis >bis.txt &&
+ git add bis.txt &&
+ git commit -m "fixup! two_exec" &&
+ (
+ git checkout -b autosquash_actual &&
+ git rebase -i --exec "git show HEAD" --autosquash HEAD~4 >actual
+ ) &&
+ git checkout autosquash &&
+ (
+ git checkout -b autosquash_expected &&
+ FAKE_LINES="1 fixup 3 fixup 4 exec_git_show_HEAD 2 exec_git_show_HEAD" &&
+ export FAKE_LINES &&
+ git rebase -i HEAD~4 >expect
+ ) &&
+ sed -e "1,13d" expect >expected &&
+ test_cmp expected actual
+'
+
+
+test_expect_success 'rebase --exec without -i shows error message' '
+ git reset --hard execute &&
+ test_must_fail git rebase --exec "git show HEAD" HEAD~2 2>actual &&
+ echo "The --exec option must be used with the --interactive option" >expected &&
+ test_i18ncmp expected actual
+'
+
+
+test_expect_success 'rebase -i --exec without <CMD>' '
+ git reset --hard execute &&
+ test_must_fail git rebase -i --exec 2>tmp &&
+ sed -e "1d" tmp >actual &&
+ test_must_fail git rebase -h >expected &&
+ test_cmp expected actual &&
+ git checkout master
+'
+
+test_expect_success 'rebase -i --root re-order and drop commits' '
+ git checkout E &&
+ FAKE_LINES="3 1 2 5" git rebase -i --root &&
+ test E = $(git cat-file commit HEAD | sed -ne \$p) &&
+ test B = $(git cat-file commit HEAD^ | sed -ne \$p) &&
+ test A = $(git cat-file commit HEAD^^ | sed -ne \$p) &&
+ test C = $(git cat-file commit HEAD^^^ | sed -ne \$p) &&
+ test 0 = $(git cat-file commit HEAD^^^ | grep -c ^parent\ )
+'
+
+test_expect_success 'rebase -i --root retain root commit author and message' '
+ git checkout A &&
+ echo B >file7 &&
+ git add file7 &&
+ GIT_AUTHOR_NAME="Twerp Snog" git commit -m "different author" &&
+ FAKE_LINES="2" git rebase -i --root &&
+ git cat-file commit HEAD | grep -q "^author Twerp Snog" &&
+ git cat-file commit HEAD | grep -q "^different author$"
+'
+
+test_expect_success 'rebase -i --root temporary sentinel commit' '
+ git checkout B &&
+ (
+ FAKE_LINES="2" &&
+ export FAKE_LINES &&
+ test_must_fail git rebase -i --root
+ ) &&
+ git cat-file commit HEAD | grep "^tree 4b825dc642cb" &&
+ git rebase --abort
+'
+
+test_expect_success 'rebase -i --root fixup root commit' '
+ git checkout B &&
+ FAKE_LINES="1 fixup 2" git rebase -i --root &&
+ test A = $(git cat-file commit HEAD | sed -ne \$p) &&
+ test B = $(git show HEAD:file1) &&
+ test 0 = $(git cat-file commit HEAD | grep -c ^parent\ )
+'
+
+test_expect_success 'rebase --edit-todo does not works on non-interactive rebase' '
+ git reset --hard &&
+ git checkout conflict-branch &&
+ test_must_fail git rebase --onto HEAD~2 HEAD~ &&
+ test_must_fail git rebase --edit-todo &&
+ git rebase --abort
+'
+
+test_expect_success 'rebase --edit-todo can be used to modify todo' '
+ git reset --hard &&
+ git checkout no-conflict-branch^0 &&
+ FAKE_LINES="edit 1 2 3" git rebase -i HEAD~3 &&
+ FAKE_LINES="2 1" git rebase --edit-todo &&
+ git rebase --continue
+ test M = $(git cat-file commit HEAD^ | sed -ne \$p) &&
+ test L = $(git cat-file commit HEAD | sed -ne \$p)
+'
+
test_done
diff --git a/t/t3405-rebase-malformed.sh b/t/t3405-rebase-malformed.sh
index e5ad67c..19eddad 100755
--- a/t/t3405-rebase-malformed.sh
+++ b/t/t3405-rebase-malformed.sh
@@ -1,6 +1,6 @@
#!/bin/sh
-test_description='rebase should not insist on git message convention'
+test_description='rebase should handle arbitrary git message'
. ./test-lib.sh
@@ -12,6 +12,11 @@ It has two paragraphs, but its first paragraph is not friendly
to oneline summary format.
EOF
+cat >G <<\EOF
+commit log message containing a diff
+EOF
+
+
test_expect_success setup '
>file1 &&
@@ -19,8 +24,9 @@ test_expect_success setup '
git add file1 file2 &&
test_tick &&
git commit -m "Initial commit" &&
+ git branch diff-in-message
- git checkout -b side &&
+ git checkout -b multi-line-subject &&
cat F >file2 &&
git add file2 &&
test_tick &&
@@ -28,6 +34,17 @@ test_expect_success setup '
git cat-file commit HEAD | sed -e "1,/^\$/d" >F0 &&
+ git checkout diff-in-message &&
+ echo "commit log message containing a diff" >G &&
+ echo "" >>G
+ cat G >file2 &&
+ git add file2 &&
+ git diff --cached >>G &&
+ test_tick &&
+ git commit -F G &&
+
+ git cat-file commit HEAD | sed -e "1,/^\$/d" >G0 &&
+
git checkout master &&
echo One >file1 &&
@@ -36,13 +53,20 @@ test_expect_success setup '
git commit -m "Second commit"
'
-test_expect_success rebase '
+test_expect_success 'rebase commit with multi-line subject' '
- git rebase master side &&
+ git rebase master multi-line-subject &&
git cat-file commit HEAD | sed -e "1,/^\$/d" >F1 &&
test_cmp F0 F1 &&
test_cmp F F0
'
+test_expect_success 'rebase commit with diff in message' '
+ git rebase master diff-in-message &&
+ git cat-file commit HEAD | sed -e "1,/^$/d" >G1 &&
+ test_cmp G0 G1 &&
+ test_cmp G G0
+'
+
test_done
diff --git a/t/t3406-rebase-message.sh b/t/t3406-rebase-message.sh
index 6898377..e6a9a0d 100755
--- a/t/t3406-rebase-message.sh
+++ b/t/t3406-rebase-message.sh
@@ -62,9 +62,16 @@ test_expect_success 'rebase -n overrides config rebase.stat config' '
! grep "^ fileX | *1 +$" diffstat.txt
'
+# Output to stderr:
+#
+# "Does not point to a valid commit: invalid-ref"
+#
+# NEEDSWORK: This "grep" is fine in real non-C locales, but
+# GETTEXT_POISON poisons the refname along with the enclosing
+# error message.
test_expect_success 'rebase --onto outputs the invalid ref' '
test_must_fail git rebase --onto invalid-ref HEAD HEAD 2>err &&
- grep "invalid-ref" err
+ test_i18ngrep "invalid-ref" err
'
test_done
diff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh
index 086c91c..0b52105 100755
--- a/t/t3412-rebase-root.sh
+++ b/t/t3412-rebase-root.sh
@@ -22,8 +22,9 @@ test_expect_success 'prepare repository' '
test_commit 4 B
'
-test_expect_success 'rebase --root expects --onto' '
- test_must_fail git rebase --root
+test_expect_success 'rebase --root fails with too many args' '
+ git checkout -B fail other &&
+ test_must_fail git rebase --onto master --root fail fail
'
test_expect_success 'setup pre-rebase hook' '
@@ -42,7 +43,7 @@ cat > expect <<EOF
EOF
test_expect_success 'rebase --root --onto <newbase>' '
- git checkout -b work &&
+ git checkout -b work other &&
git rebase --root --onto master &&
git log --pretty=tformat:"%s" > rebased &&
test_cmp expect rebased
diff --git a/t/t3501-revert-cherry-pick.sh b/t/t3501-revert-cherry-pick.sh
index 595d2ff..34c86e5 100755
--- a/t/t3501-revert-cherry-pick.sh
+++ b/t/t3501-revert-cherry-pick.sh
@@ -47,7 +47,7 @@ test_expect_success 'cherry-pick --nonsense' '
git diff --exit-code HEAD &&
test_must_fail git cherry-pick --nonsense 2>msg &&
git diff --exit-code HEAD "$pos" &&
- grep '[Uu]sage:' msg
+ test_i18ngrep '[Uu]sage:' msg
'
test_expect_success 'revert --nonsense' '
@@ -56,7 +56,7 @@ test_expect_success 'revert --nonsense' '
git diff --exit-code HEAD &&
test_must_fail git revert --nonsense 2>msg &&
git diff --exit-code HEAD "$pos" &&
- grep '[Uu]sage:' msg
+ test_i18ngrep '[Uu]sage:' msg
'
test_expect_success 'cherry-pick after renaming branch' '
diff --git a/t/t3505-cherry-pick-empty.sh b/t/t3505-cherry-pick-empty.sh
index 5a1340c..a0c6e30 100755
--- a/t/t3505-cherry-pick-empty.sh
+++ b/t/t3505-cherry-pick-empty.sh
@@ -53,6 +53,11 @@ test_expect_success 'index lockfile was removed' '
'
+test_expect_success 'cherry-pick a commit with an empty message with --allow-empty-message' '
+ git checkout -f master &&
+ git cherry-pick --allow-empty-message empty-branch
+'
+
test_expect_success 'cherry pick an empty non-ff commit without --allow-empty' '
git checkout master &&
echo fourth >>file2 &&
diff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh
index 0c81b3c..c82f721 100755
--- a/t/t3507-cherry-pick-conflict.sh
+++ b/t/t3507-cherry-pick-conflict.sh
@@ -30,6 +30,7 @@ test_expect_success setup '
test_commit initial foo a &&
test_commit base foo b &&
test_commit picked foo c &&
+ test_commit --signoff picked-signed foo d &&
git config advice.detachedhead false
'
@@ -340,4 +341,35 @@ test_expect_success 'revert conflict, diff3 -m style' '
test_cmp expected actual
'
+test_expect_success 'failed cherry-pick does not forget -s' '
+ pristine_detach initial &&
+ test_must_fail git cherry-pick -s picked &&
+ test_i18ngrep -e "Signed-off-by" .git/MERGE_MSG
+'
+
+test_expect_success 'commit after failed cherry-pick does not add duplicated -s' '
+ pristine_detach initial &&
+ test_must_fail git cherry-pick -s picked-signed &&
+ git commit -a -s &&
+ test $(git show -s |grep -c "Signed-off-by") = 1
+'
+
+test_expect_success 'commit after failed cherry-pick adds -s at the right place' '
+ pristine_detach initial &&
+ test_must_fail git cherry-pick picked &&
+ git commit -a -s &&
+ pwd &&
+ cat <<EOF > expected &&
+picked
+
+Signed-off-by: C O Mitter <committer@example.com>
+
+Conflicts:
+ foo
+EOF
+
+ git show -s --pretty=format:%B > actual &&
+ test_cmp expected actual
+'
+
test_done
diff --git a/t/t3508-cherry-pick-many-commits.sh b/t/t3508-cherry-pick-many-commits.sh
index 75f7ff4..340afc7 100755
--- a/t/t3508-cherry-pick-many-commits.sh
+++ b/t/t3508-cherry-pick-many-commits.sh
@@ -44,6 +44,21 @@ test_expect_success 'cherry-pick first..fourth works' '
check_head_differs_from fourth
'
+test_expect_success 'cherry-pick three one two works' '
+ git checkout -f first &&
+ test_commit one &&
+ test_commit two &&
+ test_commit three &&
+ git checkout -f master &&
+ git reset --hard first &&
+ git cherry-pick three one two &&
+ git diff --quiet three &&
+ git diff --quiet HEAD three &&
+ test "$(git log --reverse --format=%s first..)" = "three
+one
+two"
+'
+
test_expect_success 'output to keep user entertained during multi-pick' '
cat <<-\EOF >expected &&
[master OBJID] second
diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh
index f4e6450..b5fb527 100755
--- a/t/t3510-cherry-pick-sequence.sh
+++ b/t/t3510-cherry-pick-sequence.sh
@@ -410,7 +410,7 @@ test_expect_success '--continue respects -x in first commit in multi-pick' '
grep "cherry picked from.*$picked" msg
'
-test_expect_success '--signoff is not automatically propagated to resolved conflict' '
+test_expect_failure '--signoff is automatically propagated to resolved conflict' '
pristine_detach initial &&
test_expect_code 1 git cherry-pick --signoff base..anotherpick &&
echo "c" >foo &&
@@ -428,7 +428,7 @@ test_expect_success '--signoff is not automatically propagated to resolved confl
grep "Signed-off-by:" anotherpick_msg
'
-test_expect_success '--signoff dropped for implicit commit of resolution, multi-pick case' '
+test_expect_failure '--signoff dropped for implicit commit of resolution, multi-pick case' '
pristine_detach initial &&
test_must_fail git cherry-pick -s picked anotherpick &&
echo c >foo &&
@@ -441,7 +441,7 @@ test_expect_success '--signoff dropped for implicit commit of resolution, multi-
! grep Signed-off-by: msg
'
-test_expect_success 'sign-off needs to be reaffirmed after conflict resolution, single-pick case' '
+test_expect_failure 'sign-off needs to be reaffirmed after conflict resolution, single-pick case' '
pristine_detach initial &&
test_must_fail git cherry-pick -s picked &&
echo c >foo &&
diff --git a/t/t3902-quoted.sh b/t/t3902-quoted.sh
index 534ee08..892f567 100755
--- a/t/t3902-quoted.sh
+++ b/t/t3902-quoted.sh
@@ -16,9 +16,8 @@ echo foo 2>/dev/null > "Name and an${HT}HT"
if ! test -f "Name and an${HT}HT"
then
# FAT/NTFS does not allow tabs in filenames
- say 'Your filesystem does not allow tabs in filenames'
-else
- test_set_prereq TABS_IN_FILENAMES
+ skip_all='Your filesystem does not allow tabs in filenames'
+ test_done
fi
for_each_name () {
@@ -31,7 +30,7 @@ for_each_name () {
done
}
-test_expect_success TABS_IN_FILENAMES 'setup' '
+test_expect_success 'setup' '
mkdir "$FN" &&
for_each_name "echo initial >\"\$name\"" &&
@@ -45,7 +44,7 @@ test_expect_success TABS_IN_FILENAMES 'setup' '
'
-test_expect_success TABS_IN_FILENAMES 'setup expected files' '
+test_expect_success 'setup expected files' '
cat >expect.quoted <<\EOF &&
Name
"Name and a\nLF"
@@ -75,74 +74,74 @@ With SP in it
EOF
'
-test_expect_success TABS_IN_FILENAMES 'check fully quoted output from ls-files' '
+test_expect_success 'check fully quoted output from ls-files' '
git ls-files >current && test_cmp expect.quoted current
'
-test_expect_success TABS_IN_FILENAMES 'check fully quoted output from diff-files' '
+test_expect_success 'check fully quoted output from diff-files' '
git diff --name-only >current &&
test_cmp expect.quoted current
'
-test_expect_success TABS_IN_FILENAMES 'check fully quoted output from diff-index' '
+test_expect_success 'check fully quoted output from diff-index' '
git diff --name-only HEAD >current &&
test_cmp expect.quoted current
'
-test_expect_success TABS_IN_FILENAMES 'check fully quoted output from diff-tree' '
+test_expect_success 'check fully quoted output from diff-tree' '
git diff --name-only HEAD^ HEAD >current &&
test_cmp expect.quoted current
'
-test_expect_success TABS_IN_FILENAMES 'check fully quoted output from ls-tree' '
+test_expect_success 'check fully quoted output from ls-tree' '
git ls-tree --name-only -r HEAD >current &&
test_cmp expect.quoted current
'
-test_expect_success TABS_IN_FILENAMES 'setting core.quotepath' '
+test_expect_success 'setting core.quotepath' '
git config --bool core.quotepath false
'
-test_expect_success TABS_IN_FILENAMES 'check fully quoted output from ls-files' '
+test_expect_success 'check fully quoted output from ls-files' '
git ls-files >current && test_cmp expect.raw current
'
-test_expect_success TABS_IN_FILENAMES 'check fully quoted output from diff-files' '
+test_expect_success 'check fully quoted output from diff-files' '
git diff --name-only >current &&
test_cmp expect.raw current
'
-test_expect_success TABS_IN_FILENAMES 'check fully quoted output from diff-index' '
+test_expect_success 'check fully quoted output from diff-index' '
git diff --name-only HEAD >current &&
test_cmp expect.raw current
'
-test_expect_success TABS_IN_FILENAMES 'check fully quoted output from diff-tree' '
+test_expect_success 'check fully quoted output from diff-tree' '
git diff --name-only HEAD^ HEAD >current &&
test_cmp expect.raw current
'
-test_expect_success TABS_IN_FILENAMES 'check fully quoted output from ls-tree' '
+test_expect_success 'check fully quoted output from ls-tree' '
git ls-tree --name-only -r HEAD >current &&
test_cmp expect.raw current
diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
index cd04263..5dfbda7 100755
--- a/t/t3903-stash.sh
+++ b/t/t3903-stash.sh
@@ -610,7 +610,7 @@ test_expect_success 'stash apply shows status same as git status (relative to cu
git stash apply
) |
sed -e 1,2d >actual && # drop "Saved..." and "HEAD is now..."
- test_cmp expect actual
+ test_i18ncmp expect actual
'
cat > expect << EOF
diff --git a/t/t3910-mac-os-precompose.sh b/t/t3910-mac-os-precompose.sh
new file mode 100755
index 0000000..5fe57c5
--- /dev/null
+++ b/t/t3910-mac-os-precompose.sh
@@ -0,0 +1,153 @@
+#!/bin/sh
+#
+# Copyright (c) 2012 Torsten Bögershausen
+#
+
+test_description='utf-8 decomposed (nfd) converted to precomposed (nfc)'
+
+. ./test-lib.sh
+
+if ! test_have_prereq UTF8_NFD_TO_NFC
+then
+ skip_all="filesystem does not corrupt utf-8"
+ test_done
+fi
+
+# create utf-8 variables
+Adiarnfc=`printf '\303\204'`
+Adiarnfd=`printf 'A\314\210'`
+
+Odiarnfc=`printf '\303\226'`
+Odiarnfd=`printf 'O\314\210'`
+AEligatu=`printf '\303\206'`
+Invalidu=`printf '\303\377'`
+
+
+#Create a string with 255 bytes (decomposed)
+Alongd=$Adiarnfd$Adiarnfd$Adiarnfd$Adiarnfd$Adiarnfd$Adiarnfd$Adiarnfd #21 Byte
+Alongd=$Alongd$Alongd$Alongd #63 Byte
+Alongd=$Alongd$Alongd$Alongd$Alongd$Adiarnfd #255 Byte
+
+#Create a string with 254 bytes (precomposed)
+Alongc=$AEligatu$AEligatu$AEligatu$AEligatu$AEligatu #10 Byte
+Alongc=$Alongc$Alongc$Alongc$Alongc$Alongc #50 Byte
+Alongc=$Alongc$Alongc$Alongc$Alongc$Alongc #250 Byte
+Alongc=$Alongc$AEligatu$AEligatu #254 Byte
+
+test_expect_success "detect if nfd needed" '
+ precomposeunicode=`git config core.precomposeunicode` &&
+ test "$precomposeunicode" = false &&
+ git config core.precomposeunicode true
+'
+test_expect_success "setup" '
+ >x &&
+ git add x &&
+ git commit -m "1st commit" &&
+ git rm x &&
+ git commit -m "rm x"
+'
+test_expect_success "setup case mac" '
+ git checkout -b mac_os
+'
+# This will test nfd2nfc in readdir()
+test_expect_success "add file Adiarnfc" '
+ echo f.Adiarnfc >f.$Adiarnfc &&
+ git add f.$Adiarnfc &&
+ git commit -m "add f.$Adiarnfc"
+'
+# This will test nfd2nfc in git stage()
+test_expect_success "stage file d.Adiarnfd/f.Adiarnfd" '
+ mkdir d.$Adiarnfd &&
+ echo d.$Adiarnfd/f.$Adiarnfd >d.$Adiarnfd/f.$Adiarnfd &&
+ git stage d.$Adiarnfd/f.$Adiarnfd &&
+ git commit -m "add d.$Adiarnfd/f.$Adiarnfd"
+'
+test_expect_success "add link Adiarnfc" '
+ ln -s d.$Adiarnfd/f.$Adiarnfd l.$Adiarnfc &&
+ git add l.$Adiarnfc &&
+ git commit -m "add l.Adiarnfc"
+'
+# This will test git log
+test_expect_success "git log f.Adiar" '
+ git log f.$Adiarnfc > f.Adiarnfc.log &&
+ git log f.$Adiarnfd > f.Adiarnfd.log &&
+ test -s f.Adiarnfc.log &&
+ test -s f.Adiarnfd.log &&
+ test_cmp f.Adiarnfc.log f.Adiarnfd.log &&
+ rm f.Adiarnfc.log f.Adiarnfd.log
+'
+# This will test git ls-files
+test_expect_success "git lsfiles f.Adiar" '
+ git ls-files f.$Adiarnfc > f.Adiarnfc.log &&
+ git ls-files f.$Adiarnfd > f.Adiarnfd.log &&
+ test -s f.Adiarnfc.log &&
+ test -s f.Adiarnfd.log &&
+ test_cmp f.Adiarnfc.log f.Adiarnfd.log &&
+ rm f.Adiarnfc.log f.Adiarnfd.log
+'
+# This will test git mv
+test_expect_success "git mv" '
+ git mv f.$Adiarnfd f.$Odiarnfc &&
+ git mv d.$Adiarnfd d.$Odiarnfc &&
+ git mv l.$Adiarnfd l.$Odiarnfc &&
+ git commit -m "mv Adiarnfd Odiarnfc"
+'
+# Files can be checked out as nfc
+# And the link has been corrected from nfd to nfc
+test_expect_success "git checkout nfc" '
+ rm f.$Odiarnfc &&
+ git checkout f.$Odiarnfc
+'
+# Make it possible to checkout files with their NFD names
+test_expect_success "git checkout file nfd" '
+ rm -f f.* &&
+ git checkout f.$Odiarnfd
+'
+# Make it possible to checkout links with their NFD names
+test_expect_success "git checkout link nfd" '
+ rm l.* &&
+ git checkout l.$Odiarnfd
+'
+test_expect_success "setup case mac2" '
+ git checkout master &&
+ git reset --hard &&
+ git checkout -b mac_os_2
+'
+# This will test nfd2nfc in git commit
+test_expect_success "commit file d2.Adiarnfd/f.Adiarnfd" '
+ mkdir d2.$Adiarnfd &&
+ echo d2.$Adiarnfd/f.$Adiarnfd >d2.$Adiarnfd/f.$Adiarnfd &&
+ git add d2.$Adiarnfd/f.$Adiarnfd &&
+ git commit -m "add d2.$Adiarnfd/f.$Adiarnfd" -- d2.$Adiarnfd/f.$Adiarnfd
+'
+test_expect_success "setup for long decomposed filename" '
+ git checkout master &&
+ git reset --hard &&
+ git checkout -b mac_os_long_nfd_fn
+'
+test_expect_success "Add long decomposed filename" '
+ echo longd >$Alongd &&
+ git add * &&
+ git commit -m "Long filename"
+'
+test_expect_success "setup for long precomposed filename" '
+ git checkout master &&
+ git reset --hard &&
+ git checkout -b mac_os_long_nfc_fn
+'
+test_expect_success "Add long precomposed filename" '
+ echo longc >$Alongc &&
+ git add * &&
+ git commit -m "Long filename"
+'
+# Test if the global core.precomposeunicode stops autosensing
+# Must be the last test case
+test_expect_success "respect git config --global core.precomposeunicode" '
+ git config --global core.precomposeunicode true &&
+ rm -rf .git &&
+ git init &&
+ precomposeunicode=`git config core.precomposeunicode` &&
+ test "$precomposeunicode" = "true"
+'
+
+test_done
diff --git a/t/t4006-diff-mode.sh b/t/t4006-diff-mode.sh
index 7a3e1f9..3d4b1ba 100755
--- a/t/t4006-diff-mode.sh
+++ b/t/t4006-diff-mode.sh
@@ -36,24 +36,24 @@ test_expect_success '--stat output after text chmod' '
test_chmod -x rezrov &&
echo " 0 files changed" >expect &&
git diff HEAD --stat >actual &&
- test_cmp expect actual
+ test_i18ncmp expect actual
'
test_expect_success '--shortstat output after text chmod' '
git diff HEAD --shortstat >actual &&
- test_cmp expect actual
+ test_i18ncmp expect actual
'
test_expect_success '--stat output after binary chmod' '
test_chmod +x binbin &&
echo " 0 files changed" >expect &&
git diff HEAD --stat >actual &&
- test_cmp expect actual
+ test_i18ncmp expect actual
'
test_expect_success '--shortstat output after binary chmod' '
git diff HEAD --shortstat >actual &&
- test_cmp expect actual
+ test_i18ncmp expect actual
'
test_done
diff --git a/t/t4012-diff-binary.sh b/t/t4012-diff-binary.sh
index 6cebb39..1215ae5 100755
--- a/t/t4012-diff-binary.sh
+++ b/t/t4012-diff-binary.sh
@@ -15,13 +15,14 @@ cat >expect.binary-numstat <<\EOF
- - d
EOF
-test_expect_success 'prepare repository' \
- 'echo AIT >a && echo BIT >b && echo CIT >c && echo DIT >d &&
- git update-index --add a b c d &&
- echo git >a &&
- cat "$TEST_DIRECTORY"/test-binary-1.png >b &&
- echo git >c &&
- cat b b >d'
+test_expect_success 'prepare repository' '
+ echo AIT >a && echo BIT >b && echo CIT >c && echo DIT >d &&
+ git update-index --add a b c d &&
+ echo git >a &&
+ cat "$TEST_DIRECTORY"/test-binary-1.png >b &&
+ echo git >c &&
+ cat b b >d
+'
cat > expected <<\EOF
a | 2 +-
@@ -30,16 +31,16 @@ cat > expected <<\EOF
d | Bin
4 files changed, 2 insertions(+), 2 deletions(-)
EOF
-test_expect_success '"apply --stat" output for binary file change' '
+test_expect_success 'apply --stat output for binary file change' '
git diff >diff &&
git apply --stat --summary <diff >current &&
test_i18ncmp expected current
'
test_expect_success 'diff --shortstat output for binary file change' '
- echo " 4 files changed, 2 insertions(+), 2 deletions(-)" >expected &&
+ tail -n 1 expected >expect &&
git diff --shortstat >current &&
- test_i18ncmp expected current
+ test_i18ncmp expect current
'
test_expect_success 'diff --shortstat output for binary file change only' '
@@ -62,49 +63,42 @@ test_expect_success 'apply --numstat understands diff --binary format' '
# apply needs to be able to skip the binary material correctly
# in order to report the line number of a corrupt patch.
-test_expect_success 'apply detecting corrupt patch correctly' \
- 'git diff | sed -e 's/-CIT/xCIT/' >broken &&
- if git apply --stat --summary broken 2>detected
- then
- echo unhappy - should have detected an error
- (exit 1)
- else
- echo happy
- fi &&
- detected=`cat detected` &&
- detected=`expr "$detected" : "fatal.*at line \\([0-9]*\\)\$"` &&
- detected=`sed -ne "${detected}p" broken` &&
- test "$detected" = xCIT'
-
-test_expect_success 'apply detecting corrupt patch correctly' \
- 'git diff --binary | sed -e 's/-CIT/xCIT/' >broken &&
- if git apply --stat --summary broken 2>detected
- then
- echo unhappy - should have detected an error
- (exit 1)
- else
- echo happy
- fi &&
- detected=`cat detected` &&
- detected=`expr "$detected" : "fatal.*at line \\([0-9]*\\)\$"` &&
- detected=`sed -ne "${detected}p" broken` &&
- test "$detected" = xCIT'
+test_expect_success C_LOCALE_OUTPUT 'apply detecting corrupt patch correctly' '
+ git diff >output &&
+ sed -e "s/-CIT/xCIT/" <output >broken &&
+ test_must_fail git apply --stat --summary broken 2>detected &&
+ detected=`cat detected` &&
+ detected=`expr "$detected" : "fatal.*at line \\([0-9]*\\)\$"` &&
+ detected=`sed -ne "${detected}p" broken` &&
+ test "$detected" = xCIT
+'
+
+test_expect_success C_LOCALE_OUTPUT 'apply detecting corrupt patch correctly' '
+ git diff --binary | sed -e "s/-CIT/xCIT/" >broken &&
+ test_must_fail git apply --stat --summary broken 2>detected &&
+ detected=`cat detected` &&
+ detected=`expr "$detected" : "fatal.*at line \\([0-9]*\\)\$"` &&
+ detected=`sed -ne "${detected}p" broken` &&
+ test "$detected" = xCIT
+'
test_expect_success 'initial commit' 'git commit -a -m initial'
# Try removal (b), modification (d), and creation (e).
-test_expect_success 'diff-index with --binary' \
- 'echo AIT >a && mv b e && echo CIT >c && cat e >d &&
- git update-index --add --remove a b c d e &&
- tree0=`git write-tree` &&
- git diff --cached --binary >current &&
- git apply --stat --summary current'
-
-test_expect_success 'apply binary patch' \
- 'git reset --hard &&
- git apply --binary --index <current &&
- tree1=`git write-tree` &&
- test "$tree1" = "$tree0"'
+test_expect_success 'diff-index with --binary' '
+ echo AIT >a && mv b e && echo CIT >c && cat e >d &&
+ git update-index --add --remove a b c d e &&
+ tree0=`git write-tree` &&
+ git diff --cached --binary >current &&
+ git apply --stat --summary current
+'
+
+test_expect_success 'apply binary patch' '
+ git reset --hard &&
+ git apply --binary --index <current &&
+ tree1=`git write-tree` &&
+ test "$tree1" = "$tree0"
+'
test_expect_success 'diff --no-index with binary creation' '
echo Q | q_to_nul >binary &&
@@ -125,7 +119,7 @@ cat >expect <<EOF
EOF
test_expect_success 'diff --stat with binary files and big change count' '
- echo X | dd of=binfile bs=1k seek=1 &&
+ printf "\01\00%1024d" 1 >binfile &&
git add binfile &&
i=0 &&
while test $i -lt 10000; do
diff --git a/t/t4016-diff-quote.sh b/t/t4016-diff-quote.sh
index 97b8177..cd543ec 100755
--- a/t/t4016-diff-quote.sh
+++ b/t/t4016-diff-quote.sh
@@ -13,14 +13,12 @@ P1='pathname with HT'
P2='pathname with SP'
P3='pathname
with LF'
-if : 2>/dev/null >"$P1" && test -f "$P1" && rm -f "$P1"
-then
- test_set_prereq TABS_IN_FILENAMES
-else
- say 'Your filesystem does not allow tabs in filenames'
-fi
+echo 2>/dev/null >"$P1" && test -f "$P1" && rm -f "$P1" || {
+ skip_all='Your filesystem does not allow tabs in filenames'
+ test_done
+}
-test_expect_success TABS_IN_FILENAMES setup '
+test_expect_success setup '
echo P0.0 >"$P0.0" &&
echo P0.1 >"$P0.1" &&
echo P0.2 >"$P0.2" &&
@@ -40,7 +38,7 @@ test_expect_success TABS_IN_FILENAMES setup '
:
'
-test_expect_success TABS_IN_FILENAMES 'setup expected files' '
+test_expect_success 'setup expected files' '
cat >expect <<\EOF
rename pathname.1 => "Rpathname\twith HT.0" (100%)
rename pathname.3 => "Rpathname\nwith LF.0" (100%)
@@ -52,12 +50,12 @@ cat >expect <<\EOF
EOF
'
-test_expect_success TABS_IN_FILENAMES 'git diff --summary -M HEAD' '
+test_expect_success 'git diff --summary -M HEAD' '
git diff --summary -M HEAD >actual &&
test_cmp expect actual
'
-test_expect_success TABS_IN_FILENAMES 'git diff --numstat -M HEAD' '
+test_expect_success 'git diff --numstat -M HEAD' '
cat >expect <<-\EOF &&
0 0 pathname.1 => "Rpathname\twith HT.0"
0 0 pathname.3 => "Rpathname\nwith LF.0"
@@ -71,7 +69,7 @@ test_expect_success TABS_IN_FILENAMES 'git diff --numstat -M HEAD' '
test_cmp expect actual
'
-test_expect_success TABS_IN_FILENAMES 'git diff --stat -M HEAD' '
+test_expect_success 'git diff --stat -M HEAD' '
cat >expect <<-\EOF &&
pathname.1 => "Rpathname\twith HT.0" | 0
pathname.3 => "Rpathname\nwith LF.0" | 0
diff --git a/t/t4018-diff-funcname.sh b/t/t4018-diff-funcname.sh
index 4bd2a1c..082d3e8 100755
--- a/t/t4018-diff-funcname.sh
+++ b/t/t4018-diff-funcname.sh
@@ -105,7 +105,7 @@ test_expect_funcname () {
grep "^@@.*@@ $1" diff
}
-for p in bibtex cpp csharp fortran html java matlab objc pascal perl php python ruby tex
+for p in ada bibtex cpp csharp fortran html java matlab objc pascal perl php python ruby tex
do
test_expect_success "builtin $p pattern compiles" '
echo "*.java diff=$p" >.gitattributes &&
diff --git a/t/t4034-diff-words.sh b/t/t4034-diff-words.sh
index 30d42cb..40ab333 100755
--- a/t/t4034-diff-words.sh
+++ b/t/t4034-diff-words.sh
@@ -298,6 +298,7 @@ test_expect_success 'unset default driver' '
test_unconfig diff.wordregex
'
+test_language_driver ada
test_language_driver bibtex
test_language_driver cpp
test_language_driver csharp
diff --git a/t/t4034/ada/expect b/t/t4034/ada/expect
new file mode 100644
index 0000000..be2376e
--- /dev/null
+++ b/t/t4034/ada/expect
@@ -0,0 +1,27 @@
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index d96fdd1..df21bb0 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
+<CYAN>@@ -1,13 +1,13 @@<RESET>
+Ada.Text_IO.Put_Line("Hello World<RED>!<RESET><GREEN>?<RESET>");
+1 1e<RED>-<RESET>10 16#FE12#E2 3.141_592 '<RED>x<RESET><GREEN>y<RESET>'
+<RED>a<RESET><GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>**<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>(<RED>b<RESET><GREEN>y<RESET>)
+<RED>a<RESET><GREEN>x<RESET>:=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>/= <RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>,<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>=><RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>..<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET><><RED>b<RESET><GREEN>y<RESET>
diff --git a/t/t4034/ada/post b/t/t4034/ada/post
new file mode 100644
index 0000000..df21bb0
--- /dev/null
+++ b/t/t4034/ada/post
@@ -0,0 +1,13 @@
+Ada.Text_IO.Put_Line("Hello World?");
+1 1e10 16#FE12#E2 3.141_592 'y'
+x+y x-y
+x*y x/y
+x**y
+x(y)
+x:=y
+x=y x/= y
+x<y x<=y x>y x>=y
+x,y
+x=>y
+x..y
+x<>y
diff --git a/t/t4034/ada/pre b/t/t4034/ada/pre
new file mode 100644
index 0000000..d96fdd1
--- /dev/null
+++ b/t/t4034/ada/pre
@@ -0,0 +1,13 @@
+Ada.Text_IO.Put_Line("Hello World!");
+1 1e-10 16#FE12#E2 3.141_592 'x'
+a+b a-b
+a*b a/b
+a**b
+a(b)
+a:=b
+a=b a/= b
+a<b a<=b a>b a>=b
+a,b
+a=>b
+a..b
+a<>b
diff --git a/t/t4108-apply-threeway.sh b/t/t4108-apply-threeway.sh
new file mode 100755
index 0000000..fa5d4ef
--- /dev/null
+++ b/t/t4108-apply-threeway.sh
@@ -0,0 +1,157 @@
+#!/bin/sh
+
+test_description='git apply --3way'
+
+. ./test-lib.sh
+
+create_file () {
+ for i
+ do
+ echo "$i"
+ done
+}
+
+sanitize_conflicted_diff () {
+ sed -e '
+ /^index /d
+ s/^\(+[<>][<>][<>][<>]*\) .*/\1/
+ '
+}
+
+test_expect_success setup '
+ test_tick &&
+ create_file >one 1 2 3 4 5 6 7 &&
+ cat one >two &&
+ git add one two &&
+ git commit -m initial &&
+
+ git branch side &&
+
+ test_tick &&
+ create_file >one 1 two 3 4 5 six 7 &&
+ create_file >two 1 two 3 4 5 6 7 &&
+ git commit -a -m master &&
+
+ git checkout side &&
+ create_file >one 1 2 3 4 five 6 7 &&
+ create_file >two 1 2 3 4 five 6 7 &&
+ git commit -a -m side &&
+
+ git checkout master
+'
+
+test_expect_success 'apply without --3way' '
+ git diff side^ side >P.diff &&
+
+ # should fail to apply
+ git reset --hard &&
+ git checkout master^0 &&
+ test_must_fail git apply --index P.diff &&
+ # should leave things intact
+ git diff-files --exit-code &&
+ git diff-index --exit-code --cached HEAD
+'
+
+test_expect_success 'apply with --3way' '
+ # Merging side should be similar to applying this patch
+ git diff ...side >P.diff &&
+
+ # The corresponding conflicted merge
+ git reset --hard &&
+ git checkout master^0 &&
+ test_must_fail git merge --no-commit side &&
+ git ls-files -s >expect.ls &&
+ git diff HEAD | sanitize_conflicted_diff >expect.diff &&
+
+ # should fail to apply
+ git reset --hard &&
+ git checkout master^0 &&
+ test_must_fail git apply --index --3way P.diff &&
+ git ls-files -s >actual.ls &&
+ git diff HEAD | sanitize_conflicted_diff >actual.diff &&
+
+ # The result should resemble the corresponding merge
+ test_cmp expect.ls actual.ls &&
+ test_cmp expect.diff actual.diff
+'
+
+test_expect_success 'apply with --3way with rerere enabled' '
+ git config rerere.enabled true &&
+
+ # Merging side should be similar to applying this patch
+ git diff ...side >P.diff &&
+
+ # The corresponding conflicted merge
+ git reset --hard &&
+ git checkout master^0 &&
+ test_must_fail git merge --no-commit side &&
+
+ # Manually resolve and record the resolution
+ create_file 1 two 3 4 five six 7 >one &&
+ git rerere &&
+ cat one >expect &&
+
+ # should fail to apply
+ git reset --hard &&
+ git checkout master^0 &&
+ test_must_fail git apply --index --3way P.diff &&
+
+ # but rerere should have replayed the recorded resolution
+ test_cmp expect one
+'
+
+test_expect_success 'apply -3 with add/add conflict setup' '
+ git reset --hard &&
+
+ git checkout -b adder &&
+ create_file 1 2 3 4 5 6 7 >three &&
+ create_file 1 2 3 4 5 6 7 >four &&
+ git add three four &&
+ git commit -m "add three and four" &&
+
+ git checkout -b another adder^ &&
+ create_file 1 2 3 4 5 6 7 >three &&
+ create_file 1 2 3 four 5 6 7 >four &&
+ git add three four &&
+ git commit -m "add three and four" &&
+
+ # Merging another should be similar to applying this patch
+ git diff adder...another >P.diff &&
+
+ git checkout adder^0 &&
+ test_must_fail git merge --no-commit another &&
+ git ls-files -s >expect.ls &&
+ git diff HEAD | sanitize_conflicted_diff >expect.diff
+'
+
+test_expect_success 'apply -3 with add/add conflict' '
+ # should fail to apply ...
+ git reset --hard &&
+ git checkout adder^0 &&
+ test_must_fail git apply --index --3way P.diff &&
+ # ... and leave conflicts in the index and in the working tree
+ git ls-files -s >actual.ls &&
+ git diff HEAD | sanitize_conflicted_diff >actual.diff &&
+
+ # The result should resemble the corresponding merge
+ test_cmp expect.ls actual.ls &&
+ test_cmp expect.diff actual.diff
+'
+
+test_expect_success 'apply -3 with add/add conflict (dirty working tree)' '
+ # should fail to apply ...
+ git reset --hard &&
+ git checkout adder^0 &&
+ echo >>four &&
+ cat four >four.save &&
+ cat three >three.save &&
+ git ls-files -s >expect.ls &&
+ test_must_fail git apply --index --3way P.diff &&
+ # ... and should not touch anything
+ git ls-files -s >actual.ls &&
+ test_cmp expect.ls actual.ls &&
+ test_cmp four.save four &&
+ test_cmp three.save three
+'
+
+test_done
diff --git a/t/t4117-apply-reject.sh b/t/t4117-apply-reject.sh
index e9ccd16..8e15ecb 100755
--- a/t/t4117-apply-reject.sh
+++ b/t/t4117-apply-reject.sh
@@ -46,6 +46,14 @@ test_expect_success setup '
cat file1 >saved.file1
'
+test_expect_success 'apply --reject is incompatible with --3way' '
+ test_when_finished "cat saved.file1 >file1" &&
+ git diff >patch.0 &&
+ git checkout file1 &&
+ test_must_fail git apply --reject --3way patch.0 &&
+ git diff --exit-code
+'
+
test_expect_success 'apply without --reject should fail' '
if git apply patch.1
diff --git a/t/t4120-apply-popt.sh b/t/t4120-apply-popt.sh
index a33d510..c5fecdf 100755
--- a/t/t4120-apply-popt.sh
+++ b/t/t4120-apply-popt.sh
@@ -32,7 +32,7 @@ test_expect_success 'apply git diff with -p2' '
test_expect_success 'apply with too large -p' '
cp file1.saved file1 &&
test_must_fail git apply --stat -p3 patch.file 2>err &&
- grep "removing 3 leading" err
+ test_i18ngrep "removing 3 leading" err
'
test_expect_success 'apply (-p2) traditional diff with funny filenames' '
@@ -54,7 +54,7 @@ test_expect_success 'apply (-p2) traditional diff with funny filenames' '
test_expect_success 'apply with too large -p and fancy filename' '
cp file1.saved file1 &&
test_must_fail git apply --stat -p3 patch.escaped 2>err &&
- grep "removing 3 leading" err
+ test_i18ngrep "removing 3 leading" err
'
test_expect_success 'apply (-p2) diff, mode change only' '
diff --git a/t/t4133-apply-filenames.sh b/t/t4133-apply-filenames.sh
index 94da990..2ecb421 100755
--- a/t/t4133-apply-filenames.sh
+++ b/t/t4133-apply-filenames.sh
@@ -30,9 +30,9 @@ EOF
test_expect_success 'apply diff with inconsistent filenames in headers' '
test_must_fail git apply bad1.patch 2>err &&
- grep "inconsistent new filename" err &&
+ test_i18ngrep "inconsistent new filename" err &&
test_must_fail git apply bad2.patch 2>err &&
- grep "inconsistent old filename" err
+ test_i18ngrep "inconsistent old filename" err
'
test_done
diff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh
index 3ab670d..7f6666f 100755
--- a/t/t4200-rerere.sh
+++ b/t/t4200-rerere.sh
@@ -382,13 +382,13 @@ test_expect_success 'rerere --no-no-rerere-autoupdate' '
git update-index --index-info <failedmerge &&
cp file3.conflict file3 &&
test_must_fail git rerere --no-no-rerere-autoupdate 2>err &&
- grep [Uu]sage err &&
+ test_i18ngrep [Uu]sage err &&
test_must_fail git update-index --refresh
'
test_expect_success 'rerere -h' '
test_must_fail git rerere -h >help &&
- grep [Uu]sage help
+ test_i18ngrep [Uu]sage help
'
test_done
diff --git a/t/t4202-log.sh b/t/t4202-log.sh
index 45058cc..924ba53 100755
--- a/t/t4202-log.sh
+++ b/t/t4202-log.sh
@@ -178,11 +178,21 @@ test_expect_success 'git log --no-walk <commits> sorts by commit time' '
test_cmp expect actual
'
+test_expect_success 'git log --no-walk=sorted <commits> sorts by commit time' '
+ git log --no-walk=sorted --oneline 5d31159 804a787 394ef78 > actual &&
+ test_cmp expect actual
+'
+
cat > expect << EOF
5d31159 fourth
804a787 sixth
394ef78 fifth
EOF
+test_expect_success 'git log --no-walk=unsorted <commits> leaves list of commits as given' '
+ git log --no-walk=unsorted --oneline 5d31159 804a787 394ef78 > actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'git show <commits> leaves list of commits as given' '
git show --oneline -s 5d31159 804a787 394ef78 > actual &&
test_cmp expect actual
@@ -803,7 +813,7 @@ sanitize_output () {
test_expect_success 'log --graph with diff and stats' '
git log --graph --pretty=short --stat -p >actual &&
sanitize_output >actual.sanitized <actual &&
- test_cmp expect actual.sanitized
+ test_i18ncmp expect actual.sanitized
'
test_expect_success 'dotdot is a parent directory' '
diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh
index 4afd778..2c45de7 100755
--- a/t/t4205-log-pretty-formats.sh
+++ b/t/t4205-log-pretty-formats.sh
@@ -88,7 +88,7 @@ test_expect_success 'NUL separation with --stat' '
stat1_part=$(git diff --stat --root HEAD^) &&
printf "add bar\n$stat0_part\n\0initial\n$stat1_part\n" >expected &&
git log -z --stat --pretty="format:%s" >actual &&
- test_cmp expected actual
+ test_i18ncmp expected actual
'
test_expect_failure 'NUL termination with --stat' '
@@ -96,7 +96,7 @@ test_expect_failure 'NUL termination with --stat' '
stat1_part=$(git diff --stat --root HEAD^) &&
printf "add bar\n$stat0_part\n\0initial\n$stat1_part\n\0" >expected &&
git log -z --stat --pretty="tformat:%s" >actual &&
- test_cmp expected actual
+ test_i18ncmp expected actual
'
test_done
diff --git a/t/t5100-mailinfo.sh b/t/t5100-mailinfo.sh
index 81904d9..3e64a7a 100755
--- a/t/t5100-mailinfo.sh
+++ b/t/t5100-mailinfo.sh
@@ -11,7 +11,7 @@ test_expect_success 'split sample box' \
'git mailsplit -o. "$TEST_DIRECTORY"/t5100/sample.mbox >last &&
last=`cat last` &&
echo total is $last &&
- test `cat last` = 16'
+ test `cat last` = 17'
check_mailinfo () {
mail=$1 opt=$2
diff --git a/t/t5100/info0017 b/t/t5100/info0017
new file mode 100644
index 0000000..d2bc89f
--- /dev/null
+++ b/t/t5100/info0017
@@ -0,0 +1,5 @@
+Author: A U Thor
+Email: a.u.thor@example.com
+Subject: A E I O U
+Date: Mon, 17 Sep 2012 14:23:44 -0700
+
diff --git a/t/t5100/msg0017 b/t/t5100/msg0017
new file mode 100644
index 0000000..2ee0900
--- /dev/null
+++ b/t/t5100/msg0017
@@ -0,0 +1,2 @@
+New content here
+
diff --git a/t/t5100/patch0017 b/t/t5100/patch0017
new file mode 100644
index 0000000..35cf84c
--- /dev/null
+++ b/t/t5100/patch0017
@@ -0,0 +1,6 @@
+diff --git a/foo b/foo
+index e69de29..d95f3ad 100644
+--- a/foo
++++ b/foo
+@@ -0,0 +1 @@
++New content
diff --git a/t/t5100/sample.mbox b/t/t5100/sample.mbox
index 34a09a0..8b2ae06 100644
--- a/t/t5100/sample.mbox
+++ b/t/t5100/sample.mbox
@@ -683,3 +683,19 @@ index e69de29..d95f3ad 100644
@@ -0,0 +1 @@
+content
+From nobody Mon Sep 17 00:00:00 2001
+From: A U Thor <a.u.thor@example.com>
+Subject: A E I O U
+Date: Mon, 17 Sep 2012 14:23:44 -0700
+MIME-Version: 1.0
+Content-Type: text/plain; charset="iso-2022-jp"
+Content-type: text/plain; charset="UTF-8"
+
+New content here
+
+diff --git a/foo b/foo
+index e69de29..d95f3ad 100644
+--- a/foo
++++ b/foo
+@@ -0,0 +1 @@
++New content
diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh
index 4fd69a1..a07c871 100755
--- a/t/t5300-pack-object.sh
+++ b/t/t5300-pack-object.sh
@@ -416,6 +416,11 @@ test_expect_success \
test_expect_success \
'make sure index-pack detects the SHA1 collision' \
'test_must_fail git index-pack -o bad.idx test-3.pack 2>msg &&
- grep "SHA1 COLLISION FOUND" msg'
+ test_i18ngrep "SHA1 COLLISION FOUND" msg'
+
+test_expect_success \
+ 'make sure index-pack detects the SHA1 collision (large blobs)' \
+ 'test_must_fail git -c core.bigfilethreshold=1 index-pack -o bad.idx test-3.pack 2>msg &&
+ test_i18ngrep "SHA1 COLLISION FOUND" msg'
test_done
diff --git a/t/t5400-send-pack.sh b/t/t5400-send-pack.sh
index 250c720..78ab177 100755
--- a/t/t5400-send-pack.sh
+++ b/t/t5400-send-pack.sh
@@ -174,8 +174,7 @@ test_expect_success 'receive-pack runs auto-gc in remote repo' '
cd parent &&
echo "Even more text" >>file.txt &&
git commit -a -m "Third commit" &&
- git send-pack ../child HEAD:refs/heads/test_auto_gc >output 2>&1 &&
- grep "Auto packing the repository for optimum performance." output
+ git send-pack ../child HEAD:refs/heads/test_auto_gc
) &&
test ! -e child/.git/objects/tmp_test_object
'
diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh
index e80a2af..6322e8a 100755
--- a/t/t5500-fetch-pack.sh
+++ b/t/t5500-fetch-pack.sh
@@ -391,10 +391,55 @@ test_expect_success 'fetch mixed refs from cmdline and stdin' '
test_expect_success 'test duplicate refs from stdin' '
(
cd client &&
- test_must_fail git fetch-pack --stdin --no-progress .. <../input.dup
+ git fetch-pack --stdin --no-progress .. <../input.dup
) >output &&
cut -d " " -f 2 <output | sort >actual &&
test_cmp expect actual
'
+test_expect_success 'set up tests of missing reference' '
+ cat >expect-error <<-\EOF
+ error: no such remote ref refs/heads/xyzzy
+ EOF
+'
+
+test_expect_success 'test lonely missing ref' '
+ (
+ cd client &&
+ test_must_fail git fetch-pack --no-progress .. refs/heads/xyzzy
+ ) >/dev/null 2>error-m &&
+ test_cmp expect-error error-m
+'
+
+test_expect_success 'test missing ref after existing' '
+ (
+ cd client &&
+ test_must_fail git fetch-pack --no-progress .. refs/heads/A refs/heads/xyzzy
+ ) >/dev/null 2>error-em &&
+ test_cmp expect-error error-em
+'
+
+test_expect_success 'test missing ref before existing' '
+ (
+ cd client &&
+ test_must_fail git fetch-pack --no-progress .. refs/heads/xyzzy refs/heads/A
+ ) >/dev/null 2>error-me &&
+ test_cmp expect-error error-me
+'
+
+test_expect_success 'test --all, --depth, and explicit head' '
+ (
+ cd client &&
+ git fetch-pack --no-progress --all --depth=1 .. refs/heads/A
+ ) >out-adh 2>error-adh
+'
+
+test_expect_success 'test --all, --depth, and explicit tag' '
+ git tag OLDTAG refs/heads/B~5 &&
+ (
+ cd client &&
+ git fetch-pack --no-progress --all --depth=1 .. refs/tags/OLDTAG
+ ) >out-adt 2>error-adt
+'
+
test_done
diff --git a/t/t5504-fetch-receive-strict.sh b/t/t5504-fetch-receive-strict.sh
index 35ec294..69ee13c 100755
--- a/t/t5504-fetch-receive-strict.sh
+++ b/t/t5504-fetch-receive-strict.sh
@@ -89,7 +89,7 @@ test_expect_success 'push with !receive.fsckobjects' '
cat >exp <<EOF
To dst
-! refs/heads/master:refs/heads/test [remote rejected] (n/a (unpacker error))
+! refs/heads/master:refs/heads/test [remote rejected] (unpacker error)
EOF
test_expect_success 'push with receive.fsckobjects' '
diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index e8af615..ccc55eb 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -52,7 +52,7 @@ test_expect_success setup '
'
-test_expect_success 'remote information for the origin' '
+test_expect_success C_LOCALE_OUTPUT 'remote information for the origin' '
(
cd test &&
tokens_match origin "$(git remote)" &&
@@ -66,8 +66,6 @@ test_expect_success 'add another remote' '
cd test &&
git remote add -f second ../two &&
tokens_match "origin second" "$(git remote)" &&
- check_remote_track origin master side &&
- check_remote_track second master side another &&
check_tracking_branch second master side another &&
git for-each-ref "--format=%(refname)" refs/remotes |
sed -e "/^refs\/remotes\/origin\//d" \
@@ -77,6 +75,14 @@ test_expect_success 'add another remote' '
)
'
+test_expect_success C_LOCALE_OUTPUT 'check remote tracking' '
+(
+ cd test &&
+ check_remote_track origin master side &&
+ check_remote_track second master side another
+)
+'
+
test_expect_success 'remote forces tracking branches' '
(
cd test &&
@@ -95,7 +101,7 @@ test_expect_success 'remove remote' '
)
'
-test_expect_success 'remove remote' '
+test_expect_success C_LOCALE_OUTPUT 'remove remote' '
(
cd test &&
tokens_match origin "$(git remote)" &&
@@ -125,14 +131,14 @@ EOF
} &&
git tag footag &&
git config --add remote.oops.fetch "+refs/*:refs/*" &&
- git remote rm oops 2>actual1 &&
+ git remote remove oops 2>actual1 &&
git branch foobranch &&
git config --add remote.oops.fetch "+refs/*:refs/*" &&
git remote rm oops 2>actual2 &&
git branch -d foobranch &&
git tag -d footag &&
- test_cmp expect1 actual1 &&
- test_cmp expect2 actual2
+ test_i18ncmp expect1 actual1 &&
+ test_i18ncmp expect2 actual2
)
'
@@ -192,7 +198,7 @@ test_expect_success 'show' '
git config --add remote.two.push refs/heads/master:refs/heads/another &&
git remote show origin two > output &&
git branch -d rebase octopus &&
- test_cmp expect output)
+ test_i18ncmp expect output)
'
cat > test/expect << EOF
@@ -217,7 +223,7 @@ test_expect_success 'show -n' '
cd test &&
git remote show -n origin > output &&
mv ../one.unreachable ../one &&
- test_cmp expect output)
+ test_i18ncmp expect output)
'
test_expect_success 'prune' '
@@ -255,7 +261,7 @@ EOF
test_expect_success 'set-head --auto fails w/multiple HEADs' '
(cd test &&
test_must_fail git remote set-head --auto two >output 2>&1 &&
- test_cmp expect output)
+ test_i18ncmp expect output)
'
cat >test/expect <<EOF
@@ -285,7 +291,7 @@ test_expect_success 'prune --dry-run' '
test_must_fail git rev-parse refs/remotes/origin/side &&
(cd ../one &&
git branch -m side side2) &&
- test_cmp expect output)
+ test_i18ncmp expect output)
'
test_expect_success 'add --mirror && prune' '
@@ -672,7 +678,7 @@ test_expect_success 'migrate a remote from named file in $GIT_DIR/remotes' '
git clone one five &&
origin_url=$(pwd)/one &&
(cd five &&
- git remote rm origin &&
+ git remote remove origin &&
mkdir -p .git/remotes &&
cat ../remotes_origin > .git/remotes/origin &&
git remote rename origin origin &&
@@ -705,7 +711,7 @@ test_expect_success 'remote prune to cause a dangling symref' '
cd seven &&
git remote prune origin
) >err 2>&1 &&
- grep "has become dangling" err &&
+ test_i18ngrep "has become dangling" err &&
: And the dangling symref will not cause other annoying errors &&
(
diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh
index 6764d51..d16e5d3 100755
--- a/t/t5512-ls-remote.sh
+++ b/t/t5512-ls-remote.sh
@@ -87,17 +87,15 @@ test_expect_success 'use branch.<name>.remote if possible' '
test_expect_success 'confuses pattern as remote when no remote specified' '
cat >exp <<-\EOF &&
fatal: '\''refs*master'\'' does not appear to be a git repository
- fatal: The remote end hung up unexpectedly
+ fatal: Could not read from remote repository.
+
+ Please make sure you have the correct access rights
+ and the repository exists.
EOF
#
- # Do not expect "git ls-remote <pattern>" to work; ls-remote, correctly,
- # confuses <pattern> for <remote>. Although ugly, this behaviour is akin
- # to the confusion of refspecs for remotes by git-fetch and git-push,
- # eg:
- #
- # $ git fetch branch
- #
-
+ # Do not expect "git ls-remote <pattern>" to work; ls-remote needs
+ # <remote> if you want to feed <pattern>, just like you cannot say
+ # fetch <branch>.
# We could just as easily have used "master"; the "*" emphasizes its
# role as a pattern.
test_must_fail git ls-remote refs*master >actual 2>&1 &&
diff --git a/t/t5514-fetch-multiple.sh b/t/t5514-fetch-multiple.sh
index 227dd56..0f81409 100755
--- a/t/t5514-fetch-multiple.sh
+++ b/t/t5514-fetch-multiple.sh
@@ -151,4 +151,34 @@ test_expect_success 'git fetch --multiple (ignoring skipFetchAll)' '
test_cmp ../expect output)
'
+test_expect_success 'git fetch --all --no-tags' '
+ >expect &&
+ git clone one test5 &&
+ git clone test5 test6 &&
+ (cd test5 && git tag test-tag) &&
+ (
+ cd test6 &&
+ git fetch --all --no-tags &&
+ git tag >output
+ ) &&
+ test_cmp expect test6/output
+'
+
+test_expect_success 'git fetch --all --tags' '
+ echo test-tag >expect &&
+ git clone one test7 &&
+ git clone test7 test8 &&
+ (
+ cd test7 &&
+ test_commit test-tag &&
+ git reset --hard HEAD^
+ ) &&
+ (
+ cd test8 &&
+ git fetch --all --tags &&
+ git tag >output
+ ) &&
+ test_cmp expect test8/output
+'
+
test_done
diff --git a/t/t5530-upload-pack-error.sh b/t/t5530-upload-pack-error.sh
index 6b2a5f4..c983d36 100755
--- a/t/t5530-upload-pack-error.sh
+++ b/t/t5530-upload-pack-error.sh
@@ -35,8 +35,8 @@ test_expect_success 'upload-pack fails due to error in pack-objects packing' '
printf "0032want %s\n00000009done\n0000" \
$(git rev-parse HEAD) >input &&
test_must_fail git upload-pack . <input >/dev/null 2>output.err &&
- grep "unable to read" output.err &&
- grep "pack-objects died" output.err
+ test_i18ngrep "unable to read" output.err &&
+ test_i18ngrep "pack-objects died" output.err
'
test_expect_success 'corrupt repo differently' '
diff --git a/t/t5540-http-push.sh b/t/t5540-http-push.sh
index f141f2d..01d0d95 100755
--- a/t/t5540-http-push.sh
+++ b/t/t5540-http-push.sh
@@ -109,7 +109,7 @@ test_expect_success 'http-push fetches packed objects' '
# By reset, we force git to retrieve the packed object
(cd "$ROOT_PATH"/test_repo_clone_packed &&
git reset --hard HEAD^ &&
- git remote rm origin &&
+ git remote remove origin &&
git reflog expire --expire=0 --all &&
git prune &&
git push -f -v $HTTPD_URL/dumb/test_repo_packed.git master)
diff --git a/t/t5541-http-push.sh b/t/t5541-http-push.sh
index ef6d6b6..4b4b4a6 100755
--- a/t/t5541-http-push.sh
+++ b/t/t5541-http-push.sh
@@ -66,7 +66,10 @@ test_expect_success 'no empty path components' '
test_expect_success 'clone remote repository' '
rm -rf test_repo_clone &&
- git clone $HTTPD_URL/smart/test_repo.git test_repo_clone
+ git clone $HTTPD_URL/smart/test_repo.git test_repo_clone &&
+ (
+ cd test_repo_clone && git config push.default matching
+ )
'
test_expect_success 'push to remote repository (standard)' '
diff --git a/t/t5551-http-fetch.sh b/t/t5551-http-fetch.sh
index 2db5c35..5060879 100755
--- a/t/t5551-http-fetch.sh
+++ b/t/t5551-http-fetch.sh
@@ -32,13 +32,14 @@ setup_askpass_helper
cat >exp <<EOF
> GET /smart/repo.git/info/refs?service=git-upload-pack HTTP/1.1
> Accept: */*
+> Accept-Encoding: gzip
> Pragma: no-cache
< HTTP/1.1 200 OK
< Pragma: no-cache
< Cache-Control: no-cache, max-age=0, must-revalidate
< Content-Type: application/x-git-upload-pack-advertisement
> POST /smart/repo.git/git-upload-pack HTTP/1.1
-> Accept-Encoding: deflate, gzip
+> Accept-Encoding: gzip
> Content-Type: application/x-git-upload-pack-request
> Accept: application/x-git-upload-pack-result
> Content-Length: xxx
@@ -129,6 +130,18 @@ test_expect_success 'clone from auth-only-for-push repository' '
test_cmp expect actual
'
+test_expect_success 'disable dumb http on server' '
+ git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/repo.git" \
+ config http.getanyfile false
+'
+
+test_expect_success 'GIT_SMART_HTTP can disable smart http' '
+ (GIT_SMART_HTTP=0 &&
+ export GIT_SMART_HTTP &&
+ cd clone &&
+ test_must_fail git fetch)
+'
+
test -n "$GIT_TEST_LONG" && test_set_prereq EXPENSIVE
test_expect_success EXPENSIVE 'create 50,000 tags in the repo' '
diff --git a/t/t5701-clone-local.sh b/t/t5701-clone-local.sh
index c6feca4..7ff6e0e 100755
--- a/t/t5701-clone-local.sh
+++ b/t/t5701-clone-local.sh
@@ -124,4 +124,14 @@ test_expect_success 'cloning non-git directory fails' '
test_must_fail git clone not-a-git-repo not-a-git-repo-clone
'
+test_expect_success 'cloning file:// does not hardlink' '
+ git clone --bare file://"$(pwd)"/a non-local &&
+ ! repo_is_hardlinked non-local
+'
+
+test_expect_success 'cloning a local path with --no-local does not hardlink' '
+ git clone --bare --no-local a force-nonlocal &&
+ ! repo_is_hardlinked force-nonlocal
+'
+
test_done
diff --git a/t/t5709-clone-refspec.sh b/t/t5709-clone-refspec.sh
new file mode 100755
index 0000000..6f1ea98
--- /dev/null
+++ b/t/t5709-clone-refspec.sh
@@ -0,0 +1,156 @@
+#!/bin/sh
+
+test_description='test refspec written by clone-command'
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+ # Make two branches, "master" and "side"
+ echo one >file &&
+ git add file &&
+ git commit -m one &&
+ echo two >file &&
+ git commit -a -m two &&
+ git tag two &&
+ echo three >file &&
+ git commit -a -m three &&
+ git checkout -b side &&
+ echo four >file &&
+ git commit -a -m four &&
+ git checkout master &&
+
+ # default clone
+ git clone . dir_all &&
+
+ # default --single that follows HEAD=master
+ git clone --single-branch . dir_master &&
+
+ # default --single that follows HEAD=side
+ git checkout side &&
+ git clone --single-branch . dir_side &&
+
+ # explicit --single that follows side
+ git checkout master &&
+ git clone --single-branch --branch side . dir_side2 &&
+
+ # default --single with --mirror
+ git clone --single-branch --mirror . dir_mirror &&
+
+ # default --single with --branch and --mirror
+ git clone --single-branch --mirror --branch side . dir_mirror_side &&
+
+ # --single that does not know what branch to follow
+ git checkout two^ &&
+ git clone --single-branch . dir_detached &&
+
+ # explicit --single with tag
+ git clone --single-branch --branch two . dir_tag &&
+
+ # advance both "master" and "side" branches
+ git checkout side &&
+ echo five >file &&
+ git commit -a -m five &&
+ git checkout master &&
+ echo six >file &&
+ git commit -a -m six &&
+
+ # update tag
+ git tag -d two && git tag two
+'
+
+test_expect_success 'by default all branches will be kept updated' '
+ (
+ cd dir_all && git fetch &&
+ git for-each-ref refs/remotes/origin |
+ sed -e "/HEAD$/d" \
+ -e "s|/remotes/origin/|/heads/|" >../actual
+ ) &&
+ # follow both master and side
+ git for-each-ref refs/heads >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'by default no tags will be kept updated' '
+ (
+ cd dir_all && git fetch &&
+ git for-each-ref refs/tags >../actual
+ ) &&
+ git for-each-ref refs/tags >expect &&
+ test_must_fail test_cmp expect actual
+'
+
+test_expect_success '--single-branch while HEAD pointing at master' '
+ (
+ cd dir_master && git fetch &&
+ git for-each-ref refs/remotes/origin |
+ sed -e "/HEAD$/d" \
+ -e "s|/remotes/origin/|/heads/|" >../actual
+ ) &&
+ # only follow master
+ git for-each-ref refs/heads/master >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success '--single-branch while HEAD pointing at side' '
+ (
+ cd dir_side && git fetch &&
+ git for-each-ref refs/remotes/origin |
+ sed -e "/HEAD$/d" \
+ -e "s|/remotes/origin/|/heads/|" >../actual
+ ) &&
+ # only follow side
+ git for-each-ref refs/heads/side >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success '--single-branch with explicit --branch side' '
+ (
+ cd dir_side2 && git fetch &&
+ git for-each-ref refs/remotes/origin |
+ sed -e "/HEAD$/d" \
+ -e "s|/remotes/origin/|/heads/|" >../actual
+ ) &&
+ # only follow side
+ git for-each-ref refs/heads/side >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success '--single-branch with explicit --branch with tag fetches updated tag' '
+ (
+ cd dir_tag && git fetch &&
+ git for-each-ref refs/tags >../actual
+ ) &&
+ git for-each-ref refs/tags >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success '--single-branch with --mirror' '
+ (
+ cd dir_mirror && git fetch &&
+ git for-each-ref refs > ../actual
+ ) &&
+ git for-each-ref refs >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success '--single-branch with explicit --branch and --mirror' '
+ (
+ cd dir_mirror_side && git fetch &&
+ git for-each-ref refs > ../actual
+ ) &&
+ git for-each-ref refs >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success '--single-branch with detached' '
+ (
+ cd dir_detached && git fetch &&
+ git for-each-ref refs/remotes/origin |
+ sed -e "/HEAD$/d" \
+ -e "s|/remotes/origin/|/heads/|" >../actual
+ )
+ # nothing
+ >expect &&
+ test_cmp expect actual
+'
+
+test_done
diff --git a/t/t6022-merge-rename.sh b/t/t6022-merge-rename.sh
index 1104249..c680f78 100755
--- a/t/t6022-merge-rename.sh
+++ b/t/t6022-merge-rename.sh
@@ -242,10 +242,10 @@ test_expect_success 'merge of identical changes in a renamed file' '
rm -f A M N &&
git reset --hard &&
git checkout change+rename &&
- GIT_MERGE_VERBOSITY=3 git merge change | grep "^Skipped B" &&
+ GIT_MERGE_VERBOSITY=3 git merge change | test_i18ngrep "^Skipped B" &&
git reset --hard HEAD^ &&
git checkout change &&
- GIT_MERGE_VERBOSITY=3 git merge change+rename | grep "^Skipped B"
+ GIT_MERGE_VERBOSITY=3 git merge change+rename | test_i18ngrep "^Skipped B"
'
test_expect_success 'setup for rename + d/f conflicts' '
@@ -303,9 +303,9 @@ test_expect_success 'Rename+D/F conflict; renamed file merges but dir in way' '
git checkout -q renamed-file-has-no-conflicts^0 &&
test_must_fail git merge --strategy=recursive dir-in-way >output &&
- grep "CONFLICT (modify/delete): dir/file-in-the-way" output &&
- grep "Auto-merging dir" output &&
- grep "Adding as dir~HEAD instead" output &&
+ test_i18ngrep "CONFLICT (modify/delete): dir/file-in-the-way" output &&
+ test_i18ngrep "Auto-merging dir" output &&
+ test_i18ngrep "Adding as dir~HEAD instead" output &&
test 3 -eq "$(git ls-files -u | wc -l)" &&
test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
@@ -325,9 +325,9 @@ test_expect_success 'Same as previous, but merged other way' '
test_must_fail git merge --strategy=recursive renamed-file-has-no-conflicts >output 2>errors &&
! grep "error: refusing to lose untracked file at" errors &&
- grep "CONFLICT (modify/delete): dir/file-in-the-way" output &&
- grep "Auto-merging dir" output &&
- grep "Adding as dir~renamed-file-has-no-conflicts instead" output &&
+ test_i18ngrep "CONFLICT (modify/delete): dir/file-in-the-way" output &&
+ test_i18ngrep "Auto-merging dir" output &&
+ test_i18ngrep "Adding as dir~renamed-file-has-no-conflicts instead" output &&
test 3 -eq "$(git ls-files -u | wc -l)" &&
test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
diff --git a/t/t6037-merge-ours-theirs.sh b/t/t6037-merge-ours-theirs.sh
index 2cf42c7..3889eca 100755
--- a/t/t6037-merge-ours-theirs.sh
+++ b/t/t6037-merge-ours-theirs.sh
@@ -53,7 +53,19 @@ test_expect_success 'recursive favouring ours' '
! grep 1 file
'
-test_expect_success 'pull with -X' '
+test_expect_success 'binary file with -Xours/-Xtheirs' '
+ echo file binary >.gitattributes &&
+
+ git reset --hard master &&
+ git merge -s recursive -X theirs side &&
+ git diff --exit-code side HEAD -- file &&
+
+ git reset --hard master &&
+ git merge -s recursive -X ours side &&
+ git diff --exit-code master HEAD -- file
+'
+
+test_expect_success 'pull passes -X to underlying merge' '
git reset --hard master && git pull -s recursive -Xours . side &&
git reset --hard master && git pull -s recursive -X ours . side &&
git reset --hard master && git pull -s recursive -Xtheirs . side &&
diff --git a/t/t6042-merge-rename-corner-cases.sh b/t/t6042-merge-rename-corner-cases.sh
index 466fa38..411550d 100755
--- a/t/t6042-merge-rename-corner-cases.sh
+++ b/t/t6042-merge-rename-corner-cases.sh
@@ -380,7 +380,7 @@ test_expect_success 'handle rename/rename (2to1) conflict correctly' '
git checkout B^0 &&
test_must_fail git merge -s recursive C^0 >out &&
- grep "CONFLICT (rename/rename)" out &&
+ test_i18ngrep "CONFLICT (rename/rename)" out &&
test 2 -eq $(git ls-files -s | wc -l) &&
test 2 -eq $(git ls-files -u | wc -l) &&
diff --git a/t/t6500-gc.sh b/t/t6500-gc.sh
index 82f3639..b1a6365 100755
--- a/t/t6500-gc.sh
+++ b/t/t6500-gc.sh
@@ -11,7 +11,7 @@ test_expect_success 'gc empty repository' '
test_expect_success 'gc --gobbledegook' '
test_expect_code 129 git gc --nonsense 2>err &&
- grep "[Uu]sage: git gc" err
+ test_i18ngrep "[Uu]sage: git gc" err
'
test_expect_success 'gc -h with invalid configuration' '
@@ -22,7 +22,7 @@ test_expect_success 'gc -h with invalid configuration' '
echo "[gc] pruneexpire = CORRUPT" >>.git/config &&
test_expect_code 129 git gc -h >usage 2>&1
) &&
- grep "[Uu]sage" broken/usage
+ test_i18ngrep "[Uu]sage" broken/usage
'
test_done
diff --git a/t/t7060-wtstatus.sh b/t/t7060-wtstatus.sh
index b8cb490..f4f38a5 100755
--- a/t/t7060-wtstatus.sh
+++ b/t/t7060-wtstatus.sh
@@ -30,6 +30,9 @@ test_expect_success 'Report new path with conflict' '
cat >expect <<EOF
# On branch side
+# You have unmerged paths.
+# (fix conflicts and run "git commit")
+#
# Unmerged paths:
# (use "git add/rm <file>..." as appropriate to mark resolution)
#
@@ -118,4 +121,97 @@ test_expect_success 'git diff-index --cached -C shows 2 copies + 1 unmerged' '
test_cmp expected actual
'
+
+test_expect_success 'status when conflicts with add and rm advice (deleted by them)' '
+ git reset --hard &&
+ git checkout master &&
+ test_commit init main.txt init &&
+ git checkout -b second_branch &&
+ git rm main.txt &&
+ git commit -m "main.txt deleted on second_branch" &&
+ test_commit second conflict.txt second &&
+ git checkout master &&
+ test_commit on_second main.txt on_second &&
+ test_commit master conflict.txt master &&
+ test_must_fail git merge second_branch &&
+ cat >expected <<-\EOF &&
+ # On branch master
+ # You have unmerged paths.
+ # (fix conflicts and run "git commit")
+ #
+ # Unmerged paths:
+ # (use "git add/rm <file>..." as appropriate to mark resolution)
+ #
+ # both added: conflict.txt
+ # deleted by them: main.txt
+ #
+ no changes added to commit (use "git add" and/or "git commit -a")
+ EOF
+ git status --untracked-files=no >actual &&
+ test_i18ncmp expected actual
+'
+
+
+test_expect_success 'prepare for conflicts' '
+ git reset --hard &&
+ git checkout -b conflict &&
+ test_commit one main.txt one &&
+ git branch conflict_second &&
+ git mv main.txt sub_master.txt &&
+ git commit -m "main.txt renamed in sub_master.txt" &&
+ git checkout conflict_second &&
+ git mv main.txt sub_second.txt &&
+ git commit -m "main.txt renamed in sub_second.txt"
+'
+
+
+test_expect_success 'status when conflicts with add and rm advice (both deleted)' '
+ test_must_fail git merge conflict &&
+ cat >expected <<-\EOF &&
+ # On branch conflict_second
+ # You have unmerged paths.
+ # (fix conflicts and run "git commit")
+ #
+ # Unmerged paths:
+ # (use "git add/rm <file>..." as appropriate to mark resolution)
+ #
+ # both deleted: main.txt
+ # added by them: sub_master.txt
+ # added by us: sub_second.txt
+ #
+ no changes added to commit (use "git add" and/or "git commit -a")
+ EOF
+ git status --untracked-files=no >actual &&
+ test_i18ncmp expected actual
+'
+
+
+test_expect_success 'status when conflicts with only rm advice (both deleted)' '
+ git reset --hard conflict_second &&
+ test_must_fail git merge conflict &&
+ git add sub_master.txt &&
+ git add sub_second.txt &&
+ cat >expected <<-\EOF &&
+ # On branch conflict_second
+ # You have unmerged paths.
+ # (fix conflicts and run "git commit")
+ #
+ # Changes to be committed:
+ #
+ # new file: sub_master.txt
+ #
+ # Unmerged paths:
+ # (use "git rm <file>..." to mark resolution)
+ #
+ # both deleted: main.txt
+ #
+ # Untracked files not listed (use -u option to show untracked files)
+ EOF
+ git status --untracked-files=no >actual &&
+ test_i18ncmp expected actual &&
+ git reset --hard &&
+ git checkout master
+'
+
+
test_done
diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh
index 0278f48..5397037 100755
--- a/t/t7400-submodule-basic.sh
+++ b/t/t7400-submodule-basic.sh
@@ -438,8 +438,8 @@ test_expect_success 'moving to a commit without submodule does not leave empty d
git checkout second
'
-test_expect_success 'submodule <invalid-path> warns' '
- test_failure_with_unknown_submodule
+test_expect_success 'submodule <invalid-subcommand> fails' '
+ test_must_fail git submodule no-such-subcommand
'
test_expect_success 'add submodules without specifying an explicit path' '
@@ -501,21 +501,72 @@ test_expect_success 'set up for relative path tests' '
git add sub &&
git config -f .gitmodules submodule.sub.path sub &&
git config -f .gitmodules submodule.sub.url ../subrepo &&
- cp .git/config pristine-.git-config
+ cp .git/config pristine-.git-config &&
+ cp .gitmodules pristine-.gitmodules
)
'
-test_expect_success 'relative path works with URL' '
+test_expect_success '../subrepo works with URL - ssh://hostname/repo' '
(
cd reltest &&
cp pristine-.git-config .git/config &&
+ cp pristine-.gitmodules .gitmodules &&
git config remote.origin.url ssh://hostname/repo &&
git submodule init &&
test "$(git config submodule.sub.url)" = ssh://hostname/subrepo
)
'
-test_expect_success 'relative path works with user@host:path' '
+test_expect_success '../subrepo works with port-qualified URL - ssh://hostname:22/repo' '
+ (
+ cd reltest &&
+ cp pristine-.git-config .git/config &&
+ cp pristine-.gitmodules .gitmodules &&
+ git config remote.origin.url ssh://hostname:22/repo &&
+ git submodule init &&
+ test "$(git config submodule.sub.url)" = ssh://hostname:22/subrepo
+ )
+'
+
+# About the choice of the path in the next test:
+# - double-slash side-steps path mangling issues on Windows
+# - it is still an absolute local path
+# - there cannot be a server with a blank in its name just in case the
+# path is used erroneously to access a //server/share style path
+test_expect_success '../subrepo path works with local path - //somewhere else/repo' '
+ (
+ cd reltest &&
+ cp pristine-.git-config .git/config &&
+ cp pristine-.gitmodules .gitmodules &&
+ git config remote.origin.url "//somewhere else/repo" &&
+ git submodule init &&
+ test "$(git config submodule.sub.url)" = "//somewhere else/subrepo"
+ )
+'
+
+test_expect_success '../subrepo works with file URL - file:///tmp/repo' '
+ (
+ cd reltest &&
+ cp pristine-.git-config .git/config &&
+ cp pristine-.gitmodules .gitmodules &&
+ git config remote.origin.url file:///tmp/repo &&
+ git submodule init &&
+ test "$(git config submodule.sub.url)" = file:///tmp/subrepo
+ )
+'
+
+test_expect_success '../subrepo works with helper URL- helper:://hostname/repo' '
+ (
+ cd reltest &&
+ cp pristine-.git-config .git/config &&
+ cp pristine-.gitmodules .gitmodules &&
+ git config remote.origin.url helper:://hostname/repo &&
+ git submodule init &&
+ test "$(git config submodule.sub.url)" = helper:://hostname/subrepo
+ )
+'
+
+test_expect_success '../subrepo works with scp-style URL - user@host:repo' '
(
cd reltest &&
cp pristine-.git-config .git/config &&
@@ -525,6 +576,98 @@ test_expect_success 'relative path works with user@host:path' '
)
'
+test_expect_success '../subrepo works with scp-style URL - user@host:path/to/repo' '
+ (
+ cd reltest &&
+ cp pristine-.git-config .git/config &&
+ cp pristine-.gitmodules .gitmodules &&
+ git config remote.origin.url user@host:path/to/repo &&
+ git submodule init &&
+ test "$(git config submodule.sub.url)" = user@host:path/to/subrepo
+ )
+'
+
+test_expect_success '../subrepo works with relative local path - foo' '
+ (
+ cd reltest &&
+ cp pristine-.git-config .git/config &&
+ cp pristine-.gitmodules .gitmodules &&
+ git config remote.origin.url foo &&
+ # actual: fails with an error
+ git submodule init &&
+ test "$(git config submodule.sub.url)" = subrepo
+ )
+'
+
+test_expect_success '../subrepo works with relative local path - foo/bar' '
+ (
+ cd reltest &&
+ cp pristine-.git-config .git/config &&
+ cp pristine-.gitmodules .gitmodules &&
+ git config remote.origin.url foo/bar &&
+ git submodule init &&
+ test "$(git config submodule.sub.url)" = foo/subrepo
+ )
+'
+
+test_expect_success '../subrepo works with relative local path - ./foo' '
+ (
+ cd reltest &&
+ cp pristine-.git-config .git/config &&
+ cp pristine-.gitmodules .gitmodules &&
+ git config remote.origin.url ./foo &&
+ git submodule init &&
+ test "$(git config submodule.sub.url)" = subrepo
+ )
+'
+
+test_expect_success '../subrepo works with relative local path - ./foo/bar' '
+ (
+ cd reltest &&
+ cp pristine-.git-config .git/config &&
+ cp pristine-.gitmodules .gitmodules &&
+ git config remote.origin.url ./foo/bar &&
+ git submodule init &&
+ test "$(git config submodule.sub.url)" = foo/subrepo
+ )
+'
+
+test_expect_success '../subrepo works with relative local path - ../foo' '
+ (
+ cd reltest &&
+ cp pristine-.git-config .git/config &&
+ cp pristine-.gitmodules .gitmodules &&
+ git config remote.origin.url ../foo &&
+ git submodule init &&
+ test "$(git config submodule.sub.url)" = ../subrepo
+ )
+'
+
+test_expect_success '../subrepo works with relative local path - ../foo/bar' '
+ (
+ cd reltest &&
+ cp pristine-.git-config .git/config &&
+ cp pristine-.gitmodules .gitmodules &&
+ git config remote.origin.url ../foo/bar &&
+ git submodule init &&
+ test "$(git config submodule.sub.url)" = ../foo/subrepo
+ )
+'
+
+test_expect_success '../bar/a/b/c works with relative local path - ../foo/bar.git' '
+ (
+ cd reltest &&
+ cp pristine-.git-config .git/config &&
+ cp pristine-.gitmodules .gitmodules &&
+ mkdir -p a/b/c &&
+ (cd a/b/c; git init) &&
+ git config remote.origin.url ../foo/bar.git &&
+ git submodule add ../bar/a/b/c ./a/b/c &&
+ git submodule init &&
+ test "$(git config submodule.a/b/c.url)" = ../foo/bar/a/b/c
+ )
+'
+
test_expect_success 'moving the superproject does not break submodules' '
(
cd addtest &&
diff --git a/t/t7403-submodule-sync.sh b/t/t7403-submodule-sync.sh
index 3620215..524d5c1 100755
--- a/t/t7403-submodule-sync.sh
+++ b/t/t7403-submodule-sync.sh
@@ -26,7 +26,9 @@ test_expect_success setup '
(cd super-clone && git submodule update --init) &&
git clone super empty-clone &&
(cd empty-clone && git submodule init) &&
- git clone super top-only-clone
+ git clone super top-only-clone &&
+ git clone super relative-clone &&
+ (cd relative-clone && git submodule update --init)
'
test_expect_success 'change submodule' '
@@ -86,4 +88,90 @@ test_expect_success '"git submodule sync" should not vivify uninteresting submod
)
'
+test_expect_success '"git submodule sync" handles origin URL of the form foo' '
+ (cd relative-clone &&
+ git remote set-url origin foo &&
+ git submodule sync &&
+ (cd submodule &&
+ #actual fails with: "cannot strip off url foo
+ test "$(git config remote.origin.url)" = "../submodule"
+ )
+ )
+'
+
+test_expect_success '"git submodule sync" handles origin URL of the form foo/bar' '
+ (cd relative-clone &&
+ git remote set-url origin foo/bar &&
+ git submodule sync &&
+ (cd submodule &&
+ #actual foo/submodule
+ test "$(git config remote.origin.url)" = "../foo/submodule"
+ )
+ )
+'
+
+test_expect_success '"git submodule sync" handles origin URL of the form ./foo' '
+ (cd relative-clone &&
+ git remote set-url origin ./foo &&
+ git submodule sync &&
+ (cd submodule &&
+ #actual ./submodule
+ test "$(git config remote.origin.url)" = "../submodule"
+ )
+ )
+'
+
+test_expect_success '"git submodule sync" handles origin URL of the form ./foo/bar' '
+ (cd relative-clone &&
+ git remote set-url origin ./foo/bar &&
+ git submodule sync &&
+ (cd submodule &&
+ #actual ./foo/submodule
+ test "$(git config remote.origin.url)" = "../foo/submodule"
+ )
+ )
+'
+
+test_expect_success '"git submodule sync" handles origin URL of the form ../foo' '
+ (cd relative-clone &&
+ git remote set-url origin ../foo &&
+ git submodule sync &&
+ (cd submodule &&
+ #actual ../submodule
+ test "$(git config remote.origin.url)" = "../../submodule"
+ )
+ )
+'
+
+test_expect_success '"git submodule sync" handles origin URL of the form ../foo/bar' '
+ (cd relative-clone &&
+ git remote set-url origin ../foo/bar &&
+ git submodule sync &&
+ (cd submodule &&
+ #actual ../foo/submodule
+ test "$(git config remote.origin.url)" = "../../foo/submodule"
+ )
+ )
+'
+
+test_expect_success '"git submodule sync" handles origin URL of the form ../foo/bar with deeply nested submodule' '
+ (cd relative-clone &&
+ git remote set-url origin ../foo/bar &&
+ mkdir -p a/b/c &&
+ ( cd a/b/c &&
+ git init &&
+ :> .gitignore &&
+ git add .gitignore &&
+ test_tick &&
+ git commit -m "initial commit" ) &&
+ git submodule add ../bar/a/b/c ./a/b/c &&
+ git submodule sync &&
+ (cd a/b/c &&
+ #actual ../foo/bar/a/b/c
+ test "$(git config remote.origin.url)" = "../../../../foo/bar/a/b/c"
+ )
+ )
+'
+
+
test_done
diff --git a/t/t7409-submodule-detached-worktree.sh b/t/t7409-submodule-detached-worktree.sh
new file mode 100755
index 0000000..2fec13d
--- /dev/null
+++ b/t/t7409-submodule-detached-worktree.sh
@@ -0,0 +1,78 @@
+#!/bin/sh
+#
+# Copyright (c) 2012 Daniel Graña
+#
+
+test_description='Test submodules on detached working tree
+
+This test verifies that "git submodule" initialization, update and addition works
+on detahced working trees
+'
+
+TEST_NO_CREATE_REPO=1
+. ./test-lib.sh
+
+test_expect_success 'submodule on detached working tree' '
+ git init --bare remote &&
+ test_create_repo bundle1 &&
+ (
+ cd bundle1 &&
+ test_commit "shoot" &&
+ git rev-parse --verify HEAD >../expect
+ ) &&
+ mkdir home &&
+ (
+ cd home &&
+ export GIT_WORK_TREE="$(pwd)" GIT_DIR="$(pwd)/.dotfiles" &&
+ git clone --bare ../remote .dotfiles &&
+ git submodule add ../bundle1 .vim/bundle/sogood &&
+ test_commit "sogood" &&
+ (
+ unset GIT_WORK_TREE GIT_DIR &&
+ cd .vim/bundle/sogood &&
+ git rev-parse --verify HEAD >actual &&
+ test_cmp ../../../../expect actual
+ ) &&
+ git push origin master
+ ) &&
+ mkdir home2 &&
+ (
+ cd home2 &&
+ git clone --bare ../remote .dotfiles &&
+ export GIT_WORK_TREE="$(pwd)" GIT_DIR="$(pwd)/.dotfiles" &&
+ git checkout master &&
+ git submodule update --init &&
+ (
+ unset GIT_WORK_TREE GIT_DIR &&
+ cd .vim/bundle/sogood &&
+ git rev-parse --verify HEAD >actual &&
+ test_cmp ../../../../expect actual
+ )
+ )
+'
+
+test_expect_success 'submodule on detached working pointed by core.worktree' '
+ mkdir home3 &&
+ (
+ cd home3 &&
+ export GIT_DIR="$(pwd)/.dotfiles" &&
+ git clone --bare ../remote "$GIT_DIR" &&
+ git config core.bare false &&
+ git config core.worktree .. &&
+ git checkout master &&
+ git submodule add ../bundle1 .vim/bundle/dupe &&
+ test_commit "dupe" &&
+ git push origin master
+ ) &&
+ (
+ cd home &&
+ export GIT_DIR="$(pwd)/.dotfiles" &&
+ git config core.bare false &&
+ git config core.worktree .. &&
+ git pull &&
+ git submodule update --init &&
+ test -f .vim/bundle/dupe/shoot.t
+ )
+'
+
+test_done
diff --git a/t/t7502-commit.sh b/t/t7502-commit.sh
index 181456a..deb187e 100755
--- a/t/t7502-commit.sh
+++ b/t/t7502-commit.sh
@@ -235,44 +235,56 @@ test_expect_success 'cleanup commit messages (strip,-F,-e): output' '
test_i18ncmp expect actual
'
-echo "#
-# Author: $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL>
-#" >> expect
-
-test_expect_success 'author different from committer' '
+test_expect_success 'message shows author when it is not equal to committer' '
echo >>negative &&
- test_might_fail git commit -e -m "sample" &&
- head -n 7 .git/COMMIT_EDITMSG >actual &&
- test_i18ncmp expect actual
+ git commit -e -m "sample" -a &&
+ test_i18ngrep \
+ "^# Author: *A U Thor <author@example.com>\$" \
+ .git/COMMIT_EDITMSG
'
-mv expect expect.tmp
-sed '$d' < expect.tmp > expect
-rm -f expect.tmp
-echo "# Committer:
-#" >> expect
+test_expect_success 'setup auto-ident prerequisite' '
+ if (sane_unset GIT_COMMITTER_EMAIL &&
+ sane_unset GIT_COMMITTER_NAME &&
+ git var GIT_COMMITTER_IDENT); then
+ test_set_prereq AUTOIDENT
+ else
+ test_set_prereq NOAUTOIDENT
+ fi
+'
-test_expect_success 'committer is automatic' '
+test_expect_success AUTOIDENT 'message shows committer when it is automatic' '
echo >>negative &&
(
sane_unset GIT_COMMITTER_EMAIL &&
sane_unset GIT_COMMITTER_NAME &&
- # must fail because there is no change
- test_must_fail git commit -e -m "sample"
+ git commit -e -m "sample" -a
) &&
- head -n 8 .git/COMMIT_EDITMSG | \
- sed "s/^# Committer: .*/# Committer:/" >actual
- test_i18ncmp expect actual
+ # the ident is calculated from the system, so we cannot
+ # check the actual value, only that it is there
+ test_i18ngrep "^# Committer: " .git/COMMIT_EDITMSG
'
-pwd=`pwd`
-cat >> .git/FAKE_EDITOR << EOF
-#! /bin/sh
-echo editor started > "$pwd/.git/result"
+write_script .git/FAKE_EDITOR <<EOF
+echo editor started > "$(pwd)/.git/result"
exit 0
EOF
-chmod +x .git/FAKE_EDITOR
+
+test_expect_success NOAUTOIDENT 'do not fire editor when committer is bogus' '
+ >.git/result
+ >expect &&
+
+ echo >>negative &&
+ (
+ sane_unset GIT_COMMITTER_EMAIL &&
+ sane_unset GIT_COMMITTER_NAME &&
+ GIT_EDITOR="\"$(pwd)/.git/FAKE_EDITOR\"" &&
+ export GIT_EDITOR &&
+ test_must_fail git commit -e -m sample -a
+ ) &&
+ test_cmp expect .git/result
+'
test_expect_success 'do not fire editor in the presence of conflicts' '
@@ -293,16 +305,14 @@ test_expect_success 'do not fire editor in the presence of conflicts' '
test_must_fail git cherry-pick -n master &&
echo "editor not started" >.git/result &&
(
- GIT_EDITOR="$(pwd)/.git/FAKE_EDITOR" &&
+ GIT_EDITOR="\"$(pwd)/.git/FAKE_EDITOR\"" &&
export GIT_EDITOR &&
test_must_fail git commit
) &&
test "$(cat .git/result)" = "editor not started"
'
-pwd=`pwd`
-cat >.git/FAKE_EDITOR <<EOF
-#! $SHELL_PATH
+write_script .git/FAKE_EDITOR <<EOF
# kill -TERM command added below.
EOF
@@ -339,13 +349,12 @@ test_expect_success 'A single-liner subject with a token plus colon is not a foo
'
-cat >.git/FAKE_EDITOR <<EOF
-#!$SHELL_PATH
-mv "\$1" "\$1.orig"
+write_script .git/FAKE_EDITOR <<\EOF
+mv "$1" "$1.orig"
(
echo message
- cat "\$1.orig"
-) >"\$1"
+ cat "$1.orig"
+) >"$1"
EOF
echo '## Custom template' >template
diff --git a/t/t7508-status.sh b/t/t7508-status.sh
index c206f47..e313ef1 100755
--- a/t/t7508-status.sh
+++ b/t/t7508-status.sh
@@ -80,7 +80,7 @@ test_expect_success 'status --column' '
# dir1/untracked dir2/untracked untracked
# dir2/modified output
EOF
- test_cmp expect output
+ test_i18ncmp expect output
'
cat >expect <<\EOF
diff --git a/t/t7512-status-help.sh b/t/t7512-status-help.sh
new file mode 100755
index 0000000..b3f6eb9
--- /dev/null
+++ b/t/t7512-status-help.sh
@@ -0,0 +1,649 @@
+#!/bin/sh
+#
+# Copyright (c) 2012 Valentin Duperray, Lucien Kong, Franck Jonas,
+# Thomas Nguy, Khoi Nguyen
+# Grenoble INP Ensimag
+#
+
+test_description='git status advices'
+
+. ./test-lib.sh
+
+. "$TEST_DIRECTORY"/lib-rebase.sh
+
+set_fake_editor
+
+test_expect_success 'prepare for conflicts' '
+ test_commit init main.txt init &&
+ git branch conflicts &&
+ test_commit on_master main.txt on_master &&
+ git checkout conflicts &&
+ test_commit on_conflicts main.txt on_conflicts
+'
+
+
+test_expect_success 'status when conflicts unresolved' '
+ test_must_fail git merge master &&
+ cat >expected <<-\EOF &&
+ # On branch conflicts
+ # You have unmerged paths.
+ # (fix conflicts and run "git commit")
+ #
+ # Unmerged paths:
+ # (use "git add <file>..." to mark resolution)
+ #
+ # both modified: main.txt
+ #
+ no changes added to commit (use "git add" and/or "git commit -a")
+ EOF
+ git status --untracked-files=no >actual &&
+ test_i18ncmp expected actual
+'
+
+
+test_expect_success 'status when conflicts resolved before commit' '
+ git reset --hard conflicts &&
+ test_must_fail git merge master &&
+ echo one >main.txt &&
+ git add main.txt &&
+ cat >expected <<-\EOF &&
+ # On branch conflicts
+ # All conflicts fixed but you are still merging.
+ # (use "git commit" to conclude merge)
+ #
+ # Changes to be committed:
+ #
+ # modified: main.txt
+ #
+ # Untracked files not listed (use -u option to show untracked files)
+ EOF
+ git status --untracked-files=no >actual &&
+ test_i18ncmp expected actual
+'
+
+
+test_expect_success 'prepare for rebase conflicts' '
+ git reset --hard master &&
+ git checkout -b rebase_conflicts &&
+ test_commit one_rebase main.txt one &&
+ test_commit two_rebase main.txt two &&
+ test_commit three_rebase main.txt three
+'
+
+
+test_expect_success 'status when rebase in progress before resolving conflicts' '
+ test_when_finished "git rebase --abort" &&
+ test_must_fail git rebase HEAD^ --onto HEAD^^ &&
+ cat >expected <<-\EOF &&
+ # Not currently on any branch.
+ # You are currently rebasing.
+ # (fix conflicts and then run "git rebase --continue")
+ # (use "git rebase --skip" to skip this patch)
+ # (use "git rebase --abort" to check out the original branch)
+ #
+ # Unmerged paths:
+ # (use "git reset HEAD <file>..." to unstage)
+ # (use "git add <file>..." to mark resolution)
+ #
+ # both modified: main.txt
+ #
+ no changes added to commit (use "git add" and/or "git commit -a")
+ EOF
+ git status --untracked-files=no >actual &&
+ test_i18ncmp expected actual
+'
+
+
+test_expect_success 'status when rebase in progress before rebase --continue' '
+ git reset --hard rebase_conflicts &&
+ test_when_finished "git rebase --abort" &&
+ test_must_fail git rebase HEAD^ --onto HEAD^^ &&
+ echo three >main.txt &&
+ git add main.txt &&
+ cat >expected <<-\EOF &&
+ # Not currently on any branch.
+ # You are currently rebasing.
+ # (all conflicts fixed: run "git rebase --continue")
+ #
+ # Changes to be committed:
+ # (use "git reset HEAD <file>..." to unstage)
+ #
+ # modified: main.txt
+ #
+ # Untracked files not listed (use -u option to show untracked files)
+ EOF
+ git status --untracked-files=no >actual &&
+ test_i18ncmp expected actual
+'
+
+
+test_expect_success 'prepare for rebase_i_conflicts' '
+ git reset --hard master &&
+ git checkout -b rebase_i_conflicts &&
+ test_commit one_unmerge main.txt one_unmerge &&
+ git branch rebase_i_conflicts_second &&
+ test_commit one_master main.txt one_master &&
+ git checkout rebase_i_conflicts_second &&
+ test_commit one_second main.txt one_second
+'
+
+
+test_expect_success 'status during rebase -i when conflicts unresolved' '
+ test_when_finished "git rebase --abort" &&
+ test_must_fail git rebase -i rebase_i_conflicts &&
+ cat >expected <<-\EOF &&
+ # Not currently on any branch.
+ # You are currently rebasing.
+ # (fix conflicts and then run "git rebase --continue")
+ # (use "git rebase --skip" to skip this patch)
+ # (use "git rebase --abort" to check out the original branch)
+ #
+ # Unmerged paths:
+ # (use "git reset HEAD <file>..." to unstage)
+ # (use "git add <file>..." to mark resolution)
+ #
+ # both modified: main.txt
+ #
+ no changes added to commit (use "git add" and/or "git commit -a")
+ EOF
+ git status --untracked-files=no >actual &&
+ test_i18ncmp expected actual
+'
+
+
+test_expect_success 'status during rebase -i after resolving conflicts' '
+ git reset --hard rebase_i_conflicts_second &&
+ test_when_finished "git rebase --abort" &&
+ test_must_fail git rebase -i rebase_i_conflicts &&
+ git add main.txt &&
+ cat >expected <<-\EOF &&
+ # Not currently on any branch.
+ # You are currently rebasing.
+ # (all conflicts fixed: run "git rebase --continue")
+ #
+ # Changes to be committed:
+ # (use "git reset HEAD <file>..." to unstage)
+ #
+ # modified: main.txt
+ #
+ # Untracked files not listed (use -u option to show untracked files)
+ EOF
+ git status --untracked-files=no >actual &&
+ test_i18ncmp expected actual
+'
+
+
+test_expect_success 'status when rebasing -i in edit mode' '
+ git reset --hard master &&
+ git checkout -b rebase_i_edit &&
+ test_commit one_rebase_i main.txt one &&
+ test_commit two_rebase_i main.txt two &&
+ test_commit three_rebase_i main.txt three &&
+ FAKE_LINES="1 edit 2" &&
+ export FAKE_LINES &&
+ test_when_finished "git rebase --abort" &&
+ git rebase -i HEAD~2 &&
+ cat >expected <<-\EOF &&
+ # Not currently on any branch.
+ # You are currently editing a commit during a rebase.
+ # (use "git commit --amend" to amend the current commit)
+ # (use "git rebase --continue" once you are satisfied with your changes)
+ #
+ nothing to commit (use -u to show untracked files)
+ EOF
+ git status --untracked-files=no >actual &&
+ test_i18ncmp expected actual
+'
+
+
+test_expect_success 'status when splitting a commit' '
+ git reset --hard master &&
+ git checkout -b split_commit &&
+ test_commit one_split main.txt one &&
+ test_commit two_split main.txt two &&
+ test_commit three_split main.txt three &&
+ test_commit four_split main.txt four &&
+ FAKE_LINES="1 edit 2 3" &&
+ export FAKE_LINES &&
+ test_when_finished "git rebase --abort" &&
+ git rebase -i HEAD~3 &&
+ git reset HEAD^ &&
+ cat >expected <<-\EOF &&
+ # Not currently on any branch.
+ # You are currently splitting a commit during a rebase.
+ # (Once your working directory is clean, run "git rebase --continue")
+ #
+ # Changes not staged for commit:
+ # (use "git add <file>..." to update what will be committed)
+ # (use "git checkout -- <file>..." to discard changes in working directory)
+ #
+ # modified: main.txt
+ #
+ no changes added to commit (use "git add" and/or "git commit -a")
+ EOF
+ git status --untracked-files=no >actual &&
+ test_i18ncmp expected actual
+'
+
+
+test_expect_success 'status after editing the last commit with --amend during a rebase -i' '
+ git reset --hard master &&
+ git checkout -b amend_last &&
+ test_commit one_amend main.txt one &&
+ test_commit two_amend main.txt two &&
+ test_commit three_amend main.txt three &&
+ test_commit four_amend main.txt four &&
+ FAKE_LINES="1 2 edit 3" &&
+ export FAKE_LINES &&
+ test_when_finished "git rebase --abort" &&
+ git rebase -i HEAD~3 &&
+ git commit --amend -m "foo" &&
+ cat >expected <<-\EOF &&
+ # Not currently on any branch.
+ # You are currently editing a commit during a rebase.
+ # (use "git commit --amend" to amend the current commit)
+ # (use "git rebase --continue" once you are satisfied with your changes)
+ #
+ nothing to commit (use -u to show untracked files)
+ EOF
+ git status --untracked-files=no >actual &&
+ test_i18ncmp expected actual
+'
+
+
+test_expect_success 'prepare for several edits' '
+ git reset --hard master &&
+ git checkout -b several_edits &&
+ test_commit one_edits main.txt one &&
+ test_commit two_edits main.txt two &&
+ test_commit three_edits main.txt three &&
+ test_commit four_edits main.txt four
+'
+
+
+test_expect_success 'status: (continue first edit) second edit' '
+ FAKE_LINES="edit 1 edit 2 3" &&
+ export FAKE_LINES &&
+ test_when_finished "git rebase --abort" &&
+ git rebase -i HEAD~3 &&
+ git rebase --continue &&
+ cat >expected <<-\EOF &&
+ # Not currently on any branch.
+ # You are currently editing a commit during a rebase.
+ # (use "git commit --amend" to amend the current commit)
+ # (use "git rebase --continue" once you are satisfied with your changes)
+ #
+ nothing to commit (use -u to show untracked files)
+ EOF
+ git status --untracked-files=no >actual &&
+ test_i18ncmp expected actual
+'
+
+
+test_expect_success 'status: (continue first edit) second edit and split' '
+ git reset --hard several_edits &&
+ FAKE_LINES="edit 1 edit 2 3" &&
+ export FAKE_LINES &&
+ test_when_finished "git rebase --abort" &&
+ git rebase -i HEAD~3 &&
+ git rebase --continue &&
+ git reset HEAD^ &&
+ cat >expected <<-\EOF &&
+ # Not currently on any branch.
+ # You are currently splitting a commit during a rebase.
+ # (Once your working directory is clean, run "git rebase --continue")
+ #
+ # Changes not staged for commit:
+ # (use "git add <file>..." to update what will be committed)
+ # (use "git checkout -- <file>..." to discard changes in working directory)
+ #
+ # modified: main.txt
+ #
+ no changes added to commit (use "git add" and/or "git commit -a")
+ EOF
+ git status --untracked-files=no >actual &&
+ test_i18ncmp expected actual
+'
+
+
+test_expect_success 'status: (continue first edit) second edit and amend' '
+ git reset --hard several_edits &&
+ FAKE_LINES="edit 1 edit 2 3" &&
+ export FAKE_LINES &&
+ test_when_finished "git rebase --abort" &&
+ git rebase -i HEAD~3 &&
+ git rebase --continue &&
+ git commit --amend -m "foo" &&
+ cat >expected <<-\EOF &&
+ # Not currently on any branch.
+ # You are currently editing a commit during a rebase.
+ # (use "git commit --amend" to amend the current commit)
+ # (use "git rebase --continue" once you are satisfied with your changes)
+ #
+ nothing to commit (use -u to show untracked files)
+ EOF
+ git status --untracked-files=no >actual &&
+ test_i18ncmp expected actual
+'
+
+
+test_expect_success 'status: (amend first edit) second edit' '
+ git reset --hard several_edits &&
+ FAKE_LINES="edit 1 edit 2 3" &&
+ export FAKE_LINES &&
+ test_when_finished "git rebase --abort" &&
+ git rebase -i HEAD~3 &&
+ git commit --amend -m "a" &&
+ git rebase --continue &&
+ cat >expected <<-\EOF &&
+ # Not currently on any branch.
+ # You are currently editing a commit during a rebase.
+ # (use "git commit --amend" to amend the current commit)
+ # (use "git rebase --continue" once you are satisfied with your changes)
+ #
+ nothing to commit (use -u to show untracked files)
+ EOF
+ git status --untracked-files=no >actual &&
+ test_i18ncmp expected actual
+'
+
+
+test_expect_success 'status: (amend first edit) second edit and split' '
+ git reset --hard several_edits &&
+ FAKE_LINES="edit 1 edit 2 3" &&
+ export FAKE_LINES &&
+ test_when_finished "git rebase --abort" &&
+ git rebase -i HEAD~3 &&
+ git commit --amend -m "b" &&
+ git rebase --continue &&
+ git reset HEAD^ &&
+ cat >expected <<-\EOF &&
+ # Not currently on any branch.
+ # You are currently splitting a commit during a rebase.
+ # (Once your working directory is clean, run "git rebase --continue")
+ #
+ # Changes not staged for commit:
+ # (use "git add <file>..." to update what will be committed)
+ # (use "git checkout -- <file>..." to discard changes in working directory)
+ #
+ # modified: main.txt
+ #
+ no changes added to commit (use "git add" and/or "git commit -a")
+ EOF
+ git status --untracked-files=no >actual &&
+ test_i18ncmp expected actual
+'
+
+
+test_expect_success 'status: (amend first edit) second edit and amend' '
+ git reset --hard several_edits &&
+ FAKE_LINES="edit 1 edit 2 3" &&
+ export FAKE_LINES &&
+ test_when_finished "git rebase --abort" &&
+ git rebase -i HEAD~3 &&
+ git commit --amend -m "c" &&
+ git rebase --continue &&
+ git commit --amend -m "d" &&
+ cat >expected <<-\EOF &&
+ # Not currently on any branch.
+ # You are currently editing a commit during a rebase.
+ # (use "git commit --amend" to amend the current commit)
+ # (use "git rebase --continue" once you are satisfied with your changes)
+ #
+ nothing to commit (use -u to show untracked files)
+ EOF
+ git status --untracked-files=no >actual &&
+ test_i18ncmp expected actual
+'
+
+
+test_expect_success 'status: (split first edit) second edit' '
+ git reset --hard several_edits &&
+ FAKE_LINES="edit 1 edit 2 3" &&
+ export FAKE_LINES &&
+ test_when_finished "git rebase --abort" &&
+ git rebase -i HEAD~3 &&
+ git reset HEAD^ &&
+ git add main.txt &&
+ git commit -m "e" &&
+ git rebase --continue &&
+ cat >expected <<-\EOF &&
+ # Not currently on any branch.
+ # You are currently editing a commit during a rebase.
+ # (use "git commit --amend" to amend the current commit)
+ # (use "git rebase --continue" once you are satisfied with your changes)
+ #
+ nothing to commit (use -u to show untracked files)
+ EOF
+ git status --untracked-files=no >actual &&
+ test_i18ncmp expected actual
+'
+
+
+test_expect_success 'status: (split first edit) second edit and split' '
+ git reset --hard several_edits &&
+ FAKE_LINES="edit 1 edit 2 3" &&
+ export FAKE_LINES &&
+ test_when_finished "git rebase --abort" &&
+ git rebase -i HEAD~3 &&
+ git reset HEAD^ &&
+ git add main.txt &&
+ git commit --amend -m "f" &&
+ git rebase --continue &&
+ git reset HEAD^ &&
+ cat >expected <<-\EOF &&
+ # Not currently on any branch.
+ # You are currently splitting a commit during a rebase.
+ # (Once your working directory is clean, run "git rebase --continue")
+ #
+ # Changes not staged for commit:
+ # (use "git add <file>..." to update what will be committed)
+ # (use "git checkout -- <file>..." to discard changes in working directory)
+ #
+ # modified: main.txt
+ #
+ no changes added to commit (use "git add" and/or "git commit -a")
+ EOF
+ git status --untracked-files=no >actual &&
+ test_i18ncmp expected actual
+'
+
+
+test_expect_success 'status: (split first edit) second edit and amend' '
+ git reset --hard several_edits &&
+ FAKE_LINES="edit 1 edit 2 3" &&
+ export FAKE_LINES &&
+ test_when_finished "git rebase --abort" &&
+ git rebase -i HEAD~3 &&
+ git reset HEAD^ &&
+ git add main.txt &&
+ git commit --amend -m "g" &&
+ git rebase --continue &&
+ git commit --amend -m "h" &&
+ cat >expected <<-\EOF &&
+ # Not currently on any branch.
+ # You are currently editing a commit during a rebase.
+ # (use "git commit --amend" to amend the current commit)
+ # (use "git rebase --continue" once you are satisfied with your changes)
+ #
+ nothing to commit (use -u to show untracked files)
+ EOF
+ git status --untracked-files=no >actual &&
+ test_i18ncmp expected actual
+'
+
+
+test_expect_success 'prepare am_session' '
+ git reset --hard master &&
+ git checkout -b am_session &&
+ test_commit one_am one.txt "one" &&
+ test_commit two_am two.txt "two" &&
+ test_commit three_am three.txt "three"
+'
+
+
+test_expect_success 'status in an am session: file already exists' '
+ git checkout -b am_already_exists &&
+ test_when_finished "rm Maildir/* && git am --abort" &&
+ git format-patch -1 -oMaildir &&
+ test_must_fail git am Maildir/*.patch &&
+ cat >expected <<-\EOF &&
+ # On branch am_already_exists
+ # You are in the middle of an am session.
+ # (fix conflicts and then run "git am --resolved")
+ # (use "git am --skip" to skip this patch)
+ # (use "git am --abort" to restore the original branch)
+ #
+ nothing to commit (use -u to show untracked files)
+ EOF
+ git status --untracked-files=no >actual &&
+ test_i18ncmp expected actual
+'
+
+
+test_expect_success 'status in an am session: file does not exist' '
+ git reset --hard am_session &&
+ git checkout -b am_not_exists &&
+ git rm three.txt &&
+ git commit -m "delete three.txt" &&
+ test_when_finished "rm Maildir/* && git am --abort" &&
+ git format-patch -1 -oMaildir &&
+ test_must_fail git am Maildir/*.patch &&
+ cat >expected <<-\EOF &&
+ # On branch am_not_exists
+ # You are in the middle of an am session.
+ # (fix conflicts and then run "git am --resolved")
+ # (use "git am --skip" to skip this patch)
+ # (use "git am --abort" to restore the original branch)
+ #
+ nothing to commit (use -u to show untracked files)
+ EOF
+ git status --untracked-files=no >actual &&
+ test_i18ncmp expected actual
+'
+
+
+test_expect_success 'status in an am session: empty patch' '
+ git reset --hard am_session &&
+ git checkout -b am_empty &&
+ test_when_finished "rm Maildir/* && git am --abort" &&
+ git format-patch -3 -oMaildir &&
+ git rm one.txt two.txt three.txt &&
+ git commit -m "delete all am_empty" &&
+ echo error >Maildir/0002-two_am.patch &&
+ test_must_fail git am Maildir/*.patch &&
+ cat >expected <<-\EOF &&
+ # On branch am_empty
+ # You are in the middle of an am session.
+ # The current patch is empty.
+ # (use "git am --skip" to skip this patch)
+ # (use "git am --abort" to restore the original branch)
+ #
+ nothing to commit (use -u to show untracked files)
+ EOF
+ git status --untracked-files=no >actual &&
+ test_i18ncmp expected actual
+'
+
+
+test_expect_success 'status when bisecting' '
+ git reset --hard master &&
+ git checkout -b bisect &&
+ test_commit one_bisect main.txt one &&
+ test_commit two_bisect main.txt two &&
+ test_commit three_bisect main.txt three &&
+ test_when_finished "git bisect reset" &&
+ git bisect start &&
+ git bisect bad &&
+ git bisect good one_bisect &&
+ cat >expected <<-\EOF &&
+ # Not currently on any branch.
+ # You are currently bisecting.
+ # (use "git bisect reset" to get back to the original branch)
+ #
+ nothing to commit (use -u to show untracked files)
+ EOF
+ git status --untracked-files=no >actual &&
+ test_i18ncmp expected actual
+'
+
+
+test_expect_success 'status when rebase conflicts with statushints disabled' '
+ git reset --hard master &&
+ git checkout -b statushints_disabled &&
+ test_when_finished "git config --local advice.statushints true" &&
+ git config --local advice.statushints false &&
+ test_commit one_statushints main.txt one &&
+ test_commit two_statushints main.txt two &&
+ test_commit three_statushints main.txt three &&
+ test_when_finished "git rebase --abort" &&
+ test_must_fail git rebase HEAD^ --onto HEAD^^ &&
+ cat >expected <<-\EOF &&
+ # Not currently on any branch.
+ # You are currently rebasing.
+ #
+ # Unmerged paths:
+ # both modified: main.txt
+ #
+ no changes added to commit
+ EOF
+ git status --untracked-files=no >actual &&
+ test_i18ncmp expected actual
+'
+
+
+test_expect_success 'prepare for cherry-pick conflicts' '
+ git reset --hard master &&
+ git checkout -b cherry_branch &&
+ test_commit one_cherry main.txt one &&
+ test_commit two_cherries main.txt two &&
+ git checkout -b cherry_branch_second &&
+ test_commit second_cherry main.txt second &&
+ git checkout cherry_branch &&
+ test_commit three_cherries main.txt three
+'
+
+
+test_expect_success 'status when cherry-picking before resolving conflicts' '
+ test_when_finished "git cherry-pick --abort" &&
+ test_must_fail git cherry-pick cherry_branch_second &&
+ cat >expected <<-\EOF &&
+ # On branch cherry_branch
+ # You are currently cherry-picking.
+ # (fix conflicts and run "git commit")
+ #
+ # Unmerged paths:
+ # (use "git add <file>..." to mark resolution)
+ #
+ # both modified: main.txt
+ #
+ no changes added to commit (use "git add" and/or "git commit -a")
+ EOF
+ git status --untracked-files=no >actual &&
+ test_i18ncmp expected actual
+'
+
+
+test_expect_success 'status when cherry-picking after resolving conflicts' '
+ git reset --hard cherry_branch &&
+ test_when_finished "git cherry-pick --abort" &&
+ test_must_fail git cherry-pick cherry_branch_second &&
+ echo end >main.txt &&
+ git add main.txt &&
+ cat >expected <<-\EOF &&
+ # On branch cherry_branch
+ # You are currently cherry-picking.
+ # (all conflicts fixed: run "git commit")
+ #
+ # Changes to be committed:
+ #
+ # modified: main.txt
+ #
+ # Untracked files not listed (use -u option to show untracked files)
+ EOF
+ git status --untracked-files=no >actual &&
+ test_i18ncmp expected actual
+'
+
+
+test_done
diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh
index 9e27bbf..5e19598 100755
--- a/t/t7600-merge.sh
+++ b/t/t7600-merge.sh
@@ -157,7 +157,7 @@ test_expect_success 'merge -h with invalid index' '
>.git/index &&
test_expect_code 129 git merge -h 2>usage
) &&
- grep "[Uu]sage: git merge" broken/usage
+ test_i18ngrep "[Uu]sage: git merge" broken/usage
'
test_expect_success 'reject non-strategy with a git-merge-foo name' '
diff --git a/t/t7610-mergetool.sh b/t/t7610-mergetool.sh
index 6fa0c70..bc38737 100755
--- a/t/t7610-mergetool.sh
+++ b/t/t7610-mergetool.sh
@@ -509,4 +509,17 @@ test_expect_success 'file with no base' '
git reset --hard master >/dev/null 2>&1
'
+test_expect_success 'custom commands override built-ins' '
+ git checkout -b test14 branch1 &&
+ git config mergetool.defaults.cmd "cat \"\$REMOTE\" >\"\$MERGED\"" &&
+ git config mergetool.defaults.trustExitCode true &&
+ test_must_fail git merge master &&
+ git mergetool --no-prompt --tool defaults -- both &&
+ echo master both added >expected &&
+ test_cmp both expected &&
+ git config --unset mergetool.defaults.cmd &&
+ git config --unset mergetool.defaults.trustExitCode &&
+ git reset --hard master >/dev/null 2>&1
+'
+
test_done
diff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh
index 9c3e997..eb1d3f8 100755
--- a/t/t7800-difftool.sh
+++ b/t/t7800-difftool.sh
@@ -76,6 +76,17 @@ test_expect_success PERL 'custom commands' '
test "$diff" = "branch"
'
+# Ensures that a custom difftool.<tool>.cmd overrides built-ins
+test_expect_success PERL 'custom commands override built-ins' '
+ restore_test_defaults &&
+ git config difftool.defaults.cmd "cat \$REMOTE" &&
+
+ diff=$(git difftool --tool defaults --no-prompt branch) &&
+ test "$diff" = "master" &&
+
+ git config --unset difftool.defaults.cmd
+'
+
# Ensures that git-difftool ignores bogus --tool values
test_expect_success PERL 'difftool ignores bad --tool values' '
diff=$(git difftool --no-prompt --tool=bad-tool branch)
diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh
index 523d041..f698001 100755
--- a/t/t7810-grep.sh
+++ b/t/t7810-grep.sh
@@ -250,6 +250,84 @@ do
git -c grep.extendedRegexp=true grep "a+b*c" ab >actual &&
test_cmp expected actual
'
+
+ test_expect_success "grep $L with grep.patterntype=basic" '
+ echo "ab:a+bc" >expected &&
+ git -c grep.patterntype=basic grep "a+b*c" ab >actual &&
+ test_cmp expected actual
+ '
+
+ test_expect_success "grep $L with grep.patterntype=extended" '
+ echo "ab:abc" >expected &&
+ git -c grep.patterntype=extended grep "a+b*c" ab >actual &&
+ test_cmp expected actual
+ '
+
+ test_expect_success "grep $L with grep.patterntype=fixed" '
+ echo "ab:a+b*c" >expected &&
+ git -c grep.patterntype=fixed grep "a+b*c" ab >actual &&
+ test_cmp expected actual
+ '
+
+ test_expect_success LIBPCRE "grep $L with grep.patterntype=perl" '
+ echo "ab:a+b*c" >expected &&
+ git -c grep.patterntype=perl grep "a\x{2b}b\x{2a}c" ab >actual &&
+ test_cmp expected actual
+ '
+
+ test_expect_success "grep $L with grep.patternType=default and grep.extendedRegexp=true" '
+ echo "ab:abc" >expected &&
+ git \
+ -c grep.patternType=default \
+ -c grep.extendedRegexp=true \
+ grep "a+b*c" ab >actual &&
+ test_cmp expected actual
+ '
+
+ test_expect_success "grep $L with grep.extendedRegexp=true and grep.patternType=default" '
+ echo "ab:abc" >expected &&
+ git \
+ -c grep.extendedRegexp=true \
+ -c grep.patternType=default \
+ grep "a+b*c" ab >actual &&
+ test_cmp expected actual
+ '
+
+ test_expect_success 'grep $L with grep.patternType=extended and grep.extendedRegexp=false' '
+ echo "ab:abc" >expected &&
+ git \
+ -c grep.patternType=extended \
+ -c grep.extendedRegexp=false \
+ grep "a+b*c" ab >actual &&
+ test_cmp expected actual
+ '
+
+ test_expect_success 'grep $L with grep.patternType=basic and grep.extendedRegexp=true' '
+ echo "ab:a+bc" >expected &&
+ git \
+ -c grep.patternType=basic \
+ -c grep.extendedRegexp=true \
+ grep "a+b*c" ab >actual &&
+ test_cmp expected actual
+ '
+
+ test_expect_success 'grep $L with grep.extendedRegexp=false and grep.patternType=extended' '
+ echo "ab:abc" >expected &&
+ git \
+ -c grep.extendedRegexp=false \
+ -c grep.patternType=extended \
+ grep "a+b*c" ab >actual &&
+ test_cmp expected actual
+ '
+
+ test_expect_success 'grep $L with grep.extendedRegexp=true and grep.patternType=basic' '
+ echo "ab:a+bc" >expected &&
+ git \
+ -c grep.extendedRegexp=true \
+ -c grep.patternType=basic \
+ grep "a+b*c" ab >actual &&
+ test_cmp expected actual
+ '
done
cat >expected <<EOF
@@ -424,31 +502,41 @@ test_expect_success 'log grep setup' '
test_expect_success 'log grep (1)' '
git log --author=author --pretty=tformat:%s >actual &&
- ( echo third ; echo initial ) >expect &&
+ {
+ echo third && echo initial
+ } >expect &&
test_cmp expect actual
'
test_expect_success 'log grep (2)' '
git log --author=" * " -F --pretty=tformat:%s >actual &&
- ( echo second ) >expect &&
+ {
+ echo second
+ } >expect &&
test_cmp expect actual
'
test_expect_success 'log grep (3)' '
git log --author="^A U" --pretty=tformat:%s >actual &&
- ( echo third ; echo initial ) >expect &&
+ {
+ echo third && echo initial
+ } >expect &&
test_cmp expect actual
'
test_expect_success 'log grep (4)' '
git log --author="frotz\.com>$" --pretty=tformat:%s >actual &&
- ( echo second ) >expect &&
+ {
+ echo second
+ } >expect &&
test_cmp expect actual
'
test_expect_success 'log grep (5)' '
git log --author=Thor -F --pretty=tformat:%s >actual &&
- ( echo third ; echo initial ) >expect &&
+ {
+ echo third && echo initial
+ } >expect &&
test_cmp expect actual
'
@@ -458,11 +546,49 @@ test_expect_success 'log grep (6)' '
test_cmp expect actual
'
-test_expect_success 'log --grep --author implicitly uses all-match' '
- # grep matches initial and second but not third
- # author matches only initial and third
- git log --author="A U Thor" --grep=s --grep=l --format=%s >actual &&
- echo initial >expect &&
+test_expect_success 'log grep (7)' '
+ git log -g --grep-reflog="commit: third" --pretty=tformat:%s >actual &&
+ echo third >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'log grep (8)' '
+ git log -g --grep-reflog="commit: third" --grep-reflog="commit: second" --pretty=tformat:%s >actual &&
+ {
+ echo third && echo second
+ } >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'log grep (9)' '
+ git log -g --grep-reflog="commit: third" --author="Thor" --pretty=tformat:%s >actual &&
+ echo third >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'log grep (9)' '
+ git log -g --grep-reflog="commit: third" --author="non-existant" --pretty=tformat:%s >actual &&
+ : >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'log --grep-reflog can only be used under -g' '
+ test_must_fail git log --grep-reflog="commit: third"
+'
+
+test_expect_success 'log with multiple --grep uses union' '
+ git log --grep=i --grep=r --format=%s >actual &&
+ {
+ echo fourth && echo third && echo initial
+ } >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'log --all-match with multiple --grep uses intersection' '
+ git log --all-match --grep=i --grep=r --format=%s >actual &&
+ {
+ echo third
+ } >expect &&
test_cmp expect actual
'
@@ -474,7 +600,47 @@ test_expect_success 'log with multiple --author uses union' '
test_cmp expect actual
'
-test_expect_success 'log with --grep and multiple --author uses all-match' '
+test_expect_success 'log --all-match with multiple --author still uses union' '
+ git log --all-match --author="Thor" --author="Aster" --format=%s >actual &&
+ {
+ echo third && echo second && echo initial
+ } >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'log --grep --author uses intersection' '
+ # grep matches only third and fourth
+ # author matches only initial and third
+ git log --author="A U Thor" --grep=r --format=%s >actual &&
+ {
+ echo third
+ } >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'log --grep --grep --author takes union of greps and intersects with author' '
+ # grep matches initial and second but not third
+ # author matches only initial and third
+ git log --author="A U Thor" --grep=s --grep=l --format=%s >actual &&
+ {
+ echo initial
+ } >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'log ---all-match -grep --author --author still takes union of authors and intersects with grep' '
+ # grep matches only initial and third
+ # author matches all but second
+ git log --all-match --author="Thor" --author="Night" --grep=i --format=%s >actual &&
+ {
+ echo third && echo initial
+ } >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'log --grep --author --author takes union of authors and intersects with grep' '
+ # grep matches only initial and third
+ # author matches all but second
git log --author="Thor" --author="Night" --grep=i --format=%s >actual &&
{
echo third && echo initial
@@ -482,9 +648,25 @@ test_expect_success 'log with --grep and multiple --author uses all-match' '
test_cmp expect actual
'
-test_expect_success 'log with --grep and multiple --author uses all-match' '
- git log --author="Thor" --author="Night" --grep=q --format=%s >actual &&
- >expect &&
+test_expect_success 'log --all-match --grep --grep --author takes intersection' '
+ # grep matches only third
+ # author matches only initial and third
+ git log --all-match --author="A U Thor" --grep=i --grep=r --format=%s >actual &&
+ {
+ echo third
+ } >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'log --author does not search in timestamp' '
+ : >expect &&
+ git log --author="$GIT_AUTHOR_DATE" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'log --committer does not search in timestamp' '
+ : >expect &&
+ git log --committer="$GIT_COMMITTER_DATE" >actual &&
test_cmp expect actual
'
@@ -761,44 +943,147 @@ test_expect_success 'grep -G invalidpattern properly dies ' '
test_must_fail git grep -G "a["
'
+test_expect_success 'grep invalidpattern properly dies with grep.patternType=basic' '
+ test_must_fail git -c grep.patterntype=basic grep "a["
+'
+
test_expect_success 'grep -E invalidpattern properly dies ' '
test_must_fail git grep -E "a["
'
+test_expect_success 'grep invalidpattern properly dies with grep.patternType=extended' '
+ test_must_fail git -c grep.patterntype=extended grep "a["
+'
+
test_expect_success LIBPCRE 'grep -P invalidpattern properly dies ' '
test_must_fail git grep -P "a["
'
+test_expect_success LIBPCRE 'grep invalidpattern properly dies with grep.patternType=perl' '
+ test_must_fail git -c grep.patterntype=perl grep "a["
+'
+
test_expect_success 'grep -G -E -F pattern' '
echo "ab:a+b*c" >expected &&
git grep -G -E -F "a+b*c" ab >actual &&
test_cmp expected actual
'
+test_expect_success 'grep pattern with grep.patternType=basic, =extended, =fixed' '
+ echo "ab:a+b*c" >expected &&
+ git \
+ -c grep.patterntype=basic \
+ -c grep.patterntype=extended \
+ -c grep.patterntype=fixed \
+ grep "a+b*c" ab >actual &&
+ test_cmp expected actual
+'
+
test_expect_success 'grep -E -F -G pattern' '
echo "ab:a+bc" >expected &&
git grep -E -F -G "a+b*c" ab >actual &&
test_cmp expected actual
'
+test_expect_success 'grep pattern with grep.patternType=extended, =fixed, =basic' '
+ echo "ab:a+bc" >expected &&
+ git \
+ -c grep.patterntype=extended \
+ -c grep.patterntype=fixed \
+ -c grep.patterntype=basic \
+ grep "a+b*c" ab >actual &&
+ test_cmp expected actual
+'
+
test_expect_success 'grep -F -G -E pattern' '
echo "ab:abc" >expected &&
git grep -F -G -E "a+b*c" ab >actual &&
test_cmp expected actual
'
+test_expect_success 'grep pattern with grep.patternType=fixed, =basic, =extended' '
+ echo "ab:abc" >expected &&
+ git \
+ -c grep.patterntype=fixed \
+ -c grep.patterntype=basic \
+ -c grep.patterntype=extended \
+ grep "a+b*c" ab >actual &&
+ test_cmp expected actual
+'
+
test_expect_success 'grep -G -F -P -E pattern' '
>empty &&
test_must_fail git grep -G -F -P -E "a\x{2b}b\x{2a}c" ab >actual &&
test_cmp empty actual
'
+test_expect_success 'grep pattern with grep.patternType=fixed, =basic, =perl, =extended' '
+ >empty &&
+ test_must_fail git \
+ -c grep.patterntype=fixed \
+ -c grep.patterntype=basic \
+ -c grep.patterntype=perl \
+ -c grep.patterntype=extended \
+ grep "a\x{2b}b\x{2a}c" ab >actual &&
+ test_cmp empty actual
+'
+
test_expect_success LIBPCRE 'grep -G -F -E -P pattern' '
echo "ab:a+b*c" >expected &&
git grep -G -F -E -P "a\x{2b}b\x{2a}c" ab >actual &&
test_cmp expected actual
'
+test_expect_success LIBPCRE 'grep pattern with grep.patternType=fixed, =basic, =extended, =perl' '
+ echo "ab:a+b*c" >expected &&
+ git \
+ -c grep.patterntype=fixed \
+ -c grep.patterntype=basic \
+ -c grep.patterntype=extended \
+ -c grep.patterntype=perl \
+ grep "a\x{2b}b\x{2a}c" ab >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success LIBPCRE 'grep -P pattern with grep.patternType=fixed' '
+ echo "ab:a+b*c" >expected &&
+ git \
+ -c grep.patterntype=fixed \
+ grep -P "a\x{2b}b\x{2a}c" ab >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'grep -F pattern with grep.patternType=basic' '
+ echo "ab:a+b*c" >expected &&
+ git \
+ -c grep.patterntype=basic \
+ grep -F "*c" ab >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'grep -G pattern with grep.patternType=fixed' '
+ {
+ echo "ab:a+b*c"
+ echo "ab:a+bc"
+ } >expected &&
+ git \
+ -c grep.patterntype=fixed \
+ grep -G "a+b" ab >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'grep -E pattern with grep.patternType=fixed' '
+ {
+ echo "ab:a+b*c"
+ echo "ab:a+bc"
+ echo "ab:abc"
+ } >expected &&
+ git \
+ -c grep.patterntype=fixed \
+ grep -E "a+" ab >actual &&
+ test_cmp expected actual
+'
+
test_config() {
git config "$1" "$2" &&
test_when_finished "git config --unset $1"
diff --git a/t/t8004-blame-with-conflicts.sh b/t/t8004-blame-with-conflicts.sh
index ba19ac1..9c353ab 100755
--- a/t/t8004-blame-with-conflicts.sh
+++ b/t/t8004-blame-with-conflicts.sh
@@ -66,7 +66,7 @@ test_expect_success \
git blame file2
'
-test_expect_success 'blame runs on conflicted file in stages 1,3' '
+test_expect_success 'blame does not crash with conflicted file in stages 1,3' '
git blame file1
'
diff --git a/t/t9107-git-svn-migrate.sh b/t/t9107-git-svn-migrate.sh
index 289fc31..ee73013 100755
--- a/t/t9107-git-svn-migrate.sh
+++ b/t/t9107-git-svn-migrate.sh
@@ -27,15 +27,17 @@ test_expect_success 'setup old-looking metadata' '
head=`git rev-parse --verify refs/heads/git-svn-HEAD^0`
test_expect_success 'git-svn-HEAD is a real HEAD' "test -n '$head'"
+svnrepo_escaped=`echo $svnrepo | sed 's/ /%20/'`
+
test_expect_success 'initialize old-style (v0) git svn layout' '
mkdir -p "$GIT_DIR"/git-svn/info "$GIT_DIR"/svn/info &&
echo "$svnrepo" > "$GIT_DIR"/git-svn/info/url &&
echo "$svnrepo" > "$GIT_DIR"/svn/info/url &&
git svn migrate &&
- ! test -d "$GIT_DIR"/git svn &&
+ ! test -d "$GIT_DIR"/git-svn &&
git rev-parse --verify refs/${remotes_git_svn}^0 &&
git rev-parse --verify refs/remotes/svn^0 &&
- test "$(git config --get svn-remote.svn.url)" = "$svnrepo" &&
+ test "$(git config --get svn-remote.svn.url)" = "$svnrepo_escaped" &&
test `git config --get svn-remote.svn.fetch` = \
":refs/${remotes_git_svn}"
'
diff --git a/t/t9118-git-svn-funky-branch-names.sh b/t/t9118-git-svn-funky-branch-names.sh
index 63fc982..15f93b4 100755
--- a/t/t9118-git-svn-funky-branch-names.sh
+++ b/t/t9118-git-svn-funky-branch-names.sh
@@ -28,10 +28,15 @@ test_expect_success 'setup svnrepo' '
svn_cmd cp -m "trailing .lock" "$svnrepo/pr ject/trunk" \
"$svnrepo/pr ject/branches/trailing_dotlock.lock" &&
svn_cmd cp -m "reflog" "$svnrepo/pr ject/trunk" \
- "$svnrepo/pr ject/branches/not-a%40{0}reflog" &&
+ "$svnrepo/pr ject/branches/not-a@{0}reflog@" &&
start_httpd
'
+# SVN 1.7 will truncate "not-a%40{0]" to just "not-a".
+# Look at what SVN wound up naming the branch and use that.
+# Be sure to escape the @ if it shows up.
+non_reflog=`svn_cmd ls "$svnrepo/pr ject/branches" | grep not-a | sed 's/\///' | sed 's/@/%40/'`
+
test_expect_success 'test clone with funky branch names' '
git svn clone -s "$svnrepo/pr ject" project &&
(
@@ -42,7 +47,7 @@ test_expect_success 'test clone with funky branch names' '
git rev-parse "refs/remotes/%2Eleading_dot" &&
git rev-parse "refs/remotes/trailing_dot%2E" &&
git rev-parse "refs/remotes/trailing_dotlock%2Elock" &&
- git rev-parse "refs/remotes/not-a%40{0}reflog"
+ git rev-parse "refs/remotes/$non_reflog"
)
'
diff --git a/t/t9154-git-svn-fancy-glob.sh b/t/t9154-git-svn-fancy-glob.sh
index a6a56a6..b780e0e 100755
--- a/t/t9154-git-svn-fancy-glob.sh
+++ b/t/t9154-git-svn-fancy-glob.sh
@@ -21,6 +21,15 @@ test_expect_success 'add red branch' "
test_must_fail git rev-parse refs/remotes/blue
"
+test_expect_success 'add gre branch' "
+ GIT_CONFIG=.git/svn/.metadata git config --unset svn-remote.svn.branches-maxRev &&
+ git config svn-remote.svn.branches 'branches/{red,gre}:refs/remotes/*' &&
+ git svn fetch &&
+ git rev-parse refs/remotes/red &&
+ test_must_fail git rev-parse refs/remotes/green &&
+ test_must_fail git rev-parse refs/remotes/blue
+ "
+
test_expect_success 'add green branch' "
GIT_CONFIG=.git/svn/.metadata git config --unset svn-remote.svn.branches-maxRev &&
git config svn-remote.svn.branches 'branches/{red,green}:refs/remotes/*' &&
diff --git a/t/t9163-git-svn-reset-clears-caches.sh b/t/t9163-git-svn-reset-clears-caches.sh
new file mode 100755
index 0000000..cd4c662
--- /dev/null
+++ b/t/t9163-git-svn-reset-clears-caches.sh
@@ -0,0 +1,78 @@
+#!/bin/sh
+#
+# Copyright (c) 2012 Peter Baumann
+#
+
+test_description='git svn reset clears memoized caches'
+. ./lib-git-svn.sh
+
+svn_ver="$(svn --version --quiet)"
+case $svn_ver in
+0.* | 1.[0-4].*)
+ skip_all="skipping git-svn test - SVN too old ($svn_ver)"
+ test_done
+ ;;
+esac
+
+# ... a - b - m <- trunk
+# \ /
+# ... c <- branch1
+#
+# SVN Commits not interesting for this test are abbreviated with "..."
+#
+test_expect_success 'initialize source svn repo' '
+ svn_cmd mkdir -m "create trunk" "$svnrepo"/trunk &&
+ svn_cmd mkdir -m "create branches" "$svnrepo/branches" &&
+ svn_cmd co "$svnrepo"/trunk "$SVN_TREE" &&
+ (
+ cd "$SVN_TREE" &&
+ touch foo &&
+ svn_cmd add foo &&
+ svn_cmd commit -m "a" &&
+ svn_cmd cp -m branch "$svnrepo"/trunk "$svnrepo"/branches/branch1 &&
+ svn_cmd switch "$svnrepo"/branches/branch1 &&
+ touch bar &&
+ svn_cmd add bar &&
+ svn_cmd commit -m b &&
+ svn_cmd switch "$svnrepo"/trunk &&
+ touch baz &&
+ svn_cmd add baz &&
+ svn_cmd commit -m c &&
+ svn_cmd up &&
+ svn_cmd merge "$svnrepo"/branches/branch1 &&
+ svn_cmd commit -m "m"
+ ) &&
+ rm -rf "$SVN_TREE"
+'
+
+test_expect_success 'fetch to merge-base (a)' '
+ git svn init -s "$svnrepo" &&
+ git svn fetch --revision BASE:3
+'
+
+# git svn rebase looses the merge commit
+#
+# ... a - b - m <- trunk
+# \
+# ... c
+#
+test_expect_success 'rebase looses SVN merge (m)' '
+ git svn rebase &&
+ git svn fetch &&
+ test 1 = $(git cat-file -p master|grep parent|wc -l)
+'
+
+# git svn fetch creates correct history with merge commit
+#
+# ... a - b - m <- trunk
+# \ /
+# ... c <- branch1
+#
+test_expect_success 'reset and fetch gets the SVN merge (m) correctly' '
+ git svn reset -r 3 &&
+ git reset --hard trunk &&
+ git svn fetch &&
+ test 2 = $(git cat-file -p trunk|grep parent|wc -l)
+'
+
+test_done
diff --git a/t/t9164-git-svn-dcommit-concurrent.sh b/t/t9164-git-svn-dcommit-concurrent.sh
new file mode 100755
index 0000000..d8464d4
--- /dev/null
+++ b/t/t9164-git-svn-dcommit-concurrent.sh
@@ -0,0 +1,216 @@
+#!/bin/sh
+#
+# Copyright (c) 2012 Robert Luberda
+#
+
+test_description='concurrent git svn dcommit'
+. ./lib-git-svn.sh
+
+
+
+test_expect_success 'setup svn repository' '
+ svn_cmd checkout "$svnrepo" work.svn &&
+ (
+ cd work.svn &&
+ echo >file && echo > auto_updated_file
+ svn_cmd add file auto_updated_file &&
+ svn_cmd commit -m "initial commit"
+ ) &&
+ svn_cmd checkout "$svnrepo" work-auto-commits.svn
+'
+N=0
+next_N()
+{
+ N=$(( $N + 1 ))
+}
+
+# Setup SVN repository hooks to emulate SVN failures or concurrent commits
+# The function adds
+# either pre-commit hook, which causes SVN commit given in second argument
+# to fail
+# or post-commit hook, which creates a new commit (a new line added to
+# auto_updated_file) after given SVN commit
+# The first argument contains a type of the hook
+# The second argument contains a number (not SVN revision) of commit
+# the hook should be applied for (each time the hook is run, the given
+# number is decreased by one until it gets 0, in which case the hook
+# will execute its real action)
+setup_hook()
+{
+ hook_type="$1" # "pre-commit" or "post-commit"
+ skip_revs="$2"
+ [ "$hook_type" = "pre-commit" ] ||
+ [ "$hook_type" = "post-commit" ] ||
+ { echo "ERROR: invalid argument ($hook_type)" \
+ "passed to setup_hook" >&2 ; return 1; }
+ echo "cnt=$skip_revs" > "$hook_type-counter"
+ rm -f "$rawsvnrepo/hooks/"*-commit # drop previous hooks
+ hook="$rawsvnrepo/hooks/$hook_type"
+ cat > "$hook" <<- 'EOF1'
+ #!/bin/sh
+ set -e
+ cd "$1/.." # "$1" is repository location
+ exec >> svn-hook.log 2>&1
+ hook="$(basename "$0")"
+ echo "*** Executing $hook $@"
+ set -x
+ . ./$hook-counter
+ cnt="$(($cnt - 1))"
+ echo "cnt=$cnt" > ./$hook-counter
+ [ "$cnt" = "0" ] || exit 0
+EOF1
+ if [ "$hook_type" = "pre-commit" ]; then
+ echo "echo 'commit disallowed' >&2; exit 1" >>"$hook"
+ else
+ echo "PATH=\"$PATH\"; export PATH" >>"$hook"
+ echo "svnconf=\"$svnconf\"" >>"$hook"
+ cat >>"$hook" <<- 'EOF2'
+ cd work-auto-commits.svn
+ svn up --config-dir "$svnconf"
+ echo "$$" >> auto_updated_file
+ svn commit --config-dir "$svnconf" \
+ -m "auto-committing concurrent change"
+ exit 0
+EOF2
+ fi
+ chmod 755 "$hook"
+}
+
+check_contents()
+{
+ gitdir="$1"
+ (cd ../work.svn && svn_cmd up) &&
+ test_cmp file ../work.svn/file &&
+ test_cmp auto_updated_file ../work.svn/auto_updated_file
+}
+
+test_expect_success 'check if post-commit hook creates a concurrent commit' '
+ setup_hook post-commit 1 &&
+ (
+ cd work.svn &&
+ cp auto_updated_file au_file_saved &&
+ echo 1 >> file &&
+ svn_cmd commit -m "changing file" &&
+ svn_cmd up &&
+ test_must_fail test_cmp auto_updated_file au_file_saved
+ )
+'
+
+test_expect_success 'check if pre-commit hook fails' '
+ setup_hook pre-commit 2 &&
+ (
+ cd work.svn &&
+ echo 2 >> file &&
+ svn_cmd commit -m "changing file once again" &&
+ echo 3 >> file &&
+ test_must_fail svn_cmd commit -m "this commit should fail" &&
+ svn_cmd revert file
+ )
+'
+
+test_expect_success 'dcommit error handling' '
+ setup_hook pre-commit 2 &&
+ next_N && git svn clone "$svnrepo" work$N.git &&
+ (
+ cd work$N.git &&
+ echo 1 >> file && git commit -am "commit change $N.1" &&
+ echo 2 >> file && git commit -am "commit change $N.2" &&
+ echo 3 >> file && git commit -am "commit change $N.3" &&
+ # should fail to dcommit 2nd and 3rd change
+ # but still should leave the repository in reasonable state
+ test_must_fail git svn dcommit &&
+ git update-index --refresh &&
+ git show HEAD~2 | grep -q git-svn-id &&
+ ! git show HEAD~1 | grep -q git-svn-id &&
+ ! git show HEAD | grep -q git-svn-id
+ )
+'
+
+test_expect_success 'dcommit concurrent change in non-changed file' '
+ setup_hook post-commit 2 &&
+ next_N && git svn clone "$svnrepo" work$N.git &&
+ (
+ cd work$N.git &&
+ echo 1 >> file && git commit -am "commit change $N.1" &&
+ echo 2 >> file && git commit -am "commit change $N.2" &&
+ echo 3 >> file && git commit -am "commit change $N.3" &&
+ # should rebase and leave the repository in reasonable state
+ git svn dcommit &&
+ git update-index --refresh &&
+ check_contents &&
+ git show HEAD~3 | grep -q git-svn-id &&
+ git show HEAD~2 | grep -q git-svn-id &&
+ git show HEAD~1 | grep -q auto-committing &&
+ git show HEAD | grep -q git-svn-id
+ )
+'
+
+# An utility function used in the following test
+delete_first_line()
+{
+ file="$1" &&
+ sed 1d < "$file" > "${file}.tmp" &&
+ rm "$file" &&
+ mv "${file}.tmp" "$file"
+}
+
+test_expect_success 'dcommit concurrent non-conflicting change' '
+ setup_hook post-commit 2 &&
+ next_N && git svn clone "$svnrepo" work$N.git &&
+ (
+ cd work$N.git &&
+ cat file >> auto_updated_file &&
+ git commit -am "commit change $N.1" &&
+ delete_first_line auto_updated_file &&
+ git commit -am "commit change $N.2" &&
+ delete_first_line auto_updated_file &&
+ git commit -am "commit change $N.3" &&
+ # should rebase and leave the repository in reasonable state
+ git svn dcommit &&
+ git update-index --refresh &&
+ check_contents &&
+ git show HEAD~3 | grep -q git-svn-id &&
+ git show HEAD~2 | grep -q git-svn-id &&
+ git show HEAD~1 | grep -q auto-committing &&
+ git show HEAD | grep -q git-svn-id
+ )
+'
+
+test_expect_success 'dcommit --no-rebase concurrent non-conflicting change' '
+ setup_hook post-commit 2 &&
+ next_N && git svn clone "$svnrepo" work$N.git &&
+ (
+ cd work$N.git &&
+ cat file >> auto_updated_file &&
+ git commit -am "commit change $N.1" &&
+ delete_first_line auto_updated_file &&
+ git commit -am "commit change $N.2" &&
+ delete_first_line auto_updated_file &&
+ git commit -am "commit change $N.3" &&
+ # should fail as rebase is needed
+ test_must_fail git svn dcommit --no-rebase &&
+ # but should leave HEAD unchanged
+ git update-index --refresh &&
+ ! git show HEAD~2 | grep -q git-svn-id &&
+ ! git show HEAD~1 | grep -q git-svn-id &&
+ ! git show HEAD | grep -q git-svn-id
+ )
+'
+
+test_expect_success 'dcommit fails on concurrent conflicting change' '
+ setup_hook post-commit 1 &&
+ next_N && git svn clone "$svnrepo" work$N.git &&
+ (
+ cd work$N.git &&
+ echo a >> file &&
+ git commit -am "commit change $N.1" &&
+ echo b >> auto_updated_file &&
+ git commit -am "commit change $N.2" &&
+ echo c >> auto_updated_file &&
+ git commit -am "commit change $N.3" &&
+ test_must_fail git svn dcommit && # rebase should fail
+ test_must_fail git update-index --refresh
+ )
+'
+
+test_done
diff --git a/t/t9165-git-svn-fetch-merge-branch-of-branch.sh b/t/t9165-git-svn-fetch-merge-branch-of-branch.sh
new file mode 100755
index 0000000..13ae7e3
--- /dev/null
+++ b/t/t9165-git-svn-fetch-merge-branch-of-branch.sh
@@ -0,0 +1,60 @@
+#!/bin/sh
+#
+# Copyright (c) 2012 Steven Walter
+#
+
+test_description='git svn merge detection'
+. ./lib-git-svn.sh
+
+svn_ver="$(svn --version --quiet)"
+case $svn_ver in
+0.* | 1.[0-4].*)
+ skip_all="skipping git-svn test - SVN too old ($svn_ver)"
+ test_done
+ ;;
+esac
+
+test_expect_success 'initialize source svn repo' '
+ svn_cmd mkdir -m x "$svnrepo"/trunk &&
+ svn_cmd mkdir -m x "$svnrepo"/branches &&
+ svn_cmd co "$svnrepo"/trunk "$SVN_TREE" &&
+ (
+ cd "$SVN_TREE" &&
+ touch foo &&
+ svn_cmd add foo &&
+ svn_cmd commit -m "initial commit" &&
+ svn_cmd cp -m branch "$svnrepo"/trunk "$svnrepo"/branches/branch1 &&
+ svn_cmd switch "$svnrepo"/branches/branch1 &&
+ touch bar &&
+ svn_cmd add bar &&
+ svn_cmd commit -m branch1 &&
+ svn_cmd cp -m branch "$svnrepo"/branches/branch1 "$svnrepo"/branches/branch2 &&
+ svn_cmd switch "$svnrepo"/branches/branch2 &&
+ touch baz &&
+ svn_cmd add baz &&
+ svn_cmd commit -m branch2 &&
+ svn_cmd switch "$svnrepo"/trunk &&
+ touch bar2 &&
+ svn_cmd add bar2 &&
+ svn_cmd commit -m trunk &&
+ svn_cmd switch "$svnrepo"/branches/branch2 &&
+ svn_cmd merge "$svnrepo"/trunk &&
+ svn_cmd commit -m "merge trunk"
+ svn_cmd switch "$svnrepo"/trunk &&
+ svn_cmd merge --reintegrate "$svnrepo"/branches/branch2 &&
+ svn_cmd commit -m "merge branch2"
+ ) &&
+ rm -rf "$SVN_TREE"
+'
+
+test_expect_success 'clone svn repo' '
+ git svn init -s "$svnrepo" &&
+ git svn fetch
+'
+
+test_expect_success 'verify merge commit' 'x=$(git rev-parse HEAD^2) &&
+ y=$(git rev-parse branch2) &&
+ test "x$x" = "x$y"
+'
+
+test_done
diff --git a/t/t9166-git-svn-fetch-merge-branch-of-branch2.sh b/t/t9166-git-svn-fetch-merge-branch-of-branch2.sh
new file mode 100755
index 0000000..af0ec0e
--- /dev/null
+++ b/t/t9166-git-svn-fetch-merge-branch-of-branch2.sh
@@ -0,0 +1,53 @@
+#!/bin/sh
+#
+# Copyright (c) 2012 Steven Walter
+#
+
+test_description='git svn merge detection'
+. ./lib-git-svn.sh
+
+svn_ver="$(svn --version --quiet)"
+case $svn_ver in
+0.* | 1.[0-4].*)
+ skip_all="skipping git-svn test - SVN too old ($svn_ver)"
+ test_done
+ ;;
+esac
+
+test_expect_success 'initialize source svn repo' '
+ svn_cmd mkdir -m x "$svnrepo"/trunk &&
+ svn_cmd mkdir -m x "$svnrepo"/branches &&
+ svn_cmd co "$svnrepo"/trunk "$SVN_TREE" &&
+ (
+ cd "$SVN_TREE" &&
+ touch foo &&
+ svn_cmd add foo &&
+ svn_cmd commit -m "initial commit" &&
+ svn_cmd cp -m branch "$svnrepo"/trunk "$svnrepo"/branches/branch1 &&
+ svn_cmd switch "$svnrepo"/branches/branch1 &&
+ touch bar &&
+ svn_cmd add bar &&
+ svn_cmd commit -m branch1 &&
+ svn_cmd cp -m branch "$svnrepo"/branches/branch1 "$svnrepo"/branches/branch2 &&
+ svn_cmd switch "$svnrepo"/branches/branch2 &&
+ touch baz &&
+ svn_cmd add baz &&
+ svn_cmd commit -m branch2 &&
+ svn_cmd switch "$svnrepo"/trunk &&
+ svn_cmd merge --reintegrate "$svnrepo"/branches/branch2 &&
+ svn_cmd commit -m "merge branch2"
+ ) &&
+ rm -rf "$SVN_TREE"
+'
+
+test_expect_success 'clone svn repo' '
+ git svn init -s "$svnrepo" &&
+ git svn fetch
+'
+
+test_expect_success 'verify merge commit' 'x=$(git rev-parse HEAD^2) &&
+ y=$(git rev-parse branch2) &&
+ test "x$x" = "x$y"
+'
+
+test_done
diff --git a/t/t9800-git-p4-basic.sh b/t/t9800-git-p4-basic.sh
index 0f410c4..b7ad716 100755
--- a/t/t9800-git-p4-basic.sh
+++ b/t/t9800-git-p4-basic.sh
@@ -45,7 +45,8 @@ test_expect_success 'git p4 sync uninitialized repo' '
test_when_finished cleanup_git &&
(
cd "$git" &&
- test_must_fail git p4 sync
+ test_must_fail git p4 sync 2>errs &&
+ test_i18ngrep "Perhaps you never did" errs
)
'
@@ -126,150 +127,24 @@ test_expect_success 'clone two dirs, @all, conflicting files' '
'
test_expect_success 'exit when p4 fails to produce marshaled output' '
- badp4dir="$TRASH_DIRECTORY/badp4dir" &&
- mkdir "$badp4dir" &&
- test_when_finished "rm \"$badp4dir/p4\" && rmdir \"$badp4dir\"" &&
- cat >"$badp4dir"/p4 <<-EOF &&
+ mkdir badp4dir &&
+ test_when_finished "rm badp4dir/p4 && rmdir badp4dir" &&
+ cat >badp4dir/p4 <<-EOF &&
#!$SHELL_PATH
exit 1
EOF
- chmod 755 "$badp4dir"/p4 &&
- PATH="$badp4dir:$PATH" git p4 clone --dest="$git" //depot >errs 2>&1 ; retval=$? &&
- test $retval -eq 1 &&
- test_must_fail grep -q Traceback errs
-'
-
-test_expect_success 'add p4 files with wildcards in the names' '
- (
- cd "$cli" &&
- echo file-wild-hash >file-wild#hash &&
- echo file-wild-star >file-wild\*star &&
- echo file-wild-at >file-wild@at &&
- echo file-wild-percent >file-wild%percent &&
- p4 add -f file-wild* &&
- p4 submit -d "file wildcards"
- )
-'
-
-test_expect_success 'wildcard files git p4 clone' '
- git p4 clone --dest="$git" //depot &&
- test_when_finished cleanup_git &&
- (
- cd "$git" &&
- test -f file-wild#hash &&
- test -f file-wild\*star &&
- test -f file-wild@at &&
- test -f file-wild%percent
- )
-'
-
-test_expect_success 'wildcard files submit back to p4, add' '
- test_when_finished cleanup_git &&
- git p4 clone --dest="$git" //depot &&
- (
- cd "$git" &&
- echo git-wild-hash >git-wild#hash &&
- echo git-wild-star >git-wild\*star &&
- echo git-wild-at >git-wild@at &&
- echo git-wild-percent >git-wild%percent &&
- git add git-wild* &&
- git commit -m "add some wildcard filenames" &&
- git config git-p4.skipSubmitEdit true &&
- git p4 submit
- ) &&
- (
- cd "$cli" &&
- test_path_is_file git-wild#hash &&
- test_path_is_file git-wild\*star &&
- test_path_is_file git-wild@at &&
- test_path_is_file git-wild%percent
- )
-'
-
-test_expect_success 'wildcard files submit back to p4, modify' '
- test_when_finished cleanup_git &&
- git p4 clone --dest="$git" //depot &&
- (
- cd "$git" &&
- echo new-line >>git-wild#hash &&
- echo new-line >>git-wild\*star &&
- echo new-line >>git-wild@at &&
- echo new-line >>git-wild%percent &&
- git add git-wild* &&
- git commit -m "modify the wildcard files" &&
- git config git-p4.skipSubmitEdit true &&
- git p4 submit
- ) &&
- (
- cd "$cli" &&
- test_line_count = 2 git-wild#hash &&
- test_line_count = 2 git-wild\*star &&
- test_line_count = 2 git-wild@at &&
- test_line_count = 2 git-wild%percent
- )
-'
-
-test_expect_success 'wildcard files submit back to p4, copy' '
- test_when_finished cleanup_git &&
- git p4 clone --dest="$git" //depot &&
+ chmod 755 badp4dir/p4 &&
(
- cd "$git" &&
- cp file2 git-wild-cp#hash &&
- git add git-wild-cp#hash &&
- cp git-wild\*star file-wild-3 &&
- git add file-wild-3 &&
- git commit -m "wildcard copies" &&
- git config git-p4.detectCopies true &&
- git config git-p4.detectCopiesHarder true &&
- git config git-p4.skipSubmitEdit true &&
- git p4 submit
+ PATH="$TRASH_DIRECTORY/badp4dir:$PATH" &&
+ export PATH &&
+ test_expect_code 1 git p4 clone --dest="$git" //depot >errs 2>&1
) &&
- (
- cd "$cli" &&
- test_path_is_file git-wild-cp#hash &&
- test_path_is_file file-wild-3
- )
-'
-
-test_expect_success 'wildcard files submit back to p4, rename' '
- test_when_finished cleanup_git &&
- git p4 clone --dest="$git" //depot &&
- (
- cd "$git" &&
- git mv git-wild@at file-wild-4 &&
- git mv file-wild-3 git-wild-cp%percent &&
- git commit -m "wildcard renames" &&
- git config git-p4.detectRenames true &&
- git config git-p4.skipSubmitEdit true &&
- git p4 submit
- ) &&
- (
- cd "$cli" &&
- test_path_is_missing git-wild@at &&
- test_path_is_file git-wild-cp%percent
- )
-'
-
-test_expect_success 'wildcard files submit back to p4, delete' '
- test_when_finished cleanup_git &&
- git p4 clone --dest="$git" //depot &&
- (
- cd "$git" &&
- git rm git-wild* &&
- git commit -m "delete the wildcard files" &&
- git config git-p4.skipSubmitEdit true &&
- git p4 submit
- ) &&
- (
- cd "$cli" &&
- test_path_is_missing git-wild#hash &&
- test_path_is_missing git-wild\*star &&
- test_path_is_missing git-wild@at &&
- test_path_is_missing git-wild%percent
- )
+ cat errs &&
+ ! test_i18ngrep Traceback errs
'
test_expect_success 'clone bare' '
+ rm -rf "$git" &&
git p4 clone --dest="$git" --bare //depot &&
test_when_finished cleanup_git &&
(
@@ -280,138 +155,6 @@ test_expect_success 'clone bare' '
)
'
-p4_add_user() {
- name=$1 fullname=$2 &&
- p4 user -f -i <<-EOF &&
- User: $name
- Email: $name@localhost
- FullName: $fullname
- EOF
- p4 passwd -P secret $name
-}
-
-p4_grant_admin() {
- name=$1 &&
- {
- p4 protect -o &&
- echo " admin user $name * //depot/..."
- } | p4 protect -i
-}
-
-p4_check_commit_author() {
- file=$1 user=$2 &&
- p4 changes -m 1 //depot/$file | grep -q $user
-}
-
-make_change_by_user() {
- file=$1 name=$2 email=$3 &&
- echo "username: a change by $name" >>"$file" &&
- git add "$file" &&
- git commit --author "$name <$email>" -m "a change by $name"
-}
-
-# Test username support, submitting as user 'alice'
-test_expect_success 'preserve users' '
- p4_add_user alice Alice &&
- p4_add_user bob Bob &&
- p4_grant_admin alice &&
- git p4 clone --dest="$git" //depot &&
- test_when_finished cleanup_git &&
- (
- cd "$git" &&
- echo "username: a change by alice" >>file1 &&
- echo "username: a change by bob" >>file2 &&
- git commit --author "Alice <alice@localhost>" -m "a change by alice" file1 &&
- git commit --author "Bob <bob@localhost>" -m "a change by bob" file2 &&
- git config git-p4.skipSubmitEditCheck true &&
- P4EDITOR=touch P4USER=alice P4PASSWD=secret git p4 commit --preserve-user &&
- p4_check_commit_author file1 alice &&
- p4_check_commit_author file2 bob
- )
-'
-
-# Test username support, submitting as bob, who lacks admin rights. Should
-# not submit change to p4 (git diff should show deltas).
-test_expect_success 'refuse to preserve users without perms' '
- git p4 clone --dest="$git" //depot &&
- test_when_finished cleanup_git &&
- (
- cd "$git" &&
- git config git-p4.skipSubmitEditCheck true &&
- echo "username-noperms: a change by alice" >>file1 &&
- git commit --author "Alice <alice@localhost>" -m "perms: a change by alice" file1 &&
- P4EDITOR=touch P4USER=bob P4PASSWD=secret &&
- export P4EDITOR P4USER P4PASSWD &&
- test_must_fail git p4 commit --preserve-user &&
- ! git diff --exit-code HEAD..p4/master
- )
-'
-
-# What happens with unknown author? Without allowMissingP4Users it should fail.
-test_expect_success 'preserve user where author is unknown to p4' '
- git p4 clone --dest="$git" //depot &&
- test_when_finished cleanup_git &&
- (
- cd "$git" &&
- git config git-p4.skipSubmitEditCheck true &&
- echo "username-bob: a change by bob" >>file1 &&
- git commit --author "Bob <bob@localhost>" -m "preserve: a change by bob" file1 &&
- echo "username-unknown: a change by charlie" >>file1 &&
- git commit --author "Charlie <charlie@localhost>" -m "preserve: a change by charlie" file1 &&
- P4EDITOR=touch P4USER=alice P4PASSWD=secret &&
- export P4EDITOR P4USER P4PASSWD &&
- test_must_fail git p4 commit --preserve-user &&
- ! git diff --exit-code HEAD..p4/master &&
-
- echo "$0: repeat with allowMissingP4Users enabled" &&
- git config git-p4.allowMissingP4Users true &&
- git config git-p4.preserveUser true &&
- git p4 commit &&
- git diff --exit-code HEAD..p4/master &&
- p4_check_commit_author file1 alice
- )
-'
-
-# If we're *not* using --preserve-user, git p4 should warn if we're submitting
-# changes that are not all ours.
-# Test: user in p4 and user unknown to p4.
-# Test: warning disabled and user is the same.
-test_expect_success 'not preserving user with mixed authorship' '
- git p4 clone --dest="$git" //depot &&
- test_when_finished cleanup_git &&
- (
- cd "$git" &&
- git config git-p4.skipSubmitEditCheck true &&
- p4_add_user derek Derek &&
-
- make_change_by_user usernamefile3 Derek derek@localhost &&
- P4EDITOR=cat P4USER=alice P4PASSWD=secret &&
- export P4EDITOR P4USER P4PASSWD &&
- git p4 commit |\
- grep "git author derek@localhost does not match" &&
-
- make_change_by_user usernamefile3 Charlie charlie@localhost &&
- git p4 commit |\
- grep "git author charlie@localhost does not match" &&
-
- make_change_by_user usernamefile3 alice alice@localhost &&
- git p4 commit |\
- test_must_fail grep "git author.*does not match" &&
-
- git config git-p4.skipUserNameCheck true &&
- make_change_by_user usernamefile3 Charlie charlie@localhost &&
- git p4 commit |\
- test_must_fail grep "git author.*does not match" &&
-
- p4_check_commit_author usernamefile3 alice
- )
-'
-
-marshal_dump() {
- what=$1
- "$PYTHON_PATH" -c 'import marshal, sys; d = marshal.load(sys.stdin); print d["'$what'"]'
-}
-
# Sleep a bit so that the top-most p4 change did not happen "now". Then
# import the repo and make sure that the initial import has the same time
# as the top-most change.
@@ -429,146 +172,6 @@ test_expect_success 'initial import time from top change time' '
)
'
-# Rename a file and confirm that rename is not detected in P4.
-# Rename the new file again with detectRenames option enabled and confirm that
-# this is detected in P4.
-# Rename the new file again adding an extra line, configure a big threshold in
-# detectRenames and confirm that rename is not detected in P4.
-# Repeat, this time with a smaller threshold and confirm that the rename is
-# detected in P4.
-test_expect_success 'detect renames' '
- git p4 clone --dest="$git" //depot@all &&
- test_when_finished cleanup_git &&
- (
- cd "$git" &&
- git config git-p4.skipSubmitEdit true &&
-
- git mv file1 file4 &&
- git commit -a -m "Rename file1 to file4" &&
- git diff-tree -r -M HEAD &&
- git p4 submit &&
- p4 filelog //depot/file4 &&
- p4 filelog //depot/file4 | test_must_fail grep -q "branch from" &&
-
- git mv file4 file5 &&
- git commit -a -m "Rename file4 to file5" &&
- git diff-tree -r -M HEAD &&
- git config git-p4.detectRenames true &&
- git p4 submit &&
- p4 filelog //depot/file5 &&
- p4 filelog //depot/file5 | grep -q "branch from //depot/file4" &&
-
- git mv file5 file6 &&
- echo update >>file6 &&
- git add file6 &&
- git commit -a -m "Rename file5 to file6 with changes" &&
- git diff-tree -r -M HEAD &&
- level=$(git diff-tree -r -M HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/R0*//") &&
- test -n "$level" && test "$level" -gt 0 && test "$level" -lt 98 &&
- git config git-p4.detectRenames $(($level + 2)) &&
- git p4 submit &&
- p4 filelog //depot/file6 &&
- p4 filelog //depot/file6 | test_must_fail grep -q "branch from" &&
-
- git mv file6 file7 &&
- echo update >>file7 &&
- git add file7 &&
- git commit -a -m "Rename file6 to file7 with changes" &&
- git diff-tree -r -M HEAD &&
- level=$(git diff-tree -r -M HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/R0*//") &&
- test -n "$level" && test "$level" -gt 2 && test "$level" -lt 100 &&
- git config git-p4.detectRenames $(($level - 2)) &&
- git p4 submit &&
- p4 filelog //depot/file7 &&
- p4 filelog //depot/file7 | grep -q "branch from //depot/file6"
- )
-'
-
-# Copy a file and confirm that copy is not detected in P4.
-# Copy a file with detectCopies option enabled and confirm that copy is not
-# detected in P4.
-# Modify and copy a file with detectCopies option enabled and confirm that copy
-# is detected in P4.
-# Copy a file with detectCopies and detectCopiesHarder options enabled and
-# confirm that copy is detected in P4.
-# Modify and copy a file, configure a bigger threshold in detectCopies and
-# confirm that copy is not detected in P4.
-# Modify and copy a file, configure a smaller threshold in detectCopies and
-# confirm that copy is detected in P4.
-test_expect_success 'detect copies' '
- git p4 clone --dest="$git" //depot@all &&
- test_when_finished cleanup_git &&
- (
- cd "$git" &&
- git config git-p4.skipSubmitEdit true &&
-
- cp file2 file8 &&
- git add file8 &&
- git commit -a -m "Copy file2 to file8" &&
- git diff-tree -r -C HEAD &&
- git p4 submit &&
- p4 filelog //depot/file8 &&
- p4 filelog //depot/file8 | test_must_fail grep -q "branch from" &&
-
- cp file2 file9 &&
- git add file9 &&
- git commit -a -m "Copy file2 to file9" &&
- git diff-tree -r -C HEAD &&
- git config git-p4.detectCopies true &&
- git p4 submit &&
- p4 filelog //depot/file9 &&
- p4 filelog //depot/file9 | test_must_fail grep -q "branch from" &&
-
- echo "file2" >>file2 &&
- cp file2 file10 &&
- git add file2 file10 &&
- git commit -a -m "Modify and copy file2 to file10" &&
- git diff-tree -r -C HEAD &&
- git p4 submit &&
- p4 filelog //depot/file10 &&
- p4 filelog //depot/file10 | grep -q "branch from //depot/file" &&
-
- cp file2 file11 &&
- git add file11 &&
- git commit -a -m "Copy file2 to file11" &&
- git diff-tree -r -C --find-copies-harder HEAD &&
- src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) &&
- test "$src" = file10 &&
- git config git-p4.detectCopiesHarder true &&
- git p4 submit &&
- p4 filelog //depot/file11 &&
- p4 filelog //depot/file11 | grep -q "branch from //depot/file" &&
-
- cp file2 file12 &&
- echo "some text" >>file12 &&
- git add file12 &&
- git commit -a -m "Copy file2 to file12 with changes" &&
- git diff-tree -r -C --find-copies-harder HEAD &&
- level=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/C0*//") &&
- test -n "$level" && test "$level" -gt 0 && test "$level" -lt 98 &&
- src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) &&
- test "$src" = file10 &&
- git config git-p4.detectCopies $(($level + 2)) &&
- git p4 submit &&
- p4 filelog //depot/file12 &&
- p4 filelog //depot/file12 | test_must_fail grep -q "branch from" &&
-
- cp file2 file13 &&
- echo "different text" >>file13 &&
- git add file13 &&
- git commit -a -m "Copy file2 to file13 with changes" &&
- git diff-tree -r -C --find-copies-harder HEAD &&
- level=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/C0*//") &&
- test -n "$level" && test "$level" -gt 2 && test "$level" -lt 100 &&
- src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) &&
- test "$src" = file10 &&
- git config git-p4.detectCopies $(($level - 2)) &&
- git p4 submit &&
- p4 filelog //depot/file13 &&
- p4 filelog //depot/file13 | grep -q "branch from //depot/file"
- )
-'
-
test_expect_success 'kill p4d' '
kill_p4d
'
diff --git a/t/t9801-git-p4-branch.sh b/t/t9801-git-p4-branch.sh
index 99fe16b..9730821 100755
--- a/t/t9801-git-p4-branch.sh
+++ b/t/t9801-git-p4-branch.sh
@@ -410,6 +410,83 @@ test_expect_failure 'git p4 clone file subset branch' '
test_path_is_missing file3
)
'
+
+# From a report in http://stackoverflow.com/questions/11893688
+# where --use-client-spec caused branch prefixes not to be removed;
+# every file in git appeared into a subdirectory of the branch name.
+test_expect_success 'use-client-spec detect-branches setup' '
+ rm -rf "$cli" &&
+ mkdir "$cli" &&
+ (
+ cd "$cli" &&
+ client_view "//depot/usecs/... //client/..." &&
+ mkdir b1 &&
+ echo b1/b1-file1 >b1/b1-file1 &&
+ p4 add b1/b1-file1 &&
+ p4 submit -d "b1/b1-file1" &&
+
+ p4 integrate //depot/usecs/b1/... //depot/usecs/b2/... &&
+ p4 submit -d "b1 -> b2" &&
+ p4 branch -i <<-EOF &&
+ Branch: b2
+ View: //depot/usecs/b1/... //depot/usecs/b2/...
+ EOF
+
+ echo b2/b2-file2 >b2/b2-file2 &&
+ p4 add b2/b2-file2 &&
+ p4 submit -d "b2/b2-file2"
+ )
+'
+
+test_expect_success 'use-client-spec detect-branches files in top-level' '
+ test_when_finished cleanup_git &&
+ test_create_repo "$git" &&
+ (
+ cd "$git" &&
+ git p4 sync --detect-branches --use-client-spec //depot/usecs@all &&
+ git checkout -b master p4/usecs/b1 &&
+ test_path_is_file b1-file1 &&
+ test_path_is_missing b2-file2 &&
+ test_path_is_missing b1 &&
+ test_path_is_missing b2 &&
+
+ git checkout -b b2 p4/usecs/b2 &&
+ test_path_is_file b1-file1 &&
+ test_path_is_file b2-file2 &&
+ test_path_is_missing b1 &&
+ test_path_is_missing b2
+ )
+'
+
+test_expect_success 'use-client-spec detect-branches skips branches setup' '
+ (
+ cd "$cli" &&
+
+ p4 integrate //depot/usecs/b1/... //depot/usecs/b3/... &&
+ p4 submit -d "b1 -> b3" &&
+ p4 branch -i <<-EOF &&
+ Branch: b3
+ View: //depot/usecs/b1/... //depot/usecs/b3/...
+ EOF
+
+ echo b3/b3-file3 >b3/b3-file3 &&
+ p4 add b3/b3-file3 &&
+ p4 submit -d "b3/b3-file3"
+ )
+'
+
+test_expect_success 'use-client-spec detect-branches skips branches' '
+ client_view "//depot/usecs/... //client/..." \
+ "-//depot/usecs/b3/... //client/b3/..." &&
+ test_when_finished cleanup_git &&
+ test_create_repo "$git" &&
+ (
+ cd "$git" &&
+ git p4 sync --detect-branches --use-client-spec //depot/usecs@all &&
+ test_must_fail git rev-parse refs/remotes/p4/usecs/b3
+ )
+'
+
test_expect_success 'kill p4d' '
kill_p4d
'
diff --git a/t/t9805-git-p4-skip-submit-edit.sh b/t/t9805-git-p4-skip-submit-edit.sh
index 353dcfb..ff2cc79 100755
--- a/t/t9805-git-p4-skip-submit-edit.sh
+++ b/t/t9805-git-p4-skip-submit-edit.sh
@@ -38,7 +38,7 @@ test_expect_success 'no config, unedited, say no' '
cd "$git" &&
echo line >>file1 &&
git commit -a -m "change 3 (not really)" &&
- printf "bad response\nn\n" | git p4 submit &&
+ printf "bad response\nn\n" | test_expect_code 1 git p4 submit &&
p4 changes //depot/... >wc &&
test_line_count = 2 wc
)
@@ -78,20 +78,19 @@ test_expect_success 'skipSubmitEditCheck' '
test_expect_success 'no config, edited' '
git p4 clone --dest="$git" //depot &&
test_when_finished cleanup_git &&
- ed="$TRASH_DIRECTORY/ed.sh" &&
- test_when_finished "rm \"$ed\"" &&
- cat >"$ed" <<-EOF &&
+ test_when_finished "rm ed.sh" &&
+ cat >ed.sh <<-EOF &&
#!$SHELL_PATH
sleep 1
touch "\$1"
exit 0
EOF
- chmod 755 "$ed" &&
+ chmod 755 ed.sh &&
(
cd "$git" &&
echo line >>file1 &&
git commit -a -m "change 5" &&
- P4EDITOR="" EDITOR="\"$ed\"" git p4 submit &&
+ P4EDITOR="" EDITOR="\"$TRASH_DIRECTORY/ed.sh\"" git p4 submit &&
p4 changes //depot/... >wc &&
test_line_count = 5 wc
)
diff --git a/t/t9806-git-p4-options.sh b/t/t9806-git-p4-options.sh
index 2892367..fa40cc8 100755
--- a/t/t9806-git-p4-options.sh
+++ b/t/t9806-git-p4-options.sh
@@ -39,10 +39,9 @@ test_expect_success 'clone --branch' '
'
test_expect_success 'clone --changesfile' '
- cf="$TRASH_DIRECTORY/cf" &&
- test_when_finished "rm \"$cf\"" &&
- printf "1\n3\n" >"$cf" &&
- git p4 clone --changesfile="$cf" --dest="$git" //depot &&
+ test_when_finished "rm cf" &&
+ printf "1\n3\n" >cf &&
+ git p4 clone --changesfile="$TRASH_DIRECTORY/cf" --dest="$git" //depot &&
test_when_finished cleanup_git &&
(
cd "$git" &&
@@ -55,10 +54,9 @@ test_expect_success 'clone --changesfile' '
'
test_expect_success 'clone --changesfile, @all' '
- cf="$TRASH_DIRECTORY/cf" &&
- test_when_finished "rm \"$cf\"" &&
- printf "1\n3\n" >"$cf" &&
- test_must_fail git p4 clone --changesfile="$cf" --dest="$git" //depot@all
+ test_when_finished "rm cf" &&
+ printf "1\n3\n" >cf &&
+ test_must_fail git p4 clone --changesfile="$TRASH_DIRECTORY/cf" --dest="$git" //depot@all
'
# imports both master and p4/master in refs/heads
@@ -128,7 +126,7 @@ test_expect_success 'clone --use-client-spec' '
exec >/dev/null &&
test_must_fail git p4 clone --dest="$git" --use-client-spec
) &&
- cli2="$TRASH_DIRECTORY/cli2" &&
+ cli2=$(test-path-utils real_path "$TRASH_DIRECTORY/cli2") &&
mkdir -p "$cli2" &&
test_when_finished "rmdir \"$cli2\"" &&
(
@@ -151,7 +149,6 @@ test_expect_success 'clone --use-client-spec' '
cleanup_git &&
# same thing again, this time with variable instead of option
- mkdir "$git" &&
(
cd "$git" &&
git init &&
diff --git a/t/t9807-git-p4-submit.sh b/t/t9807-git-p4-submit.sh
index f23b4c3..0ae048f 100755
--- a/t/t9807-git-p4-submit.sh
+++ b/t/t9807-git-p4-submit.sh
@@ -54,6 +54,47 @@ test_expect_success 'submit --origin' '
)
'
+test_expect_success 'submit --dry-run' '
+ test_when_finished cleanup_git &&
+ git p4 clone --dest="$git" //depot &&
+ (
+ cd "$git" &&
+ test_commit "dry-run1" &&
+ test_commit "dry-run2" &&
+ git p4 submit --dry-run >out &&
+ test_i18ngrep "Would apply" out
+ ) &&
+ (
+ cd "$cli" &&
+ test_path_is_missing "dry-run1.t" &&
+ test_path_is_missing "dry-run2.t"
+ )
+'
+
+test_expect_success 'submit --dry-run --export-labels' '
+ test_when_finished cleanup_git &&
+ git p4 clone --dest="$git" //depot &&
+ (
+ cd "$git" &&
+ echo dry-run1 >dry-run1 &&
+ git add dry-run1 &&
+ git commit -m "dry-run1" dry-run1 &&
+ git config git-p4.skipSubmitEdit true &&
+ git p4 submit &&
+ echo dry-run2 >dry-run2 &&
+ git add dry-run2 &&
+ git commit -m "dry-run2" dry-run2 &&
+ git tag -m "dry-run-tag1" dry-run-tag1 HEAD^ &&
+ git p4 submit --dry-run --export-labels >out &&
+ test_i18ngrep "Would create p4 label" out
+ ) &&
+ (
+ cd "$cli" &&
+ test_path_is_file "dry-run1" &&
+ test_path_is_missing "dry-run2"
+ )
+'
+
test_expect_success 'submit with allowSubmit' '
test_when_finished cleanup_git &&
git p4 clone --dest="$git" //depot &&
@@ -182,6 +223,185 @@ test_expect_success 'submit rename' '
)
'
+#
+# Converting git commit message to p4 change description, including
+# parsing out the optional Jobs: line.
+#
+test_expect_success 'simple one-line description' '
+ test_when_finished cleanup_git &&
+ git p4 clone --dest="$git" //depot &&
+ (
+ cd "$git" &&
+ echo desc2 >desc2 &&
+ git add desc2 &&
+ cat >msg <<-EOF &&
+ One-line description line for desc2.
+ EOF
+ git commit -F - <msg &&
+ git config git-p4.skipSubmitEdit true &&
+ git p4 submit &&
+ change=$(p4 -G changes -m 1 //depot/... | \
+ marshal_dump change) &&
+ # marshal_dump always adds a newline
+ p4 -G describe $change | marshal_dump desc | sed \$d >pmsg &&
+ test_cmp msg pmsg
+ )
+'
+
+test_expect_success 'description with odd formatting' '
+ test_when_finished cleanup_git &&
+ git p4 clone --dest="$git" //depot &&
+ (
+ cd "$git" &&
+ echo desc3 >desc3 &&
+ git add desc3 &&
+ (
+ printf "subject line\n\n\tExtra tab\nline.\n\n" &&
+ printf "Description:\n\tBogus description marker\n\n" &&
+ # git commit eats trailing newlines; only use one
+ printf "Files:\n\tBogus descs marker\n"
+ ) >msg &&
+ git commit -F - <msg &&
+ git config git-p4.skipSubmitEdit true &&
+ git p4 submit &&
+ change=$(p4 -G changes -m 1 //depot/... | \
+ marshal_dump change) &&
+ # marshal_dump always adds a newline
+ p4 -G describe $change | marshal_dump desc | sed \$d >pmsg &&
+ test_cmp msg pmsg
+ )
+'
+
+make_job() {
+ name="$1" &&
+ tab="$(printf \\t)" &&
+ p4 job -o | \
+ sed -e "/^Job:/s/.*/Job: $name/" \
+ -e "/^Description/{ n; s/.*/$tab job text/; }" | \
+ p4 job -i
+}
+
+test_expect_success 'description with Jobs section at end' '
+ test_when_finished cleanup_git &&
+ git p4 clone --dest="$git" //depot &&
+ (
+ cd "$git" &&
+ echo desc4 >desc4 &&
+ git add desc4 &&
+ echo 6060842 >jobname &&
+ (
+ printf "subject line\n\n\tExtra tab\nline.\n\n" &&
+ printf "Files:\n\tBogus files marker\n" &&
+ printf "Junk: 3164175\n" &&
+ printf "Jobs: $(cat jobname)\n"
+ ) >msg &&
+ git commit -F - <msg &&
+ git config git-p4.skipSubmitEdit true &&
+ # build a job
+ make_job $(cat jobname) &&
+ git p4 submit &&
+ change=$(p4 -G changes -m 1 //depot/... | \
+ marshal_dump change) &&
+ # marshal_dump always adds a newline
+ p4 -G describe $change | marshal_dump desc | sed \$d >pmsg &&
+ # make sure Jobs line and all following is gone
+ sed "/^Jobs:/,\$d" msg >jmsg &&
+ test_cmp jmsg pmsg &&
+ # make sure p4 knows about job
+ p4 -G describe $change | marshal_dump job0 >job0 &&
+ test_cmp jobname job0
+ )
+'
+
+test_expect_success 'description with Jobs and values on separate lines' '
+ test_when_finished cleanup_git &&
+ git p4 clone --dest="$git" //depot &&
+ (
+ cd "$git" &&
+ echo desc5 >desc5 &&
+ git add desc5 &&
+ echo PROJ-6060842 >jobname1 &&
+ echo PROJ-6060847 >jobname2 &&
+ (
+ printf "subject line\n\n\tExtra tab\nline.\n\n" &&
+ printf "Files:\n\tBogus files marker\n" &&
+ printf "Junk: 3164175\n" &&
+ printf "Jobs:\n" &&
+ printf "\t$(cat jobname1)\n" &&
+ printf "\t$(cat jobname2)\n"
+ ) >msg &&
+ git commit -F - <msg &&
+ git config git-p4.skipSubmitEdit true &&
+ # build two jobs
+ make_job $(cat jobname1) &&
+ make_job $(cat jobname2) &&
+ git p4 submit &&
+ change=$(p4 -G changes -m 1 //depot/... | \
+ marshal_dump change) &&
+ # marshal_dump always adds a newline
+ p4 -G describe $change | marshal_dump desc | sed \$d >pmsg &&
+ # make sure Jobs line and all following is gone
+ sed "/^Jobs:/,\$d" msg >jmsg &&
+ test_cmp jmsg pmsg &&
+ # make sure p4 knows about the two jobs
+ p4 -G describe $change >change &&
+ (
+ marshal_dump job0 <change &&
+ marshal_dump job1 <change
+ ) | sort >jobs &&
+ cat jobname1 jobname2 | sort >expected &&
+ test_cmp expected jobs
+ )
+'
+
+test_expect_success 'description with Jobs section and bogus following text' '
+ test_when_finished cleanup_git &&
+ git p4 clone --dest="$git" //depot &&
+ (
+ cd "$git" &&
+ echo desc6 >desc6 &&
+ git add desc6 &&
+ echo 6060843 >jobname &&
+ (
+ printf "subject line\n\n\tExtra tab\nline.\n\n" &&
+ printf "Files:\n\tBogus files marker\n" &&
+ printf "Junk: 3164175\n" &&
+ printf "Jobs: $(cat jobname)\n" &&
+ printf "MoreJunk: 3711\n"
+ ) >msg &&
+ git commit -F - <msg &&
+ git config git-p4.skipSubmitEdit true &&
+ # build a job
+ make_job $(cat jobname) &&
+ test_must_fail git p4 submit 2>err &&
+ test_i18ngrep "Unknown field name" err
+ ) &&
+ (
+ cd "$cli" &&
+ p4 revert desc6 &&
+ rm desc6
+ )
+'
+
+test_expect_success 'submit --prepare-p4-only' '
+ test_when_finished cleanup_git &&
+ git p4 clone --dest="$git" //depot &&
+ (
+ cd "$git" &&
+ echo prep-only-add >prep-only-add &&
+ git add prep-only-add &&
+ git commit -m "prep only add" &&
+ git p4 submit --prepare-p4-only >out &&
+ test_i18ngrep "prepared for submission" out &&
+ test_i18ngrep "must be deleted" out
+ ) &&
+ (
+ cd "$cli" &&
+ test_path_is_file prep-only-add &&
+ p4 fstat -T action prep-only-add | grep -w add
+ )
+'
+
test_expect_success 'kill p4d' '
kill_p4d
'
diff --git a/t/t9808-git-p4-chdir.sh b/t/t9808-git-p4-chdir.sh
index 2f8014a..dc92e60 100755
--- a/t/t9808-git-p4-chdir.sh
+++ b/t/t9808-git-p4-chdir.sh
@@ -21,7 +21,7 @@ test_expect_success 'init depot' '
# environment variable is set
test_expect_success 'P4CONFIG and absolute dir clone' '
printf "P4PORT=$P4PORT\nP4CLIENT=$P4CLIENT\n" >p4config &&
- test_when_finished "rm \"$TRASH_DIRECTORY/p4config\"" &&
+ test_when_finished "rm p4config" &&
test_when_finished cleanup_git &&
(
P4CONFIG=p4config && export P4CONFIG &&
@@ -33,7 +33,7 @@ test_expect_success 'P4CONFIG and absolute dir clone' '
# same thing, but with relative directory name, note missing $ on --dest
test_expect_success 'P4CONFIG and relative dir clone' '
printf "P4PORT=$P4PORT\nP4CLIENT=$P4CLIENT\n" >p4config &&
- test_when_finished "rm \"$TRASH_DIRECTORY/p4config\"" &&
+ test_when_finished "rm p4config" &&
test_when_finished cleanup_git &&
(
P4CONFIG=p4config && export P4CONFIG &&
diff --git a/t/t9809-git-p4-client-view.sh b/t/t9809-git-p4-client-view.sh
index 7d993ef..281be29 100755
--- a/t/t9809-git-p4-client-view.sh
+++ b/t/t9809-git-p4-client-view.sh
@@ -9,23 +9,6 @@ test_expect_success 'start p4d' '
'
#
-# Construct a client with this list of View lines
-#
-client_view() {
- (
- cat <<-EOF &&
- Client: client
- Description: client
- Root: $cli
- View:
- EOF
- for arg ; do
- printf "\t$arg\n"
- done
- ) | p4 client -i
-}
-
-#
# Verify these files exist, exactly. Caller creates
# a list of files in file "files".
#
diff --git a/t/t9810-git-p4-rcs.sh b/t/t9810-git-p4-rcs.sh
index b00ad09..fe30ad8 100755
--- a/t/t9810-git-p4-rcs.sh
+++ b/t/t9810-git-p4-rcs.sh
@@ -1,6 +1,6 @@
#!/bin/sh
-test_description='git-p4 rcs keywords'
+test_description='git p4 rcs keywords'
. ./lib-git-p4.sh
@@ -147,7 +147,7 @@ test_expect_success 'scrub ko files differently' '
)
'
-# hack; git-p4 submit should do it on its own
+# hack; git p4 submit should do it on its own
test_expect_success 'cleanup after failure' '
(
cd "$cli" &&
@@ -160,9 +160,6 @@ test_expect_success 'cleanup after failure' '
# the cli file so that submit will get a conflict. Make sure that
# scrubbing doesn't make a mess of things.
#
-# Assumes that git-p4 exits leaving the p4 file open, with the
-# conflict-generating patch unapplied.
-#
# This might happen only if the git repo is behind the p4 repo at
# submit time, and there is a conflict.
#
@@ -181,19 +178,16 @@ test_expect_success 'do not scrub plain text' '
sed -i "s/^line5/line5 p4 edit/" file_text &&
p4 submit -d "file5 p4 edit"
) &&
- ! git p4 submit &&
+ echo s | test_expect_code 1 git p4 submit &&
(
- # exepct something like:
- # file_text - file(s) not opened on this client
- # but not copious diff output
+ # make sure the file is not left open
cd "$cli" &&
- p4 diff file_text >wc &&
- test_line_count = 1 wc
+ ! p4 fstat -T action file_text
)
)
'
-# hack; git-p4 submit should do it on its own
+# hack; git p4 submit should do it on its own
test_expect_success 'cleanup after failure 2' '
(
cd "$cli" &&
@@ -244,7 +238,7 @@ test_expect_success 'cope with rcs keyword expansion damage' '
cd "$git" &&
git config git-p4.skipSubmitEdit true &&
git config git-p4.attemptRCSCleanup true &&
- (cd ../cli && p4_append_to_file kwfile1.c) &&
+ (cd "$cli" && p4_append_to_file kwfile1.c) &&
old_lines=$(wc -l <kwfile1.c) &&
"$PERL_PATH" -n -i -e "print unless m/Revision:/" kwfile1.c &&
new_lines=$(wc -l <kwfile1.c) &&
@@ -343,44 +337,6 @@ test_expect_failure 'Add keywords in git which do not match the default p4 value
)
'
-# Check that the existing merge conflict handling still works.
-# Modify kwfile1.c in git, and delete in p4. We should be able
-# to skip the git commit.
-#
-test_expect_success 'merge conflict handling still works' '
- test_when_finished cleanup_git &&
- (
- cd "$cli" &&
- echo "Hello:\$Id\$" >merge2.c &&
- echo "World" >>merge2.c &&
- p4 add -t ktext merge2.c &&
- p4 submit -d "add merge test file"
- ) &&
- git p4 clone --dest="$git" //depot &&
- (
- cd "$git" &&
- sed -e "/Hello/d" merge2.c >merge2.c.tmp &&
- mv merge2.c.tmp merge2.c &&
- git add merge2.c &&
- git commit -m "Modifying merge2.c"
- ) &&
- (
- cd "$cli" &&
- p4 delete merge2.c &&
- p4 submit -d "remove merge test file"
- ) &&
- (
- cd "$git" &&
- test -f merge2.c &&
- git config git-p4.skipSubmitEdit true &&
- git config git-p4.attemptRCSCleanup true &&
- !(echo "s" | git p4 submit) &&
- git rebase --skip &&
- ! test -f merge2.c
- )
-'
-
-
test_expect_success 'kill p4d' '
kill_p4d
'
diff --git a/t/t9812-git-p4-wildcards.sh b/t/t9812-git-p4-wildcards.sh
new file mode 100755
index 0000000..143d413
--- /dev/null
+++ b/t/t9812-git-p4-wildcards.sh
@@ -0,0 +1,147 @@
+#!/bin/sh
+
+test_description='git p4 wildcards'
+
+. ./lib-git-p4.sh
+
+test_expect_success 'start p4d' '
+ start_p4d
+'
+
+test_expect_success 'add p4 files with wildcards in the names' '
+ (
+ cd "$cli" &&
+ printf "file2\nhas\nsome\nrandom\ntext\n" >file2 &&
+ p4 add file2 &&
+ echo file-wild-hash >file-wild#hash &&
+ echo file-wild-star >file-wild\*star &&
+ echo file-wild-at >file-wild@at &&
+ echo file-wild-percent >file-wild%percent &&
+ p4 add -f file-wild* &&
+ p4 submit -d "file wildcards"
+ )
+'
+
+test_expect_success 'wildcard files git p4 clone' '
+ git p4 clone --dest="$git" //depot &&
+ test_when_finished cleanup_git &&
+ (
+ cd "$git" &&
+ test -f file-wild#hash &&
+ test -f file-wild\*star &&
+ test -f file-wild@at &&
+ test -f file-wild%percent
+ )
+'
+
+test_expect_success 'wildcard files submit back to p4, add' '
+ test_when_finished cleanup_git &&
+ git p4 clone --dest="$git" //depot &&
+ (
+ cd "$git" &&
+ echo git-wild-hash >git-wild#hash &&
+ echo git-wild-star >git-wild\*star &&
+ echo git-wild-at >git-wild@at &&
+ echo git-wild-percent >git-wild%percent &&
+ git add git-wild* &&
+ git commit -m "add some wildcard filenames" &&
+ git config git-p4.skipSubmitEdit true &&
+ git p4 submit
+ ) &&
+ (
+ cd "$cli" &&
+ test_path_is_file git-wild#hash &&
+ test_path_is_file git-wild\*star &&
+ test_path_is_file git-wild@at &&
+ test_path_is_file git-wild%percent
+ )
+'
+
+test_expect_success 'wildcard files submit back to p4, modify' '
+ test_when_finished cleanup_git &&
+ git p4 clone --dest="$git" //depot &&
+ (
+ cd "$git" &&
+ echo new-line >>git-wild#hash &&
+ echo new-line >>git-wild\*star &&
+ echo new-line >>git-wild@at &&
+ echo new-line >>git-wild%percent &&
+ git add git-wild* &&
+ git commit -m "modify the wildcard files" &&
+ git config git-p4.skipSubmitEdit true &&
+ git p4 submit
+ ) &&
+ (
+ cd "$cli" &&
+ test_line_count = 2 git-wild#hash &&
+ test_line_count = 2 git-wild\*star &&
+ test_line_count = 2 git-wild@at &&
+ test_line_count = 2 git-wild%percent
+ )
+'
+
+test_expect_success 'wildcard files submit back to p4, copy' '
+ test_when_finished cleanup_git &&
+ git p4 clone --dest="$git" //depot &&
+ (
+ cd "$git" &&
+ cp file2 git-wild-cp#hash &&
+ git add git-wild-cp#hash &&
+ cp git-wild\*star file-wild-3 &&
+ git add file-wild-3 &&
+ git commit -m "wildcard copies" &&
+ git config git-p4.detectCopies true &&
+ git config git-p4.detectCopiesHarder true &&
+ git config git-p4.skipSubmitEdit true &&
+ git p4 submit
+ ) &&
+ (
+ cd "$cli" &&
+ test_path_is_file git-wild-cp#hash &&
+ test_path_is_file file-wild-3
+ )
+'
+
+test_expect_success 'wildcard files submit back to p4, rename' '
+ test_when_finished cleanup_git &&
+ git p4 clone --dest="$git" //depot &&
+ (
+ cd "$git" &&
+ git mv git-wild@at file-wild-4 &&
+ git mv file-wild-3 git-wild-cp%percent &&
+ git commit -m "wildcard renames" &&
+ git config git-p4.detectRenames true &&
+ git config git-p4.skipSubmitEdit true &&
+ git p4 submit
+ ) &&
+ (
+ cd "$cli" &&
+ test_path_is_missing git-wild@at &&
+ test_path_is_file git-wild-cp%percent
+ )
+'
+
+test_expect_success 'wildcard files submit back to p4, delete' '
+ test_when_finished cleanup_git &&
+ git p4 clone --dest="$git" //depot &&
+ (
+ cd "$git" &&
+ git rm git-wild* &&
+ git commit -m "delete the wildcard files" &&
+ git config git-p4.skipSubmitEdit true &&
+ git p4 submit
+ ) &&
+ (
+ cd "$cli" &&
+ test_path_is_missing git-wild#hash &&
+ test_path_is_missing git-wild\*star &&
+ test_path_is_missing git-wild@at &&
+ test_path_is_missing git-wild%percent
+ )
+'
+
+test_expect_success 'kill p4d' '
+ kill_p4d
+'
+
+test_done
diff --git a/t/t9813-git-p4-preserve-users.sh b/t/t9813-git-p4-preserve-users.sh
new file mode 100755
index 0000000..f2e85e5
--- /dev/null
+++ b/t/t9813-git-p4-preserve-users.sh
@@ -0,0 +1,153 @@
+#!/bin/sh
+
+test_description='git p4 preserve users'
+
+. ./lib-git-p4.sh
+
+test_expect_success 'start p4d' '
+ start_p4d
+'
+
+test_expect_success 'create files' '
+ (
+ cd "$cli" &&
+ p4 client -o | sed "/LineEnd/s/:.*/:unix/" | p4 client -i &&
+ echo file1 >file1 &&
+ echo file2 >file2 &&
+ p4 add file1 file2 &&
+ p4 submit -d "add files"
+ )
+'
+
+p4_add_user() {
+ name=$1 fullname=$2 &&
+ p4 user -f -i <<-EOF &&
+ User: $name
+ Email: $name@localhost
+ FullName: $fullname
+ EOF
+ p4 passwd -P secret $name
+}
+
+p4_grant_admin() {
+ name=$1 &&
+ {
+ p4 protect -o &&
+ echo " admin user $name * //depot/..."
+ } | p4 protect -i
+}
+
+p4_check_commit_author() {
+ file=$1 user=$2 &&
+ p4 changes -m 1 //depot/$file | grep -q $user
+}
+
+make_change_by_user() {
+ file=$1 name=$2 email=$3 &&
+ echo "username: a change by $name" >>"$file" &&
+ git add "$file" &&
+ git commit --author "$name <$email>" -m "a change by $name"
+}
+
+# Test username support, submitting as user 'alice'
+test_expect_success 'preserve users' '
+ p4_add_user alice Alice &&
+ p4_add_user bob Bob &&
+ p4_grant_admin alice &&
+ git p4 clone --dest="$git" //depot &&
+ test_when_finished cleanup_git &&
+ (
+ cd "$git" &&
+ echo "username: a change by alice" >>file1 &&
+ echo "username: a change by bob" >>file2 &&
+ git commit --author "Alice <alice@localhost>" -m "a change by alice" file1 &&
+ git commit --author "Bob <bob@localhost>" -m "a change by bob" file2 &&
+ git config git-p4.skipSubmitEditCheck true &&
+ P4EDITOR=touch P4USER=alice P4PASSWD=secret git p4 commit --preserve-user &&
+ p4_check_commit_author file1 alice &&
+ p4_check_commit_author file2 bob
+ )
+'
+
+# Test username support, submitting as bob, who lacks admin rights. Should
+# not submit change to p4 (git diff should show deltas).
+test_expect_success 'refuse to preserve users without perms' '
+ git p4 clone --dest="$git" //depot &&
+ test_when_finished cleanup_git &&
+ (
+ cd "$git" &&
+ git config git-p4.skipSubmitEditCheck true &&
+ echo "username-noperms: a change by alice" >>file1 &&
+ git commit --author "Alice <alice@localhost>" -m "perms: a change by alice" file1 &&
+ P4EDITOR=touch P4USER=bob P4PASSWD=secret &&
+ export P4EDITOR P4USER P4PASSWD &&
+ test_must_fail git p4 commit --preserve-user &&
+ ! git diff --exit-code HEAD..p4/master
+ )
+'
+
+# What happens with unknown author? Without allowMissingP4Users it should fail.
+test_expect_success 'preserve user where author is unknown to p4' '
+ git p4 clone --dest="$git" //depot &&
+ test_when_finished cleanup_git &&
+ (
+ cd "$git" &&
+ git config git-p4.skipSubmitEditCheck true &&
+ echo "username-bob: a change by bob" >>file1 &&
+ git commit --author "Bob <bob@localhost>" -m "preserve: a change by bob" file1 &&
+ echo "username-unknown: a change by charlie" >>file1 &&
+ git commit --author "Charlie <charlie@localhost>" -m "preserve: a change by charlie" file1 &&
+ P4EDITOR=touch P4USER=alice P4PASSWD=secret &&
+ export P4EDITOR P4USER P4PASSWD &&
+ test_must_fail git p4 commit --preserve-user &&
+ ! git diff --exit-code HEAD..p4/master &&
+
+ echo "$0: repeat with allowMissingP4Users enabled" &&
+ git config git-p4.allowMissingP4Users true &&
+ git config git-p4.preserveUser true &&
+ git p4 commit &&
+ git diff --exit-code HEAD..p4/master &&
+ p4_check_commit_author file1 alice
+ )
+'
+
+# If we're *not* using --preserve-user, git-p4 should warn if we're submitting
+# changes that are not all ours.
+# Test: user in p4 and user unknown to p4.
+# Test: warning disabled and user is the same.
+test_expect_success 'not preserving user with mixed authorship' '
+ git p4 clone --dest="$git" //depot &&
+ test_when_finished cleanup_git &&
+ (
+ cd "$git" &&
+ git config git-p4.skipSubmitEditCheck true &&
+ p4_add_user derek Derek &&
+
+ make_change_by_user usernamefile3 Derek derek@localhost &&
+ P4EDITOR=cat P4USER=alice P4PASSWD=secret &&
+ export P4EDITOR P4USER P4PASSWD &&
+ git p4 commit |\
+ grep "git author derek@localhost does not match" &&
+
+ make_change_by_user usernamefile3 Charlie charlie@localhost &&
+ git p4 commit |\
+ grep "git author charlie@localhost does not match" &&
+
+ make_change_by_user usernamefile3 alice alice@localhost &&
+ git p4 commit |\
+ test_must_fail grep "git author.*does not match" &&
+
+ git config git-p4.skipUserNameCheck true &&
+ make_change_by_user usernamefile3 Charlie charlie@localhost &&
+ git p4 commit |\
+ test_must_fail grep "git author.*does not match" &&
+
+ p4_check_commit_author usernamefile3 alice
+ )
+'
+
+test_expect_success 'kill p4d' '
+ kill_p4d
+'
+
+test_done
diff --git a/t/t9814-git-p4-rename.sh b/t/t9814-git-p4-rename.sh
new file mode 100755
index 0000000..3bf1224
--- /dev/null
+++ b/t/t9814-git-p4-rename.sh
@@ -0,0 +1,206 @@
+#!/bin/sh
+
+test_description='git p4 rename'
+
+. ./lib-git-p4.sh
+
+test_expect_success 'start p4d' '
+ start_p4d
+'
+
+# We rely on this behavior to detect for p4 move availability.
+test_expect_success 'p4 help unknown returns 1' '
+ (
+ cd "$cli" &&
+ (
+ p4 help client >errs 2>&1
+ echo $? >retval
+ )
+ echo 0 >expected &&
+ test_cmp expected retval &&
+ rm retval &&
+ (
+ p4 help nosuchcommand >errs 2>&1
+ echo $? >retval
+ )
+ echo 1 >expected &&
+ test_cmp expected retval &&
+ rm retval
+ )
+'
+
+test_expect_success 'create files' '
+ (
+ cd "$cli" &&
+ p4 client -o | sed "/LineEnd/s/:.*/:unix/" | p4 client -i &&
+ cat >file1 <<-EOF &&
+ A large block of text
+ in file1 that will generate
+ enough context so that rename
+ and copy detection will find
+ something interesting to do.
+ EOF
+ cat >file2 <<-EOF &&
+ /*
+ * This blob looks a bit
+ * different.
+ */
+ int main(int argc, char **argv)
+ {
+ char text[200];
+
+ strcpy(text, "copy/rename this");
+ printf("text is %s\n", text);
+ return 0;
+ }
+ EOF
+ p4 add file1 file2 &&
+ p4 submit -d "add files"
+ )
+'
+
+# Rename a file and confirm that rename is not detected in P4.
+# Rename the new file again with detectRenames option enabled and confirm that
+# this is detected in P4.
+# Rename the new file again adding an extra line, configure a big threshold in
+# detectRenames and confirm that rename is not detected in P4.
+# Repeat, this time with a smaller threshold and confirm that the rename is
+# detected in P4.
+test_expect_success 'detect renames' '
+ git p4 clone --dest="$git" //depot@all &&
+ test_when_finished cleanup_git &&
+ (
+ cd "$git" &&
+ git config git-p4.skipSubmitEdit true &&
+
+ git mv file1 file4 &&
+ git commit -a -m "Rename file1 to file4" &&
+ git diff-tree -r -M HEAD &&
+ git p4 submit &&
+ p4 filelog //depot/file4 >filelog &&
+ ! grep " from //depot" filelog &&
+
+ git mv file4 file5 &&
+ git commit -a -m "Rename file4 to file5" &&
+ git diff-tree -r -M HEAD &&
+ git config git-p4.detectRenames true &&
+ git p4 submit &&
+ p4 filelog //depot/file5 >filelog &&
+ grep " from //depot/file4" filelog &&
+
+ git mv file5 file6 &&
+ echo update >>file6 &&
+ git add file6 &&
+ git commit -a -m "Rename file5 to file6 with changes" &&
+ git diff-tree -r -M HEAD &&
+ level=$(git diff-tree -r -M HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/R0*//") &&
+ test -n "$level" && test "$level" -gt 0 && test "$level" -lt 98 &&
+ git config git-p4.detectRenames $(($level + 2)) &&
+ git p4 submit &&
+ p4 filelog //depot/file6 >filelog &&
+ ! grep " from //depot" filelog &&
+
+ git mv file6 file7 &&
+ echo update >>file7 &&
+ git add file7 &&
+ git commit -a -m "Rename file6 to file7 with changes" &&
+ git diff-tree -r -M HEAD &&
+ level=$(git diff-tree -r -M HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/R0*//") &&
+ test -n "$level" && test "$level" -gt 2 && test "$level" -lt 100 &&
+ git config git-p4.detectRenames $(($level - 2)) &&
+ git p4 submit &&
+ p4 filelog //depot/file7 >filelog &&
+ grep " from //depot/file6" filelog
+ )
+'
+
+# Copy a file and confirm that copy is not detected in P4.
+# Copy a file with detectCopies option enabled and confirm that copy is not
+# detected in P4.
+# Modify and copy a file with detectCopies option enabled and confirm that copy
+# is detected in P4.
+# Copy a file with detectCopies and detectCopiesHarder options enabled and
+# confirm that copy is detected in P4.
+# Modify and copy a file, configure a bigger threshold in detectCopies and
+# confirm that copy is not detected in P4.
+# Modify and copy a file, configure a smaller threshold in detectCopies and
+# confirm that copy is detected in P4.
+test_expect_success 'detect copies' '
+ git p4 clone --dest="$git" //depot@all &&
+ test_when_finished cleanup_git &&
+ (
+ cd "$git" &&
+ git config git-p4.skipSubmitEdit true &&
+
+ cp file2 file8 &&
+ git add file8 &&
+ git commit -a -m "Copy file2 to file8" &&
+ git diff-tree -r -C HEAD &&
+ git p4 submit &&
+ p4 filelog //depot/file8 &&
+ p4 filelog //depot/file8 | test_must_fail grep -q "branch from" &&
+
+ cp file2 file9 &&
+ git add file9 &&
+ git commit -a -m "Copy file2 to file9" &&
+ git diff-tree -r -C HEAD &&
+ git config git-p4.detectCopies true &&
+ git p4 submit &&
+ p4 filelog //depot/file9 &&
+ p4 filelog //depot/file9 | test_must_fail grep -q "branch from" &&
+
+ echo "file2" >>file2 &&
+ cp file2 file10 &&
+ git add file2 file10 &&
+ git commit -a -m "Modify and copy file2 to file10" &&
+ git diff-tree -r -C HEAD &&
+ git p4 submit &&
+ p4 filelog //depot/file10 &&
+ p4 filelog //depot/file10 | grep -q "branch from //depot/file" &&
+
+ cp file2 file11 &&
+ git add file11 &&
+ git commit -a -m "Copy file2 to file11" &&
+ git diff-tree -r -C --find-copies-harder HEAD &&
+ src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) &&
+ test "$src" = file10 &&
+ git config git-p4.detectCopiesHarder true &&
+ git p4 submit &&
+ p4 filelog //depot/file11 &&
+ p4 filelog //depot/file11 | grep -q "branch from //depot/file" &&
+
+ cp file2 file12 &&
+ echo "some text" >>file12 &&
+ git add file12 &&
+ git commit -a -m "Copy file2 to file12 with changes" &&
+ git diff-tree -r -C --find-copies-harder HEAD &&
+ level=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/C0*//") &&
+ test -n "$level" && test "$level" -gt 0 && test "$level" -lt 98 &&
+ src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) &&
+ test "$src" = file10 -o "$src" = file11 &&
+ git config git-p4.detectCopies $(($level + 2)) &&
+ git p4 submit &&
+ p4 filelog //depot/file12 &&
+ p4 filelog //depot/file12 | test_must_fail grep -q "branch from" &&
+
+ cp file2 file13 &&
+ echo "different text" >>file13 &&
+ git add file13 &&
+ git commit -a -m "Copy file2 to file13 with changes" &&
+ git diff-tree -r -C --find-copies-harder HEAD &&
+ level=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/C0*//") &&
+ test -n "$level" && test "$level" -gt 2 && test "$level" -lt 100 &&
+ src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) &&
+ test "$src" = file10 -o "$src" = file11 -o "$src" = file12 &&
+ git config git-p4.detectCopies $(($level - 2)) &&
+ git p4 submit &&
+ p4 filelog //depot/file13 &&
+ p4 filelog //depot/file13 | grep -q "branch from //depot/file"
+ )
+'
+
+test_expect_success 'kill p4d' '
+ kill_p4d
+'
+
+test_done
diff --git a/t/t9815-git-p4-submit-fail.sh b/t/t9815-git-p4-submit-fail.sh
new file mode 100755
index 0000000..d2b7b3d
--- /dev/null
+++ b/t/t9815-git-p4-submit-fail.sh
@@ -0,0 +1,429 @@
+#!/bin/sh
+
+test_description='git p4 submit failure handling'
+
+. ./lib-git-p4.sh
+
+test_expect_success 'start p4d' '
+ start_p4d
+'
+
+test_expect_success 'init depot' '
+ (
+ cd "$cli" &&
+ p4 client -o | sed "/LineEnd/s/:.*/:unix/" | p4 client -i &&
+ echo line1 >file1 &&
+ p4 add file1 &&
+ p4 submit -d "line1 in file1"
+ )
+'
+
+test_expect_success 'conflict on one commit' '
+ test_when_finished cleanup_git &&
+ git p4 clone --dest="$git" //depot &&
+ (
+ cd "$cli" &&
+ p4 open file1 &&
+ echo line2 >>file1 &&
+ p4 submit -d "line2 in file1"
+ ) &&
+ (
+ # now this commit should cause a conflict
+ cd "$git" &&
+ git config git-p4.skipSubmitEdit true &&
+ echo line3 >>file1 &&
+ git add file1 &&
+ git commit -m "line3 in file1 will conflict" &&
+ test_expect_code 1 git p4 submit >out &&
+ test_i18ngrep "No commits applied" out
+ )
+'
+
+test_expect_success 'conflict on second of two commits' '
+ test_when_finished cleanup_git &&
+ git p4 clone --dest="$git" //depot &&
+ (
+ cd "$cli" &&
+ p4 open file1 &&
+ echo line3 >>file1 &&
+ p4 submit -d "line3 in file1"
+ ) &&
+ (
+ cd "$git" &&
+ git config git-p4.skipSubmitEdit true &&
+ # this commit is okay
+ test_commit "first_commit_okay" &&
+ # now this submit should cause a conflict
+ echo line4 >>file1 &&
+ git add file1 &&
+ git commit -m "line4 in file1 will conflict" &&
+ test_expect_code 1 git p4 submit >out &&
+ test_i18ngrep "Applied only the commits" out
+ )
+'
+
+test_expect_success 'conflict on first of two commits, skip' '
+ test_when_finished cleanup_git &&
+ git p4 clone --dest="$git" //depot &&
+ (
+ cd "$cli" &&
+ p4 open file1 &&
+ echo line4 >>file1 &&
+ p4 submit -d "line4 in file1"
+ ) &&
+ (
+ cd "$git" &&
+ git config git-p4.skipSubmitEdit true &&
+ # this submit should cause a conflict
+ echo line5 >>file1 &&
+ git add file1 &&
+ git commit -m "line5 in file1 will conflict" &&
+ # but this commit is okay
+ test_commit "okay_commit_after_skip" &&
+ echo s | test_expect_code 1 git p4 submit >out &&
+ test_i18ngrep "Applied only the commits" out
+ )
+'
+
+test_expect_success 'conflict on first of two commits, quit' '
+ test_when_finished cleanup_git &&
+ git p4 clone --dest="$git" //depot &&
+ (
+ cd "$cli" &&
+ p4 open file1 &&
+ echo line7 >>file1 &&
+ p4 submit -d "line7 in file1"
+ ) &&
+ (
+ cd "$git" &&
+ git config git-p4.skipSubmitEdit true &&
+ # this submit should cause a conflict
+ echo line8 >>file1 &&
+ git add file1 &&
+ git commit -m "line8 in file1 will conflict" &&
+ # but this commit is okay
+ test_commit "okay_commit_after_quit" &&
+ echo q | test_expect_code 1 git p4 submit >out &&
+ test_i18ngrep "No commits applied" out
+ )
+'
+
+test_expect_success 'conflict cli and config options' '
+ test_when_finished cleanup_git &&
+ git p4 clone --dest="$git" //depot &&
+ (
+ cd "$git" &&
+ git p4 submit --conflict=ask &&
+ git p4 submit --conflict=skip &&
+ git p4 submit --conflict=quit &&
+ test_expect_code 2 git p4 submit --conflict=foo &&
+ test_expect_code 2 git p4 submit --conflict &&
+ git config git-p4.conflict foo &&
+ test_expect_code 1 git p4 submit &&
+ git config --unset git-p4.conflict &&
+ git p4 submit
+ )
+'
+
+test_expect_success 'conflict on first of two commits, --conflict=skip' '
+ test_when_finished cleanup_git &&
+ git p4 clone --dest="$git" //depot &&
+ (
+ cd "$cli" &&
+ p4 open file1 &&
+ echo line9 >>file1 &&
+ p4 submit -d "line9 in file1"
+ ) &&
+ (
+ cd "$git" &&
+ git config git-p4.skipSubmitEdit true &&
+ # this submit should cause a conflict
+ echo line10 >>file1 &&
+ git add file1 &&
+ git commit -m "line10 in file1 will conflict" &&
+ # but this commit is okay
+ test_commit "okay_commit_after_auto_skip" &&
+ test_expect_code 1 git p4 submit --conflict=skip >out &&
+ test_i18ngrep "Applied only the commits" out
+ )
+'
+
+test_expect_success 'conflict on first of two commits, --conflict=quit' '
+ test_when_finished cleanup_git &&
+ git p4 clone --dest="$git" //depot &&
+ (
+ cd "$cli" &&
+ p4 open file1 &&
+ echo line11 >>file1 &&
+ p4 submit -d "line11 in file1"
+ ) &&
+ (
+ cd "$git" &&
+ git config git-p4.skipSubmitEdit true &&
+ # this submit should cause a conflict
+ echo line12 >>file1 &&
+ git add file1 &&
+ git commit -m "line12 in file1 will conflict" &&
+ # but this commit is okay
+ test_commit "okay_commit_after_auto_quit" &&
+ test_expect_code 1 git p4 submit --conflict=quit >out &&
+ test_i18ngrep "No commits applied" out
+ )
+'
+
+#
+# Cleanup after submit fail, all cases. Some modifications happen
+# before trying to apply the patch. Make sure these are unwound
+# properly. Put each one in a diff along with something that will
+# obviously conflict. Make sure it is back to normal after.
+#
+
+test_expect_success 'cleanup edit p4 populate' '
+ (
+ cd "$cli" &&
+ echo text file >text &&
+ p4 add text &&
+ echo text+x file >text+x &&
+ chmod 755 text+x &&
+ p4 add text+x &&
+ p4 submit -d "populate p4"
+ )
+'
+
+setup_conflict() {
+ # clone before modifying file1 to force it to conflict
+ test_when_finished cleanup_git &&
+ git p4 clone --dest="$git" //depot &&
+ # ticks outside subshells
+ test_tick &&
+ (
+ cd "$cli" &&
+ p4 open file1 &&
+ echo $test_tick >>file1 &&
+ p4 submit -d "$test_tick in file1"
+ ) &&
+ test_tick &&
+ (
+ cd "$git" &&
+ git config git-p4.skipSubmitEdit true &&
+ # easy conflict
+ echo $test_tick >>file1 &&
+ git add file1
+ # caller will add more and submit
+ )
+}
+
+test_expect_success 'cleanup edit after submit fail' '
+ setup_conflict &&
+ (
+ cd "$git" &&
+ echo another line >>text &&
+ git add text &&
+ git commit -m "conflict" &&
+ test_expect_code 1 git p4 submit
+ ) &&
+ (
+ cd "$cli" &&
+ # make sure it is not open
+ ! p4 fstat -T action text
+ )
+'
+
+test_expect_success 'cleanup add after submit fail' '
+ setup_conflict &&
+ (
+ cd "$git" &&
+ echo new file >textnew &&
+ git add textnew &&
+ git commit -m "conflict" &&
+ test_expect_code 1 git p4 submit
+ ) &&
+ (
+ cd "$cli" &&
+ # make sure it is not there
+ # and that p4 thinks it is not added
+ # P4 returns 0 both for "not there but added" and
+ # "not there", so grep.
+ test_path_is_missing textnew &&
+ p4 fstat -T action textnew 2>&1 | grep "no such file"
+ )
+'
+
+test_expect_success 'cleanup delete after submit fail' '
+ setup_conflict &&
+ (
+ cd "$git" &&
+ git rm text+x &&
+ git commit -m "conflict" &&
+ test_expect_code 1 git p4 submit
+ ) &&
+ (
+ cd "$cli" &&
+ # make sure it is there
+ test_path_is_file text+x &&
+ ! p4 fstat -T action text+x
+ )
+'
+
+test_expect_success 'cleanup copy after submit fail' '
+ setup_conflict &&
+ (
+ cd "$git" &&
+ cp text text2 &&
+ git add text2 &&
+ git commit -m "conflict" &&
+ git config git-p4.detectCopies true &&
+ git config git-p4.detectCopiesHarder true &&
+ # make sure setup is okay
+ git diff-tree -r -C --find-copies-harder HEAD | grep text2 | grep C100 &&
+ test_expect_code 1 git p4 submit
+ ) &&
+ (
+ cd "$cli" &&
+ test_path_is_missing text2 &&
+ p4 fstat -T action text2 2>&1 | grep "no such file"
+ )
+'
+
+test_expect_success 'cleanup rename after submit fail' '
+ setup_conflict &&
+ (
+ cd "$git" &&
+ git mv text text2 &&
+ git commit -m "conflict" &&
+ git config git-p4.detectRenames true &&
+ # make sure setup is okay
+ git diff-tree -r -M HEAD | grep text2 | grep R100 &&
+ test_expect_code 1 git p4 submit
+ ) &&
+ (
+ cd "$cli" &&
+ test_path_is_missing text2 &&
+ p4 fstat -T action text2 2>&1 | grep "no such file"
+ )
+'
+
+#
+# Cleanup after deciding not to submit during editTemplate. This
+# involves unwinding more work, because files have been added, deleted
+# and chmod-ed now. Same approach as above.
+#
+
+test_expect_success 'cleanup edit after submit cancel' '
+ test_when_finished cleanup_git &&
+ git p4 clone --dest="$git" //depot &&
+ (
+ cd "$git" &&
+ echo line >>text &&
+ git add text &&
+ git commit -m text &&
+ echo n | test_expect_code 1 git p4 submit &&
+ git reset --hard HEAD^
+ ) &&
+ (
+ cd "$cli" &&
+ ! p4 fstat -T action text &&
+ test_cmp "$git"/text text
+ )
+'
+
+test_expect_success 'cleanup add after submit cancel' '
+ test_when_finished cleanup_git &&
+ git p4 clone --dest="$git" //depot &&
+ (
+ cd "$git" &&
+ echo line >textnew &&
+ git add textnew &&
+ git commit -m textnew &&
+ echo n | test_expect_code 1 git p4 submit
+ ) &&
+ (
+ cd "$cli" &&
+ test_path_is_missing textnew &&
+ p4 fstat -T action textnew 2>&1 | grep "no such file"
+ )
+'
+
+test_expect_success 'cleanup delete after submit cancel' '
+ test_when_finished cleanup_git &&
+ git p4 clone --dest="$git" //depot &&
+ (
+ cd "$git" &&
+ git rm text &&
+ git commit -m "rm text" &&
+ echo n | test_expect_code 1 git p4 submit
+ ) &&
+ (
+ cd "$cli" &&
+ test_path_is_file text &&
+ ! p4 fstat -T action text
+ )
+'
+
+test_expect_success 'cleanup copy after submit cancel' '
+ test_when_finished cleanup_git &&
+ git p4 clone --dest="$git" //depot &&
+ (
+ cd "$git" &&
+ cp text text2 &&
+ git add text2 &&
+ git commit -m text2 &&
+ git config git-p4.detectCopies true &&
+ git config git-p4.detectCopiesHarder true &&
+ git diff-tree -r -C --find-copies-harder HEAD | grep text2 | grep C100 &&
+ echo n | test_expect_code 1 git p4 submit
+ ) &&
+ (
+ cd "$cli" &&
+ test_path_is_missing text2 &&
+ p4 fstat -T action text2 2>&1 | grep "no such file"
+ )
+'
+
+test_expect_success 'cleanup rename after submit cancel' '
+ test_when_finished cleanup_git &&
+ git p4 clone --dest="$git" //depot &&
+ (
+ cd "$git" &&
+ git mv text text2 &&
+ git commit -m text2 &&
+ git config git-p4.detectRenames true &&
+ git diff-tree -r -M HEAD | grep text2 | grep R100 &&
+ echo n | test_expect_code 1 git p4 submit
+ ) &&
+ (
+ cd "$cli" &&
+ test_path_is_missing text2 &&
+ p4 fstat -T action text2 2>&1 | grep "no such file"
+ test_path_is_file text &&
+ ! p4 fstat -T action text
+ )
+'
+
+test_expect_success 'cleanup chmod after submit cancel' '
+ test_when_finished cleanup_git &&
+ git p4 clone --dest="$git" //depot &&
+ (
+ cd "$git" &&
+ chmod u+x text &&
+ chmod u-x text+x &&
+ git add text text+x &&
+ git commit -m "chmod texts" &&
+ echo n | test_expect_code 1 git p4 submit
+ ) &&
+ (
+ cd "$cli" &&
+ test_path_is_file text &&
+ ! p4 fstat -T action text &&
+ stat --format=%A text | egrep ^-r-- &&
+ test_path_is_file text+x &&
+ ! p4 fstat -T action text+x &&
+ stat --format=%A text+x | egrep ^-r-x
+ )
+'
+
+test_expect_success 'kill p4d' '
+ kill_p4d
+'
+
+test_done
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index 256e6a0..cbd0fb6 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -3,21 +3,9 @@
# Copyright (c) 2012 Felipe Contreras
#
-if test -n "$BASH" && test -z "$POSIXLY_CORRECT"; then
- # we are in full-on bash mode
- true
-elif type bash >/dev/null 2>&1; then
- # execute in full-on bash mode
- unset POSIXLY_CORRECT
- exec bash "$0" "$@"
-else
- echo '1..0 #SKIP skipping bash completion tests; bash not available'
- exit 0
-fi
-
test_description='test bash completion'
-. ./test-lib.sh
+. ./lib-bash.sh
complete ()
{
@@ -73,6 +61,15 @@ test_completion ()
test_cmp expected out
}
+# Like test_completion, but reads expectation from stdin,
+# which is convenient when it is multiline. We also process "_" into
+# spaces to make test vectors more readable.
+test_completion_long ()
+{
+ tr _ " " >expected &&
+ test_completion "$1"
+}
+
newline=$'\n'
test_expect_success '__gitcomp - trailing space - options' '
@@ -240,4 +237,55 @@ test_expect_success 'general options plus command' '
test_completion "git --no-replace-objects check" "checkout "
'
+test_expect_success 'setup for ref completion' '
+ echo content >file1 &&
+ echo more >file2 &&
+ git add . &&
+ git commit -m one &&
+ git branch mybranch &&
+ git tag mytag
+'
+
+test_expect_success 'checkout completes ref names' '
+ test_completion_long "git checkout m" <<-\EOF
+ master_
+ mybranch_
+ mytag_
+ EOF
+'
+
+test_expect_success 'show completes all refs' '
+ test_completion_long "git show m" <<-\EOF
+ master_
+ mybranch_
+ mytag_
+ EOF
+'
+
+test_expect_success '<ref>: completes paths' '
+ test_completion_long "git show mytag:f" <<-\EOF
+ file1_
+ file2_
+ EOF
+'
+
+test_expect_success 'complete tree filename with spaces' '
+ echo content >"name with spaces" &&
+ git add . &&
+ git commit -m spaces &&
+ test_completion_long "git show HEAD:nam" <<-\EOF
+ name with spaces_
+ EOF
+'
+
+test_expect_failure 'complete tree filename with metacharacters' '
+ echo content >"name with \${meta}" &&
+ git add . &&
+ git commit -m meta &&
+ test_completion_long "git show HEAD:nam" <<-\EOF
+ name with ${meta}_
+ name with spaces_
+ EOF
+'
+
test_done
diff --git a/t/t9903-bash-prompt.sh b/t/t9903-bash-prompt.sh
new file mode 100755
index 0000000..f17c1f8
--- /dev/null
+++ b/t/t9903-bash-prompt.sh
@@ -0,0 +1,456 @@
+#!/bin/sh
+#
+# Copyright (c) 2012 SZEDER Gábor
+#
+
+test_description='test git-specific bash prompt functions'
+
+. ./lib-bash.sh
+
+. "$GIT_BUILD_DIR/contrib/completion/git-prompt.sh"
+
+actual="$TRASH_DIRECTORY/actual"
+
+test_expect_success 'setup for prompt tests' '
+ mkdir -p subdir/subsubdir &&
+ git init otherrepo &&
+ echo 1 > file &&
+ git add file &&
+ test_tick &&
+ git commit -m initial &&
+ git tag -a -m msg1 t1 &&
+ git checkout -b b1 &&
+ echo 2 > file &&
+ git commit -m "second b1" file &&
+ echo 3 > file &&
+ git commit -m "third b1" file &&
+ git tag -a -m msg2 t2 &&
+ git checkout -b b2 master &&
+ echo 0 > file &&
+ git commit -m "second b2" file &&
+ git checkout master
+'
+
+test_expect_success 'gitdir - from command line (through $__git_dir)' '
+ echo "$TRASH_DIRECTORY/otherrepo/.git" > expected &&
+ (
+ __git_dir="$TRASH_DIRECTORY/otherrepo/.git" &&
+ __gitdir > "$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'gitdir - repo as argument' '
+ echo "otherrepo/.git" > expected &&
+ __gitdir "otherrepo" > "$actual" &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'gitdir - remote as argument' '
+ echo "remote" > expected &&
+ __gitdir "remote" > "$actual" &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'gitdir - .git directory in cwd' '
+ echo ".git" > expected &&
+ __gitdir > "$actual" &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'gitdir - .git directory in parent' '
+ echo "$TRASH_DIRECTORY/.git" > expected &&
+ (
+ cd subdir/subsubdir &&
+ __gitdir > "$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'gitdir - cwd is a .git directory' '
+ echo "." > expected &&
+ (
+ cd .git &&
+ __gitdir > "$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'gitdir - parent is a .git directory' '
+ echo "$TRASH_DIRECTORY/.git" > expected &&
+ (
+ cd .git/refs/heads &&
+ __gitdir > "$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'gitdir - $GIT_DIR set while .git directory in cwd' '
+ echo "$TRASH_DIRECTORY/otherrepo/.git" > expected &&
+ (
+ GIT_DIR="$TRASH_DIRECTORY/otherrepo/.git" &&
+ export GIT_DIR &&
+ __gitdir > "$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'gitdir - $GIT_DIR set while .git directory in parent' '
+ echo "$TRASH_DIRECTORY/otherrepo/.git" > expected &&
+ (
+ GIT_DIR="$TRASH_DIRECTORY/otherrepo/.git" &&
+ export GIT_DIR &&
+ cd subdir &&
+ __gitdir > "$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'gitdir - non-existing $GIT_DIR' '
+ (
+ GIT_DIR="$TRASH_DIRECTORY/non-existing" &&
+ export GIT_DIR &&
+ test_must_fail __gitdir
+ )
+'
+
+test_expect_success 'gitdir - gitfile in cwd' '
+ echo "$TRASH_DIRECTORY/otherrepo/.git" > expected &&
+ echo "gitdir: $TRASH_DIRECTORY/otherrepo/.git" > subdir/.git &&
+ test_when_finished "rm -f subdir/.git" &&
+ (
+ cd subdir &&
+ __gitdir > "$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'gitdir - gitfile in parent' '
+ echo "$TRASH_DIRECTORY/otherrepo/.git" > expected &&
+ echo "gitdir: $TRASH_DIRECTORY/otherrepo/.git" > subdir/.git &&
+ test_when_finished "rm -f subdir/.git" &&
+ (
+ cd subdir/subsubdir &&
+ __gitdir > "$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success SYMLINKS 'gitdir - resulting path avoids symlinks' '
+ echo "$TRASH_DIRECTORY/otherrepo/.git" > expected &&
+ mkdir otherrepo/dir &&
+ test_when_finished "rm -rf otherrepo/dir" &&
+ ln -s otherrepo/dir link &&
+ test_when_finished "rm -f link" &&
+ (
+ cd link &&
+ __gitdir > "$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'gitdir - not a git repository' '
+ (
+ cd subdir/subsubdir &&
+ GIT_CEILING_DIRECTORIES="$TRASH_DIRECTORY" &&
+ export GIT_CEILING_DIRECTORIES &&
+ test_must_fail __gitdir
+ )
+'
+
+test_expect_success 'prompt - branch name' '
+ printf " (master)" > expected &&
+ __git_ps1 > "$actual" &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - detached head' '
+ printf " ((%s...))" $(git log -1 --format="%h" b1^) > expected &&
+ git checkout b1^ &&
+ test_when_finished "git checkout master" &&
+ __git_ps1 > "$actual" &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - describe detached head - contains' '
+ printf " ((t2~1))" > expected &&
+ git checkout b1^ &&
+ test_when_finished "git checkout master" &&
+ (
+ GIT_PS1_DESCRIBE_STYLE=contains &&
+ __git_ps1 > "$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - describe detached head - branch' '
+ printf " ((b1~1))" > expected &&
+ git checkout b1^ &&
+ test_when_finished "git checkout master" &&
+ (
+ GIT_PS1_DESCRIBE_STYLE=branch &&
+ __git_ps1 > "$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - describe detached head - describe' '
+ printf " ((t1-1-g%s))" $(git log -1 --format="%h" b1^) > expected &&
+ git checkout b1^ &&
+ test_when_finished "git checkout master" &&
+ (
+ GIT_PS1_DESCRIBE_STYLE=describe &&
+ __git_ps1 > "$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - describe detached head - default' '
+ printf " ((t2))" > expected &&
+ git checkout --detach b1 &&
+ test_when_finished "git checkout master" &&
+ __git_ps1 > "$actual" &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - inside .git directory' '
+ printf " (GIT_DIR!)" > expected &&
+ (
+ cd .git &&
+ __git_ps1 > "$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - deep inside .git directory' '
+ printf " (GIT_DIR!)" > expected &&
+ (
+ cd .git/refs/heads &&
+ __git_ps1 > "$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - inside bare repository' '
+ printf " (BARE:master)" > expected &&
+ git init --bare bare.git &&
+ test_when_finished "rm -rf bare.git" &&
+ (
+ cd bare.git &&
+ __git_ps1 > "$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - interactive rebase' '
+ printf " (b1|REBASE-i)" > expected
+ echo "#!$SHELL_PATH" >fake_editor.sh &&
+ cat >>fake_editor.sh <<\EOF &&
+echo "edit $(git log -1 --format="%h")" > "$1"
+EOF
+ test_when_finished "rm -f fake_editor.sh" &&
+ chmod a+x fake_editor.sh &&
+ test_set_editor "$TRASH_DIRECTORY/fake_editor.sh" &&
+ git checkout b1 &&
+ test_when_finished "git checkout master" &&
+ git rebase -i HEAD^ &&
+ test_when_finished "git rebase --abort"
+ __git_ps1 > "$actual" &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - rebase merge' '
+ printf " (b2|REBASE-m)" > expected &&
+ git checkout b2 &&
+ test_when_finished "git checkout master" &&
+ test_must_fail git rebase --merge b1 b2 &&
+ test_when_finished "git rebase --abort" &&
+ __git_ps1 > "$actual" &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - rebase' '
+ printf " ((t2)|REBASE)" > expected &&
+ git checkout b2 &&
+ test_when_finished "git checkout master" &&
+ test_must_fail git rebase b1 b2 &&
+ test_when_finished "git rebase --abort" &&
+ __git_ps1 > "$actual" &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - merge' '
+ printf " (b1|MERGING)" > expected &&
+ git checkout b1 &&
+ test_when_finished "git checkout master" &&
+ test_must_fail git merge b2 &&
+ test_when_finished "git reset --hard" &&
+ __git_ps1 > "$actual" &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - cherry-pick' '
+ printf " (master|CHERRY-PICKING)" > expected &&
+ test_must_fail git cherry-pick b1 &&
+ test_when_finished "git reset --hard" &&
+ __git_ps1 > "$actual" &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - bisect' '
+ printf " (master|BISECTING)" > expected &&
+ git bisect start &&
+ test_when_finished "git bisect reset" &&
+ __git_ps1 > "$actual" &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - dirty status indicator - clean' '
+ printf " (master)" > expected &&
+ (
+ GIT_PS1_SHOWDIRTYSTATE=y &&
+ __git_ps1 > "$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - dirty status indicator - dirty worktree' '
+ printf " (master *)" > expected &&
+ echo "dirty" > file &&
+ test_when_finished "git reset --hard" &&
+ (
+ GIT_PS1_SHOWDIRTYSTATE=y &&
+ __git_ps1 > "$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - dirty status indicator - dirty index' '
+ printf " (master +)" > expected &&
+ echo "dirty" > file &&
+ test_when_finished "git reset --hard" &&
+ git add -u &&
+ (
+ GIT_PS1_SHOWDIRTYSTATE=y &&
+ __git_ps1 > "$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - dirty status indicator - dirty index and worktree' '
+ printf " (master *+)" > expected &&
+ echo "dirty index" > file &&
+ test_when_finished "git reset --hard" &&
+ git add -u &&
+ echo "dirty worktree" > file &&
+ (
+ GIT_PS1_SHOWDIRTYSTATE=y &&
+ __git_ps1 > "$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - dirty status indicator - before root commit' '
+ printf " (master #)" > expected &&
+ (
+ GIT_PS1_SHOWDIRTYSTATE=y &&
+ cd otherrepo &&
+ __git_ps1 > "$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - dirty status indicator - disabled by config' '
+ printf " (master)" > expected &&
+ echo "dirty" > file &&
+ test_when_finished "git reset --hard" &&
+ test_config bash.showDirtyState false &&
+ (
+ GIT_PS1_SHOWDIRTYSTATE=y &&
+ __git_ps1 > "$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - dirty status indicator - not shown inside .git directory' '
+ printf " (GIT_DIR!)" > expected &&
+ echo "dirty" > file &&
+ test_when_finished "git reset --hard" &&
+ (
+ GIT_PS1_SHOWDIRTYSTATE=y &&
+ cd .git &&
+ __git_ps1 > "$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - stash status indicator - no stash' '
+ printf " (master)" > expected &&
+ (
+ GIT_PS1_SHOWSTASHSTATE=y &&
+ __git_ps1 > "$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - stash status indicator - stash' '
+ printf " (master $)" > expected &&
+ echo 2 >file &&
+ git stash &&
+ test_when_finished "git stash drop" &&
+ (
+ GIT_PS1_SHOWSTASHSTATE=y &&
+ __git_ps1 > "$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - stash status indicator - not shown inside .git directory' '
+ printf " (GIT_DIR!)" > expected &&
+ echo 2 >file &&
+ git stash &&
+ test_when_finished "git stash drop" &&
+ (
+ GIT_PS1_SHOWSTASHSTATE=y &&
+ cd .git &&
+ __git_ps1 > "$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - untracked files status indicator - no untracked files' '
+ printf " (master)" > expected &&
+ (
+ GIT_PS1_SHOWUNTRACKEDFILES=y &&
+ cd otherrepo &&
+ __git_ps1 > "$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - untracked files status indicator - untracked files' '
+ printf " (master %%)" > expected &&
+ (
+ GIT_PS1_SHOWUNTRACKEDFILES=y &&
+ __git_ps1 > "$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - untracked files status indicator - not shown inside .git directory' '
+ printf " (GIT_DIR!)" > expected &&
+ (
+ GIT_PS1_SHOWUNTRACKEDFILES=y &&
+ cd .git &&
+ __git_ps1 > "$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - format string starting with dash' '
+ printf -- "-master" > expected &&
+ __git_ps1 "-%s" > "$actual" &&
+ test_cmp expected "$actual"
+'
+
+test_done
diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh
index 9096398..8889ba5 100644
--- a/t/test-lib-functions.sh
+++ b/t/test-lib-functions.sh
@@ -144,11 +144,22 @@ test_pause () {
test_commit () {
notick= &&
- if test "z$1" = "z--notick"
- then
- notick=yes
+ signoff= &&
+ while test $# != 0
+ do
+ case "$1" in
+ --notick)
+ notick=yes
+ ;;
+ --signoff)
+ signoff="$1"
+ ;;
+ *)
+ break
+ ;;
+ esac
shift
- fi &&
+ done &&
file=${2:-"$1.t"} &&
echo "${3-$1}" > "$file" &&
git add "$file" &&
@@ -156,7 +167,7 @@ test_commit () {
then
test_tick
fi &&
- git commit -m "$1" &&
+ git commit $signoff -m "$1" &&
git tag "$1"
}
@@ -221,9 +232,35 @@ write_script () {
# capital letters by convention).
test_set_prereq () {
- satisfied="$satisfied$1 "
+ satisfied_prereq="$satisfied_prereq$1 "
+}
+satisfied_prereq=" "
+lazily_testable_prereq= lazily_tested_prereq=
+
+# Usage: test_lazy_prereq PREREQ 'script'
+test_lazy_prereq () {
+ lazily_testable_prereq="$lazily_testable_prereq$1 "
+ eval test_prereq_lazily_$1=\$2
+}
+
+test_run_lazy_prereq_ () {
+ script='
+mkdir -p "$TRASH_DIRECTORY/prereq-test-dir" &&
+(
+ cd "$TRASH_DIRECTORY/prereq-test-dir" &&'"$2"'
+)'
+ say >&3 "checking prerequisite: $1"
+ say >&3 "$script"
+ test_eval_ "$script"
+ eval_ret=$?
+ rm -rf "$TRASH_DIRECTORY/prereq-test-dir"
+ if test "$eval_ret" = 0; then
+ say >&3 "prerequisite $1 ok"
+ else
+ say >&3 "prerequisite $1 not satisfied"
+ fi
+ return $eval_ret
}
-satisfied=" "
test_have_prereq () {
# prerequisites can be concatenated with ','
@@ -238,8 +275,24 @@ test_have_prereq () {
for prerequisite
do
+ case " $lazily_tested_prereq " in
+ *" $prerequisite "*)
+ ;;
+ *)
+ case " $lazily_testable_prereq " in
+ *" $prerequisite "*)
+ eval "script=\$test_prereq_lazily_$prerequisite" &&
+ if test_run_lazy_prereq_ "$prerequisite" "$script"
+ then
+ test_set_prereq $prerequisite
+ fi
+ lazily_tested_prereq="$lazily_tested_prereq$prerequisite "
+ esac
+ ;;
+ esac
+
total_prereq=$(($total_prereq + 1))
- case $satisfied in
+ case "$satisfied_prereq" in
*" $prerequisite "*)
ok_prereq=$(($ok_prereq + 1))
;;
diff --git a/t/test-lib.sh b/t/test-lib.sh
index acda33d..514282c 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -15,6 +15,38 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see http://www.gnu.org/licenses/ .
+# Keep the original TERM for say_color
+ORIGINAL_TERM=$TERM
+
+# Test the binaries we have just built. The tests are kept in
+# t/ subdirectory and are run in 'trash directory' subdirectory.
+if test -z "$TEST_DIRECTORY"
+then
+ # We allow tests to override this, in case they want to run tests
+ # outside of t/, e.g. for running tests on the test library
+ # itself.
+ TEST_DIRECTORY=$(pwd)
+fi
+if test -z "$TEST_OUTPUT_DIRECTORY"
+then
+ # Similarly, override this to store the test-results subdir
+ # elsewhere
+ TEST_OUTPUT_DIRECTORY=$TEST_DIRECTORY
+fi
+GIT_BUILD_DIR="$TEST_DIRECTORY"/..
+
+################################################################
+# It appears that people try to run tests without building...
+"$GIT_BUILD_DIR/git" >/dev/null
+if test $? != 1
+then
+ echo >&2 'error: you do not seem to have built git yet.'
+ exit 1
+fi
+
+. "$GIT_BUILD_DIR"/GIT-BUILD-OPTIONS
+export PERL_PATH SHELL_PATH
+
# if --tee was passed, write the output not only to the terminal, but
# additionally to the file test-results/$BASENAME.out, too.
case "$GIT_TEST_TEE_STARTED, $* " in
@@ -24,16 +56,13 @@ done,*)
*' --tee '*|*' --va'*)
mkdir -p test-results
BASE=test-results/$(basename "$0" .sh)
- (GIT_TEST_TEE_STARTED=done ${SHELL-sh} "$0" "$@" 2>&1;
+ (GIT_TEST_TEE_STARTED=done ${SHELL_PATH} "$0" "$@" 2>&1;
echo $? > $BASE.exit) | tee $BASE.out
test "$(cat $BASE.exit)" = 0
exit
;;
esac
-# Keep the original TERM for say_color
-ORIGINAL_TERM=$TERM
-
# For repeatability, reset the environment to known value.
LANG=C
LC_ALL=C
@@ -46,7 +75,7 @@ EDITOR=:
# /usr/xpg4/bin/sh and /bin/ksh to bail out. So keep the unsets
# deriving from the command substitution clustered with the other
# ones.
-unset VISUAL EMAIL LANGUAGE COLUMNS $(perl -e '
+unset VISUAL EMAIL LANGUAGE COLUMNS $("$PERL_PATH" -e '
my @env = keys %ENV;
my $ok = join("|", qw(
TRACE
@@ -61,6 +90,7 @@ unset VISUAL EMAIL LANGUAGE COLUMNS $(perl -e '
my @vars = grep(/^GIT_/ && !/^GIT_($ok)/o, @env);
print join("\n", @vars);
')
+unset XDG_CONFIG_HOME
GIT_AUTHOR_EMAIL=author@example.com
GIT_AUTHOR_NAME='A U Thor'
GIT_COMMITTER_EMAIL=committer@example.com
@@ -72,6 +102,27 @@ export GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME
export GIT_COMMITTER_EMAIL GIT_COMMITTER_NAME
export EDITOR
+# Add libc MALLOC and MALLOC_PERTURB test
+# only if we are not executing the test with valgrind
+if expr " $GIT_TEST_OPTS " : ".* --valgrind " >/dev/null ||
+ test -n "$TEST_NO_MALLOC_CHECK"
+then
+ setup_malloc_check () {
+ : nothing
+ }
+ teardown_malloc_check () {
+ : nothing
+ }
+else
+ setup_malloc_check () {
+ MALLOC_CHECK_=3 MALLOC_PERTURB_=165
+ export MALLOC_CHECK_ MALLOC_PERTURB_
+ }
+ teardown_malloc_check () {
+ unset MALLOC_CHECK_ MALLOC_PERTURB_
+ }
+fi
+
# Protect ourselves from common misconfiguration to export
# CDPATH into the environment
unset CDPATH
@@ -79,12 +130,12 @@ unset CDPATH
unset GREP_OPTIONS
case $(echo $GIT_TRACE |tr "[A-Z]" "[a-z]") in
- 1|2|true)
- echo "* warning: Some tests will not work if GIT_TRACE" \
- "is set as to trace on STDERR ! *"
- echo "* warning: Please set GIT_TRACE to something" \
- "other than 1, 2 or true ! *"
- ;;
+1|2|true)
+ echo "* warning: Some tests will not work if GIT_TRACE" \
+ "is set as to trace on STDERR ! *"
+ echo "* warning: Please set GIT_TRACE to something" \
+ "other than 1, 2 or true ! *"
+ ;;
esac
# Convenience
@@ -151,17 +202,23 @@ do
esac
done
-if test -n "$color"; then
+if test -n "$color"
+then
say_color () {
(
TERM=$ORIGINAL_TERM
export TERM
case "$1" in
- error) tput bold; tput setaf 1;; # bold red
- skip) tput bold; tput setaf 2;; # bold green
- pass) tput setaf 2;; # green
- info) tput setaf 3;; # brown
- *) test -n "$quiet" && return;;
+ error)
+ tput bold; tput setaf 1;; # bold red
+ skip)
+ tput bold; tput setaf 2;; # bold green
+ pass)
+ tput setaf 2;; # green
+ info)
+ tput setaf 3;; # brown
+ *)
+ test -n "$quiet" && return;;
esac
shift
printf "%s" "$*"
@@ -229,7 +286,7 @@ trap 'die' EXIT
# The user-facing functions are loaded from a separate file so that
# test_perf subshells can have them too
-. "${TEST_DIRECTORY:-.}"/test-lib-functions.sh
+. "$TEST_DIRECTORY/test-lib-functions.sh"
# You are not expected to call test_ok_ and test_failure_ directly, use
# the text_expect_* functions instead.
@@ -275,9 +332,12 @@ test_run_ () {
if test -z "$immediate" || test $eval_ret = 0 || test -n "$expecting_failure"
then
+ setup_malloc_check
test_eval_ "$test_cleanup"
+ teardown_malloc_check
fi
- if test "$verbose" = "t" && test -n "$HARNESS_ACTIVE"; then
+ if test "$verbose" = "t" && test -n "$HARNESS_ACTIVE"
+ then
echo ""
fi
return "$eval_ret"
@@ -325,7 +385,8 @@ test_at_end_hook_ () {
test_done () {
GIT_EXIT_OK=t
- if test -z "$HARNESS_ACTIVE"; then
+ if test -z "$HARNESS_ACTIVE"
+ then
test_results_dir="$TEST_OUTPUT_DIRECTORY/test-results"
mkdir -p "$test_results_dir"
test_results_path="$test_results_dir/${0%.sh}-$$.counts"
@@ -354,10 +415,18 @@ test_done () {
case "$test_failure" in
0)
# Maybe print SKIP message
+ if test -n "$skip_all" && test $test_count -gt 0
+ then
+ error "Can't use skip_all after running some tests"
+ fi
[ -z "$skip_all" ] || skip_all=" # SKIP $skip_all"
- if test $test_external_has_tap -eq 0; then
- say_color pass "# passed all $msg"
+ if test $test_external_has_tap -eq 0
+ then
+ if test $test_count -gt 0
+ then
+ say_color pass "# passed all $msg"
+ fi
say "1..$test_count$skip_all"
fi
@@ -370,7 +439,8 @@ test_done () {
exit 0 ;;
*)
- if test $test_external_has_tap -eq 0; then
+ if test $test_external_has_tap -eq 0
+ then
say_color error "# failed $test_failure among $msg"
say "1..$test_count"
fi
@@ -380,23 +450,6 @@ test_done () {
esac
}
-# Test the binaries we have just built. The tests are kept in
-# t/ subdirectory and are run in 'trash directory' subdirectory.
-if test -z "$TEST_DIRECTORY"
-then
- # We allow tests to override this, in case they want to run tests
- # outside of t/, e.g. for running tests on the test library
- # itself.
- TEST_DIRECTORY=$(pwd)
-fi
-if test -z "$TEST_OUTPUT_DIRECTORY"
-then
- # Similarly, override this to store the test-results subdir
- # elsewhere
- TEST_OUTPUT_DIRECTORY=$TEST_DIRECTORY
-fi
-GIT_BUILD_DIR="$TEST_DIRECTORY"/..
-
if test -n "$valgrind"
then
make_symlink () {
@@ -467,22 +520,26 @@ then
PATH=$GIT_VALGRIND/bin:$PATH
GIT_EXEC_PATH=$GIT_VALGRIND/bin
export GIT_VALGRIND
-elif test -n "$GIT_TEST_INSTALLED" ; then
+elif test -n "$GIT_TEST_INSTALLED"
+then
GIT_EXEC_PATH=$($GIT_TEST_INSTALLED/git --exec-path) ||
error "Cannot run git from $GIT_TEST_INSTALLED."
PATH=$GIT_TEST_INSTALLED:$GIT_BUILD_DIR:$PATH
GIT_EXEC_PATH=${GIT_TEST_EXEC_PATH:-$GIT_EXEC_PATH}
else # normal case, use ../bin-wrappers only unless $with_dashes:
git_bin_dir="$GIT_BUILD_DIR/bin-wrappers"
- if ! test -x "$git_bin_dir/git" ; then
- if test -z "$with_dashes" ; then
+ if ! test -x "$git_bin_dir/git"
+ then
+ if test -z "$with_dashes"
+ then
say "$git_bin_dir/git is not executable; using GIT_EXEC_PATH"
fi
with_dashes=t
fi
PATH="$git_bin_dir:$PATH"
GIT_EXEC_PATH=$GIT_BUILD_DIR
- if test -n "$with_dashes" ; then
+ if test -n "$with_dashes"
+ then
PATH="$GIT_BUILD_DIR:$PATH"
fi
fi
@@ -492,10 +549,6 @@ GIT_CONFIG_NOSYSTEM=1
GIT_ATTR_NOSYSTEM=1
export PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR GIT_CONFIG_NOSYSTEM GIT_ATTR_NOSYSTEM
-. "$GIT_BUILD_DIR"/GIT-BUILD-OPTIONS
-
-export PERL_PATH
-
if test -z "$GIT_TEST_CMP"
then
if test -n "$GIT_TEST_CMP_USE_COPIED_CONTEXT"
@@ -521,7 +574,8 @@ then
}
fi
-if ! test -x "$GIT_BUILD_DIR"/test-chmtime; then
+if ! test -x "$GIT_BUILD_DIR"/test-chmtime
+then
echo >&2 'You need to build test-chmtime:'
echo >&2 'Run "make test-chmtime" in the source (toplevel) directory'
exit 1
@@ -544,7 +598,8 @@ rm -fr "$test" || {
HOME="$TRASH_DIRECTORY"
export HOME
-if test -z "$TEST_NO_CREATE_REPO"; then
+if test -z "$TEST_NO_CREATE_REPO"
+then
test_create_repo "$test"
else
mkdir -p "$test"
@@ -659,9 +714,29 @@ test_i18ngrep () {
fi
}
-# test whether the filesystem supports symbolic links
-ln -s x y 2>/dev/null && test -h y 2>/dev/null && test_set_prereq SYMLINKS
-rm -f y
+test_lazy_prereq SYMLINKS '
+ # test whether the filesystem supports symbolic links
+ ln -s x y && test -h y
+'
+
+test_lazy_prereq CASE_INSENSITIVE_FS '
+ echo good >CamelCase &&
+ echo bad >camelcase &&
+ test "$(cat CamelCase)" != good
+'
+
+test_lazy_prereq UTF8_NFD_TO_NFC '
+ # check whether FS converts nfd unicode to nfc
+ auml=$(printf "\303\244")
+ aumlcdiar=$(printf "\141\314\210")
+ >"$auml" &&
+ case "$(echo *)" in
+ "$aumlcdiar")
+ true ;;
+ *)
+ false ;;
+ esac
+'
# When the tests are run as root, permission tests will report that
# things are writable when they shouldn't be.
diff --git a/test-credential.c b/test-credential.c
deleted file mode 100644
index dee200e..0000000
--- a/test-credential.c
+++ /dev/null
@@ -1,38 +0,0 @@
-#include "cache.h"
-#include "credential.h"
-#include "string-list.h"
-
-static const char usage_msg[] =
-"test-credential <fill|approve|reject> [helper...]";
-
-int main(int argc, const char **argv)
-{
- const char *op;
- struct credential c = CREDENTIAL_INIT;
- int i;
-
- op = argv[1];
- if (!op)
- usage(usage_msg);
- for (i = 2; i < argc; i++)
- string_list_append(&c.helpers, argv[i]);
-
- if (credential_read(&c, stdin) < 0)
- die("unable to read credential from stdin");
-
- if (!strcmp(op, "fill")) {
- credential_fill(&c);
- if (c.username)
- printf("username=%s\n", c.username);
- if (c.password)
- printf("password=%s\n", c.password);
- }
- else if (!strcmp(op, "approve"))
- credential_approve(&c);
- else if (!strcmp(op, "reject"))
- credential_reject(&c);
- else
- usage(usage_msg);
-
- return 0;
-}
diff --git a/test-line-buffer.c b/test-line-buffer.c
index 7ec9b13..ef1d7ba 100644
--- a/test-line-buffer.c
+++ b/test-line-buffer.c
@@ -87,6 +87,5 @@ int main(int argc, char *argv[])
die("input error");
if (ferror(stdout))
die("output error");
- buffer_reset(&stdin_buf);
return 0;
}
diff --git a/test-string-list.c b/test-string-list.c
new file mode 100644
index 0000000..4693295
--- /dev/null
+++ b/test-string-list.c
@@ -0,0 +1,123 @@
+#include "cache.h"
+#include "string-list.h"
+
+/*
+ * Parse an argument into a string list. arg should either be a
+ * ':'-separated list of strings, or "-" to indicate an empty string
+ * list (as opposed to "", which indicates a string list containing a
+ * single empty string). list->strdup_strings must be set.
+ */
+static void parse_string_list(struct string_list *list, const char *arg)
+{
+ if (!strcmp(arg, "-"))
+ return;
+
+ (void)string_list_split(list, arg, ':', -1);
+}
+
+static void write_list(const struct string_list *list)
+{
+ int i;
+ for (i = 0; i < list->nr; i++)
+ printf("[%d]: \"%s\"\n", i, list->items[i].string);
+}
+
+static void write_list_compact(const struct string_list *list)
+{
+ int i;
+ if (!list->nr)
+ printf("-\n");
+ else {
+ printf("%s", list->items[0].string);
+ for (i = 1; i < list->nr; i++)
+ printf(":%s", list->items[i].string);
+ printf("\n");
+ }
+}
+
+static int prefix_cb(struct string_list_item *item, void *cb_data)
+{
+ const char *prefix = (const char *)cb_data;
+ return !prefixcmp(item->string, prefix);
+}
+
+int main(int argc, char **argv)
+{
+ if (argc == 5 && !strcmp(argv[1], "split")) {
+ struct string_list list = STRING_LIST_INIT_DUP;
+ int i;
+ const char *s = argv[2];
+ int delim = *argv[3];
+ int maxsplit = atoi(argv[4]);
+
+ i = string_list_split(&list, s, delim, maxsplit);
+ printf("%d\n", i);
+ write_list(&list);
+ string_list_clear(&list, 0);
+ return 0;
+ }
+
+ if (argc == 5 && !strcmp(argv[1], "split_in_place")) {
+ struct string_list list = STRING_LIST_INIT_NODUP;
+ int i;
+ char *s = xstrdup(argv[2]);
+ int delim = *argv[3];
+ int maxsplit = atoi(argv[4]);
+
+ i = string_list_split_in_place(&list, s, delim, maxsplit);
+ printf("%d\n", i);
+ write_list(&list);
+ string_list_clear(&list, 0);
+ free(s);
+ return 0;
+ }
+
+ if (argc == 4 && !strcmp(argv[1], "filter")) {
+ /*
+ * Retain only the items that have the specified prefix.
+ * Arguments: list|- prefix
+ */
+ struct string_list list = STRING_LIST_INIT_DUP;
+ const char *prefix = argv[3];
+
+ parse_string_list(&list, argv[2]);
+ filter_string_list(&list, 0, prefix_cb, (void *)prefix);
+ write_list_compact(&list);
+ string_list_clear(&list, 0);
+ return 0;
+ }
+
+ if (argc == 3 && !strcmp(argv[1], "remove_duplicates")) {
+ struct string_list list = STRING_LIST_INIT_DUP;
+
+ parse_string_list(&list, argv[2]);
+ string_list_remove_duplicates(&list, 0);
+ write_list_compact(&list);
+ string_list_clear(&list, 0);
+ return 0;
+ }
+
+ if (argc == 4 && !strcmp(argv[1], "longest_prefix")) {
+ /* arguments: <colon-separated-prefixes>|- <string> */
+ struct string_list prefixes = STRING_LIST_INIT_DUP;
+ int retval;
+ const char *prefix_string = argv[2];
+ const char *string = argv[3];
+ const char *match;
+
+ parse_string_list(&prefixes, prefix_string);
+ match = string_list_longest_prefix(&prefixes, string);
+ if (match) {
+ printf("%s\n", match);
+ retval = 0;
+ }
+ else
+ retval = 1;
+ string_list_clear(&prefixes, 0);
+ return retval;
+ }
+
+ fprintf(stderr, "%s: unknown function name: %s\n", argv[0],
+ argv[1] ? argv[1] : "(there was none)");
+ return 1;
+}
diff --git a/test-svn-fe.c b/test-svn-fe.c
index 332a5f7..83633a2 100644
--- a/test-svn-fe.c
+++ b/test-svn-fe.c
@@ -31,9 +31,7 @@ static int apply_delta(int argc, char *argv[])
die_errno("cannot close preimage");
if (buffer_deinit(&delta))
die_errno("cannot close delta");
- buffer_reset(&preimage);
strbuf_release(&preimage_view.buf);
- buffer_reset(&delta);
return 0;
}
diff --git a/trace.c b/trace.c
index d953416..5ec0e3b 100644
--- a/trace.c
+++ b/trace.c
@@ -62,7 +62,7 @@ static int get_trace_fd(const char *key, int *need_close)
static const char err_msg[] = "Could not trace into fd given by "
"GIT_TRACE environment variable";
-void trace_vprintf(const char *key, const char *fmt, va_list ap)
+static void trace_vprintf(const char *key, const char *fmt, va_list ap)
{
struct strbuf buf = STRBUF_INIT;
diff --git a/transport-helper.c b/transport-helper.c
index 61c928f..cfe0988 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -444,6 +444,21 @@ static int fetch_with_import(struct transport *transport,
free(fastimport.argv);
fastimport.argv = NULL;
+ /*
+ * The fast-import stream of a remote helper that advertises
+ * the "refspec" capability writes to the refs named after the
+ * right hand side of the first refspec matching each ref we
+ * were fetching.
+ *
+ * (If no "refspec" capability was specified, for historical
+ * reasons we default to *:*.)
+ *
+ * Store the result in to_fetch[i].old_sha1. Callers such
+ * as "git fetch" can use the value to write feedback to the
+ * terminal, populate FETCH_HEAD, and determine what new value
+ * should be written to peer_ref if the update is a
+ * fast-forward or this is a forced update.
+ */
for (i = 0; i < nr_heads; i++) {
char *private;
posn = to_fetch[i];
diff --git a/transport.c b/transport.c
index 1811b50..9932f40 100644
--- a/transport.c
+++ b/transport.c
@@ -518,8 +518,7 @@ static int fetch_refs_via_pack(struct transport *transport,
int nr_heads, struct ref **to_fetch)
{
struct git_transport_data *data = transport->data;
- char **heads = xmalloc(nr_heads * sizeof(*heads));
- char **origh = xmalloc(nr_heads * sizeof(*origh));
+ struct string_list sought = STRING_LIST_INIT_DUP;
const struct ref *refs;
char *dest = xstrdup(transport->url);
struct fetch_pack_args args;
@@ -538,7 +537,7 @@ static int fetch_refs_via_pack(struct transport *transport,
args.depth = data->options.depth;
for (i = 0; i < nr_heads; i++)
- origh[i] = heads[i] = xstrdup(to_fetch[i]->name);
+ string_list_append(&sought, to_fetch[i]->name);
if (!data->got_remote_heads) {
connect_setup(transport, 0, 0);
@@ -548,7 +547,7 @@ static int fetch_refs_via_pack(struct transport *transport,
refs = fetch_pack(&args, data->fd, data->conn,
refs_tmp ? refs_tmp : transport->remote_refs,
- dest, nr_heads, heads, &transport->pack_lockfile);
+ dest, &sought, &transport->pack_lockfile);
close(data->fd[0]);
close(data->fd[1]);
if (finish_connect(data->conn))
@@ -558,10 +557,7 @@ static int fetch_refs_via_pack(struct transport *transport,
free_refs(refs_tmp);
- for (i = 0; i < nr_heads; i++)
- free(origh[i]);
- free(origh);
- free(heads);
+ string_list_clear(&sought, 0);
free(dest);
return (refs ? 0 : -1);
}
diff --git a/transport.h b/transport.h
index b866c12..3b21c4a 100644
--- a/transport.h
+++ b/transport.h
@@ -106,6 +106,7 @@ struct transport {
#define TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND 256
#define TRANSPORT_SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3)
+#define TRANSPORT_SUMMARY(x) (int)(TRANSPORT_SUMMARY_WIDTH + strlen(x) - gettext_width(x)), (x)
/* Returns a transport suitable for the url */
struct transport *transport_get(struct remote *, const char *);
diff --git a/tree.c b/tree.c
index 676e9f7..62fed63 100644
--- a/tree.c
+++ b/tree.c
@@ -22,7 +22,8 @@ static int read_one_entry_opt(const unsigned char *sha1, const char *base, int b
ce = xcalloc(1, size);
ce->ce_mode = create_ce_mode(mode);
- ce->ce_flags = create_ce_flags(baselen + len, stage);
+ ce->ce_flags = create_ce_flags(stage);
+ ce->ce_namelen = baselen + len;
memcpy(ce->name, base, baselen);
memcpy(ce->name + baselen, pathname, len+1);
hashcpy(ce->sha1, sha1);
@@ -133,8 +134,8 @@ static int cmp_cache_name_compare(const void *a_, const void *b_)
ce1 = *((const struct cache_entry **)a_);
ce2 = *((const struct cache_entry **)b_);
- return cache_name_compare(ce1->name, ce1->ce_flags,
- ce2->name, ce2->ce_flags);
+ return cache_name_stage_compare(ce1->name, ce1->ce_namelen, ce_stage(ce1),
+ ce2->name, ce2->ce_namelen, ce_stage(ce2));
}
int read_tree(struct tree *tree, int stage, struct pathspec *match)
diff --git a/unpack-trees.c b/unpack-trees.c
index 33a5819..6d96366 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -539,7 +539,8 @@ static struct cache_entry *create_ce_entry(const struct traverse_info *info, con
struct cache_entry *ce = xcalloc(1, cache_entry_size(len));
ce->ce_mode = create_ce_mode(n->mode);
- ce->ce_flags = create_ce_flags(len, stage);
+ ce->ce_flags = create_ce_flags(stage);
+ ce->ce_namelen = len;
hashcpy(ce->sha1, n->sha1);
make_traverse_path(ce->name, info, n);
@@ -1296,7 +1297,7 @@ static int verify_clean_subdirectory(struct cache_entry *ce,
* First let's make sure we do not have a local modification
* in that directory.
*/
- namelen = strlen(ce->name);
+ namelen = ce_namelen(ce);
for (i = locate_in_src_index(ce, o);
i < o->src_index->cache_nr;
i++) {
diff --git a/upload-pack.c b/upload-pack.c
index bb08e2e..2e90ccb 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -11,6 +11,7 @@
#include "list-objects.h"
#include "run-command.h"
#include "sigchain.h"
+#include "version.h"
static const char upload_pack_usage[] = "git upload-pack [--strict] [--timeout=<n>] <dir>";
@@ -734,9 +735,11 @@ static int send_ref(const char *refname, const unsigned char *sha1, int flag, vo
}
if (capabilities)
- packet_write(1, "%s %s%c%s%s\n", sha1_to_hex(sha1), refname_nons,
+ packet_write(1, "%s %s%c%s%s agent=%s\n",
+ sha1_to_hex(sha1), refname_nons,
0, capabilities,
- stateless_rpc ? " no-done" : "");
+ stateless_rpc ? " no-done" : "",
+ git_user_agent_sanitized());
else
packet_write(1, "%s %s\n", sha1_to_hex(sha1), refname_nons);
capabilities = NULL;
diff --git a/userdiff.c b/userdiff.c
index 1e7184f..ed958ef 100644
--- a/userdiff.c
+++ b/userdiff.c
@@ -14,6 +14,15 @@ static int drivers_alloc;
{ name, NULL, -1, { pattern, REG_EXTENDED | REG_ICASE }, \
word_regex "|[^[:space:]]|[\xc0-\xff][\x80-\xbf]+" }
static struct userdiff_driver builtin_drivers[] = {
+IPATTERN("ada",
+ "!^(.*[ \t])?(is new|renames|is separate)([ \t].*)?$\n"
+ "!^[ \t]*with[ \t].*$\n"
+ "^[ \t]*((procedure|function)[ \t]+.*)$\n"
+ "^[ \t]*((package|protected|task)[ \t]+.*)$",
+ /* -- */
+ "[a-zA-Z][a-zA-Z0-9_]*"
+ "|[0-9][-+0-9#_.eE]"
+ "|=>|\\.\\.|\\*\\*|:=|/=|>=|<=|<<|>>|<>"),
IPATTERN("fortran",
"!^([C*]|[ \t]*!)\n"
"!^[ \t]*MODULE[ \t]+PROCEDURE[ \t]\n"
diff --git a/utf8.c b/utf8.c
index 8acbc66..a544f15 100644
--- a/utf8.c
+++ b/utf8.c
@@ -433,19 +433,12 @@ int is_encoding_utf8(const char *name)
#else
typedef char * iconv_ibp;
#endif
-char *reencode_string(const char *in, const char *out_encoding, const char *in_encoding)
+char *reencode_string_iconv(const char *in, size_t insz, iconv_t conv)
{
- iconv_t conv;
- size_t insz, outsz, outalloc;
+ size_t outsz, outalloc;
char *out, *outpos;
iconv_ibp cp;
- if (!in_encoding)
- return NULL;
- conv = iconv_open(out_encoding, in_encoding);
- if (conv == (iconv_t) -1)
- return NULL;
- insz = strlen(in);
outsz = insz;
outalloc = outsz + 1; /* for terminating NUL */
out = xmalloc(outalloc);
@@ -459,7 +452,6 @@ char *reencode_string(const char *in, const char *out_encoding, const char *in_e
size_t sofar;
if (errno != E2BIG) {
free(out);
- iconv_close(conv);
return NULL;
}
/* insz has remaining number of bytes.
@@ -478,6 +470,20 @@ char *reencode_string(const char *in, const char *out_encoding, const char *in_e
break;
}
}
+ return out;
+}
+
+char *reencode_string(const char *in, const char *out_encoding, const char *in_encoding)
+{
+ iconv_t conv;
+ char *out;
+
+ if (!in_encoding)
+ return NULL;
+ conv = iconv_open(out_encoding, in_encoding);
+ if (conv == (iconv_t) -1)
+ return NULL;
+ out = reencode_string_iconv(in, strlen(in), conv);
iconv_close(conv);
return out;
}
diff --git a/utf8.h b/utf8.h
index 81f2c82..3c0ae76 100644
--- a/utf8.h
+++ b/utf8.h
@@ -14,6 +14,7 @@ int strbuf_add_wrapped_bytes(struct strbuf *buf, const char *data, int len,
int indent, int indent2, int width);
#ifndef NO_ICONV
+char *reencode_string_iconv(const char *in, size_t insz, iconv_t conv);
char *reencode_string(const char *in, const char *out_encoding, const char *in_encoding);
#else
#define reencode_string(a,b,c) NULL
diff --git a/vcs-svn/fast_export.c b/vcs-svn/fast_export.c
index b823b85..1f04697 100644
--- a/vcs-svn/fast_export.c
+++ b/vcs-svn/fast_export.c
@@ -42,11 +42,6 @@ void fast_export_deinit(void)
die_errno("error closing fast-import feedback stream");
}
-void fast_export_reset(void)
-{
- buffer_reset(&report_buffer);
-}
-
void fast_export_delete(const char *path)
{
putchar('D');
@@ -163,7 +158,7 @@ static int parse_cat_response_line(const char *header, off_t *len)
if (ends_with(header, headerlen, " missing"))
return error("cat-blob reports missing blob: %s", header);
- type = memmem(header, headerlen, " blob ", strlen(" blob "));
+ type = strstr(header, " blob ");
if (!type)
return error("cat-blob header has wrong object type: %s", header);
n = strtoumax(type + strlen(" blob "), (char **) &end, 10);
@@ -259,7 +254,7 @@ static int parse_ls_response(const char *response, uint32_t *mode,
}
/* Mode. */
- if (response_end - response < strlen("100644") ||
+ if (response_end - response < (signed) strlen("100644") ||
response[strlen("100644")] != ' ')
die("invalid ls response: missing mode: %s", response);
*mode = 0;
@@ -272,7 +267,7 @@ static int parse_ls_response(const char *response, uint32_t *mode,
}
/* ' blob ' or ' tree ' */
- if (response_end - response < strlen(" blob ") ||
+ if (response_end - response < (signed) strlen(" blob ") ||
(response[1] != 'b' && response[1] != 't'))
die("unexpected ls response: not a tree or blob: %s", response);
response += strlen(" blob ");
diff --git a/vcs-svn/fast_export.h b/vcs-svn/fast_export.h
index aa629f5..8823aca 100644
--- a/vcs-svn/fast_export.h
+++ b/vcs-svn/fast_export.h
@@ -6,7 +6,6 @@ struct line_buffer;
void fast_export_init(int fd);
void fast_export_deinit(void);
-void fast_export_reset(void);
void fast_export_delete(const char *path);
void fast_export_modify(const char *path, uint32_t mode, const char *dataref);
diff --git a/vcs-svn/line_buffer.c b/vcs-svn/line_buffer.c
index 01fcb84..57cc1ce 100644
--- a/vcs-svn/line_buffer.c
+++ b/vcs-svn/line_buffer.c
@@ -124,7 +124,3 @@ off_t buffer_skip_bytes(struct line_buffer *buf, off_t nbytes)
}
return done;
}
-
-void buffer_reset(struct line_buffer *buf)
-{
-}
diff --git a/vcs-svn/line_buffer.h b/vcs-svn/line_buffer.h
index 8901f21..ee23b4f 100644
--- a/vcs-svn/line_buffer.h
+++ b/vcs-svn/line_buffer.h
@@ -14,7 +14,6 @@ struct line_buffer {
int buffer_init(struct line_buffer *buf, const char *filename);
int buffer_fdinit(struct line_buffer *buf, int fd);
int buffer_deinit(struct line_buffer *buf);
-void buffer_reset(struct line_buffer *buf);
int buffer_tmpfile_init(struct line_buffer *buf);
FILE *buffer_tmpfile_rewind(struct line_buffer *buf); /* prepare to write. */
diff --git a/vcs-svn/sliding_window.c b/vcs-svn/sliding_window.c
index ec2707c..f11d490 100644
--- a/vcs-svn/sliding_window.c
+++ b/vcs-svn/sliding_window.c
@@ -54,7 +54,7 @@ int move_window(struct sliding_view *view, off_t off, size_t width)
return -1;
if (off < view->off || off + width < view->off + view->width)
return error("invalid delta: window slides left");
- if (view->max_off >= 0 && view->max_off < off + width)
+ if (view->max_off >= 0 && view->max_off < off + (off_t) width)
return error("delta preimage ends early");
file_offset = view->off + view->buf.len;
diff --git a/vcs-svn/svndiff.c b/vcs-svn/svndiff.c
index 1647c1a..74c97c4 100644
--- a/vcs-svn/svndiff.c
+++ b/vcs-svn/svndiff.c
@@ -77,8 +77,9 @@ static int error_short_read(struct line_buffer *input)
static int read_chunk(struct line_buffer *delta, off_t *delta_len,
struct strbuf *buf, size_t len)
{
+ assert(*delta_len >= 0);
strbuf_reset(buf);
- if (len > *delta_len ||
+ if (len > (uintmax_t) *delta_len ||
buffer_read_binary(delta, buf, len) != len)
return error_short_read(delta);
*delta_len -= buf->len;
@@ -258,6 +259,7 @@ static int apply_window_in_core(struct window *ctx)
static int apply_one_window(struct line_buffer *delta, off_t *delta_len,
struct sliding_view *preimage, FILE *out)
{
+ int rv = -1;
struct window ctx = WINDOW_INIT(preimage);
size_t out_len;
size_t instructions_len;
@@ -275,27 +277,26 @@ static int apply_one_window(struct line_buffer *delta, off_t *delta_len,
if (apply_window_in_core(&ctx))
goto error_out;
if (ctx.out.len != out_len) {
- error("invalid delta: incorrect postimage length");
+ rv = error("invalid delta: incorrect postimage length");
goto error_out;
}
if (write_strbuf(&ctx.out, out))
goto error_out;
- window_release(&ctx);
- return 0;
+ rv = 0;
error_out:
window_release(&ctx);
- return -1;
+ return rv;
}
int svndiff0_apply(struct line_buffer *delta, off_t delta_len,
struct sliding_view *preimage, FILE *postimage)
{
- assert(delta && preimage && postimage);
+ assert(delta && preimage && postimage && delta_len >= 0);
if (read_magic(delta, &delta_len))
return -1;
while (delta_len) { /* For each window: */
- off_t pre_off = pre_off; /* stupid GCC... */
+ off_t pre_off = -1;
size_t pre_len;
if (read_offset(delta, &pre_off, &delta_len) ||
diff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c
index 0899790..2b168ae 100644
--- a/vcs-svn/svndump.c
+++ b/vcs-svn/svndump.c
@@ -34,14 +34,13 @@
#define NODE_CTX 2 /* node metadata */
#define INTERNODE_CTX 3 /* between nodes */
-#define LENGTH_UNKNOWN (~0)
#define DATE_RFC2822_LEN 31
static struct line_buffer input = LINE_BUFFER_INIT;
static struct {
- uint32_t action, propLength, srcRev, type;
- off_t text_length;
+ uint32_t action, srcRev, type;
+ off_t prop_length, text_length;
struct strbuf src, dst;
uint32_t text_delta, prop_delta;
} node_ctx;
@@ -61,7 +60,7 @@ static void reset_node_ctx(char *fname)
{
node_ctx.type = 0;
node_ctx.action = NODEACT_UNKNOWN;
- node_ctx.propLength = LENGTH_UNKNOWN;
+ node_ctx.prop_length = -1;
node_ctx.text_length = -1;
strbuf_reset(&node_ctx.src);
node_ctx.srcRev = 0;
@@ -209,7 +208,7 @@ static void read_props(void)
static void handle_node(void)
{
const uint32_t type = node_ctx.type;
- const int have_props = node_ctx.propLength != LENGTH_UNKNOWN;
+ const int have_props = node_ctx.prop_length != -1;
const int have_text = node_ctx.text_length != -1;
/*
* Old text for this node:
@@ -273,7 +272,7 @@ static void handle_node(void)
if (have_props) {
if (!node_ctx.prop_delta)
node_ctx.type = type;
- if (node_ctx.propLength)
+ if (node_ctx.prop_length)
read_props();
}
@@ -361,7 +360,7 @@ void svndump_read(const char *url)
reset_rev_ctx(atoi(val));
break;
case sizeof("Node-path"):
- if (prefixcmp(t, "Node-"))
+ if (constcmp(t, "Node-"))
continue;
if (!constcmp(t + strlen("Node-"), "path")) {
if (active_ctx == NODE_CTX)
@@ -409,22 +408,26 @@ void svndump_read(const char *url)
node_ctx.srcRev = atoi(val);
break;
case sizeof("Text-content-length"):
- if (!constcmp(t, "Text-content-length")) {
+ if (constcmp(t, "Text") && constcmp(t, "Prop"))
+ continue;
+ if (constcmp(t + 4, "-content-length"))
+ continue;
+ {
char *end;
- uintmax_t textlen;
+ uintmax_t len;
- textlen = strtoumax(val, &end, 10);
+ len = strtoumax(val, &end, 10);
if (!isdigit(*val) || *end)
die("invalid dump: non-numeric length %s", val);
- if (textlen > maximum_signed_value_of_type(off_t))
+ if (len > maximum_signed_value_of_type(off_t))
die("unrepresentable length in dump: %s", val);
- node_ctx.text_length = (off_t) textlen;
+
+ if (*t == 'T')
+ node_ctx.text_length = (off_t) len;
+ else
+ node_ctx.prop_length = (off_t) len;
break;
}
- if (constcmp(t, "Prop-content-length"))
- continue;
- node_ctx.propLength = atoi(val);
- break;
case sizeof("Text-delta"):
if (!constcmp(t, "Text-delta")) {
node_ctx.text_delta = !strcmp(val, "true");
@@ -499,8 +502,6 @@ void svndump_deinit(void)
void svndump_reset(void)
{
- fast_export_reset();
- buffer_reset(&input);
strbuf_release(&dump_ctx.uuid);
strbuf_release(&dump_ctx.url);
strbuf_release(&rev_ctx.log);
diff --git a/version.c b/version.c
new file mode 100644
index 0000000..6106a80
--- /dev/null
+++ b/version.c
@@ -0,0 +1,38 @@
+#include "git-compat-util.h"
+#include "version.h"
+#include "strbuf.h"
+
+const char git_version_string[] = GIT_VERSION;
+
+const char *git_user_agent(void)
+{
+ static const char *agent = NULL;
+
+ if (!agent) {
+ agent = getenv("GIT_USER_AGENT");
+ if (!agent)
+ agent = GIT_USER_AGENT;
+ }
+
+ return agent;
+}
+
+const char *git_user_agent_sanitized(void)
+{
+ static const char *agent = NULL;
+
+ if (!agent) {
+ struct strbuf buf = STRBUF_INIT;
+ int i;
+
+ strbuf_addstr(&buf, git_user_agent());
+ strbuf_trim(&buf);
+ for (i = 0; i < buf.len; i++) {
+ if (buf.buf[i] <= 32 || buf.buf[i] >= 127)
+ buf.buf[i] = '.';
+ }
+ agent = buf.buf;
+ }
+
+ return agent;
+}
diff --git a/version.h b/version.h
new file mode 100644
index 0000000..6911a4f
--- /dev/null
+++ b/version.h
@@ -0,0 +1,9 @@
+#ifndef VERSION_H
+#define VERSION_H
+
+extern const char git_version_string[];
+
+const char *git_user_agent(void);
+const char *git_user_agent_sanitized(void);
+
+#endif /* VERSION_H */
diff --git a/wrapper.c b/wrapper.c
index b5e33e4..68739aa 100644
--- a/wrapper.c
+++ b/wrapper.c
@@ -403,6 +403,19 @@ int remove_or_warn(unsigned int mode, const char *file)
return S_ISGITLINK(mode) ? rmdir_or_warn(file) : unlink_or_warn(file);
}
+void warn_on_inaccessible(const char *path)
+{
+ warning(_("unable to access '%s': %s"), path, strerror(errno));
+}
+
+int access_or_warn(const char *path, int mode)
+{
+ int ret = access(path, mode);
+ if (ret && errno != ENOENT)
+ warn_on_inaccessible(path);
+ return ret;
+}
+
struct passwd *xgetpwuid_self(void)
{
struct passwd *pw;
diff --git a/wt-status.c b/wt-status.c
index dd6d8c4..2a9658b 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -12,6 +12,7 @@
#include "refs.h"
#include "submodule.h"
#include "column.h"
+#include "strbuf.h"
static char default_wt_status_colors[][COLOR_MAXLEN] = {
GIT_COLOR_NORMAL, /* WT_STATUS_HEADER */
@@ -99,8 +100,8 @@ void status_printf(struct wt_status *s, const char *color,
va_end(ap);
}
-void status_printf_more(struct wt_status *s, const char *color,
- const char *fmt, ...)
+static void status_printf_more(struct wt_status *s, const char *color,
+ const char *fmt, ...)
{
va_list ap;
@@ -130,9 +131,34 @@ void wt_status_prepare(struct wt_status *s)
static void wt_status_print_unmerged_header(struct wt_status *s)
{
+ int i;
+ int del_mod_conflict = 0;
+ int both_deleted = 0;
+ int not_deleted = 0;
const char *c = color(WT_STATUS_HEADER, s);
status_printf_ln(s, c, _("Unmerged paths:"));
+
+ for (i = 0; i < s->change.nr; i++) {
+ struct string_list_item *it = &(s->change.items[i]);
+ struct wt_status_change_data *d = it->util;
+
+ switch (d->stagemask) {
+ case 0:
+ break;
+ case 1:
+ both_deleted = 1;
+ break;
+ case 3:
+ case 5:
+ del_mod_conflict = 1;
+ break;
+ default:
+ not_deleted = 1;
+ break;
+ }
+ }
+
if (!advice_status_hints)
return;
if (s->whence != FROM_COMMIT)
@@ -141,7 +167,17 @@ static void wt_status_print_unmerged_header(struct wt_status *s)
status_printf_ln(s, c, _(" (use \"git reset %s <file>...\" to unstage)"), s->reference);
else
status_printf_ln(s, c, _(" (use \"git rm --cached <file>...\" to unstage)"));
- status_printf_ln(s, c, _(" (use \"git add/rm <file>...\" as appropriate to mark resolution)"));
+
+ if (!both_deleted) {
+ if (!del_mod_conflict)
+ status_printf_ln(s, c, _(" (use \"git add <file>...\" to mark resolution)"));
+ else
+ status_printf_ln(s, c, _(" (use \"git add/rm <file>...\" as appropriate to mark resolution)"));
+ } else if (!del_mod_conflict && !not_deleted) {
+ status_printf_ln(s, c, _(" (use \"git rm <file>...\" to mark resolution)"));
+ } else {
+ status_printf_ln(s, c, _(" (use \"git add/rm <file>...\" as appropriate to mark resolution)"));
+ }
status_printf_ln(s, c, "");
}
@@ -185,7 +221,7 @@ static void wt_status_print_other_header(struct wt_status *s,
const char *how)
{
const char *c = color(WT_STATUS_HEADER, s);
- status_printf_ln(s, c, _("%s files:"), what);
+ status_printf_ln(s, c, "%s:", what);
if (!advice_status_hints)
return;
status_printf_ln(s, c, _(" (use \"git %s <file>...\" to include in what will be committed)"), how);
@@ -728,6 +764,211 @@ static void wt_status_print_tracking(struct wt_status *s)
color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "#");
}
+static int has_unmerged(struct wt_status *s)
+{
+ int i;
+
+ for (i = 0; i < s->change.nr; i++) {
+ struct wt_status_change_data *d;
+ d = s->change.items[i].util;
+ if (d->stagemask)
+ return 1;
+ }
+ return 0;
+}
+
+static void show_merge_in_progress(struct wt_status *s,
+ struct wt_status_state *state,
+ const char *color)
+{
+ if (has_unmerged(s)) {
+ status_printf_ln(s, color, _("You have unmerged paths."));
+ if (advice_status_hints)
+ status_printf_ln(s, color,
+ _(" (fix conflicts and run \"git commit\")"));
+ } else {
+ status_printf_ln(s, color,
+ _("All conflicts fixed but you are still merging."));
+ if (advice_status_hints)
+ status_printf_ln(s, color,
+ _(" (use \"git commit\" to conclude merge)"));
+ }
+ wt_status_print_trailer(s);
+}
+
+static void show_am_in_progress(struct wt_status *s,
+ struct wt_status_state *state,
+ const char *color)
+{
+ status_printf_ln(s, color,
+ _("You are in the middle of an am session."));
+ if (state->am_empty_patch)
+ status_printf_ln(s, color,
+ _("The current patch is empty."));
+ if (advice_status_hints) {
+ if (!state->am_empty_patch)
+ status_printf_ln(s, color,
+ _(" (fix conflicts and then run \"git am --resolved\")"));
+ status_printf_ln(s, color,
+ _(" (use \"git am --skip\" to skip this patch)"));
+ status_printf_ln(s, color,
+ _(" (use \"git am --abort\" to restore the original branch)"));
+ }
+ wt_status_print_trailer(s);
+}
+
+static char *read_line_from_git_path(const char *filename)
+{
+ struct strbuf buf = STRBUF_INIT;
+ FILE *fp = fopen(git_path("%s", filename), "r");
+ if (!fp) {
+ strbuf_release(&buf);
+ return NULL;
+ }
+ strbuf_getline(&buf, fp, '\n');
+ if (!fclose(fp)) {
+ return strbuf_detach(&buf, NULL);
+ } else {
+ strbuf_release(&buf);
+ return NULL;
+ }
+}
+
+static int split_commit_in_progress(struct wt_status *s)
+{
+ int split_in_progress = 0;
+ char *head = read_line_from_git_path("HEAD");
+ char *orig_head = read_line_from_git_path("ORIG_HEAD");
+ char *rebase_amend = read_line_from_git_path("rebase-merge/amend");
+ char *rebase_orig_head = read_line_from_git_path("rebase-merge/orig-head");
+
+ if (!head || !orig_head || !rebase_amend || !rebase_orig_head ||
+ !s->branch || strcmp(s->branch, "HEAD"))
+ return split_in_progress;
+
+ if (!strcmp(rebase_amend, rebase_orig_head)) {
+ if (strcmp(head, rebase_amend))
+ split_in_progress = 1;
+ } else if (strcmp(orig_head, rebase_orig_head)) {
+ split_in_progress = 1;
+ }
+
+ if (!s->amend && !s->nowarn && !s->workdir_dirty)
+ split_in_progress = 0;
+
+ free(head);
+ free(orig_head);
+ free(rebase_amend);
+ free(rebase_orig_head);
+ return split_in_progress;
+}
+
+static void show_rebase_in_progress(struct wt_status *s,
+ struct wt_status_state *state,
+ const char *color)
+{
+ struct stat st;
+
+ if (has_unmerged(s)) {
+ status_printf_ln(s, color, _("You are currently rebasing."));
+ if (advice_status_hints) {
+ status_printf_ln(s, color,
+ _(" (fix conflicts and then run \"git rebase --continue\")"));
+ status_printf_ln(s, color,
+ _(" (use \"git rebase --skip\" to skip this patch)"));
+ status_printf_ln(s, color,
+ _(" (use \"git rebase --abort\" to check out the original branch)"));
+ }
+ } else if (state->rebase_in_progress || !stat(git_path("MERGE_MSG"), &st)) {
+ status_printf_ln(s, color, _("You are currently rebasing."));
+ if (advice_status_hints)
+ status_printf_ln(s, color,
+ _(" (all conflicts fixed: run \"git rebase --continue\")"));
+ } else if (split_commit_in_progress(s)) {
+ status_printf_ln(s, color, _("You are currently splitting a commit during a rebase."));
+ if (advice_status_hints)
+ status_printf_ln(s, color,
+ _(" (Once your working directory is clean, run \"git rebase --continue\")"));
+ } else {
+ status_printf_ln(s, color, _("You are currently editing a commit during a rebase."));
+ if (advice_status_hints && !s->amend) {
+ status_printf_ln(s, color,
+ _(" (use \"git commit --amend\" to amend the current commit)"));
+ status_printf_ln(s, color,
+ _(" (use \"git rebase --continue\" once you are satisfied with your changes)"));
+ }
+ }
+ wt_status_print_trailer(s);
+}
+
+static void show_cherry_pick_in_progress(struct wt_status *s,
+ struct wt_status_state *state,
+ const char *color)
+{
+ status_printf_ln(s, color, _("You are currently cherry-picking."));
+ if (advice_status_hints) {
+ if (has_unmerged(s))
+ status_printf_ln(s, color,
+ _(" (fix conflicts and run \"git commit\")"));
+ else
+ status_printf_ln(s, color,
+ _(" (all conflicts fixed: run \"git commit\")"));
+ }
+ wt_status_print_trailer(s);
+}
+
+static void show_bisect_in_progress(struct wt_status *s,
+ struct wt_status_state *state,
+ const char *color)
+{
+ status_printf_ln(s, color, _("You are currently bisecting."));
+ if (advice_status_hints)
+ status_printf_ln(s, color,
+ _(" (use \"git bisect reset\" to get back to the original branch)"));
+ wt_status_print_trailer(s);
+}
+
+static void wt_status_print_state(struct wt_status *s)
+{
+ const char *state_color = color(WT_STATUS_HEADER, s);
+ struct wt_status_state state;
+ struct stat st;
+
+ memset(&state, 0, sizeof(state));
+
+ if (!stat(git_path("MERGE_HEAD"), &st)) {
+ state.merge_in_progress = 1;
+ } else if (!stat(git_path("rebase-apply"), &st)) {
+ if (!stat(git_path("rebase-apply/applying"), &st)) {
+ state.am_in_progress = 1;
+ if (!stat(git_path("rebase-apply/patch"), &st) && !st.st_size)
+ state.am_empty_patch = 1;
+ } else {
+ state.rebase_in_progress = 1;
+ }
+ } else if (!stat(git_path("rebase-merge"), &st)) {
+ if (!stat(git_path("rebase-merge/interactive"), &st))
+ state.rebase_interactive_in_progress = 1;
+ else
+ state.rebase_in_progress = 1;
+ } else if (!stat(git_path("CHERRY_PICK_HEAD"), &st)) {
+ state.cherry_pick_in_progress = 1;
+ }
+ if (!stat(git_path("BISECT_LOG"), &st))
+ state.bisect_in_progress = 1;
+
+ if (state.merge_in_progress)
+ show_merge_in_progress(s, &state, state_color);
+ else if (state.am_in_progress)
+ show_am_in_progress(s, &state, state_color);
+ else if (state.rebase_in_progress || state.rebase_interactive_in_progress)
+ show_rebase_in_progress(s, &state, state_color);
+ else if (state.cherry_pick_in_progress)
+ show_cherry_pick_in_progress(s, &state, state_color);
+ if (state.bisect_in_progress)
+ show_bisect_in_progress(s, &state, state_color);
+}
+
void wt_status_print(struct wt_status *s)
{
const char *branch_color = color(WT_STATUS_ONBRANCH, s);
@@ -750,6 +991,7 @@ void wt_status_print(struct wt_status *s)
wt_status_print_tracking(s);
}
+ wt_status_print_state(s);
if (s->is_initial) {
status_printf_ln(s, color(WT_STATUS_HEADER, s), "");
status_printf_ln(s, color(WT_STATUS_HEADER, s), _("Initial commit"));
@@ -766,9 +1008,9 @@ void wt_status_print(struct wt_status *s)
wt_status_print_submodule_summary(s, 1); /* unstaged */
}
if (s->show_untracked_files) {
- wt_status_print_other(s, &s->untracked, _("Untracked"), "add");
+ wt_status_print_other(s, &s->untracked, _("Untracked files"), "add");
if (s->show_ignored_files)
- wt_status_print_other(s, &s->ignored, _("Ignored"), "add -f");
+ wt_status_print_other(s, &s->ignored, _("Ignored files"), "add -f");
} else if (s->commitable)
status_printf_ln(s, GIT_COLOR_NORMAL, _("Untracked files not listed%s"),
advice_status_hints
@@ -781,23 +1023,31 @@ void wt_status_print(struct wt_status *s)
status_printf_ln(s, GIT_COLOR_NORMAL, _("No changes"));
else if (s->nowarn)
; /* nothing */
- else if (s->workdir_dirty)
- printf(_("no changes added to commit%s\n"),
- advice_status_hints
- ? _(" (use \"git add\" and/or \"git commit -a\")") : "");
- else if (s->untracked.nr)
- printf(_("nothing added to commit but untracked files present%s\n"),
- advice_status_hints
- ? _(" (use \"git add\" to track)") : "");
- else if (s->is_initial)
- printf(_("nothing to commit%s\n"), advice_status_hints
- ? _(" (create/copy files and use \"git add\" to track)") : "");
- else if (!s->show_untracked_files)
- printf(_("nothing to commit%s\n"), advice_status_hints
- ? _(" (use -u to show untracked files)") : "");
- else
- printf(_("nothing to commit%s\n"), advice_status_hints
- ? _(" (working directory clean)") : "");
+ else if (s->workdir_dirty) {
+ if (advice_status_hints)
+ printf(_("no changes added to commit "
+ "(use \"git add\" and/or \"git commit -a\")\n"));
+ else
+ printf(_("no changes added to commit\n"));
+ } else if (s->untracked.nr) {
+ if (advice_status_hints)
+ printf(_("nothing added to commit but untracked files "
+ "present (use \"git add\" to track)\n"));
+ else
+ printf(_("nothing added to commit but untracked files present\n"));
+ } else if (s->is_initial) {
+ if (advice_status_hints)
+ printf(_("nothing to commit (create/copy files "
+ "and use \"git add\" to track)\n"));
+ else
+ printf(_("nothing to commit\n"));
+ } else if (!s->show_untracked_files) {
+ if (advice_status_hints)
+ printf(_("nothing to commit (use -u to show untracked files)\n"));
+ else
+ printf(_("nothing to commit\n"));
+ } else
+ printf(_("nothing to commit, working directory clean\n"));
}
}
diff --git a/wt-status.h b/wt-status.h
index 14aa9f7..236b41f 100644
--- a/wt-status.h
+++ b/wt-status.h
@@ -71,6 +71,16 @@ struct wt_status {
struct string_list ignored;
};
+struct wt_status_state {
+ int merge_in_progress;
+ int am_in_progress;
+ int am_empty_patch;
+ int rebase_in_progress;
+ int rebase_interactive_in_progress;
+ int cherry_pick_in_progress;
+ int bisect_in_progress;
+};
+
void wt_status_prepare(struct wt_status *s);
void wt_status_print(struct wt_status *s);
void wt_status_collect(struct wt_status *s);
@@ -82,7 +92,5 @@ void status_printf_ln(struct wt_status *s, const char *color, const char *fmt, .
;
void status_printf(struct wt_status *s, const char *color, const char *fmt, ...)
;
-void status_printf_more(struct wt_status *s, const char *color, const char *fmt, ...)
- __attribute__((format(printf, 3, 4)));
#endif /* STATUS_H */